diff -Nru a/CREDITS b/CREDITS
--- a/CREDITS	Tue Apr  8 02:31:12 2003
+++ b/CREDITS	Fri May  9 09:26:36 2003
@@ -1549,6 +1549,18 @@
 S: 8103 Rein
 S: Austria
 
+N: Mitsuru Kanda
+E: mk@linux-ipv6.org
+E: mk@isl.rdc.toshiba.co.jp
+E: mk@karaba.org
+W: http://www.karaba.org/~mk/
+P: 1024D/2EC7E30D 9A35 D378 F084 9EA4 EFBA  925B 1C93 B376 F0EF BE59
+D: IPsec, IPv6
+D: USAGI/WIDE Project, TOSHIBA CORPORATION
+S: 2-47-8, Takinogawa,
+S: Kita, Tokyo 114-0023
+S: Japan
+
 N: Jan Kara
 E: jack@atrey.karlin.mff.cuni.cz
 E: jack@suse.cz
@@ -2200,6 +2212,17 @@
 S: Garland, Texas 75044
 S: USA
 
+N: Kazunori Miyazawa
+E: miyazawa@linux-ipv6.org
+E: Kazunori.Miyazawa@jp.yokogawa.com
+E: kazunori@miyazawa.org
+W: http://www.miyazawa.org/~kazunori/
+D: IPsec, IPv6
+D: USAGI/WIDE Project, Yokogawa Electric Corporation
+S: 2-20-4-203, Nakacho,
+S: Musashino, Tokyo 180-0006
+S: Japan
+
 N: Patrick Mochel
 E: mochel@osdl.org
 E: mochelp@infinity.powertie.org
@@ -3027,8 +3050,8 @@
 W: http://www.cs.helsinki.fi/Linus.Torvalds
 P: 1024/A86B35C5 96 54 50 29 EC 11 44 7A  BE 67 3C 24 03 13 62 C8
 D: Original kernel hacker
-S: 1050 Woodduck Avenue
-S: Santa Clara, California 95051
+S: 3990 Freedom Circle
+S: Santa Clara, California 95054
 S: USA
 
 N: Marcelo W. Tosatti
@@ -3440,6 +3463,17 @@
 E: yokota@netlab.is.tsukuba.ac.jp
 D: Workbit NinjaSCSI-3/32Bi PCMCIA driver
 D: Workbit NinjaSCSI-32Bi/UDE driver
+S: Japan
+
+N: Hideaki YOSHIFUJI
+E: hideaki@yoshifuji.org
+E: yoshfuji@linux-ipv6.org
+W: http://www.yoshifuji.org/~hideaki/
+P: 1024D/E0620EEA 9022 65EB 1ECF 3AD1 0BDF  80D8 4807 F894 E062 0EEA
+D: IPv6 and other networking related stuff
+D: USAGI/WIDE Project, The University of Tokyo
+S: Green House #102, 1-15-5, Nishikata, 
+S: Bunkyo, Tokyo 113-0024
 S: Japan
 
 N: Eric Youngdale
diff -Nru a/Documentation/BK-usage/bk-kernel-howto.txt b/Documentation/BK-usage/bk-kernel-howto.txt
--- a/Documentation/BK-usage/bk-kernel-howto.txt	Sat Oct 26 19:54:59 2002
+++ b/Documentation/BK-usage/bk-kernel-howto.txt	Sun May 11 11:44:17 2003
@@ -273,3 +273,11 @@
 A tag is just an alias for a specific changeset... and since changesets
 are ordered, a tag is thus a marker for a specific point in time (or
 specific state of the tree).
+
+
+3) Is there an easy way to generate One Big Patch versus mainline,
+   for my long-lived kernel branch?
+A. Yes.  This requires BK 3.x, though.
+
+	bk export -tpatch -r`bk repogca bk://linux.bkbits.net/linux-2.5`,+
+
diff -Nru a/Documentation/Changes b/Documentation/Changes
--- a/Documentation/Changes	Fri Apr  4 09:04:01 2003
+++ b/Documentation/Changes	Wed May  7 21:17:51 2003
@@ -50,7 +50,7 @@
 
 o  Gnu C                  2.95.3                  # gcc --version
 o  Gnu make               3.78                    # make --version
-o  binutils               2.9.5.0.25              # ld -v
+o  binutils               2.12                    # ld -v
 o  util-linux             2.10o                   # fdformat --version
 o  module-init-tools      0.9.9                   # depmod -V
 o  e2fsprogs              1.29                    # tune2fs
diff -Nru a/Documentation/driver-model/binding.txt b/Documentation/driver-model/binding.txt
--- a/Documentation/driver-model/binding.txt	Fri Jan 10 13:28:21 2003
+++ b/Documentation/driver-model/binding.txt	Wed Apr 16 13:57:23 2003
@@ -11,11 +11,11 @@
 Bus
 ~~~
 
-The bus type structure contains a list of all devices that on that bus
+The bus type structure contains a list of all devices that are on that bus
 type in the system. When device_register is called for a device, it is
 inserted into the end of this list. The bus object also contains a
 list of all drivers of that bus type. When driver_register is called
-for a driver, it is inserted into the end of this list. These are the
+for a driver, it is inserted at the end of this list. These are the
 two events which trigger driver binding.
 
 
@@ -42,7 +42,7 @@
 ~~~~~~~~~~~~
 
 Upon the successful completion of probe, the device is registered with
-the class to which it belongs. Device drivers belong to one and only
+the class to which it belongs. Device drivers belong to one and only one
 class, and that is set in the driver's devclass field. 
 devclass_add_device is called to enumerate the device within the class
 and actually register it with the class, which happens with the
@@ -61,7 +61,7 @@
 
 
 sysfs
-~~~~~~~~
+~~~~~
 
 A symlink is created in the bus's 'devices' directory that points to
 the device's directory in the physical hierarchy.
diff -Nru a/Documentation/driver-model/bus.txt b/Documentation/driver-model/bus.txt
--- a/Documentation/driver-model/bus.txt	Tue Jan 14 07:45:55 2003
+++ b/Documentation/driver-model/bus.txt	Wed Apr 16 13:57:23 2003
@@ -58,7 +58,7 @@
 
 The format of device ID structures and the semantics for comparing
 them are inherently bus-specific. Drivers typically declare an array
-of device IDs of device they support that reside in a bus-specific
+of device IDs of devices they support that reside in a bus-specific
 driver structure. 
 
 The purpose of the match callback is provide the bus an opportunity to
@@ -153,7 +153,7 @@
 	    |-- agpgart
 	    `-- e100
 
-Each device that is discovered a bus of that type gets a symlink in
+Each device that is discovered on a bus of that type gets a symlink in
 the bus's devices directory to the device's directory in the physical
 hierarchy:
 
diff -Nru a/Documentation/driver-model/class.txt b/Documentation/driver-model/class.txt
--- a/Documentation/driver-model/class.txt	Fri Jan 10 13:28:21 2003
+++ b/Documentation/driver-model/class.txt	Wed Apr 16 13:57:23 2003
@@ -105,7 +105,7 @@
 
 
 Drivers registered with the class get a symlink in the drivers/ directory 
-that points the driver's directory (under its bus directory):
+that points to the driver's directory (under its bus directory):
 
    class/
    `-- input
diff -Nru a/Documentation/driver-model/device.txt b/Documentation/driver-model/device.txt
--- a/Documentation/driver-model/device.txt	Fri Jan 10 13:28:21 2003
+++ b/Documentation/driver-model/device.txt	Wed Apr 16 13:57:23 2003
@@ -47,11 +47,13 @@
 
 children:      List of child devices.
 
+parent:        *** FIXME ***
+
 name:	       ASCII description of device. 
 	       Example: " 3Com Corporation 3c905 100BaseTX [Boomerang]"
 
 bus_id:	       ASCII representation of device's bus position. This 
-	       field should a name unique across all devices on the
+	       field should be a name unique across all devices on the
 	       bus type the device belongs to. 
 
 	       Example: PCI bus_ids are in the form of
@@ -66,12 +68,12 @@
 
 dir:	       Device's sysfs directory.
 
+class_num:     Class-enumerated value of the device.
+
 driver:	       Pointer to struct device_driver that controls the device.
 
 driver_data:   Driver-specific data.
 
-class_num:     Class-enumerated value of the device.
-
 platform_data: Platform data specific to the device.
 
 current_state: Current power state of the device.
@@ -108,7 +110,7 @@
 if the reference is not already 0 (if it's in the process of being
 removed already).
 
-A driver can take use the lock in the device structure using: 
+A driver can access the lock in the device structure using: 
 
 void lock_device(struct device * dev);
 void unlock_device(struct device * dev);
diff -Nru a/Documentation/driver-model/driver.txt b/Documentation/driver-model/driver.txt
--- a/Documentation/driver-model/driver.txt	Tue Mar 11 10:20:18 2003
+++ b/Documentation/driver-model/driver.txt	Wed Apr 16 13:57:23 2003
@@ -63,9 +63,9 @@
 model because the bus they belong to has a bus-specific structure with
 bus-specific fields that cannot be generalized. 
 
-The most common example this are device ID structures. A driver
+The most common example of this are device ID structures. A driver
 typically defines an array of device IDs that it supports. The format
-of this structure and the semantics for comparing device IDs is
+of these structures and the semantics for comparing device IDs are
 completely bus-specific. Defining them as bus-specific entities would
 sacrifice type-safety, so we keep bus-specific structures around. 
 
@@ -77,8 +77,8 @@
        struct device_driver	  driver;
 };
 
-A definition that included bus-specific fields would look something
-like (using the eepro100 driver again):
+A definition that included bus-specific fields would look like
+(using the eepro100 driver again):
 
 static struct pci_driver eepro100_driver = {
        .id_table       = eepro100_pci_tbl,
@@ -109,7 +109,7 @@
 Most drivers, however, will have a bus-specific structure and will
 need to register with the bus using something like pci_driver_register.
 
-It is important that drivers register their drivers as early as
+It is important that drivers register their driver structure as early as
 possible. Registration with the core initializes several fields in the
 struct device_driver object, including the reference count and the
 lock. These fields are assumed to be valid at all times and may be
@@ -148,7 +148,7 @@
 
 
 sysfs
-~~~~~~~~
+~~~~~
 
 When a driver is registered, a sysfs directory is created in its
 bus's directory. In this directory, the driver can export an interface
@@ -205,7 +205,7 @@
 user-defined policy.
 
 SUSPEND_NOTIFY notifies the device that a suspend transition is about
-to happen. This happens on system power state transition to verify
+to happen. This happens on system power state transitions to verify
 that all devices can successfully suspend.
 
 A driver may choose to fail on this call, which should cause the
diff -Nru a/Documentation/driver-model/interface.txt b/Documentation/driver-model/interface.txt
--- a/Documentation/driver-model/interface.txt	Fri Jan 10 13:28:21 2003
+++ b/Documentation/driver-model/interface.txt	Wed Apr 16 13:57:23 2003
@@ -82,7 +82,7 @@
 and the enumerated value is stored in the struct intf_data for that device. 
 
 sysfs
-~~~~~~~~
+~~~~~
 Each interface is given a directory in the directory of the device
 class it belongs to:
 
@@ -120,10 +120,10 @@
 
 Many interfaces have a major number associated with them and each
 device gets a minor number. Or, multiple interfaces might share one
-major number, and each get receive a range of minor numbers (like in
+major number, and each will receive a range of minor numbers (like in
 the case of input devices).
 
 These major and minor numbers could be stored in the interface
-structure. Major and minor allocation could happen when the interface
+structure. Major and minor allocations could happen when the interface
 is registered with the class, or via a helper function. 
 
diff -Nru a/Documentation/driver-model/overview.txt b/Documentation/driver-model/overview.txt
--- a/Documentation/driver-model/overview.txt	Mon Mar 31 15:55:40 2003
+++ b/Documentation/driver-model/overview.txt	Wed Apr 16 13:57:23 2003
@@ -9,7 +9,7 @@
 ~~~~~~~~
 
 This driver model is a unification of all the current, disparate driver models
-that are currently in the kernel. It is intended is to augment the
+that are currently in the kernel. It is intended to augment the
 bus-specific drivers for bridges and devices by consolidating a set of data
 and operations into globally accessible data structures.
 
@@ -23,7 +23,7 @@
 of the global tree.
 
 Common data fields can also be moved out of the local bus models into the
-global model. Some of the manipulation of these fields can also be
+global model. Some of the manipulations of these fields can also be
 consolidated. Most likely, manipulation functions will become a set
 of helper functions, which the bus drivers wrap around to include any
 bus-specific items.
@@ -71,7 +71,7 @@
 This abstraction is prevention of unnecessary pain during transitional phases.
 If the name of the field changes or is removed, then every downstream driver
 will break. On the other hand, if only the bus layer (and not the device
-layer) accesses struct device, it is only those that need to change.
+layer) accesses struct device, it is only that layer that needs to change.
 
 
 User Interface
@@ -96,9 +96,9 @@
 This directory may be populated at each layer of discovery - the global layer,
 the bus layer, or the device layer.
 
-The global layer currently creates two files - name and 'power'. The
+The global layer currently creates two files - 'name' and 'power'. The
 former only reports the name of the device. The latter reports the
-current power state of the device. It also be used to set the current
+current power state of the device. It will also be used to set the current
 power state. 
 
 The bus layer may also create files for the devices it finds while probing the
diff -Nru a/Documentation/driver-model/platform.txt b/Documentation/driver-model/platform.txt
--- a/Documentation/driver-model/platform.txt	Tue Mar 11 10:20:18 2003
+++ b/Documentation/driver-model/platform.txt	Wed Apr 16 13:57:23 2003
@@ -10,9 +10,9 @@
 
 Platform drivers
 ~~~~~~~~~~~~~~~~
-Drivers for platform devices have typically very simple and
+Drivers for platform devices are typically very simple and
 unstructured. Either the device was present at a particular I/O port
-and the driver was loaded, or there was not. There was no possibility
+and the driver was loaded, or it was not. There was no possibility
 of hotplugging or alternative discovery besides probing at a specific
 I/O address and expecting a specific response.
 
@@ -49,7 +49,7 @@
 
 Bus IDs
 ~~~~~~~
-Bus IDs are the canonical name for the device. There is no globally
+Bus IDs are the canonical names for the devices. There is no globally
 standard addressing mechanism for legacy devices. In the IA-32 world,
 we have Pnp IDs to use, as well as the legacy I/O ports. However,
 neither tell what the device really is or have any meaning on other
@@ -62,7 +62,7 @@
 
 For example, a serial driver might find a device at I/O 0x3f8. The
 ACPI firmware might also discover a device with PnP ID (_HID)
-PNP0501. Both correspond to the same device should be mapped to the
+PNP0501. Both correspond to the same device and should be mapped to the
 canonical name 'serial'. 
 
 The bus_id field should be a concatenation of the canonical name and
@@ -88,7 +88,7 @@
 ~~~~~~~~~~~~~~
 Legacy drivers assume they are bound to the device once they start up
 and probe an I/O port. Divorcing them from this will be a difficult
-process. However, that shouldn't prevent us from impelementing
+process. However, that shouldn't prevent us from implementing
 firmware-based enumeration. 
 
 The firmware should notify the platform bus about devices before the
diff -Nru a/Documentation/driver-model/porting.txt b/Documentation/driver-model/porting.txt
--- a/Documentation/driver-model/porting.txt	Tue Jan  7 14:17:09 2003
+++ b/Documentation/driver-model/porting.txt	Wed Apr 16 13:57:23 2003
@@ -128,7 +128,7 @@
 
   The bus_id is an ASCII string that contains the device's address on
   the bus. The format of this string is bus-specific. This is
-  necessary for representing device in sysfs. 
+  necessary for representing devices in sysfs. 
 
   parent is the physical parent of the device. It is important that
   the bus driver sets this field correctly. 
@@ -286,7 +286,7 @@
 It would be difficult and tedious to force every driver on a bus to
 simultaneously convert their drivers to generic format. Instead, the
 bus driver should define single instances of the generic methods that
-forward calls to the bus-specific drivers. For instance: 
+forward call to the bus-specific drivers. For instance: 
 
 
 static int pci_device_remove(struct device * dev)
@@ -330,8 +330,8 @@
 devices must be bound to a driver, or drivers must be bound to all
 devices that it supports. 
 
-Drivers typically contain a list of device IDs that it supports. The
-bus driver compares this ID to the ID of devices registered with it. 
+A driver typically contains a list of device IDs that it supports. The
+bus driver compares these IDs to the IDs of devices registered with it. 
 The format of the device IDs, and the semantics for comparing them are
 bus-specific, so the generic model does attempt to generalize them. 
 
@@ -396,7 +396,7 @@
 Step 7: Cleaning up the bus driver.
 
 The generic bus, device, and driver structures provide several fields
-that can replace those define privately to the bus driver. 
+that can replace those defined privately to the bus driver. 
 
 - Device list.
 
diff -Nru a/Documentation/kobject.txt b/Documentation/kobject.txt
--- a/Documentation/kobject.txt	Tue Mar 11 10:20:18 2003
+++ b/Documentation/kobject.txt	Mon May 12 15:14:33 2003
@@ -9,7 +9,7 @@
 
 The kobject infrastructure performs basic object management that larger
 data structures and subsystems can leverage, rather than reimplement
-similar functionality. This functionality consists primarily concerns:
+similar functionality. This functionality primarily concerns:
 
 - Object reference counting.
 - Maintaining lists (sets) of objects.
@@ -45,7 +45,7 @@
 struct kobject is a simple data type that provides a foundation for
 more complex object types. It provides a set of basic fields that
 almost all complex data types share. kobjects are intended to be
-embedded in larger data structures and replace fields it duplicates. 
+embedded in larger data structures and replace fields they duplicate. 
 
 1.2 Defintion
 
@@ -77,7 +77,7 @@
 includes inserting the kobject in the list of its dominant kset and
 creating a directory for it in sysfs.
 
-Alternatively, one may use a kobject without adding to its kset's list
+Alternatively, one may use a kobject without adding it to its kset's list
 or exporting it via sysfs, by simply calling kobject_init(). An
 initialized kobject may later be added to the object hierarchy by
 calling kobject_add(). An initialized kobject may be used for
@@ -87,8 +87,8 @@
 equivalent to calling kobject_register().
 
 When a kobject is unregistered, it is removed from its kset's list,
-removed from the sysfs filesystem, and its reference decremented. List
-and sysfs removal happen in kobject_del(), and may be called
+removed from the sysfs filesystem, and its reference count is decremented.
+List and sysfs removal happen in kobject_del(), and may be called
 manually. kobject_put() decrements the reference count, and may also
 be called manually. 
 
@@ -98,8 +98,8 @@
 it is already positive. 
 
 When a kobject's reference count reaches 0, the method struct
-ktype::release() (which the kobject's kset points to) is called. This
-allows any memory allocated for the object to be freed.
+kobj_type::release() (which the kobject's kset points to) is called.
+This allows any memory allocated for the object to be freed.
 
 
 1.4 sysfs
@@ -118,7 +118,7 @@
 
 2. ksets
 
-2.1 Desecription
+2.1 Description
 
 A kset is a set of kobjects that are embedded in the same type. 
 
@@ -163,9 +163,9 @@
 	 kset_register(&disk->kset);
 
 - The kset that the disk's embedded object belongs to is the
-  block_kset, and is pointed to disk->kset.kobj.kset. 
+  block_kset, and is pointed to by disk->kset.kobj.kset. 
 
-- The type of object of the disk's _subordinate_ list are partitions, 
+- The type of objects on the disk's _subordinate_ list are partitions, 
   and is set in disk->kset.ktype. 
 
 - The kset is then registered, which handles initializing and adding
@@ -218,13 +218,13 @@
 - sysfs_ops: Provides conversion functions for sysfs access. Please
   see the sysfs documentation for more information. 
 
-- default_attrs: Default attributes to exported via sysfs when the
+- default_attrs: Default attributes to be exported via sysfs when the
   object is registered. 
 
 
 Instances of struct kobj_type are not registered; only referenced by
 the kset. A kobj_type may be referenced by an arbitrary number of
-ksets, as their may be disparate sets of identical objects. 
+ksets, as there may be disparate sets of identical objects. 
 
 
 
diff -Nru a/Documentation/networking/3c509.txt b/Documentation/networking/3c509.txt
--- a/Documentation/networking/3c509.txt	Tue Mar 11 10:20:18 2003
+++ b/Documentation/networking/3c509.txt	Sat May 17 14:09:32 2003
@@ -52,7 +52,7 @@
 For example, setting two cards to 10base2/IRQ10 and AUI/IRQ11 is done by using
 the xcvr and irq module options:
 
-   options 3c509 xcvr=3,3 irq=10,11
+   options 3c509 xcvr=3,1 irq=10,11
 
 
 (2) Full-duplex mode
diff -Nru a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
--- a/Documentation/networking/ip-sysctl.txt	Sun Feb 23 22:46:32 2003
+++ b/Documentation/networking/ip-sysctl.txt	Mon May 19 23:44:05 2003
@@ -613,12 +613,6 @@
 	routers are present.
 	Default: 3
 
-icmp/*:
-ratelimit - INTEGER
-	Limit the maximal rates for sending ICMPv6 packets.
-	0 to disable any limiting, otherwise the maximal rate in jiffies(1)
-	Default: 100
-
 use_tempaddr - INTEGER
 	Preference for Privacy Extensions (RFC3041).
 	  <= 0 : disable Privacy Extensions
@@ -648,6 +642,12 @@
 	Number of attempts before give up attempting to generate
 	valid temporary addresses.
 	Default: 5
+
+icmp/*:
+ratelimit - INTEGER
+	Limit the maximal rates for sending ICMPv6 packets.
+	0 to disable any limiting, otherwise the maximal rate in jiffies(1)
+	Default: 100
 
 
 IPv6 Update by:
diff -Nru a/Documentation/scsi/aic79xx.txt b/Documentation/scsi/aic79xx.txt
--- a/Documentation/scsi/aic79xx.txt	Wed Jan 22 13:44:44 2003
+++ b/Documentation/scsi/aic79xx.txt	Thu May  1 10:04:05 2003
@@ -371,9 +371,33 @@
     - Fax Technical Support at +852-2869-7100
 
 -------------------------------------------------------------------
-
-(c) 2003 Adaptec, Inc. All Rights Reserved. No part of this 
-publication may be reproduced, stored in a retrieval system, or 
-transmitted in any form or by any means, electronic, mechanical, 
-photocopying, recording or otherwise, without prior written consent 
-of Adaptec, Inc., 691 South Milpitas Blvd., Milpitas, CA 95035.
+/*
+ * Copyright (c) 2003 Adaptec Inc. 691 S. Milpitas Blvd., Milpitas CA 95035 USA.
+ * All rights reserved.
+ *
+ * You are permitted to redistribute, use and modify this README file in whole
+ * or in part in conjunction with redistribution of software governed by the
+ * General Public License, provided that the following conditions are met:
+ * 1. Redistributions of README file 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.
+ * 3. Modifications or new contributions must be attributed in a copyright
+ *    notice identifying the author ("Contributor") and added below the
+ *    original copyright notice. The copyright notice is for purposes of
+ *    identifying contributors and should not be deemed as permission to alter
+ *    the permissions given by Adaptec.
+ *
+ * THIS README FILE IS PROVIDED BY ADAPTEC AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ANY
+ * WARRANTIES OF NON-INFRINGEMENT OR THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * ADAPTEC 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 README
+ * FILE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff -Nru a/Documentation/scsi/aic7xxx.txt b/Documentation/scsi/aic7xxx.txt
--- a/Documentation/scsi/aic7xxx.txt	Wed Jan 22 13:44:44 2003
+++ b/Documentation/scsi/aic7xxx.txt	Thu May  1 10:04:05 2003
@@ -132,6 +132,16 @@
 
 2. Version History
 
+        6.2.33 - Dynamically disable PCI parity error reporting after
+		 10 errors are reported to the user.  These errors are
+		 the result of some other device issuing PCI transactions
+		 with bad parity.  Once the user has been informed of the
+		 problem, continuing to report the errors just degrades
+		 our performance.
+
+        6.2.32 - Dynamically sized S/G lists to avoid SCSI malloc
+		 pool fragmentation and SCSI mid-layer deadlock.
+
         6.2.28 - Domain Validation Fixes
                  PCI parity error disable
                  Enhanced Memory Mapped I/O probe
@@ -160,6 +170,7 @@
        Default Value: 0x0000
    -----------------------------------------------------------------
               Option: no_probe
+              Option: probe_eisa_vl
           Definition: Do not probe for EISA/VLB controllers.
                       This is a toggle.  If the driver is compiled
                       to not probe EISA/VLB controllers by default,
@@ -339,9 +350,33 @@
     - Fax Technical Support at +852-2869-7100
 
 -------------------------------------------------------------------
-
-(c) 2002 Adaptec, Inc. All Rights Reserved. No part of this 
-publication may be reproduced, stored in a retrieval system, or 
-transmitted in any form or by any means, electronic, mechanical, 
-photocopying, recording or otherwise, without prior written consent 
-of Adaptec, Inc., 691 South Milpitas Blvd., Milpitas, CA 95035.
+/*
+ * Copyright (c) 2003 Adaptec Inc. 691 S. Milpitas Blvd., Milpitas CA 95035 USA.
+ * All rights reserved.
+ *
+ * You are permitted to redistribute, use and modify this README file in whole
+ * or in part in conjunction with redistribution of software governed by the
+ * General Public License, provided that the following conditions are met:
+ * 1. Redistributions of README file 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.
+ * 3. Modifications or new contributions must be attributed in a copyright
+ *    notice identifying the author ("Contributor") and added below the
+ *    original copyright notice. The copyright notice is for purposes of
+ *    identifying contributors and should not be deemed as permission to alter
+ *    the permissions given by Adaptec.
+ *
+ * THIS README FILE IS PROVIDED BY ADAPTEC AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ANY
+ * WARRANTIES OF NON-INFRINGEMENT OR THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * ADAPTEC 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 README
+ * FILE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
diff -Nru a/Documentation/video4linux/bttv/CARDLIST b/Documentation/video4linux/bttv/CARDLIST
--- a/Documentation/video4linux/bttv/CARDLIST	Wed Jan  8 01:59:58 2003
+++ b/Documentation/video4linux/bttv/CARDLIST	Sat May 17 14:09:43 2003
@@ -22,7 +22,7 @@
   card=20 - CEI Raffles Card
   card=21 - Lifeview FlyVideo 98/ Lucky Star Image World ConferenceTV LR50
   card=22 - Askey CPH050/ Phoebe Tv Master + FM
-  card=23 - Modular Technology MM205 PCTV, bt878
+  card=23 - Modular Technology MM201/MM202/MM205/MM210/MM215 PCTV, bt878
   card=24 - Askey CPH05X/06X (bt878) [many vendors]
   card=25 - Terratec TerraTV+ Version 1.0 (Bt848)/ Terra TValue Version 1.0/ Vobis TV-Boostar
   card=26 - Hauppauge WinCam newer (bt878)
@@ -39,7 +39,7 @@
   card=37 - Prolink PixelView PlayTV pro
   card=38 - Askey CPH06X TView99
   card=39 - Pinnacle PCTV Studio/Rave
-  card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878)
+  card=40 - STB TV PCI FM, Gateway P/N 6000704 (bt878), 3Dfx VoodooTV 100
   card=41 - AVerMedia TVPhone 98
   card=42 - ProVideo PV951
   card=43 - Little OnAir TV
@@ -81,11 +81,27 @@
   card=79 - DSP Design TCVIDEO
   card=80 - Hauppauge WinTV PVR
   card=81 - GV-BCTV5/PCI
+  card=82 - Osprey 100/150 (878)
+  card=83 - Osprey 100/150 (848)
+  card=84 - Osprey 101 (848)
+  card=85 - Osprey 101/151
+  card=86 - Osprey 101/151 w/ svid
+  card=87 - Osprey 200/201/250/251
+  card=88 - Osprey 200/250
+  card=89 - Osprey 210/220
+  card=90 - Osprey 500
+  card=91 - Osprey 540
+  card=92 - Osprey 2000
+  card=93 - IDS Eagle
+  card=94 - Pinnacle PCTV Sat
+  card=95 - Formac ProTV II
+  card=96 - MachTV
+  card=97 - Euresys Picolo
 
 tuner.o
   type=0 - Temic PAL (4002 FH5)
   type=1 - Philips PAL_I (FI1246 and compatibles)
-  type=2 - Philips NTSC (FI1236 and compatibles)
+  type=2 - Philips NTSC (FI1236,FM1236 and compatibles)
   type=3 - Philips (SECAM+PAL_BG) (FI1216MF, FM1216MF, FR1216MF)
   type=4 - NoTuner
   type=5 - Philips PAL_BG (FI1216 and compatibles)
diff -Nru a/Documentation/video4linux/bttv/Cards b/Documentation/video4linux/bttv/Cards
--- a/Documentation/video4linux/bttv/Cards	Wed Jan  8 01:59:58 2003
+++ b/Documentation/video4linux/bttv/Cards	Sat May 17 14:09:43 2003
@@ -179,7 +179,8 @@
   has not yet been seen (perhaps it was the german name for LR90 [stereo]).
   These cards are sold by many OEMs too.
 
-  FlyVideo A2 = LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) {Germany}
+  FlyVideo A2 (Elta 8680)= LR90 Rev.F (w/Remote, w/o FM, stereo TV by tda9821) {Germany}
+  Lifeview 3000 (Elta 8681) as sold by Plus(April 2002), Germany = LR138 w/ saa7134
 
 
 Typhoon TV card series:
@@ -397,6 +398,8 @@
    AVerTV98 mit Fernbedienung (BT-878 chip)
    AVerTV/FM98 (BT-878 chip)
 
+   VDOmate (www.averm.com.cn) = M168U ?
+
 Aimslab
 -------
    Video Highway or "Video Highway TR200" (ISA)
@@ -413,7 +416,8 @@
    LT9306/MD9306 = CPH061
    LT9415/MD9415 = LR90 Rev.F or Rev.G
           MD9592 = Avermedia TVphone98 (PCI_ID=1461:0003), PCB-Rev=M168II-B (w/TDA9873H)
-          MD9717 = KNC One (Rev D4, saa7134)
+          MD9717 = KNC One (Rev D4, saa7134, FM1216 MK2 tuner)
+          MD5044 = KNC One (Rev D4, saa7134, FM1216ME MK3 tuner)
 
 Modular Technologies (www.modulartech.com) UK
 ---------------------------------------------
@@ -481,7 +485,8 @@
    Studio PCTV Pro  (Bt878 stereo w/ FM)
    Pinnacle PCTV    (Bt878, MT2032)
    Pinnacle PCTV Pro (Bt878, MT2032)
-   Pinncale PCTV Sat (bt878a, HM1821/1221)
+   Pinncale PCTV Sat (bt878a, HM1821/1221) ["Conexant CX24110 with CX24108 tuner, aka HM1221/HM1811"]
+   Pinnacle PCTV Sat XE
 
    M(J)PEG capture and playback:
    DC1+ (ISA)
@@ -654,9 +659,9 @@
    WinTV PVR 450
 
   US models
-  990 WinTV-PVR-350 (249USD)
-  980 WinTV-PVR-250 (149USD)
-  880 WinTV-PVR-PCI (199USD)
+  990 WinTV-PVR-350 (249USD) (iTVC15 chipset + radio)
+  980 WinTV-PVR-250 (149USD) (iTVC15 chipset)
+  880 WinTV-PVR-PCI (199USD) (KFIR chipset + bt878)
   881 WinTV-PVR-USB
   190 WinTV-GO
   191 WinTV-GO-FM
@@ -697,11 +702,40 @@
   566 WinTV USB (UK)
   573 WinTV USB FM
   429 Impact VCB (bt848)
-  600 USB Libe (Video-In 1x Comp, 1xSVHS)
+  600 USB Live (Video-In 1x Comp, 1xSVHS)
   542 WinTV Nova
   717 WinTV DVB-S
   909 Nova-t PCI
   893 Nova-t USB   (Duplicate entry)
+  802 MyTV
+  804 MyView
+  809 MyVideo
+  872 MyTV2Go FM
+
+ 
+  546 WinTV Nova-S CI
+  543 WinTV Nova
+  907 Nova-S USB
+  908 Nova-T USB
+  717 WinTV Nexus-S
+  157 DEC3000-s Standalone + USB
+
+  Spain
+  685 WinTV-Go
+  690 WinTV-PrimioFM
+  416 WinTV-PCI Nicam Estereo
+  677 WinTV-PCI-FM
+  699 WinTV-Theater
+  683 WinTV-USB
+  678 WinTV-USB-FM
+  983 WinTV-PVR-250
+  883 WinTV-PVR-PCI
+  993 WinTV-PVR-350
+  893 WinTV-PVR-USB
+  728 WinTV-DVB-C PCI
+  832 MyTV2Go
+  869 MyTV2Go-FM
+  805 MyVideo (USB)
   
 
 Matrix-Vision
@@ -713,6 +747,7 @@
 Conceptronic (.net)
 ------------
    TVCON FM,  TV card w/ FM = CPH05x
+   TVCON = CPH06x
 
 BestData
 --------
@@ -747,11 +782,22 @@
 
 Kworld (www.kworld.com.tw)
 --------------------------
-   KWORLD KW-TV878RF-Pro TV Capture with FM Radio
-   KWORLD KW-TV878R-Pro TV
-   KWORLD KW-TVL878RF  (low profile)
-   KWORLD KW-TV878R TV Capture (No FM Radio)
-   KWORLD KW-TV878RF TV
+  PC TV Station
+   KWORLD KW-TV878R  TV (no radio)
+   KWORLD KW-TV878RF TV (w/ radio)
+
+   KWORLD KW-TVL878RF (low profile)
+
+   KWORLD KW-TV713XRF (saa7134)
+
+
+  MPEG TV Station (same cards as above plus WinDVR Software MPEG en/decoder)
+   KWORLD KW-TV878R -Pro   TV (no Radio)
+   KWORLD KW-TV878RF-Pro   TV (w/ Radio)
+   KWORLD KW-TV878R -Ultra TV (no Radio)
+   KWORLD KW-TV878RF-Ultra TV (w/ Radio)
+
+
 
 JTT/ Justy Corp.http://www.justy.co.jp/ (www.jtt.com.jp website down)
 ---------------------------------------------------------------------
@@ -793,7 +839,7 @@
    TV-FM =KNC1 saa7134
    Standard PCI (DVB-S) = Technotrend Budget
    Standard PCI (DVB-S) w/ CI
-   Satelco Hoghend PCI (DVB-S) = Technotrend Premium
+   Satelco Highend PCI (DVB-S) = Technotrend Premium
 
 
 Sensoray www.sensoray.com
@@ -879,3 +925,37 @@
 Mercury www.kobian.com (UK and FR)
     LR50
     LR138RBG-Rx  == LR138
+
+TEC sound (package and manuals don't have any other manufacturer info) TecSound
+    Though educated googling found: www.techmakers.com
+    TV-Mate = Zoltrix VP-8482
+
+Lorenzen www.lorenzen.de
+--------
+     SL DVB-S PCI = Technotrend Budget PCI (su1278 or bsru version)
+
+Origo (.uk) www.origo2000.com
+     PC TV Card = LR50
+
+I/O Magic www.iomagic.com
+---------
+    PC PVR - Desktop TV Personal Video Recorder DR-PCTV100 = Pinnacle ROB2D-51009464 4.0 + Cyberlink PowerVCR II
+
+Arowana
+-------
+    TV-Karte / Poso Power TV (?) = Zoltrix VP-8482 (?)
+
+iTVC15 boards:
+-------------
+kuroutoshikou.com ITVC15
+yuan.com MPG160 PCI TV (Internal PCI MPEG2 encoder card plus TV-tuner)
+
+Asus www.asuscom.com
+   Asus TV Tuner Card 880 NTSC (low profile, cx23880)
+   Asus TV (saa7134)
+
+Hoontech
+--------
+http://www.hoontech.com/korean/download/down_driver_list03.html
+   HART Vision 848 (H-ART Vision 848)
+   HART Vision 878 (H-Art Vision 878)
diff -Nru a/Documentation/video4linux/bttv/Sound-FAQ b/Documentation/video4linux/bttv/Sound-FAQ
--- a/Documentation/video4linux/bttv/Sound-FAQ	Tue Mar 11 10:20:19 2003
+++ b/Documentation/video4linux/bttv/Sound-FAQ	Sat May 17 14:09:43 2003
@@ -79,10 +79,11 @@
 What you have to do is figure out the correct values for gpiomask and
 the audiomux array.  If you have Windows and the drivers four your
 card installed, you might to check out if you can read these registers
-values used by the windows driver.  A tool to do this is available from
-ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil, but it does'nt
-work with bt878 boards according to some reports I received.  Another
-one is available from http://www.kki.net.pl/~borgx/bTV.html.
+values used by the windows driver.  A tool to do this is available
+from ftp://telepresence.dmem.strath.ac.uk/pub/bt848/winutil, but it
+does'nt work with bt878 boards according to some reports I received.
+Another one with bt878 suport is available from
+http://btwincap.sourceforge.net/Files/btspy2.00.zip
 
 You might also dig around in the *.ini files of the Windows applications.
 You can have a look at the board to see which of the gpio pins are
diff -Nru a/MAINTAINERS b/MAINTAINERS
--- a/MAINTAINERS	Sun Apr 27 21:05:06 2003
+++ b/MAINTAINERS	Fri May  9 09:26:35 2003
@@ -679,7 +679,7 @@
 
 EXT3 FILE SYSTEM
 P:	Stephen Tweedie, Andrew Morton
-M:	sct@redhat.com, akpm@zip.com.au, adilger@clusterfs.com
+M:	sct@redhat.com, akpm@digeo.com, adilger@clusterfs.com
 L:	ext3-users@redhat.com
 S:	Maintained
 
@@ -801,20 +801,13 @@
 M:	drivers@neukum.org
 S:	Maintained
 
-I2C DRIVERS
-P:	Simon Vogl
-M:	simon@tk.uni-linz.ac.at
-P:	Frodo Looijaard
-M:	frodol@dds.nl
-L:	linux-i2c@pelican.tk.uni-linz.ac.at
-W:	http://www.tk.uni-linz.ac.at/~simon/private/i2c
-S:	Maintained
-
-SENSORS DRIVERS
+I2C AND SENSORS DRIVERS
 P:      Frodo Looijaard
 M:      frodol@dds.nl
 P:      Philip Edelbrock
 M:      phil@netroedge.com
+P:	Greg Kroah-Hartman
+M:	greg@kroah.com
 L:      sensors@stimpy.netroedge.com
 W:      http://www.lm-sensors.nu/
 S:      Maintained
@@ -1264,7 +1257,7 @@
 
 NETWORK DEVICE DRIVERS
 P:	Andrew Morton
-M:	akpm@zip.com.au
+M:	akpm@digeo.com
 P:	Jeff Garzik
 M:	jgarzik@pobox.com
 L:	linux-net@vger.kernel.org
@@ -1285,6 +1278,8 @@
 M:	pekkas@netcore.fi
 P:	James Morris
 M:	jmorris@intercode.com.au
+P:	Hideaki YOSHIFUJI
+M:	yoshfuji@linux-ipv6.org
 L:	netdev@oss.sgi.com
 S:	Maintained
 
diff -Nru a/Makefile b/Makefile
--- a/Makefile	Sun May  4 16:48:05 2003
+++ b/Makefile	Wed May 21 04:34:44 2003
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 5
 SUBLEVEL = 69
-EXTRAVERSION =
+EXTRAVERSION = -bk15
 
 # *DOCUMENTATION*
 # To see a list of typical targets execute "make help"
@@ -90,7 +90,7 @@
   KBUILD_MODULES := 1
 endif
 
-export KBUILD_MODULES KBUILD_BUILTIN KBUILD_VERBOSE
+export KBUILD_MODULES KBUILD_BUILTIN KBUILD_VERBOSE KBUILD_CHECKSRC
 
 # Beautify output
 # ---------------------------------------------------------------------------
@@ -118,6 +118,16 @@
   KBUILD_VERBOSE = 1
 endif
 
+ifdef C
+  ifeq ("$(origin C)", "command line")
+    KBUILD_CHECKSRC = $(C)
+  endif
+endif
+ifndef KBUILD_CHECKSRC
+  KBUILD_CHECKSRC = 0
+endif
+
+
 MAKEFLAGS += --no-print-directory
 
 # For maximum performance (+ possibly random breakage, uncomment
@@ -172,6 +182,7 @@
 DEPMOD		= /sbin/depmod
 KALLSYMS	= scripts/kallsyms
 PERL		= perl
+CHECK		= /home/torvalds/parser/check
 MODFLAGS	= -DMODULE
 CFLAGS_MODULE   = $(MODFLAGS)
 AFLAGS_MODULE   = $(MODFLAGS)
@@ -189,7 +200,7 @@
 export	VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION KERNELRELEASE ARCH \
 	CONFIG_SHELL TOPDIR HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \
 	CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE \
-	HOSTCXX HOSTCXXFLAGS LDFLAGS_BLOB LDFLAGS_MODULE
+	HOSTCXX HOSTCXXFLAGS LDFLAGS_BLOB LDFLAGS_MODULE CHECK
 
 export CPPFLAGS NOSTDINC_FLAGS OBJCOPYFLAGS LDFLAGS
 export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE 
diff -Nru a/arch/alpha/kernel/core_marvel.c b/arch/alpha/kernel/core_marvel.c
--- a/arch/alpha/kernel/core_marvel.c	Thu Apr 24 00:15:06 2003
+++ b/arch/alpha/kernel/core_marvel.c	Mon May 12 18:59:21 2003
@@ -780,7 +780,7 @@
 		rtc_access.function = 0x49;		/* GET_TOY */
 		if (write) rtc_access.function = 0x48;	/* PUT_TOY */
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 		if (smp_processor_id() != boot_cpuid)
 			smp_call_function_on_cpu(__marvel_access_rtc,
 						 &rtc_access,
diff -Nru a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S
--- a/arch/alpha/kernel/entry.S	Wed Feb 26 13:17:30 2003
+++ b/arch/alpha/kernel/entry.S	Mon May 12 18:59:21 2003
@@ -849,7 +849,7 @@
 	   about this loop.  */
 	ldq	$3, TASK_REAL_PARENT($2)
 1:	ldl	$1, TASK_TGID($3)
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	mov	$3, $4
 	mb
 	ldq	$3, TASK_REAL_PARENT($2)
diff -Nru a/arch/alpha/kernel/irq.c b/arch/alpha/kernel/irq.c
--- a/arch/alpha/kernel/irq.c	Mon Apr 21 10:00:46 2003
+++ b/arch/alpha/kernel/irq.c	Mon May 12 18:59:21 2003
@@ -556,7 +556,7 @@
 unlock:
 		spin_unlock_irqrestore(&irq_desc[i].lock, flags);
 	}
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	seq_puts(p, "IPI: ");
 	for (i = 0; i < NR_CPUS; i++)
 		if (cpu_online(i))
diff -Nru a/arch/alpha/kernel/module.c b/arch/alpha/kernel/module.c
--- a/arch/alpha/kernel/module.c	Sun Mar 23 16:17:40 2003
+++ b/arch/alpha/kernel/module.c	Mon May 12 21:23:07 2003
@@ -300,3 +300,8 @@
 {
 	return 0;
 }
+
+void
+module_arch_cleanup(struct module *mod)
+{
+}
diff -Nru a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c
--- a/arch/alpha/kernel/process.c	Sun Mar  2 18:13:32 2003
+++ b/arch/alpha/kernel/process.c	Tue May 20 11:25:56 2003
@@ -235,23 +235,18 @@
 alpha_clone(unsigned long clone_flags, unsigned long usp, int *parent_tid,
 	    int *child_tid, unsigned long tls_value, struct pt_regs *regs)
 {
-	struct task_struct *p;
-
 	if (!usp)
 		usp = rdusp();
 
-	p = do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0,
-		    parent_tid, child_tid);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0,
+		       parent_tid, child_tid);
 }
 
 int
 alpha_vfork(struct pt_regs *regs)
 {
-	struct task_struct *p;
-	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(),
-		    regs, 0, NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, rdusp(),
+		       regs, 0, NULL, NULL);
 }
 
 /*
diff -Nru a/arch/alpha/kernel/ptrace.c b/arch/alpha/kernel/ptrace.c
--- a/arch/alpha/kernel/ptrace.c	Mon Feb 17 04:49:09 2003
+++ b/arch/alpha/kernel/ptrace.c	Tue May 20 10:47:24 2003
@@ -366,8 +366,8 @@
 		ret = -EIO;
 		if ((unsigned long) data > _NSIG)
 			break;
-		/* Mark single stepping.  */
-		child->thread_info->bpt_nsaved = -1;
+		/* Set single stepping.  */
+		ptrace_set_bpt(child);
 		clear_tsk_thread_flag(child, TIF_SYSCALL_TRACE);
 		wake_up_process(child);
 		child->exit_code = data;
@@ -397,11 +397,11 @@
 		return;
 	if (!(current->ptrace & PT_PTRACED))
 		return;
-	current->exit_code = SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
-					? 0x80 : 0);
-	current->state = TASK_STOPPED;
-	notify_parent(current, SIGCHLD);
-	schedule();
+	/* The 0x80 provides a way for the tracing parent to distinguish
+	   between a syscall stop and SIGTRAP delivery */
+	ptrace_notify(SIGTRAP | ((current->ptrace & PT_TRACESYSGOOD)
+				 ? 0x80 : 0));
+
 	/*
 	 * This isn't the same as continuing with a signal, but it will do
 	 * for normal use.  strace only continues with a signal if the
diff -Nru a/arch/alpha/kernel/smp.c b/arch/alpha/kernel/smp.c
--- a/arch/alpha/kernel/smp.c	Mon Mar 31 14:29:49 2003
+++ b/arch/alpha/kernel/smp.c	Tue May 20 11:25:56 2003
@@ -417,7 +417,12 @@
 	/* Don't care about the contents of regs since we'll never
 	   reschedule the forked task. */
 	struct pt_regs regs;
-	return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+	int pid;
+	pid = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+	if (pid < 0)
+		return NULL;
+
+	return find_task_by_pid (pid);
 }
 
 /*
@@ -436,7 +441,7 @@
 	   wish.  We can't use kernel_thread since we must avoid
 	   rescheduling the child.  */
 	idle = fork_by_hand();
-	if (IS_ERR(idle))
+	if (!idle)
 		panic("failed fork for CPU %d", cpuid);
 
 	init_idle(idle, cpuid);
diff -Nru a/arch/alpha/kernel/sys_titan.c b/arch/alpha/kernel/sys_titan.c
--- a/arch/alpha/kernel/sys_titan.c	Thu Jan 16 16:01:37 2003
+++ b/arch/alpha/kernel/sys_titan.c	Sun May 11 13:03:12 2003
@@ -204,13 +204,14 @@
        .set_affinity   = titan_set_irq_affinity,
 };
 
-static void
+static irqreturn_t
 titan_intr_nop(int irq, void *dev_id, struct pt_regs *regs)                    
 {
       /*
        * This is a NOP interrupt handler for the purposes of
        * event counting -- just return.
        */                                                                     
+       return IRQ_HANDLED;
 }
 
 static void __init
diff -Nru a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
--- a/arch/arm/common/sa1111.c	Fri Mar 21 15:39:32 2003
+++ b/arch/arm/common/sa1111.c	Mon May 12 19:06:25 2003
@@ -419,7 +419,7 @@
 
 	spin_lock_irqsave(&sachip->lock, flags);
 
-#if CONFIG_ARCH_SA1100
+#ifdef CONFIG_ARCH_SA1100
 	/*
 	 * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
 	 * (SA-1110 Developer's Manual, section 9.1.2.1)
diff -Nru a/arch/arm/kernel/asm-offsets.c b/arch/arm/kernel/asm-offsets.c
--- a/arch/arm/kernel/asm-offsets.c	Tue Mar  4 17:00:35 2003
+++ b/arch/arm/kernel/asm-offsets.c	Tue Apr 29 07:00:53 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1995-2001 Russell King
+ * Copyright (C) 1995-2003 Russell King
  *               2001-2002 Keith Owens
  *     
  * Generate definitions needed by assembly language modules.
@@ -24,12 +24,21 @@
 #if defined(__APCS_26__)
 #error Sorry, your compiler targets APCS-26 but this kernel requires APCS-32
 #endif
-#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 95)
-#error Sorry, your compiler is known to miscompile kernels.  Only use gcc 2.95.3 and later.
-#endif
-#if __GNUC__ == 2 && __GNUC_MINOR__ == 95
-/* shame we can't detect the .1 or .2 releases */
-#warning GCC 2.95.2 and earlier miscompiles kernels.
+/*
+ * GCC 2.95.1, 2.95.2: ignores register clobber list in asm().
+ * GCC 3.0, 3.1: general bad code generation.
+ * GCC 3.2.0: incorrect function argument offset calculation.
+ * GCC 3.2.x: miscompiles NEW_AUX_ENT in fs/binfmt_elf.c
+ *            (http://gcc.gnu.org/cgi-bin/gnatsweb.pl?cmd=view&pr=8896)
+ */
+#if __GNUC__ < 2 || \
+   (__GNUC__ == 2 && __GNUC_MINOR__ < 95) || \
+   (__GNUC__ == 2 && __GNUC_MINOR__ == 95 && __GNUC_PATCHLEVEL__ != 0 && \
+					     __GNUC_PATCHLEVEL__ < 3) || \
+   (__GNUC__ == 3 && __GNUC_MINOR__ < 2) || \
+   (__GNUC__ == 3 && __GNUC_MINOR__ == 2 && __GNUC_PATCHLEVEL__ < 1)
+#error Your compiler is too buggy; it is known to miscompile kernels.
+#error    Known good compilers: 2.95.3, 2.95.4, 2.96, 3.2.2+PR8896
 #endif
 
 /* Use marker if you need to separate the values later */
@@ -61,7 +70,6 @@
   DEFINE(LPTE_WRITE,		L_PTE_WRITE);
   DEFINE(LPTE_EXEC,		L_PTE_EXEC);
   DEFINE(LPTE_DIRTY,		L_PTE_DIRTY);
-  BLANK();
   BLANK();
   DEFINE(PAGE_SZ,	       	PAGE_SIZE);
   BLANK();
diff -Nru a/arch/arm/kernel/calls.S b/arch/arm/kernel/calls.S
--- a/arch/arm/kernel/calls.S	Tue Jan 14 15:28:43 2003
+++ b/arch/arm/kernel/calls.S	Tue Apr 29 07:00:53 2003
@@ -1,7 +1,7 @@
 /*
- *  linux/arch/arm/lib/calls.h
+ *  linux/arch/arm/kernel/calls.S
  *
- *  Copyright (C) 1995-1998 Russell King
+ *  Copyright (C) 1995-2003 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
diff -Nru a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
--- a/arch/arm/kernel/entry-armv.S	Mon Apr 28 14:12:53 2003
+++ b/arch/arm/kernel/entry-armv.S	Tue Apr 22 05:39:46 2003
@@ -621,7 +621,7 @@
 		rsb	\irqstat, \irqnr, #0
 		and	\irqstat, \irqstat, \irqnr
 		clz	\irqnr, \irqstat
-		rsb	\irqnr, \irqnr, #23
+		rsb	\irqnr, \irqnr, #(31 - PXA_IRQ_SKIP)
 1001:
 		.endm
 
diff -Nru a/arch/arm/kernel/irq.c b/arch/arm/kernel/irq.c
--- a/arch/arm/kernel/irq.c	Sat Mar  8 14:50:43 2003
+++ b/arch/arm/kernel/irq.c	Mon May 12 16:21:20 2003
@@ -58,6 +58,11 @@
 {
 }
 
+irqreturn_t no_action(int irq, void *dev_id, struct pt_regs *regs)
+{
+	return IRQ_NONE;
+}
+
 void do_bad_IRQ(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
 {
 	irq_err_count += 1;
@@ -222,6 +227,7 @@
 __do_irq(unsigned int irq, struct irqaction *action, struct pt_regs *regs)
 {
 	unsigned int status;
+	int retval = 0;
 
 	spin_unlock(&irq_controller_lock);
 
@@ -231,7 +237,7 @@
 	status = 0;
 	do {
 		status |= action->flags;
-		action->handler(irq, action->dev_id, regs);
+		retval |= action->handler(irq, action->dev_id, regs);
 		action = action->next;
 	} while (action);
 
@@ -239,6 +245,19 @@
 		add_interrupt_randomness(irq);
 
 	spin_lock_irq(&irq_controller_lock);
+
+	if (retval != 1) {
+		static int count = 100;
+		if (count) {
+			count--;
+			if (retval) {
+				printk("irq event %d: bogus retval mask %x\n",
+					irq, retval);
+			} else {
+				printk("irq %d: nobody cared\n", irq);
+			}
+		}
+	}
 }
 
 /*
@@ -606,7 +625,7 @@
  *	SA_SAMPLE_RANDOM	The interrupt can be used for entropy
  *
  */
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+int request_irq(unsigned int irq, irqreturn_t (*handler)(int, void *, struct pt_regs *),
 		 unsigned long irq_flags, const char * devname, void *dev_id)
 {
 	unsigned long retval;
diff -Nru a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
--- a/arch/arm/kernel/module.c	Mon Jan 13 09:46:25 2003
+++ b/arch/arm/kernel/module.c	Mon May 12 21:23:07 2003
@@ -159,3 +159,8 @@
 {
 	return 0;
 }
+
+void
+module_arch_cleanup(struct module *mod)
+{
+}
diff -Nru a/arch/arm/kernel/pm.c b/arch/arm/kernel/pm.c
--- a/arch/arm/kernel/pm.c	Thu Mar  6 07:59:45 2003
+++ b/arch/arm/kernel/pm.c	Tue May 13 06:48:46 2003
@@ -16,10 +16,18 @@
 #include <asm/leds.h>
 #include <asm/system.h>
 
+/*
+ * Tell the linker that pm_do_suspend may not be present.
+ */
+extern int pm_do_suspend(void) __attribute__((weak));
+
 int suspend(void)
 {
 	int ret;
 
+	if (!pm_do_suspend)
+		return -ENOSYS;
+
 	/*
 	 * Suspend "legacy" devices.
 	 */
@@ -82,9 +90,26 @@
 }
 
 #ifdef CONFIG_SYSCTL
+/*
+ * We really want this to die.  It's a disgusting hack using unallocated
+ * sysctl numbers.  We should be using a real interface.
+ */
+
 #include <linux/init.h>
 #include <linux/sysctl.h>
 
+static int
+pm_sysctl_proc_handler(ctl_table *ctl, int write, struct file *filp,
+		       void *buffer, size_t *lenp)
+{
+	int ret = -EIO;
+	printk("PM: task %s (pid %d) uses deprecated sysctl PM interface\n",
+		current->comm, current->pid);
+	if (write)
+		ret = suspend();
+	return ret;
+}
+
 /*
  * This came from arch/arm/mach-sa1100/pm.c:
  * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
@@ -102,13 +127,23 @@
 
 static struct ctl_table pm_table[] =
 {
-	{ACPI_S1_SLP_TYP, "suspend", NULL, 0, 0600, NULL, (proc_handler *)&suspend},
+	{
+		.ctl_name	= ACPI_S1_SLP_TYP,
+		.procname	= "suspend",
+		.mode		= 0200,
+		.proc_handler	= pm_sysctl_proc_handler,
+	},
 	{0}
 };
 
 static struct ctl_table pm_dir_table[] =
 {
-	{CTL_ACPI, "pm", NULL, 0, 0555, pm_table},
+	{
+		.ctl_name	= CTL_ACPI,
+		.procname	= "pm",
+		.mode		= 0555,
+		.child		= pm_table,
+	},
 	{0}
 };
 
diff -Nru a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
--- a/arch/arm/kernel/ptrace.c	Mon Feb 24 12:16:14 2003
+++ b/arch/arm/kernel/ptrace.c	Tue May 13 10:56:54 2003
@@ -18,10 +18,12 @@
 #include <linux/ptrace.h>
 #include <linux/user.h>
 #include <linux/security.h>
+#include <linux/init.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
 #include <asm/system.h>
+#include <asm/traps.h>
 
 #include "ptrace.h"
 
@@ -32,7 +34,7 @@
  * in exit.c or in signal.c.
  */
 
-#if 1
+#if 0
 /*
  * Breakpoint SWI instruction: SWI &9F0001
  */
@@ -479,24 +481,46 @@
 {
 	siginfo_t info;
 
-	/*
-	 * The PC is always left pointing at the next instruction.  Fix this.
-	 */
-	regs->ARM_pc -= 4;
-
-	if (tsk->thread.debug.nsaved == 0)
-		printk(KERN_ERR "ptrace: bogus breakpoint trap\n");
-
 	ptrace_cancel_bpt(tsk);
 
 	info.si_signo = SIGTRAP;
 	info.si_errno = 0;
 	info.si_code  = TRAP_BRKPT;
-	info.si_addr  = (void *)instruction_pointer(regs) -
-			 (thumb_mode(regs) ? 2 : 4);
+	info.si_addr  = (void *)instruction_pointer(regs);
 
 	force_sig_info(SIGTRAP, &info, tsk);
 }
+
+static int break_trap(struct pt_regs *regs, unsigned int instr)
+{
+	ptrace_break(current, regs);
+	return 0;
+}
+
+static struct undef_hook arm_break_hook = {
+	.instr_mask	= 0x0fffffff,
+	.instr_val	= 0x07f001f0,
+	.cpsr_mask	= PSR_T_BIT,
+	.cpsr_val	= 0,
+	.fn		= break_trap,
+};
+
+static struct undef_hook thumb_break_hook = {
+	.instr_mask	= 0xffff,
+	.instr_val	= 0xde01,
+	.cpsr_mask	= PSR_T_BIT,
+	.cpsr_val	= PSR_T_BIT,
+	.fn		= break_trap,
+};
+
+static int __init ptrace_break_init(void)
+{
+	register_undef_hook(&arm_break_hook);
+	register_undef_hook(&thumb_break_hook);
+	return 0;
+}
+
+core_initcall(ptrace_break_init);
 
 /*
  * Read the word at offset "off" into the "struct user".  We
diff -Nru a/arch/arm/kernel/sys_arm.c b/arch/arm/kernel/sys_arm.c
--- a/arch/arm/kernel/sys_arm.c	Fri Apr 11 12:07:00 2003
+++ b/arch/arm/kernel/sys_arm.c	Tue May 20 02:20:28 2003
@@ -238,9 +238,7 @@
  */
 asmlinkage int sys_fork(struct pt_regs *regs)
 {
-	struct task_struct *p;
-	p = do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
 }
 
 /* Clone a task - this clones the calling program thread.
@@ -248,8 +246,6 @@
  */
 asmlinkage int sys_clone(unsigned long clone_flags, unsigned long newsp, struct pt_regs *regs)
 {
-	struct task_struct *p;
-
 	/*
 	 * We don't support SETTID / CLEARTID
 	 */
@@ -259,16 +255,12 @@
 	if (!newsp)
 		newsp = regs->ARM_sp;
 
-	p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL);
-
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, regs, 0, NULL, NULL);
 }
 
 asmlinkage int sys_vfork(struct pt_regs *regs)
 {
-	struct task_struct *p;
-	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->ARM_sp, regs, 0, NULL, NULL);
 }
 
 /* sys_execve() executes a new program.
diff -Nru a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c
--- a/arch/arm/kernel/traps.c	Tue Mar  4 16:44:21 2003
+++ b/arch/arm/kernel/traps.c	Tue May 13 10:56:54 2003
@@ -34,7 +34,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
-#include <asm/semaphore.h>
+#include <asm/traps.h>
 
 #include "ptrace.h"
 
@@ -240,17 +240,56 @@
     	die(str, regs, err);
 }
 
+static LIST_HEAD(undef_hook);
+static spinlock_t undef_lock = SPIN_LOCK_UNLOCKED;
+
+void register_undef_hook(struct undef_hook *hook)
+{
+	spin_lock_irq(&undef_lock);
+	list_add(&hook->node, &undef_hook);
+	spin_unlock_irq(&undef_lock);
+}
+
+void unregister_undef_hook(struct undef_hook *hook)
+{
+	spin_lock_irq(&undef_lock);
+	list_del(&hook->node);
+	spin_unlock_irq(&undef_lock);
+}
+
 asmlinkage void do_undefinstr(struct pt_regs *regs)
 {
-	unsigned long *pc;
+	unsigned int correction = thumb_mode(regs) ? 2 : 4;
+	unsigned int instr;
+	struct undef_hook *hook;
 	siginfo_t info;
+	void *pc;
 
 	/*
-	 * According to the ARM ARM, PC is 2 or 4 bytes ahead, depending
-	 * whether we're in Thumb mode or not.
+	 * According to the ARM ARM, PC is 2 or 4 bytes ahead,
+	 * depending whether we're in Thumb mode or not.
+	 * Correct this offset.
 	 */
-	regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
-	pc = (unsigned long *)instruction_pointer(regs);
+	regs->ARM_pc -= correction;
+
+	pc = (void *)instruction_pointer(regs);
+	if (thumb_mode(regs)) {
+		get_user(instr, (u16 *)pc);
+	} else {
+		get_user(instr, (u32 *)pc);
+	}
+
+	spin_lock_irq(&undef_lock);
+	list_for_each_entry(hook, &undef_hook, node) {
+		if ((instr & hook->instr_mask) == hook->instr_val &&
+		    (regs->ARM_cpsr & hook->cpsr_mask) == hook->cpsr_val) {
+			if (hook->fn(regs, instr) == 0) {
+				spin_unlock_irq(&undef_lock);
+				return;
+			}
+		}
+	}
+	spin_unlock_irq(&undef_lock);
 
 #ifdef CONFIG_DEBUG_USER
 	printk(KERN_INFO "%s (%d): undefined instruction: pc=%p\n",
@@ -377,6 +416,7 @@
 		return 0;
 
 	case NR(breakpoint): /* SWI BREAK_POINT */
+		regs->ARM_pc -= thumb_mode(regs) ? 2 : 4;
 		ptrace_break(current, regs);
 		return regs->ARM_r0;
 
diff -Nru a/arch/arm/lib/copy_page.S b/arch/arm/lib/copy_page.S
--- a/arch/arm/lib/copy_page.S	Tue Mar  4 09:04:40 2003
+++ b/arch/arm/lib/copy_page.S	Thu May  8 08:36:52 2003
@@ -13,11 +13,7 @@
 #include <asm/assembler.h>
 #include <asm/constants.h>
 
-#ifndef PLD
-#define COPY_COUNT PAGE_SZ/64
-#else
-#define COPY_COUNT PAGE_SZ/64-1
-#endif
+#define COPY_COUNT (PAGE_SZ/64 PLD( -1 ))
 
 		.text
 		.align	5
diff -Nru a/arch/arm/mach-footbridge/dc21285.c b/arch/arm/mach-footbridge/dc21285.c
--- a/arch/arm/mach-footbridge/dc21285.c	Wed Mar 26 07:30:03 2003
+++ b/arch/arm/mach-footbridge/dc21285.c	Tue May 13 08:20:49 2003
@@ -65,7 +65,7 @@
 		    int size, u32 *value)
 {
 	unsigned long addr = dc21285_base_address(bus, devfn);
-	u32 v;
+	u32 v = 0xffffffff;
 
 	if (addr)
 		switch (size) {
@@ -82,8 +82,6 @@
 				: "=r" (v) : "r" (addr), "r" (where));
 			break;
 		}
-	else
-		v = 0xffffffff;
 
 	*value = v;
 
@@ -154,7 +152,7 @@
 /*
  * Warn on PCI errors.
  */
-static void dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_abort_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned int cmd;
 	unsigned int status;
@@ -180,9 +178,11 @@
 	}
 
 	*CSR_PCICMD = cmd;
+
+	return IRQ_HANDLED;
 }
 
-static void dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_serr_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct timer_list *timer = dev_id;
 	unsigned int cntl;
@@ -200,15 +200,19 @@
 	disable_irq(irq);
 	timer->expires = jiffies + HZ;
 	add_timer(timer);
+
+	return IRQ_HANDLED;
 }
 
-static void dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_discard_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	printk(KERN_DEBUG "PCI: discard timer expired\n");
 	*CSR_SA110_CNTL &= 0xffffde07;
+
+	return IRQ_HANDLED;
 }
 
-static void dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_dparity_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned int cmd;
 
@@ -218,9 +222,11 @@
 
 	cmd = *CSR_PCICMD & 0xffff;
 	*CSR_PCICMD = cmd | 1 << 24;
+
+	return IRQ_HANDLED;
 }
 
-static void dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t dc21285_parity_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct timer_list *timer = dev_id;
 	unsigned int cmd;
@@ -238,6 +244,8 @@
 	disable_irq(irq);
 	timer->expires = jiffies + HZ;
 	add_timer(timer);
+
+	return IRQ_HANDLED;
 }
 
 int __init dc21285_setup(int nr, struct pci_sys_data *sys)
diff -Nru a/arch/arm/mach-integrator/mm.c b/arch/arm/mach-integrator/mm.c
--- a/arch/arm/mach-integrator/mm.c	Tue Jun  4 16:19:02 2002
+++ b/arch/arm/mach-integrator/mm.c	Tue May 13 09:30:31 2003
@@ -43,8 +43,6 @@
  * f1500000	15000000	RTC
  * f1600000	16000000	UART 0
  * f1700000	17000000	UART 1
- * f1800000	18000000	Keyboard
- * f1900000	19000000	Mouse
  * f1a00000	1a000000	Debug LEDs
  * f1b00000	1b000000	GPIO
  */
@@ -58,8 +56,6 @@
  { IO_ADDRESS(INTEGRATOR_RTC_BASE),   INTEGRATOR_RTC_BASE,   SZ_4K,  MT_DEVICE },
  { IO_ADDRESS(INTEGRATOR_UART0_BASE), INTEGRATOR_UART0_BASE, SZ_4K,  MT_DEVICE },
  { IO_ADDRESS(INTEGRATOR_UART1_BASE), INTEGRATOR_UART1_BASE, SZ_4K,  MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_KBD_BASE),   INTEGRATOR_KBD_BASE,   SZ_4K,  MT_DEVICE },
- { IO_ADDRESS(INTEGRATOR_MOUSE_BASE), INTEGRATOR_MOUSE_BASE, SZ_4K,  MT_DEVICE },
  { IO_ADDRESS(INTEGRATOR_DBG_BASE),   INTEGRATOR_DBG_BASE,   SZ_4K,  MT_DEVICE },
  { IO_ADDRESS(INTEGRATOR_GPIO_BASE),  INTEGRATOR_GPIO_BASE,  SZ_4K,  MT_DEVICE },
  { PCI_MEMORY_VADDR,                  PHYS_PCI_MEM_BASE,     SZ_16M, MT_DEVICE },
diff -Nru a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
--- a/arch/arm/mach-pxa/irq.c	Sun Mar  2 23:32:23 2003
+++ b/arch/arm/mach-pxa/irq.c	Tue Apr 22 05:39:46 2003
@@ -50,9 +50,9 @@
  * Use this instead of directly setting GRER/GFER.
  */
 
-static int GPIO_IRQ_rising_edge[3];
-static int GPIO_IRQ_falling_edge[3];
-static int GPIO_IRQ_mask[3];
+static long GPIO_IRQ_rising_edge[3];
+static long GPIO_IRQ_falling_edge[3];
+static long GPIO_IRQ_mask[3];
 
 static int pxa_gpio_irq_type(unsigned int irq, unsigned int type)
 {
@@ -189,7 +189,6 @@
 	.ack		= pxa_ack_muxed_gpio,
 	.mask		= pxa_mask_muxed_gpio,
 	.unmask		= pxa_unmask_muxed_gpio,
-	.rerun		= pxa_manual_rerun,
 	.type		= pxa_gpio_irq_type,
 };
 
@@ -217,20 +216,17 @@
 	/* GPIO 0 and 1 must have their mask bit always set */
 	GPIO_IRQ_mask[0] = 3;
 
+	for (irq = PXA_IRQ(PXA_IRQ_SKIP); irq <= PXA_IRQ(31); irq++) {
+		set_irq_chip(irq, &pxa_internal_chip);
+		set_irq_handler(irq, do_level_IRQ);
+		set_irq_flags(irq, IRQF_VALID);
+	}
+
 	for (irq = IRQ_GPIO0; irq <= IRQ_GPIO1; irq++) {
 		set_irq_chip(irq, &pxa_low_gpio_chip);
 		set_irq_handler(irq, do_edge_IRQ);
 		set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
 	}
-
-	for (irq = PXA_IRQ(11); irq <= PXA_IRQ(31); irq++) {
-		set_irq_chip(irq, &pxa_internal_chip);
-		set_irq_handler(irq, do_level_IRQ);
-		set_irq_flags(irq, IRQF_VALID);
-	}
-	/* Those are reserved */
-	set_irq_flags(PXA_IRQ(15), 0);
-	set_irq_flags(PXA_IRQ(16), 0);
 
 	for (irq = IRQ_GPIO(2); irq <= IRQ_GPIO(80); irq++) {
 		set_irq_chip(irq, &pxa_muxed_gpio_chip);
diff -Nru a/arch/arm/mach-pxa/lubbock.c b/arch/arm/mach-pxa/lubbock.c
--- a/arch/arm/mach-pxa/lubbock.c	Mon Feb 17 14:55:12 2003
+++ b/arch/arm/mach-pxa/lubbock.c	Thu May  1 15:07:26 2003
@@ -33,57 +33,41 @@
 
 #include "generic.h"
 
-static void lubbock_ack_irq(unsigned int irq)
-{
-	int lubbock_irq = (irq - LUBBOCK_IRQ(0));
-	LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq);
-}
+
+static unsigned long lubbock_irq_enabled;
 
 static void lubbock_mask_irq(unsigned int irq)
 {
 	int lubbock_irq = (irq - LUBBOCK_IRQ(0));
-	LUB_IRQ_MASK_EN &= ~(1 << lubbock_irq);
+	LUB_IRQ_MASK_EN = (lubbock_irq_enabled &= ~(1 << lubbock_irq));
 }
 
 static void lubbock_unmask_irq(unsigned int irq)
 {
 	int lubbock_irq = (irq - LUBBOCK_IRQ(0));
-	LUB_IRQ_MASK_EN |= (1 << lubbock_irq);
+	/* the irq can be acknowledged only if deasserted, so it's done here */
+	LUB_IRQ_SET_CLR &= ~(1 << lubbock_irq);
+	LUB_IRQ_MASK_EN = (lubbock_irq_enabled |= (1 << lubbock_irq));
 }
 
 static struct irqchip lubbock_irq_chip = {
-	.ack		= lubbock_ack_irq,
+	.ack		= lubbock_mask_irq,
 	.mask		= lubbock_mask_irq,
 	.unmask		= lubbock_unmask_irq,
 };
 
-void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc,
-			 struct pt_regs *regs)
+static void lubbock_irq_handler(unsigned int irq, struct irqdesc *desc,
+				struct pt_regs *regs)
 {
-	unsigned int enabled, pending;
-
-	/* get active pending irq mask */
-	enabled = LUB_IRQ_MASK_EN & 0x003f;
-	pending = LUB_IRQ_SET_CLR & enabled;
-
+	unsigned long pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
 	do {
-//printk("%s a: set_clr %#x, mask_en %#x LR/DR %d/%d\n", __FUNCTION__, LUB_IRQ_SET_CLR, LUB_IRQ_MASK_EN, GPLR(0)&1, GEDR(0)&1 );
-		/* clear our parent irq */
-		GEDR(0) = GPIO_bit(0);
-
-		/* process them */
-		irq = LUBBOCK_IRQ(0);
-		desc = irq_desc + irq;
-		do {
-			if (pending & 1)
-				desc->handle(irq, desc, regs);
-			irq++;
-			desc++;
-			pending >>= 1;
-		} while (pending);
-//printk("%s b: set_clr %#x, mask_en %#x LR/DR %d/%d\n", __FUNCTION__, LUB_IRQ_SET_CLR, LUB_IRQ_MASK_EN, GPLR(0)&1, GEDR(0)&1 );
-		enabled = LUB_IRQ_MASK_EN & 0x003f;
-		pending = LUB_IRQ_SET_CLR & enabled;
+		GEDR(0) = GPIO_bit(0);	/* clear our parent irq */
+		if (likely(pending)) {
+			irq = LUBBOCK_IRQ(0) + __ffs(pending);
+			desc = irq_desc + irq;
+			desc->handle(irq, desc, regs);
+		}
+		pending = LUB_IRQ_SET_CLR & lubbock_irq_enabled;
 	} while (pending);
 }
 
diff -Nru a/arch/arm/mach-rpc/dma.c b/arch/arm/mach-rpc/dma.c
--- a/arch/arm/mach-rpc/dma.c	Tue Nov 19 07:28:03 2002
+++ b/arch/arm/mach-rpc/dma.c	Sat May 17 14:18:47 2003
@@ -57,7 +57,7 @@
 		if (end > PAGE_SIZE)
 			end = PAGE_SIZE;
 
-		if (offset + (int) TRANSFER_SIZE > end)
+		if (offset + TRANSFER_SIZE >= end)
 			flags |= DMA_END_L;
 
 		sg->length = end - TRANSFER_SIZE;
@@ -83,7 +83,7 @@
 	sg->length |= flags;
 }
 
-static void iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t iomd_dma_handle(int irq, void *dev_id, struct pt_regs *regs)
 {
 	dma_t *dma = (dma_t *)dev_id;
 	unsigned long base = dma->dma_base;
@@ -93,30 +93,36 @@
 
 		status = iomd_readb(base + ST);
 		if (!(status & DMA_ST_INT))
-			return;
+			return IRQ_HANDLED;
 
-		if (status & DMA_ST_OFL && !dma->sg)
-			break;
-
-		iomd_get_next_sg(&dma->cur_sg, dma);
+		if ((dma->state ^ status) & DMA_ST_AB)
+			iomd_get_next_sg(&dma->cur_sg, dma);
 
 		switch (status & (DMA_ST_OFL | DMA_ST_AB)) {
 		case DMA_ST_OFL:			/* OIA */
 		case DMA_ST_AB:				/* .IB */
 			iomd_writel(dma->cur_sg.dma_address, base + CURA);
 			iomd_writel(dma->cur_sg.length, base + ENDA);
+			dma->state = DMA_ST_AB;
 			break;
 
 		case DMA_ST_OFL | DMA_ST_AB:		/* OIB */
 		case 0:					/* .IA */
 			iomd_writel(dma->cur_sg.dma_address, base + CURB);
 			iomd_writel(dma->cur_sg.length, base + ENDB);
+			dma->state = 0;
 			break;
 		}
+
+		if (status & DMA_ST_OFL &&
+		    dma->cur_sg.length == (DMA_END_S|DMA_END_L))
+			break;
 	} while (1);
 
-	iomd_writeb(0, dma->dma_base + CR);
+	dma->state = ~DMA_ST_AB;
 	disable_irq(irq);
+
+	return IRQ_HANDLED;
 }
 
 static int iomd_request_dma(dmach_t channel, dma_t *dma)
@@ -150,6 +156,7 @@
 		}
 
 		iomd_writeb(DMA_CR_C, dma_base + CR);
+		dma->state = DMA_ST_AB;
 	}
 		
 	if (dma->dma_mode == DMA_MODE_READ)
@@ -163,13 +170,11 @@
 {
 	unsigned long dma_base = dma->dma_base;
 	unsigned long flags;
-	unsigned int ctrl;
 
 	local_irq_save(flags);
-	ctrl = iomd_readb(dma_base + CR);
-	if (ctrl & DMA_CR_E)
+	if (dma->state != ~DMA_ST_AB)
 		disable_irq(dma->dma_irq);
-	iomd_writeb(ctrl & ~DMA_CR_E, dma_base + CR);
+	iomd_writeb(0, dma_base + CR);
 	local_irq_restore(flags);
 }
 
diff -Nru a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
--- a/arch/arm/mm/consistent.c	Sun Apr 27 12:27:29 2003
+++ b/arch/arm/mm/consistent.c	Tue Apr 29 07:00:53 2003
@@ -330,7 +330,7 @@
 core_initcall(consistent_init);
 
 /*
- * make an area consistent for devices.
+ * Make an area consistent for devices.
  */
 void consistent_sync(void *vaddr, size_t size, int direction)
 {
diff -Nru a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
--- a/arch/arm/tools/mach-types	Mon Apr 28 15:43:10 2003
+++ b/arch/arm/tools/mach-types	Tue May 13 08:20:49 2003
@@ -6,7 +6,7 @@
 # To add an entry into this database, please see Documentation/arm/README,
 # or contact rmk@arm.linux.org.uk
 #
-# Last update: Sat Apr 26 11:41:41 2003
+# Last update: Wed May 7 23:43:08 2003
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -328,3 +328,14 @@
 nipc2			ARCH_NIPC2		NIPC2			317
 fu7202			ARCH_FU7202		FU7202			318
 adsagx			ARCH_ADSAGX		ADSAGX			319
+pxa_pooh		ARCH_PXA_POOH		PXA_POOH		320
+bandon			ARCH_BANDON		BANDON			321
+pcm7210			ARCH_PCM7210		PCM7210			322
+nms9200			ARCH_NMS9200		NMS9200			323
+gealog			ARCH_GEALOG		GEALOG			324
+m7140			SA1100_M7140		M7140			325
+korebot			ARCH_KOREBOT		KOREBOT			326
+iq31244			ARCH_IQ31244		IQ31244			327
+koan393			SA1100_KOAN393		KOAN393			328
+inhandftip3		ARCH_INHANDFTIP3	INHANDFTIP3		329
+gonzo			ARCH_GONZO		GONZO			330
diff -Nru a/arch/cris/drivers/eeprom.c b/arch/cris/drivers/eeprom.c
--- a/arch/cris/drivers/eeprom.c	Mon Feb 24 07:22:24 2003
+++ b/arch/cris/drivers/eeprom.c	Mon May 12 18:59:20 2003
@@ -163,7 +163,7 @@
   init_waitqueue_head(&eeprom.wait_q);
   eeprom.busy = 0;
 
-#if CONFIG_ETRAX_I2C_EEPROM_PROBE
+#ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE
 #define EETEXT "Found"
 #else
 #define EETEXT "Assuming"
@@ -191,7 +191,7 @@
   eeprom.usec_delay_step = 128;
   eeprom.adapt_state = 0;
   
-#if CONFIG_ETRAX_I2C_EEPROM_PROBE
+#ifdef CONFIG_ETRAX_I2C_EEPROM_PROBE
   i2c_start();
   i2c_outbyte(0x80);
   if(!i2c_getack())
diff -Nru a/arch/i386/Kconfig b/arch/i386/Kconfig
--- a/arch/i386/Kconfig	Wed Apr 30 00:03:51 2003
+++ b/arch/i386/Kconfig	Sun May  4 23:38:39 2003
@@ -65,19 +65,16 @@
 
 config X86_SUMMIT
 	bool "Summit/EXA (IBM x440)"
+	depends on SMP
 	help
 	  This option is needed for IBM systems that use the Summit/EXA chipset.
 	  In particular, it is needed for the x440.
 
 	  If you don't have one of these computers, you should say N here.
 
-config ACPI_SRAT
-	bool
-	default y
-	depends on NUMA && X86_SUMMIT
-
 config X86_BIGSMP
 	bool "Support for other sub-arch SMP systems with more than 8 CPUs"
+	depends on SMP
 	help
 	  This option is needed for the systems that have more than 8 CPUs
 	  and if the system is not of any sub-arch type above.
@@ -95,8 +92,24 @@
 	  A kernel compiled for the Visual Workstation will not run on PCs
 	  and vice versa. See <file:Documentation/sgi-visws.txt> for details.
 
+config X86_GENERICARCH
+       bool "Generic architecture (Summit, bigsmp, default)"
+       depends on SMP
+       help
+          This option compiles in the Summit, bigsmp, default subarchitectures.
+	  It is intended for a generic binary kernel.
+
 endchoice
 
+config ACPI_SRAT
+	bool
+	default y
+	depends on NUMA && (X86_SUMMIT || X86_GENERICARCH)
+
+config X86_CYCLONE_TIMER
+       bool 
+       default y
+       depends on X86_SUMMIT || X86_GENERICARCH
 
 choice
 	prompt "Processor family"
@@ -666,7 +679,7 @@
 # Common NUMA Features
 config NUMA
 	bool "Numa Memory Allocation Support"
-	depends on SMP && HIGHMEM64G && (X86_PC || X86_NUMAQ || (X86_SUMMIT && ACPI && !ACPI_HT_ONLY))
+	depends on SMP && HIGHMEM64G && (X86_PC || X86_NUMAQ || X86_GENERICARCH || (X86_SUMMIT && ACPI && !ACPI_HT_ONLY))
 	default n if X86_PC
 	default y if (X86_NUMAQ || X86_SUMMIT)
 
@@ -764,7 +777,7 @@
 # Summit needs it only when NUMA is on
 config BOOT_IOREMAP
 	bool
-	depends on (X86_SUMMIT && NUMA)
+	depends on ((X86_SUMMIT || X86_GENERICARCH) && NUMA)
 	default y
 
 endmenu
diff -Nru a/arch/i386/Makefile b/arch/i386/Makefile
--- a/arch/i386/Makefile	Sat May  3 22:45:16 2003
+++ b/arch/i386/Makefile	Sun May  4 23:38:34 2003
@@ -73,6 +73,11 @@
 mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-i386/mach-summit
 mcore-$(CONFIG_X86_SUMMIT)  := mach-default
 
+# generic subarchitecture
+mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic
+mcore-$(CONFIG_X86_GENERICARCH) := mach-default
+core-$(CONFIG_X86_GENERICARCH) += arch/i386/mach-generic/
+
 # default subarch .h files
 mflags-y += -Iinclude/asm-i386/mach-default
 
diff -Nru a/arch/i386/kernel/Makefile b/arch/i386/kernel/Makefile
--- a/arch/i386/kernel/Makefile	Wed Apr 23 14:03:25 2003
+++ b/arch/i386/kernel/Makefile	Sat May 17 14:09:37 2003
@@ -17,6 +17,7 @@
 obj-$(CONFIG_X86_MSR)		+= msr.o
 obj-$(CONFIG_X86_CPUID)		+= cpuid.o
 obj-$(CONFIG_MICROCODE)		+= microcode.o
+obj-$(CONFIG_PM)		+= suspend.o
 obj-$(CONFIG_APM)		+= apm.o
 obj-$(CONFIG_X86_SMP)		+= smp.o smpboot.o
 obj-$(CONFIG_X86_TRAMPOLINE)	+= trampoline.o
diff -Nru a/arch/i386/kernel/acpi/sleep.c b/arch/i386/kernel/acpi/sleep.c
--- a/arch/i386/kernel/acpi/sleep.c	Tue Feb 18 14:09:01 2003
+++ b/arch/i386/kernel/acpi/sleep.c	Mon May 12 18:59:20 2003
@@ -75,7 +75,7 @@
 		printk(KERN_ERR "ACPI: Wakeup code way too big, S3 disabled.\n");
 		return;
 	}
-#if CONFIG_X86_PAE
+#ifdef CONFIG_X86_PAE
 	printk(KERN_ERR "ACPI: S3 and PAE do not like each other for now, S3 disabled.\n");
 	return;
 #endif
diff -Nru a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c
--- a/arch/i386/kernel/apm.c	Sun Apr 20 12:56:03 2003
+++ b/arch/i386/kernel/apm.c	Wed May 14 19:10:19 2003
@@ -226,6 +226,7 @@
 #include <asm/system.h>
 #include <asm/uaccess.h>
 #include <asm/desc.h>
+#include <asm/suspend.h>
 
 #include "io_ports.h"
 
@@ -1165,9 +1166,13 @@
 #endif
 }
 
-static inline void reinit_timer(void)
+static void reinit_timer(void)
 {
 #ifdef INIT_TIMER_AFTER_SUSPEND
+	unsigned long	flags;
+	extern spinlock_t i8253_lock;
+
+	spin_lock_irqsave(&i8253_lock, flags);
 	/* set the clock to 100 Hz */
 	outb_p(0x34, PIT_MODE);		/* binary, mode 2, LSB/MSB, ch 0 */
 	udelay(10);
@@ -1175,6 +1180,7 @@
 	udelay(10);
 	outb(LATCH >> 8, PIT_CH0);	/* MSB */
 	udelay(10);
+	spin_unlock_irqrestore(&i8253_lock, flags);
 #endif
 }
 
@@ -1212,7 +1218,9 @@
 	spin_unlock(&i8253_lock);
 	write_sequnlock_irq(&xtime_lock);
 
+	save_processor_state();
 	err = set_system_power_state(APM_STATE_SUSPEND);
+	restore_processor_state();
 
 	write_seqlock_irq(&xtime_lock);
 	spin_lock(&i8253_lock);
diff -Nru a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c
--- a/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c	Tue Mar 11 15:37:30 2003
+++ b/arch/i386/kernel/cpu/cpufreq/gx-suspmod.c	Wed Apr 30 16:09:13 2003
@@ -147,7 +147,7 @@
 #ifdef SUSPMOD_DEBUG
 #define dprintk(msg...) printk(KERN_DEBUG "cpufreq:" msg)
 #else
-#define dprintk(msg...) do { } while(0);
+#define dprintk(msg...) do { } while(0)
 #endif
 
 /**
diff -Nru a/arch/i386/kernel/cpu/cpufreq/longhaul.c b/arch/i386/kernel/cpu/cpufreq/longhaul.c
--- a/arch/i386/kernel/cpu/cpufreq/longhaul.c	Sun Apr  6 17:54:39 2003
+++ b/arch/i386/kernel/cpu/cpufreq/longhaul.c	Wed Apr 30 16:09:13 2003
@@ -37,7 +37,7 @@
 #ifdef DEBUG
 #define dprintk(msg...) printk(msg)
 #else
-#define dprintk(msg...) do { } while(0);
+#define dprintk(msg...) do { } while(0)
 #endif
 
 static unsigned int numscales=16, numvscales;
diff -Nru a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c
--- a/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	Mon Mar 17 05:57:02 2003
+++ b/arch/i386/kernel/cpu/cpufreq/p4-clockmod.c	Mon May 12 21:23:13 2003
@@ -104,18 +104,20 @@
 	}
 
 	rdmsr(MSR_IA32_THERM_STATUS, l, h);
+#if 0
 	if (l & 0x01)
-//		printk(KERN_DEBUG PFX "CPU#%d currently thermal throttled\n", cpu);
-
+		printk(KERN_DEBUG PFX "CPU#%d currently thermal throttled\n", cpu);
+#endif
 	if (has_N44_O17_errata[cpu] && (newstate == DC_25PT || newstate == DC_DFLT))
 		newstate = DC_38PT;
 
 	rdmsr(MSR_IA32_THERM_CONTROL, l, h);
 	if (newstate == DC_DISABLE) {
-//		printk(KERN_INFO PFX "CPU#%d disabling modulation\n", cpu);
+		/* printk(KERN_INFO PFX "CPU#%d disabling modulation\n", cpu); */
 		wrmsr(MSR_IA32_THERM_CONTROL, l & ~(1<<4), h);
 	} else {
-//		printk(KERN_INFO PFX "CPU#%d setting duty cycle to %d%%\n", cpu, ((125 * newstate) / 10));
+		/* printk(KERN_INFO PFX "CPU#%d setting duty cycle to %d%%\n",
+			cpu, ((125 * newstate) / 10)); */
 		/* bits 63 - 5	: reserved 
 		 * bit  4	: enable/disable
 		 * bits 3-1	: duty cycle
diff -Nru a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c
--- a/arch/i386/kernel/cpu/cpufreq/powernow-k7.c	Tue Mar 11 16:54:54 2003
+++ b/arch/i386/kernel/cpu/cpufreq/powernow-k7.c	Tue May 13 19:21:24 2003
@@ -24,6 +24,7 @@
 #include <asm/msr.h>
 #include <asm/timex.h>
 #include <asm/io.h>
+#include <asm/system.h>
 
 #include "powernow-k7.h"
 
@@ -32,7 +33,7 @@
 #ifdef DEBUG
 #define dprintk(msg...) printk(msg)
 #else
-#define dprintk(msg...) do { } while(0);
+#define dprintk(msg...) do { } while(0)
 #endif
 
 #define PFX "powernow: "
@@ -89,7 +90,7 @@
 	rdmsr (msr, l__, h__);	\
 	val = l__;	\
 	val |= ((u64)h__<<32);	\
-} while(0);
+} while(0)
 #endif
 
 #ifndef wrmsrl
@@ -236,20 +237,24 @@
 
 	if (have_a0 == 1)	/* A0 errata 5 */
 		__asm__("\tcli\n");
-	rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
-	fidvidctl.bits.SGTC = latency;	/* Stop grant timeout counter */
 
-	fidvidctl.bits.FID = fid;
-	fidvidctl.bits.FIDC = 1;
+	/* First change the frequency. */
+	if (fidvidctl.bits.FID != fid) {
+		rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
+		fidvidctl.bits.SGTC = latency;	/* Stop grant timeout counter */
+		fidvidctl.bits.FID = fid;
+		fidvidctl.bits.FIDC = 1;
+		wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
+	}
 
-	/* Set the voltage lazily. Ie, only do voltage transition
-	   if its changed since last time (Some speeds have the same voltage) */
+	/* Now change voltage. */
 	if (fidvidctl.bits.VID != vid) {
+		rdmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
 		fidvidctl.bits.VID = vid;
 		fidvidctl.bits.VIDC = 1;
+		wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
 	}
 
-	wrmsrl (MSR_K7_FID_VID_CTL, fidvidctl.val);
 	if (have_a0 == 1)
 		__asm__("\tsti\n");
 
@@ -386,6 +391,10 @@
 
 static int __init powernow_init (void)
 {
+	if (dmi_broken & BROKEN_CPUFREQ) {
+		printk (KERN_INFO PFX "Disabled at boot time by DMI,\n");
+		return -ENODEV;
+	}
 	if (check_powernow()==0)
 		return -ENODEV;
 	return cpufreq_register_driver(&powernow_driver);
diff -Nru a/arch/i386/kernel/cpu/mtrr/if.c b/arch/i386/kernel/cpu/mtrr/if.c
--- a/arch/i386/kernel/cpu/mtrr/if.c	Tue Feb  4 17:52:11 2003
+++ b/arch/i386/kernel/cpu/mtrr/if.c	Wed May 14 23:43:54 2003
@@ -49,7 +49,7 @@
 	      struct file *file, int page)
 {
 	int reg;
-	unsigned int *fcount = file->private_data;
+	unsigned int *fcount = FILE_FCOUNT(file);
 
 	if (!page) {
 		if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)))
@@ -70,7 +70,7 @@
 
 /* RED-PEN: seq_file can seek now. this is ignored. */
 static ssize_t
-mtrr_write(struct file *file, const char *buf, size_t len, loff_t * ppos)
+mtrr_write(struct file *file, const char __user *buf, size_t len, loff_t * ppos)
 /*  Format of control line:
     "base=%Lx size=%Lx type=%s"     OR:
     "disable=%d"
@@ -133,12 +133,13 @@
 
 static int
 mtrr_ioctl(struct inode *inode, struct file *file,
-	   unsigned int cmd, unsigned long arg)
+	   unsigned int cmd, unsigned long __arg)
 {
 	int err;
 	mtrr_type type;
 	struct mtrr_sentry sentry;
 	struct mtrr_gentry gentry;
+	void __user *arg = (void __user *) __arg;
 
 	switch (cmd) {
 	default:
@@ -146,7 +147,7 @@
 	case MTRRIOC_ADD_ENTRY:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+		if (copy_from_user(&sentry, arg, sizeof sentry))
 			return -EFAULT;
 		err =
 		    mtrr_file_add(sentry.base, sentry.size, sentry.type, 1,
@@ -157,7 +158,7 @@
 	case MTRRIOC_SET_ENTRY:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+		if (copy_from_user(&sentry, arg, sizeof sentry))
 			return -EFAULT;
 		err = mtrr_add(sentry.base, sentry.size, sentry.type, 0);
 		if (err < 0)
@@ -166,7 +167,7 @@
 	case MTRRIOC_DEL_ENTRY:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+		if (copy_from_user(&sentry, arg, sizeof sentry))
 			return -EFAULT;
 		err = mtrr_file_del(sentry.base, sentry.size, file, 0);
 		if (err < 0)
@@ -175,14 +176,14 @@
 	case MTRRIOC_KILL_ENTRY:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+		if (copy_from_user(&sentry, arg, sizeof sentry))
 			return -EFAULT;
 		err = mtrr_del(-1, sentry.base, sentry.size);
 		if (err < 0)
 			return err;
 		break;
 	case MTRRIOC_GET_ENTRY:
-		if (copy_from_user(&gentry, (void *) arg, sizeof gentry))
+		if (copy_from_user(&gentry, arg, sizeof gentry))
 			return -EFAULT;
 		if (gentry.regnum >= num_var_ranges)
 			return -EINVAL;
@@ -198,13 +199,13 @@
 			gentry.type = type;
 		}
 
-		if (copy_to_user((void *) arg, &gentry, sizeof gentry))
+		if (copy_to_user(arg, &gentry, sizeof gentry))
 			return -EFAULT;
 		break;
 	case MTRRIOC_ADD_PAGE_ENTRY:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+		if (copy_from_user(&sentry, arg, sizeof sentry))
 			return -EFAULT;
 		err =
 		    mtrr_file_add(sentry.base, sentry.size, sentry.type, 1,
@@ -215,7 +216,7 @@
 	case MTRRIOC_SET_PAGE_ENTRY:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+		if (copy_from_user(&sentry, arg, sizeof sentry))
 			return -EFAULT;
 		err = mtrr_add_page(sentry.base, sentry.size, sentry.type, 0);
 		if (err < 0)
@@ -224,7 +225,7 @@
 	case MTRRIOC_DEL_PAGE_ENTRY:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+		if (copy_from_user(&sentry, arg, sizeof sentry))
 			return -EFAULT;
 		err = mtrr_file_del(sentry.base, sentry.size, file, 1);
 		if (err < 0)
@@ -233,21 +234,21 @@
 	case MTRRIOC_KILL_PAGE_ENTRY:
 		if (!capable(CAP_SYS_ADMIN))
 			return -EPERM;
-		if (copy_from_user(&sentry, (void *) arg, sizeof sentry))
+		if (copy_from_user(&sentry, arg, sizeof sentry))
 			return -EFAULT;
 		err = mtrr_del_page(-1, sentry.base, sentry.size);
 		if (err < 0)
 			return err;
 		break;
 	case MTRRIOC_GET_PAGE_ENTRY:
-		if (copy_from_user(&gentry, (void *) arg, sizeof gentry))
+		if (copy_from_user(&gentry, arg, sizeof gentry))
 			return -EFAULT;
 		if (gentry.regnum >= num_var_ranges)
 			return -EINVAL;
 		mtrr_if->get(gentry.regnum, &gentry.base, &gentry.size, &type);
 		gentry.type = type;
 
-		if (copy_to_user((void *) arg, &gentry, sizeof gentry))
+		if (copy_to_user(arg, &gentry, sizeof gentry))
 			return -EFAULT;
 		break;
 	}
diff -Nru a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c
--- a/arch/i386/kernel/dmi_scan.c	Thu Apr 17 12:53:36 2003
+++ b/arch/i386/kernel/dmi_scan.c	Mon May 12 21:41:52 2003
@@ -511,6 +511,14 @@
 	return 0;
 }
 
+static __init int acer_cpufreq_pst(struct dmi_blacklist *d)
+{
+	printk(KERN_WARNING "%s laptop with broken PST tables in BIOS detected.\n", d->ident);
+	printk(KERN_WARNING "You need to downgrade to 3A21 (09/09/2002), or try a newer BIOS than 3A71 (01/20/2003)\n");
+	printk(KERN_WARNING "cpufreq scaling has been disabled as a result of this.\n");
+	dmi_broken |= BROKEN_CPUFREQ;
+	return 0;
+}
 
 
 /*
@@ -823,6 +831,17 @@
 	{ disable_smbus, "IBM", {
 			MATCH(DMI_SYS_VENDOR, "IBM"),
 			NO_MATCH, NO_MATCH, NO_MATCH
+			} },
+
+	/*
+	 * Some Athlon laptops have really fucked PST tables.
+	 * A BIOS update is all that can save them.
+	 * Mention this, and disable cpufreq.
+	 */
+	{ acer_cpufreq_pst, "Acer Aspire", {
+			MATCH(DMI_SYS_VENDOR, "Insyde Software"),
+			MATCH(DMI_BIOS_VERSION, "3A71"),
+			NO_MATCH, NO_MATCH,
 			} },
 
 	{ NULL, }
diff -Nru a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S
--- a/arch/i386/kernel/entry.S	Wed Apr 23 13:37:55 2003
+++ b/arch/i386/kernel/entry.S	Fri May 16 15:04:55 2003
@@ -497,13 +497,19 @@
 	pushl $do_debug
 	jmp error_code
 
+/*
+ * NMI is doubly nasty. It can happen _while_ we're handling
+ * a debug fault, and the debug fault hasn't yet been able to
+ * clear up the stack. So we first check whether we got  an
+ * NMI on the sysenter entry path, but after that we need to
+ * check whether we got an NMI on the debug path where the debug
+ * fault happened on the sysenter path.
+ */
 ENTRY(nmi)
 	cmpl $sysenter_entry,(%esp)
 	je nmi_stack_fixup
-	cmpl $debug - 1,(%esp)
-	jle nmi_stack_correct
-	cmpl $debug_esp_fix_insn,(%esp)
-	jle nmi_debug_stack_fixup
+	cmpl $sysenter_entry,12(%esp)
+	je nmi_debug_stack_check
 nmi_stack_correct:
 	pushl %eax
 	SAVE_ALL
@@ -517,6 +523,13 @@
 nmi_stack_fixup:
 	FIX_STACK(12,nmi_stack_correct, 1)
 	jmp nmi_stack_correct
+nmi_debug_stack_check:
+	cmpw $__KERNEL_CS,16(%esp)
+	jne nmi_stack_correct
+	cmpl $debug - 1,(%esp)
+	jle nmi_stack_correct
+	cmpl $debug_esp_fix_insn,(%esp)
+	jle nmi_debug_stack_fixup
 nmi_debug_stack_fixup:
 	FIX_STACK(24,nmi_stack_correct, 1)
 	jmp nmi_stack_correct
diff -Nru a/arch/i386/kernel/head.S b/arch/i386/kernel/head.S
--- a/arch/i386/kernel/head.S	Mon Mar 17 02:19:12 2003
+++ b/arch/i386/kernel/head.S	Mon May 12 18:59:20 2003
@@ -483,7 +483,7 @@
 	.quad 0x0000000000000000	/* 0xf0 - unused */
 	.quad 0x0000000000000000	/* 0xf8 - GDT entry 31: double-fault TSS */
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	.fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */
 #endif
 
diff -Nru a/arch/i386/kernel/i386_ksyms.c b/arch/i386/kernel/i386_ksyms.c
--- a/arch/i386/kernel/i386_ksyms.c	Sat Apr 12 21:45:43 2003
+++ b/arch/i386/kernel/i386_ksyms.c	Mon May 12 21:22:56 2003
@@ -73,9 +73,6 @@
 #ifdef CONFIG_X86_NUMAQ
 EXPORT_SYMBOL(xquad_portio);
 #endif
-#ifndef CONFIG_X86_WP_WORKS_OK
-EXPORT_SYMBOL(__verify_write);
-#endif
 EXPORT_SYMBOL(dump_thread);
 EXPORT_SYMBOL(dump_fpu);
 EXPORT_SYMBOL(dump_extended_fpu);
diff -Nru a/arch/i386/kernel/i8259.c b/arch/i386/kernel/i8259.c
--- a/arch/i386/kernel/i8259.c	Sun Apr 20 14:14:28 2003
+++ b/arch/i386/kernel/i8259.c	Mon Apr 21 17:23:12 2003
@@ -373,11 +373,16 @@
 
 static void setup_timer(void)
 {
+	extern spinlock_t i8253_lock;
+	unsigned long flags;
+
+	spin_lock_irqsave(&i8253_lock, flags);
 	outb_p(0x34,PIT_MODE);		/* binary, mode 2, LSB/MSB, ch 0 */
 	udelay(10);
 	outb_p(LATCH & 0xff , PIT_CH0);	/* LSB */
 	udelay(10);
 	outb(LATCH >> 8 , PIT_CH0);	/* MSB */
+	spin_unlock_irqrestore(&i8253_lock, flags);
 }
 
 static int timer_resume(struct device *dev, u32 level)
diff -Nru a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c
--- a/arch/i386/kernel/io_apic.c	Fri Apr 25 20:56:10 2003
+++ b/arch/i386/kernel/io_apic.c	Wed May 14 23:43:55 2003
@@ -219,6 +219,14 @@
 {
 	struct IO_APIC_route_entry entry;
 	unsigned long flags;
+	
+	/* Check delivery_mode to be sure we're not clearing an SMI pin */
+	spin_lock_irqsave(&ioapic_lock, flags);
+	*(((int*)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
+	*(((int*)&entry) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
+	spin_unlock_irqrestore(&ioapic_lock, flags);
+	if (entry.delivery_mode == dest_SMI)
+		return;
 
 	/*
 	 * Disable it in the IO-APIC irq-routing table:
@@ -240,22 +248,22 @@
 			clear_IO_APIC_pin(apic, pin);
 }
 
-static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
+static void set_ioapic_affinity (unsigned int irq, unsigned long cpu_mask)
 {
 	unsigned long flags;
 	int pin;
 	struct irq_pin_list *entry = irq_2_pin + irq;
-
-	/*
-	 * Only the first 8 bits are valid.
-	 */
-	mask = mask << 24;
+	unsigned int apicid_value;
+	
+	apicid_value = cpu_mask_to_apicid(cpu_mask);
+	/* Prepare to do the io_apic_write */
+	apicid_value = apicid_value << 24;
 	spin_lock_irqsave(&ioapic_lock, flags);
 	for (;;) {
 		pin = entry->pin;
 		if (pin == -1)
 			break;
-		io_apic_write(entry->apic, 0x10 + 1 + pin*2, mask);
+		io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value);
 		if (!entry->next)
 			break;
 		entry = irq_2_pin + entry->next;
@@ -279,8 +287,10 @@
 
 extern unsigned long irq_affinity[NR_IRQS];
 
-static int __cacheline_aligned pending_irq_balance_apicid[NR_IRQS];
-static int irqbalance_disabled = NO_BALANCE_IRQ;
+static int __cacheline_aligned pending_irq_balance_cpumask[NR_IRQS];
+
+#define IRQBALANCE_CHECK_ARCH -999
+static int irqbalance_disabled = IRQBALANCE_CHECK_ARCH;
 static int physical_balance = 0;
 
 struct irq_cpu_info {
@@ -342,8 +352,10 @@
 	unsigned long allowed_mask;
 	unsigned int new_cpu;
 		
-	if (irqbalance_disabled)
+	if (irqbalance_disabled == IRQBALANCE_CHECK_ARCH && NO_BALANCE_IRQ)
 		return;
+	else if (irqbalance_disabled) 
+		return; 
 
 	allowed_mask = cpu_online_map & irq_affinity[irq];
 	new_cpu = move(cpu, allowed_mask, now, 1);
@@ -352,7 +364,7 @@
 		unsigned long flags;
 
 		spin_lock_irqsave(&desc->lock, flags);
-		pending_irq_balance_apicid[irq]=cpu_to_logical_apicid(new_cpu);
+		pending_irq_balance_cpumask[irq] = 1 << new_cpu;
 		spin_unlock_irqrestore(&desc->lock, flags);
 	}
 }
@@ -549,8 +561,7 @@
 				selected_irq, min_loaded);
 		/* mark for change destination */
 		spin_lock_irqsave(&desc->lock, flags);
-		pending_irq_balance_apicid[selected_irq] =
-				cpu_to_logical_apicid(min_loaded);
+		pending_irq_balance_cpumask[selected_irq] = 1 << min_loaded;
 		spin_unlock_irqrestore(&desc->lock, flags);
 		/* Since we made a change, come back sooner to 
 		 * check for more variation.
@@ -582,7 +593,7 @@
 	
 	/* push everything to CPU 0 to give us a starting point.  */
 	for (i = 0 ; i < NR_IRQS ; i++)
-		pending_irq_balance_apicid[i] = cpu_to_logical_apicid(0);
+		pending_irq_balance_cpumask[i] = 1;
 
 repeat:
 	set_current_state(TASK_INTERRUPTIBLE);
@@ -659,9 +670,9 @@
 static inline void move_irq(int irq)
 {
 	/* note - we hold the desc->lock */
-	if (unlikely(pending_irq_balance_apicid[irq])) {
-		set_ioapic_affinity(irq, pending_irq_balance_apicid[irq]);
-		pending_irq_balance_apicid[irq] = 0;
+	if (unlikely(pending_irq_balance_cpumask[irq])) {
+		set_ioapic_affinity(irq, pending_irq_balance_cpumask[irq]);
+		pending_irq_balance_cpumask[irq] = 0;
 	}
 }
 
diff -Nru a/arch/i386/kernel/ioport.c b/arch/i386/kernel/ioport.c
--- a/arch/i386/kernel/ioport.c	Sat Jan  4 10:06:07 2003
+++ b/arch/i386/kernel/ioport.c	Fri Mar 14 07:19:48 2003
@@ -84,15 +84,17 @@
 		t->ts_io_bitmap = bitmap;
 	}
 
-	tss = init_tss + get_cpu();
-	if (bitmap)
-		tss->bitmap = IO_BITMAP_OFFSET;	/* Activate it in the TSS */
-
 	/*
 	 * do it in the per-thread copy and in the TSS ...
 	 */
 	set_bitmap(t->ts_io_bitmap, from, num, !turn_on);
-	set_bitmap(tss->io_bitmap, from, num, !turn_on);
+	tss = init_tss + get_cpu();
+	if (tss->bitmap == IO_BITMAP_OFFSET) { /* already active? */
+		set_bitmap(tss->io_bitmap, from, num, !turn_on);
+	} else {
+		memcpy(tss->io_bitmap, t->ts_io_bitmap, IO_BITMAP_BYTES);
+		tss->bitmap = IO_BITMAP_OFFSET;	/* Activate it in the TSS */
+	}
 	put_cpu();
 out:
 	return ret;
diff -Nru a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c
--- a/arch/i386/kernel/irq.c	Tue Apr 22 03:15:43 2003
+++ b/arch/i386/kernel/irq.c	Mon May 12 18:59:20 2003
@@ -92,7 +92,7 @@
  * each architecture has to answer this themselves, it doesn't deserve
  * a generic callback i think.
  */
-#if CONFIG_X86
+#ifdef CONFIG_X86
 	printk("unexpected IRQ trap at vector %02x\n", irq);
 #ifdef CONFIG_X86_LOCAL_APIC
 	/*
@@ -173,7 +173,7 @@
 		if (cpu_online(j))
 			seq_printf(p, "%10u ", nmi_count(j));
 	seq_putc(p, '\n');
-#if CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_X86_LOCAL_APIC
 	seq_printf(p, "LOC: ");
 	for (j = 0; j < NR_CPUS; j++)
 		if (cpu_online(j))
@@ -189,7 +189,7 @@
 	return 0;
 }
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 inline void synchronize_irq(unsigned int irq)
 {
 	while (irq_desc[irq].status & IRQ_INPROGRESS)
@@ -828,7 +828,7 @@
 
 #define HEX_DIGITS 8
 
-static unsigned int parse_hex_value (const char *buffer,
+static unsigned int parse_hex_value (const char __user *buffer,
 		unsigned long count, unsigned long *ret)
 {
 	unsigned char hexnum [HEX_DIGITS];
@@ -865,7 +865,7 @@
 	return 0;
 }
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 
 static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
 
@@ -878,7 +878,7 @@
 	return sprintf (page, "%08lx\n", irq_affinity[(long)data]);
 }
 
-static int irq_affinity_write_proc (struct file *file, const char *buffer,
+static int irq_affinity_write_proc (struct file *file, const char __user *buffer,
 					unsigned long count, void *data)
 {
 	int irq = (long) data, full_count = count, err;
@@ -914,7 +914,7 @@
 	return sprintf (page, "%08lx\n", *mask);
 }
 
-static int prof_cpu_mask_write_proc (struct file *file, const char *buffer,
+static int prof_cpu_mask_write_proc (struct file *file, const char __user *buffer,
 					unsigned long count, void *data)
 {
 	unsigned long *mask = (unsigned long *) data, full_count = count, err;
@@ -944,7 +944,7 @@
 	/* create /proc/irq/1234 */
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	{
 		struct proc_dir_entry *entry;
 
diff -Nru a/arch/i386/kernel/ldt.c b/arch/i386/kernel/ldt.c
--- a/arch/i386/kernel/ldt.c	Sun Mar  2 18:13:55 2003
+++ b/arch/i386/kernel/ldt.c	Fri May  9 14:21:10 2003
@@ -119,7 +119,7 @@
 	}
 }
 
-static int read_ldt(void * ptr, unsigned long bytecount)
+static int read_ldt(void __user * ptr, unsigned long bytecount)
 {
 	int err;
 	unsigned long size;
@@ -148,7 +148,7 @@
 	return bytecount;
 }
 
-static int read_default_ldt(void * ptr, unsigned long bytecount)
+static int read_default_ldt(void __user * ptr, unsigned long bytecount)
 {
 	int err;
 	unsigned long size;
@@ -167,7 +167,7 @@
 	return err;
 }
 
-static int write_ldt(void * ptr, unsigned long bytecount, int oldmode)
+static int write_ldt(void __user * ptr, unsigned long bytecount, int oldmode)
 {
 	struct mm_struct * mm = current->mm;
 	__u32 entry_1, entry_2, *lp;
@@ -226,7 +226,7 @@
 	return error;
 }
 
-asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
+asmlinkage int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
 {
 	int ret = -ENOSYS;
 
diff -Nru a/arch/i386/kernel/module.c b/arch/i386/kernel/module.c
--- a/arch/i386/kernel/module.c	Tue Apr 22 03:17:44 2003
+++ b/arch/i386/kernel/module.c	Mon May 12 21:23:07 2003
@@ -123,3 +123,7 @@
 	} 	
 	return 0;
 }
+
+void module_arch_cleanup(struct module *mod)
+{
+}
diff -Nru a/arch/i386/kernel/mpparse.c b/arch/i386/kernel/mpparse.c
--- a/arch/i386/kernel/mpparse.c	Wed Apr 23 10:32:20 2003
+++ b/arch/i386/kernel/mpparse.c	Sun May  4 23:38:34 2003
@@ -73,7 +73,9 @@
 /* Bitmask of physically existing CPUs */
 unsigned long phys_cpu_present_map;
 
+#ifndef CONFIG_X86_GENERICARCH
 int x86_summit = 0;
+#endif
 u8 bios_cpu_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
 
 /*
diff -Nru a/arch/i386/kernel/msr.c b/arch/i386/kernel/msr.c
--- a/arch/i386/kernel/msr.c	Tue Mar 18 13:22:30 2003
+++ b/arch/i386/kernel/msr.c	Sun Apr  6 15:05:55 2003
@@ -120,8 +120,6 @@
   preempt_disable();
   if ( cpu == smp_processor_id() ) {
     ret = wrmsr_eio(reg, eax, edx);
-    preempt_enable();
-    return ret;
   } else {
     cmd.cpu = cpu;
     cmd.reg = reg;
@@ -129,17 +127,20 @@
     cmd.data[1] = edx;
     
     smp_call_function(msr_smp_wrmsr, &cmd, 1, 1);
-    preempt_enable();
-    return cmd.err;
+    ret = cmd.err;
   }
+  preempt_enable();
+  return ret;
 }
 
 static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
 {
   struct msr_command cmd;
+  int ret;
 
+  preempt_disable();
   if ( cpu == smp_processor_id() ) {
-    return rdmsr_eio(reg, eax, edx);
+    ret = rdmsr_eio(reg, eax, edx);
   } else {
     cmd.cpu = cpu;
     cmd.reg = reg;
@@ -149,8 +150,10 @@
     *eax = cmd.data[0];
     *edx = cmd.data[1];
 
-    return cmd.err;
+    ret = cmd.err;
   }
+  preempt_enable();
+  return ret;
 }
 
 #else /* ! CONFIG_SMP */
diff -Nru a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c
--- a/arch/i386/kernel/process.c	Wed Apr 16 15:34:51 2003
+++ b/arch/i386/kernel/process.c	Sun May 18 17:00:00 2003
@@ -212,7 +212,6 @@
  */
 int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
 {
-	struct task_struct *p;
 	struct pt_regs regs;
 
 	memset(&regs, 0, sizeof(regs));
@@ -228,8 +227,7 @@
 	regs.eflags = 0x286;
 
 	/* Ok, create the new process.. */
-	p = do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
 }
 
 /*
@@ -518,27 +516,22 @@
 
 asmlinkage int sys_fork(struct pt_regs regs)
 {
-	struct task_struct *p;
-
-	p = do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
 }
 
 asmlinkage int sys_clone(struct pt_regs regs)
 {
-	struct task_struct *p;
 	unsigned long clone_flags;
 	unsigned long newsp;
-	int *parent_tidptr, *child_tidptr;
+	int __user *parent_tidptr, *child_tidptr;
 
 	clone_flags = regs.ebx;
 	newsp = regs.ecx;
-	parent_tidptr = (int *)regs.edx;
-	child_tidptr = (int *)regs.edi;
+	parent_tidptr = (int __user *)regs.edx;
+	child_tidptr = (int __user *)regs.edi;
 	if (!newsp)
 		newsp = regs.esp;
-	p = do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, parent_tidptr, child_tidptr);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(clone_flags & ~CLONE_IDLETASK, newsp, &regs, 0, parent_tidptr, child_tidptr);
 }
 
 /*
@@ -553,10 +546,7 @@
  */
 asmlinkage int sys_vfork(struct pt_regs regs)
 {
-	struct task_struct *p;
-
-	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0, NULL, NULL);
 }
 
 /*
diff -Nru a/arch/i386/kernel/ptrace.c b/arch/i386/kernel/ptrace.c
--- a/arch/i386/kernel/ptrace.c	Thu Feb 13 08:45:49 2003
+++ b/arch/i386/kernel/ptrace.c	Mon May 12 11:10:09 2003
@@ -155,7 +155,7 @@
  */
 static int
 ptrace_get_thread_area(struct task_struct *child,
-		       int idx, struct user_desc *user_desc)
+		       int idx, struct user_desc __user *user_desc)
 {
 	struct user_desc info;
 	struct desc_struct *desc;
@@ -206,7 +206,7 @@
  */
 static int
 ptrace_set_thread_area(struct task_struct *child,
-		       int idx, struct user_desc *user_desc)
+		       int idx, struct user_desc __user *user_desc)
 {
 	struct user_desc info;
 	struct desc_struct *desc;
@@ -458,7 +458,7 @@
 		ret = 0;
 		if (!child->used_math)
 			init_fpu(child);
-		get_fpregs((struct user_i387_struct *)data, child);
+		get_fpregs((struct user_i387_struct __user *)data, child);
 		break;
 	}
 
@@ -469,7 +469,7 @@
 			break;
 		}
 		child->used_math = 1;
-		set_fpregs(child, (struct user_i387_struct *)data);
+		set_fpregs(child, (struct user_i387_struct __user *)data);
 		ret = 0;
 		break;
 	}
@@ -482,7 +482,7 @@
 		}
 		if (!child->used_math)
 			init_fpu(child);
-		ret = get_fpxregs((struct user_fxsr_struct *)data, child);
+		ret = get_fpxregs((struct user_fxsr_struct __user *)data, child);
 		break;
 	}
 
@@ -493,18 +493,18 @@
 			break;
 		}
 		child->used_math = 1;
-		ret = set_fpxregs(child, (struct user_fxsr_struct *)data);
+		ret = set_fpxregs(child, (struct user_fxsr_struct __user *)data);
 		break;
 	}
 
 	case PTRACE_GET_THREAD_AREA:
 		ret = ptrace_get_thread_area(child,
-					     addr, (struct user_desc *) data);
+					     addr, (struct user_desc __user *) data);
 		break;
 
 	case PTRACE_SET_THREAD_AREA:
 		ret = ptrace_set_thread_area(child,
-					     addr, (struct user_desc *) data);
+					     addr, (struct user_desc __user *) data);
 		break;
 
 	default:
diff -Nru a/arch/i386/kernel/reboot.c b/arch/i386/kernel/reboot.c
--- a/arch/i386/kernel/reboot.c	Fri Feb 14 14:48:47 2003
+++ b/arch/i386/kernel/reboot.c	Mon May 12 18:59:20 2003
@@ -215,7 +215,7 @@
 
 void machine_restart(char * __unused)
 {
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	int cpuid;
 	
 	cpuid = GET_APIC_ID(apic_read(APIC_ID));
diff -Nru a/arch/i386/kernel/setup.c b/arch/i386/kernel/setup.c
--- a/arch/i386/kernel/setup.c	Wed Apr 30 01:07:09 2003
+++ b/arch/i386/kernel/setup.c	Mon May 19 11:26:52 2003
@@ -91,6 +91,7 @@
 
 extern void early_cpu_init(void);
 extern void dmi_scan_machine(void);
+extern void generic_apic_probe(char *);
 extern int root_mountflags;
 extern char _text, _etext, _edata, _end;
 extern int blk_nohighio;
@@ -596,7 +597,7 @@
 	} else {
 		if (highmem_pages == -1)
 			highmem_pages = 0;
-#if CONFIG_HIGHMEM
+#ifdef CONFIG_HIGHMEM
 		if (highmem_pages >= max_pfn) {
 			printk(KERN_ERR "highmem size specified (%uMB) is bigger than pages available (%luMB)!.\n", pages_to_mb(highmem_pages), pages_to_mb(max_pfn));
 			highmem_pages = 0;
@@ -798,13 +799,13 @@
 /* Use inline assembly to define this because the nops are defined 
    as inline assembly strings in the include files and we cannot 
    get them easily into strings. */
-asm("intelnops: " 
+asm("\t.data\nintelnops: " 
     GENERIC_NOP1 GENERIC_NOP2 GENERIC_NOP3 GENERIC_NOP4 GENERIC_NOP5 GENERIC_NOP6
     GENERIC_NOP7 GENERIC_NOP8); 
-asm("k8nops: " 
+asm("\t.data\nk8nops: " 
     K8_NOP1 K8_NOP2 K8_NOP3 K8_NOP4 K8_NOP5 K8_NOP6
     K8_NOP7 K8_NOP8); 
-asm("k7nops: " 
+asm("\t.data\nk7nops: " 
     K7_NOP1 K7_NOP2 K7_NOP3 K7_NOP4 K7_NOP5 K7_NOP6
     K7_NOP7 K7_NOP8); 
     
@@ -959,6 +960,13 @@
 	smp_alloc_memory(); /* AP processor realmode stacks in low memory*/
 #endif
 	paging_init();
+
+	dmi_scan_machine();
+
+#ifdef CONFIG_X86_GENERICARCH
+	generic_apic_probe(*cmdline_p);
+#endif	
+
 #ifdef CONFIG_ACPI_BOOT
 	/*
 	 * Parse the ACPI tables for possible boot-time SMP configuration.
@@ -980,7 +988,6 @@
 	conswitchp = &dummy_con;
 #endif
 #endif
-	dmi_scan_machine();
 }
 
 static int __init highio_setup(char *str)
diff -Nru a/arch/i386/kernel/signal.c b/arch/i386/kernel/signal.c
--- a/arch/i386/kernel/signal.c	Sat May  3 22:45:16 2003
+++ b/arch/i386/kernel/signal.c	Mon May 12 14:35:19 2003
@@ -116,7 +116,7 @@
 }
 
 asmlinkage int
-sys_sigaltstack(const stack_t *uss, stack_t *uoss)
+sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss)
 {
 	struct pt_regs *regs = (struct pt_regs *) &uss;
 	return do_sigaltstack(uss, uoss, regs->esp);
@@ -244,6 +244,11 @@
 		goto badframe;
 	/* It is more difficult to avoid calling this function than to
 	   call it and ignore errors.  */
+	/*
+	 * THIS CANNOT WORK! "&st" is a kernel address, and "do_sigaltstack()"
+	 * takes a user address (and verifies that it is a user address). End
+	 * result: it does exactly _nothing_.
+	 */
 	do_sigaltstack(&st, NULL, regs->esp);
 
 	return eax;
diff -Nru a/arch/i386/kernel/smp.c b/arch/i386/kernel/smp.c
--- a/arch/i386/kernel/smp.c	Thu Mar 27 21:08:54 2003
+++ b/arch/i386/kernel/smp.c	Sun May  4 23:38:34 2003
@@ -123,7 +123,7 @@
 	return SET_APIC_DEST_FIELD(mask);
 }
 
-static inline void __send_IPI_shortcut(unsigned int shortcut, int vector)
+inline void __send_IPI_shortcut(unsigned int shortcut, int vector)
 {
 	/*
 	 * Subtle. In the case of the 'never do double writes' workaround
@@ -155,7 +155,7 @@
 	__send_IPI_shortcut(APIC_DEST_SELF, vector);
 }
 
-static inline void send_IPI_mask_bitmask(int mask, int vector)
+inline void send_IPI_mask_bitmask(int mask, int vector)
 {
 	unsigned long cfg;
 	unsigned long flags;
@@ -186,7 +186,7 @@
 	local_irq_restore(flags);
 }
 
-static inline void send_IPI_mask_sequence(int mask, int vector)
+inline void send_IPI_mask_sequence(int mask, int vector)
 {
 	unsigned long cfg, flags;
 	unsigned int query_cpu, query_mask;
diff -Nru a/arch/i386/kernel/smpboot.c b/arch/i386/kernel/smpboot.c
--- a/arch/i386/kernel/smpboot.c	Tue Apr  8 11:19:15 2003
+++ b/arch/i386/kernel/smpboot.c	Sun May 18 17:00:00 2003
@@ -493,7 +493,7 @@
 	 * don't care about the eip and regs settings since
 	 * we'll never reschedule the forked task.
 	 */
-	return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
 }
 
 #ifdef CONFIG_NUMA
@@ -793,6 +793,7 @@
 	idle = fork_by_hand();
 	if (IS_ERR(idle))
 		panic("failed fork for CPU %d", cpu);
+	wake_up_forked_process(idle);
 
 	/*
 	 * We remove it from the pidhash and the runqueue
@@ -935,7 +936,7 @@
 
 static void __init smp_boot_cpus(unsigned int max_cpus)
 {
-	int apicid, cpu, bit;
+	int apicid, cpu, bit, kicked;
 
 	/*
 	 * Setup boot CPU information
@@ -1018,7 +1019,8 @@
 	 */
 	Dprintk("CPU present map: %lx\n", phys_cpu_present_map);
 
-	for (bit = 0; bit < NR_CPUS; bit++) {
+	kicked = 1;
+	for (bit = 0; kicked < NR_CPUS && bit < BITS_PER_LONG; bit++) {
 		apicid = cpu_present_to_apicid(bit);
 		/*
 		 * Don't even attempt to start the boot CPU!
@@ -1034,6 +1036,8 @@
 		if (do_boot_cpu(apicid))
 			printk("CPU #%d not responding - cannot use it.\n",
 								apicid);
+		else
+			++kicked;
 	}
 
 	/*
@@ -1149,11 +1153,13 @@
 
 void __init smp_cpus_done(unsigned int max_cpus)
 {
+#ifdef CONFIG_X86_IO_APIC
 	setup_ioapic_dest(TARGET_CPUS);
+#endif
 	zap_low_mappings();
 }
 
-void __init smp_intr_init()
+void __init smp_intr_init(void)
 {
 	/*
 	 * IRQ0 must be given a fixed assignment and initialized,
diff -Nru a/arch/i386/kernel/suspend.c b/arch/i386/kernel/suspend.c
--- a/arch/i386/kernel/suspend.c	Thu Apr  3 15:03:46 2003
+++ b/arch/i386/kernel/suspend.c	Sat May 17 14:09:37 2003
@@ -27,9 +27,7 @@
 #include <asm/tlbflush.h>
 
 static struct saved_context saved_context;
-unsigned long saved_context_eax, saved_context_ebx, saved_context_ecx, saved_context_edx;
-unsigned long saved_context_esp, saved_context_ebp, saved_context_esi, saved_context_edi;
-unsigned long saved_context_eflags;
+static void fix_processor_context(void);
 
 extern void enable_sep_cpu(void *);
 
@@ -107,7 +105,7 @@
 	do_fpu_end();
 }
 
-void fix_processor_context(void)
+static void fix_processor_context(void)
 {
 	int cpu = smp_processor_id();
 	struct tss_struct * t = init_tss + cpu;
@@ -132,3 +130,6 @@
 	}
 
 }
+
+EXPORT_SYMBOL(save_processor_state);
+EXPORT_SYMBOL(restore_processor_state);
diff -Nru a/arch/i386/kernel/suspend_asm.S b/arch/i386/kernel/suspend_asm.S
--- a/arch/i386/kernel/suspend_asm.S	Wed Dec 25 23:45:34 2002
+++ b/arch/i386/kernel/suspend_asm.S	Sat May 17 14:09:56 2003
@@ -6,6 +6,34 @@
 #include <asm/segment.h>
 #include <asm/page.h>
 
+	.data
+	.align	4
+	.globl	saved_context_eax, saved_context_ebx
+	.globl	saved_context_ecx, saved_context_edx
+	.globl	saved_context_esp, saved_context_ebp
+	.globl	saved_context_esi, saved_context_edi
+	.globl	saved_context_eflags
+saved_context_eax:
+	.long	0
+saved_context_ebx:
+	.long	0
+saved_context_ecx:
+	.long	0
+saved_context_edx:
+	.long	0
+saved_context_esp:
+	.long	0
+saved_context_ebp:
+	.long	0
+saved_context_esi:
+	.long	0
+saved_context_edi:
+	.long	0
+saved_context_eflags:
+	.long	0
+
+	.text
+
 ENTRY(do_magic)
 	pushl %ebx
 	cmpl $0,8(%esp)
diff -Nru a/arch/i386/kernel/sys_i386.c b/arch/i386/kernel/sys_i386.c
--- a/arch/i386/kernel/sys_i386.c	Wed Apr  2 12:31:12 2003
+++ b/arch/i386/kernel/sys_i386.c	Fri May  9 14:22:12 2003
@@ -26,7 +26,7 @@
  * sys_pipe() is the normal C calling standard for creating
  * a pipe. It's not the way Unix traditionally does this, though.
  */
-asmlinkage int sys_pipe(unsigned long * fildes)
+asmlinkage int sys_pipe(unsigned long __user * fildes)
 {
 	int fd[2];
 	int error;
@@ -88,7 +88,7 @@
 	unsigned long offset;
 };
 
-asmlinkage int old_mmap(struct mmap_arg_struct *arg)
+asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
 {
 	struct mmap_arg_struct a;
 	int err = -EFAULT;
@@ -106,15 +106,15 @@
 }
 
 
-extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+extern asmlinkage int sys_select(int, fd_set __user *, fd_set __user *, fd_set __user *, struct timeval __user *);
 
 struct sel_arg_struct {
 	unsigned long n;
-	fd_set *inp, *outp, *exp;
-	struct timeval *tvp;
+	fd_set __user *inp, *outp, *exp;
+	struct timeval __user *tvp;
 };
 
-asmlinkage int old_select(struct sel_arg_struct *arg)
+asmlinkage int old_select(struct sel_arg_struct __user *arg)
 {
 	struct sel_arg_struct a;
 
@@ -130,7 +130,7 @@
  * This is really horribly ugly.
  */
 asmlinkage int sys_ipc (uint call, int first, int second,
-			int third, void *ptr, long fifth)
+			int third, void __user *ptr, long fifth)
 {
 	int version, ret;
 
@@ -139,10 +139,10 @@
 
 	switch (call) {
 	case SEMOP:
-		return sys_semtimedop (first, (struct sembuf *)ptr, second, NULL);
+		return sys_semtimedop (first, (struct sembuf __user *)ptr, second, NULL);
 	case SEMTIMEDOP:
-		return sys_semtimedop(first, (struct sembuf *)ptr, second,
-					(const struct timespec *)fifth);
+		return sys_semtimedop(first, (struct sembuf __user *)ptr, second,
+					(const struct timespec __user *)fifth);
 
 	case SEMGET:
 		return sys_semget (first, second, third);
@@ -150,13 +150,13 @@
 		union semun fourth;
 		if (!ptr)
 			return -EINVAL;
-		if (get_user(fourth.__pad, (void **) ptr))
+		if (get_user(fourth.__pad, (void * __user *) ptr))
 			return -EFAULT;
 		return sys_semctl (first, second, third, fourth);
 	}
 
 	case MSGSND:
-		return sys_msgsnd (first, (struct msgbuf *) ptr, 
+		return sys_msgsnd (first, (struct msgbuf __user *) ptr, 
 				   second, third);
 	case MSGRCV:
 		switch (version) {
@@ -166,7 +166,7 @@
 				return -EINVAL;
 			
 			if (copy_from_user(&tmp,
-					   (struct ipc_kludge *) ptr, 
+					   (struct ipc_kludge __user *) ptr, 
 					   sizeof (tmp)))
 				return -EFAULT;
 			return sys_msgrcv (first, tmp.msgp, second,
@@ -174,35 +174,36 @@
 		}
 		default:
 			return sys_msgrcv (first,
-					   (struct msgbuf *) ptr,
+					   (struct msgbuf __user *) ptr,
 					   second, fifth, third);
 		}
 	case MSGGET:
 		return sys_msgget ((key_t) first, second);
 	case MSGCTL:
-		return sys_msgctl (first, second, (struct msqid_ds *) ptr);
+		return sys_msgctl (first, second, (struct msqid_ds __user *) ptr);
 
 	case SHMAT:
 		switch (version) {
 		default: {
 			ulong raddr;
-			ret = sys_shmat (first, (char *) ptr, second, &raddr);
+			ret = sys_shmat (first, (char __user *) ptr, second, &raddr);
 			if (ret)
 				return ret;
-			return put_user (raddr, (ulong *) third);
+			return put_user (raddr, (ulong __user *) third);
 		}
 		case 1:	/* iBCS2 emulator entry point */
 			if (!segment_eq(get_fs(), get_ds()))
 				return -EINVAL;
-			return sys_shmat (first, (char *) ptr, second, (ulong *) third);
+			/* The "(ulong *) third" is valid _only_ because of the kernel segment thing */
+			return sys_shmat (first, (char __user *) ptr, second, (ulong *) third);
 		}
 	case SHMDT: 
-		return sys_shmdt ((char *)ptr);
+		return sys_shmdt ((char __user *)ptr);
 	case SHMGET:
 		return sys_shmget (first, second, third);
 	case SHMCTL:
 		return sys_shmctl (first, second,
-				   (struct shmid_ds *) ptr);
+				   (struct shmid_ds __user *) ptr);
 	default:
 		return -ENOSYS;
 	}
@@ -211,7 +212,7 @@
 /*
  * Old cruft
  */
-asmlinkage int sys_uname(struct old_utsname * name)
+asmlinkage int sys_uname(struct old_utsname __user * name)
 {
 	int err;
 	if (!name)
@@ -222,7 +223,7 @@
 	return err?-EFAULT:0;
 }
 
-asmlinkage int sys_olduname(struct oldold_utsname * name)
+asmlinkage int sys_olduname(struct oldold_utsname __user * name)
 {
 	int error;
 
diff -Nru a/arch/i386/kernel/sysenter.c b/arch/i386/kernel/sysenter.c
--- a/arch/i386/kernel/sysenter.c	Tue Apr 22 19:16:02 2003
+++ b/arch/i386/kernel/sysenter.c	Thu May 15 07:45:50 2003
@@ -21,21 +21,6 @@
 
 extern asmlinkage void sysenter_entry(void);
 
-/*
- * Create a per-cpu fake "SEP thread" stack, so that we can
- * enter the kernel without having to worry about things like
- * "current" etc not working (debug traps and NMI's can happen
- * before we can switch over to the "real" thread).
- *
- * Return the resulting fake stack pointer.
- */
-struct fake_sep_struct {
-	struct thread_info thread;
-	struct task_struct task;
-	unsigned char trampoline[32] __attribute__((aligned(1024)));
-	unsigned char stack[0];
-} __attribute__((aligned(8192)));
-	
 void enable_sep_cpu(void *info)
 {
 	int cpu = get_cpu();
diff -Nru a/arch/i386/kernel/timers/Makefile b/arch/i386/kernel/timers/Makefile
--- a/arch/i386/kernel/timers/Makefile	Mon Feb 10 06:04:32 2003
+++ b/arch/i386/kernel/timers/Makefile	Sun May  4 23:38:34 2003
@@ -4,4 +4,4 @@
 
 obj-y := timer.o timer_none.o timer_tsc.o timer_pit.o
 
-obj-$(CONFIG_X86_SUMMIT)	+= timer_cyclone.o
+obj-$(CONFIG_X86_CYCLONE_TIMER)	+= timer_cyclone.o
diff -Nru a/arch/i386/kernel/timers/timer.c b/arch/i386/kernel/timers/timer.c
--- a/arch/i386/kernel/timers/timer.c	Thu Mar 27 21:15:25 2003
+++ b/arch/i386/kernel/timers/timer.c	Sun May  4 23:38:34 2003
@@ -6,12 +6,12 @@
 /* list of externed timers */
 extern struct timer_opts timer_pit;
 extern struct timer_opts timer_tsc;
-#ifdef CONFIG_X86_SUMMIT
+#ifdef CONFIG_X86_CYCLONE_TIMER
 extern struct timer_opts timer_cyclone;
 #endif
 /* list of timers, ordered by preference, NULL terminated */
 static struct timer_opts* timers[] = {
-#ifdef CONFIG_X86_SUMMIT
+#ifdef CONFIG_X86_CYCLONE_TIMER
 	&timer_cyclone,
 #endif
 	&timer_tsc,
diff -Nru a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c
--- a/arch/i386/kernel/traps.c	Mon Apr 21 09:19:26 2003
+++ b/arch/i386/kernel/traps.c	Mon May 12 18:59:20 2003
@@ -101,7 +101,7 @@
 		stack = (unsigned long*)&stack;
 
 	printk("Call Trace:");
-#if CONFIG_KALLSYMS
+#ifdef CONFIG_KALLSYMS
 	printk("\n");
 #endif
 	i = 1;
@@ -438,7 +438,7 @@
 	unsigned char reason = get_nmi_reason();
  
 	if (!(reason & 0xc0)) {
-#if CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_X86_LOCAL_APIC
 		/*
 		 * Ok, so this is none of the documented NMI sources,
 		 * so it must be the NMI watchdog.
diff -Nru a/arch/i386/kernel/vm86.c b/arch/i386/kernel/vm86.c
--- a/arch/i386/kernel/vm86.c	Sun Apr 20 14:14:28 2003
+++ b/arch/i386/kernel/vm86.c	Fri May  9 14:22:12 2003
@@ -170,7 +170,7 @@
 static int do_vm86_irq_handling(int subfunction, int irqnumber);
 static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk);
 
-asmlinkage int sys_vm86old(struct vm86_struct * v86)
+asmlinkage int sys_vm86old(struct vm86_struct __user * v86)
 {
 	struct kernel_vm86_struct info; /* declare this _on top_,
 					 * this avoids wasting of stack space.
@@ -199,7 +199,7 @@
 }
 
 
-asmlinkage int sys_vm86(unsigned long subfunction, struct vm86plus_struct * v86)
+asmlinkage int sys_vm86(unsigned long subfunction, struct vm86plus_struct __user * v86)
 {
 	struct kernel_vm86_struct info; /* declare this _on top_,
 					 * this avoids wasting of stack space.
@@ -239,7 +239,7 @@
 		goto out;
 	info.regs32 = (struct pt_regs *) &subfunction;
 	info.vm86plus.is_vm86pus = 1;
-	tsk->thread.vm86_info = (struct vm86_struct *)v86;
+	tsk->thread.vm86_info = (struct vm86_struct __user *)v86;
 	do_sys_vm86(&info, tsk);
 	ret = 0;	/* we never return here */
 out:
diff -Nru a/arch/i386/lib/usercopy.c b/arch/i386/lib/usercopy.c
--- a/arch/i386/lib/usercopy.c	Sat Mar 22 12:06:31 2003
+++ b/arch/i386/lib/usercopy.c	Tue May 13 14:32:29 2003
@@ -6,17 +6,22 @@
  * Copyright 1997 Linus Torvalds
  */
 #include <linux/config.h>
+#include <linux/mm.h>
+#include <linux/highmem.h>
+#include <linux/blkdev.h>
 #include <asm/uaccess.h>
 #include <asm/mmx.h>
 
-static inline int movsl_is_ok(const void *a1, const void *a2, unsigned long n)
+static inline int __movsl_is_ok(unsigned long a1, unsigned long a2, unsigned long n)
 {
 #ifdef CONFIG_X86_INTEL_USERCOPY
-	if (n >= 64 && (((const long)a1 ^ (const long)a2) & movsl_mask.mask))
+	if (n >= 64 && ((a1 ^ a2) & movsl_mask.mask))
 		return 0;
 #endif
 	return 1;
 }
+#define movsl_is_ok(a1,a2,n) \
+	__movsl_is_ok((unsigned long)(a1),(unsigned long)(a2),(n))
 
 /*
  * Copy a null terminated string from userspace.
@@ -71,7 +76,7 @@
  * and returns @count.
  */
 long
-__strncpy_from_user(char *dst, const char *src, long count)
+__strncpy_from_user(char *dst, const char __user *src, long count)
 {
 	long res;
 	__do_strncpy_from_user(dst, src, count, res);
@@ -97,7 +102,7 @@
  * and returns @count.
  */
 long
-strncpy_from_user(char *dst, const char *src, long count)
+strncpy_from_user(char *dst, const char __user *src, long count)
 {
 	long res = -EFAULT;
 	if (access_ok(VERIFY_READ, src, 1))
@@ -142,7 +147,7 @@
  * On success, this will be zero.
  */
 unsigned long
-clear_user(void *to, unsigned long n)
+clear_user(void __user *to, unsigned long n)
 {
 	if (access_ok(VERIFY_WRITE, to, n))
 		__do_clear_user(to, n);
@@ -161,7 +166,7 @@
  * On success, this will be zero.
  */
 unsigned long
-__clear_user(void *to, unsigned long n)
+__clear_user(void __user *to, unsigned long n)
 {
 	__do_clear_user(to, n);
 	return n;
@@ -178,7 +183,7 @@
  * On exception, returns 0.
  * If the string is too long, returns a value greater than @n.
  */
-long strnlen_user(const char *s, long n)
+long strnlen_user(const char __user *s, long n)
 {
 	unsigned long mask = -__addr_ok(s);
 	unsigned long res, tmp;
@@ -481,20 +486,67 @@
 } while (0)
 
 
-unsigned long __copy_to_user_ll(void *to, const void *from, unsigned long n)
+unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n)
 {
+#ifndef CONFIG_X86_WP_WORKS_OK
+	if (unlikely(boot_cpu_data.wp_works_ok == 0) &&
+			((unsigned long )to) < TASK_SIZE) {
+		/* 
+		 * CPU does not honor the WP bit when writing
+		 * from supervisory mode, and due to preemption or SMP,
+		 * the page tables can change at any time.
+		 * Do it manually.	Manfred <manfred@colorfullife.com>
+		 */
+		while (n) {
+		      	unsigned long offset = ((unsigned long)to)%PAGE_SIZE;
+			unsigned long len = PAGE_SIZE - offset;
+			int retval;
+			struct page *pg;
+			void *maddr;
+			
+			if (len > n)
+				len = n;
+
+survive:
+			down_read(&current->mm->mmap_sem);
+			retval = get_user_pages(current, current->mm,
+					(unsigned long )to, 1, 1, 0, &pg, NULL);
+
+			if (retval == -ENOMEM && current->pid == 1) {
+				up_read(&current->mm->mmap_sem);
+				blk_congestion_wait(WRITE, HZ/50);
+				goto survive;
+			}
+
+			if (retval != 1)
+		       		break;
+
+			maddr = kmap_atomic(pg, KM_USER0);
+			memcpy(maddr + offset, from, len);
+			kunmap_atomic(maddr, KM_USER0);
+			set_page_dirty_lock(pg);
+			put_page(pg);
+			up_read(&current->mm->mmap_sem);
+
+			from += len;
+			to += len;
+			n -= len;
+		}
+		return n;
+	}
+#endif
 	if (movsl_is_ok(to, from, n))
-		__copy_user(to, from, n);
+		__copy_user((void *)to, from, n);
 	else
-		n = __copy_user_intel(to, from, n);
+		n = __copy_user_intel((void *)to, from, n);
 	return n;
 }
 
-unsigned long __copy_from_user_ll(void *to, const void *from, unsigned long n)
+unsigned long __copy_from_user_ll(void *to, const void __user *from, unsigned long n)
 {
 	if (movsl_is_ok(to, from, n))
-		__copy_user_zeroing(to, from, n);
+		__copy_user_zeroing(to, (const void *) from, n);
 	else
-		n = __copy_user_zeroing_intel(to, from, n);
+		n = __copy_user_zeroing_intel(to, (const void *) from, n);
 	return n;
 }
diff -Nru a/arch/i386/mach-generic/Makefile b/arch/i386/mach-generic/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/Makefile	Sun May  4 23:38:46 2003
@@ -0,0 +1,18 @@
+#
+# Makefile for the generic architecture
+#
+
+EXTRA_CFLAGS	+= -I../kernel
+
+obj-y				:= probe.o summit.o bigsmp.o default.o
+
+
+#
+# Makefile for the generic architecture
+#
+
+EXTRA_CFLAGS	+= -I../kernel
+
+obj-y				:= probe.o summit.o bigsmp.o default.o
+
+
diff -Nru a/arch/i386/mach-generic/bigsmp.c b/arch/i386/mach-generic/bigsmp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/bigsmp.c	Sun May  4 23:38:34 2003
@@ -0,0 +1,23 @@
+/* 
+ * APIC driver for "bigsmp" XAPIC machines with more than 8 virtual CPUs.
+ * Drives the local APIC in "clustered mode".
+ */
+#define APIC_DEFINITION 1
+#include <asm/genapic.h>
+#include <asm/fixmap.h>
+#include <asm/apicdef.h>
+#include <linux/kernel.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <asm/mach-bigsmp/mach_apic.h>
+#include <asm/mach-bigsmp/mach_ipi.h>
+#include <asm/mach-default/mach_mpparse.h>
+
+int dmi_bigsmp; /* can be set by dmi scanners */
+
+static __init int probe_bigsmp(void)
+{ 
+	return dmi_bigsmp; 
+} 
+
+struct genapic apic_bigsmp = APIC_INIT("bigsmp", probe_bigsmp); 
diff -Nru a/arch/i386/mach-generic/default.c b/arch/i386/mach-generic/default.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/default.c	Sun May  4 23:38:34 2003
@@ -0,0 +1,22 @@
+/* 
+ * Default generic APIC driver. This handles upto 8 CPUs.
+ */
+#define APIC_DEFINITION 1
+#include <asm/genapic.h>
+#include <asm/fixmap.h>
+#include <asm/apicdef.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <asm/mach-default/mach_apic.h>
+#include <asm/mach-default/mach_ipi.h>
+#include <asm/mach-default/mach_mpparse.h>
+
+/* should be called last. */
+static __init int probe_default(void)
+{ 
+	return 1;
+} 
+
+struct genapic apic_default = APIC_INIT("default", probe_default); 
diff -Nru a/arch/i386/mach-generic/probe.c b/arch/i386/mach-generic/probe.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/probe.c	Sun May  4 23:38:34 2003
@@ -0,0 +1,96 @@
+/* Copyright 2003 Andi Kleen, SuSE Labs. 
+ * Subject to the GNU Public License, v.2 
+ * 
+ * Generic x86 APIC driver probe layer.
+ */  
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/init.h>
+#include <asm/fixmap.h>
+#include <asm/apicdef.h>
+#include <asm/genapic.h>
+
+extern struct genapic apic_summit;
+extern struct genapic apic_bigsmp;
+extern struct genapic apic_default;
+
+struct genapic *genapic = &apic_default;
+
+struct genapic *apic_probe[] __initdata = { 
+	&apic_summit,
+	&apic_bigsmp, 
+	&apic_default,	/* must be last */
+	NULL,
+};
+
+void __init generic_apic_probe(char *command_line) 
+{ 
+	char *s;
+	int i;
+	int changed = 0;
+
+	s = strstr(command_line, "apic=");
+	if (s && (s == command_line || isspace(s[-1]))) { 
+		char *p = strchr(s, ' '), old; 
+		if (!p)
+			p = strchr(s, '\0'); 
+		old = *p; 
+		*p = 0; 
+		for (i = 0; !changed && apic_probe[i]; i++) {
+			if (!strcmp(apic_probe[i]->name, s+5)) { 
+				changed = 1;
+				genapic = apic_probe[i];
+			}
+		}
+		if (!changed)
+			printk(KERN_ERR "Unknown genapic `%s' specified.\n", s);
+		*p = old;
+	} 
+	for (i = 0; !changed && apic_probe[i]; i++) { 
+		if (apic_probe[i]->probe()) {
+			changed = 1;
+			genapic = apic_probe[i]; 
+		} 
+	}
+	/* Not visible without early console */ 
+	if (!changed) 
+		panic("Didn't find an APIC driver"); 
+
+	printk(KERN_INFO "Using APIC driver %s\n", genapic->name);
+} 
+
+/* These functions can switch the APIC even after the initial ->probe() */
+
+int __init mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid)
+{ 
+	int i;
+	for (i = 0; apic_probe[i]; ++i) { 
+		if (apic_probe[i]->mps_oem_check(mpc,oem,productid)) { 
+			genapic = apic_probe[i];
+			printk(KERN_INFO "Switched to APIC driver `%s'.\n", 
+			       genapic->name);
+			return 1;
+		} 
+	} 
+	return 0;
+} 
+
+int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+{
+	int i;
+	for (i = 0; apic_probe[i]; ++i) { 
+		if (apic_probe[i]->acpi_madt_oem_check(oem_id, oem_table_id)) { 
+			genapic = apic_probe[i];
+			printk(KERN_INFO "Switched to APIC driver `%s'.\n", 
+			       genapic->name);
+			return 1;
+		} 
+	} 
+	return 0;	
+}
+
+int hard_smp_processor_id(void)
+{
+	return genapic->get_apic_id(*(unsigned long *)(APIC_BASE+APIC_ID));
+}
diff -Nru a/arch/i386/mach-generic/summit.c b/arch/i386/mach-generic/summit.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/i386/mach-generic/summit.c	Sun May  4 23:38:34 2003
@@ -0,0 +1,22 @@
+/* 
+ * APIC driver for the IBM "Summit" chipset.
+ */
+#define APIC_DEFINITION 1
+#include <asm/genapic.h>
+#include <asm/fixmap.h>
+#include <asm/apicdef.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/smp.h>
+#include <linux/init.h>
+#include <asm/mach-summit/mach_apic.h>
+#include <asm/mach-summit/mach_ipi.h>
+#include <asm/mach-summit/mach_mpparse.h>
+
+static __init int probe_summit(void)
+{ 
+	/* probed later in mptable/ACPI hooks */
+	return 0;
+} 
+
+struct genapic apic_summit = APIC_INIT("summit", probe_summit); 
diff -Nru a/arch/i386/mach-voyager/voyager_smp.c b/arch/i386/mach-voyager/voyager_smp.c
--- a/arch/i386/mach-voyager/voyager_smp.c	Sun Mar  2 23:32:20 2003
+++ b/arch/i386/mach-voyager/voyager_smp.c	Tue May 20 03:13:39 2003
@@ -247,7 +247,7 @@
 
 /* This is for the new dynamic CPU boot code */
 volatile unsigned long cpu_callin_map = 0;
-unsigned long cpu_callout_map = 0;
+volatile unsigned long cpu_callout_map = 0;
 
 /* The per processor IRQ masks (these are usually kept in sync) */
 static __u16 vic_irq_mask[NR_CPUS] __cacheline_aligned;
@@ -531,7 +531,7 @@
 	struct pt_regs regs;
 	/* don't care about the eip and regs settings since we'll
 	 * never reschedule the forked task. */
-	return do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+	return copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
 }
 
 
@@ -592,6 +592,8 @@
 	idle = fork_by_hand();
 	if(IS_ERR(idle))
 		panic("failed fork for CPU%d", cpu);
+
+	wake_up_forked_process(idle);
 
 	init_idle(idle, cpu);
 
diff -Nru a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c
--- a/arch/i386/mm/fault.c	Thu Mar  6 08:19:03 2003
+++ b/arch/i386/mm/fault.c	Wed May  7 21:19:37 2003
@@ -29,87 +29,6 @@
 
 extern void die(const char *,struct pt_regs *,long);
 
-#ifndef CONFIG_X86_WP_WORKS_OK
-/*
- * Ugly, ugly, but the goto's result in better assembly..
- */
-int __verify_write(const void * addr, unsigned long size)
-{
-	struct mm_struct *mm = current->mm;
-	struct vm_area_struct * vma;
-	unsigned long start = (unsigned long) addr;
-
-	if (!size || segment_eq(get_fs(),KERNEL_DS))
-		return 1;
-
-	down_read(&mm->mmap_sem);
-	vma = find_vma(current->mm, start);
-	if (!vma)
-		goto bad_area;
-	if (vma->vm_start > start)
-		goto check_stack;
-
-good_area:
-	if (!(vma->vm_flags & VM_WRITE))
-		goto bad_area;
-	size--;
-	size += start & ~PAGE_MASK;
-	size >>= PAGE_SHIFT;
-	start &= PAGE_MASK;
-
-	for (;;) {
-	survive:
-		switch (handle_mm_fault(current->mm, vma, start, 1)) {
-			case VM_FAULT_SIGBUS:
-				goto bad_area;
-			case VM_FAULT_OOM:
-				goto out_of_memory;
-			case VM_FAULT_MINOR:
-			case VM_FAULT_MAJOR:
-				break;
-			default:
-				BUG();
-		}
-		if (!size)
-			break;
-		size--;
-		start += PAGE_SIZE;
-		if (start < vma->vm_end)
-			continue;
-		vma = vma->vm_next;
-		if (!vma || vma->vm_start != start)
-			goto bad_area;
-		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;;
-	}
-	/*
-	 * We really need to hold mmap_sem over the whole access to
-	 * userspace, else another thread could change permissions.
-	 * This is unfixable, so don't use i386-class machines for
-	 * critical servers.
-	 */
-	up_read(&mm->mmap_sem);
-	return 1;
-
-check_stack:
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
-	if (expand_stack(vma, start) == 0)
-		goto good_area;
-
-bad_area:
-	up_read(&mm->mmap_sem);
-	return 0;
-
-out_of_memory:
-	if (current->pid == 1) {
-		yield();
-		goto survive;
-	}
-	goto bad_area;
-}
-#endif
-
 /*
  * Unlock any spinlocks which will prevent us from getting the
  * message out 
@@ -405,8 +324,12 @@
 
 		if (!pgd_present(*pgd_k))
 			goto no_context;
-		set_pgd(pgd, *pgd_k);
-		
+
+		/*
+		 * set_pgd(pgd, *pgd_k); here would be useless on PAE
+		 * and redundant with the set_pmd() on non-PAE.
+		 */
+
 		pmd = pmd_offset(pgd, address);
 		pmd_k = pmd_offset(pgd_k, address);
 		if (!pmd_present(*pmd_k))
diff -Nru a/arch/i386/mm/highmem.c b/arch/i386/mm/highmem.c
--- a/arch/i386/mm/highmem.c	Thu Mar 27 21:16:14 2003
+++ b/arch/i386/mm/highmem.c	Mon May 12 18:59:20 2003
@@ -36,7 +36,7 @@
 
 	idx = type + KM_TYPE_NR*smp_processor_id();
 	vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx);
-#if CONFIG_DEBUG_HIGHMEM
+#ifdef CONFIG_DEBUG_HIGHMEM
 	if (!pte_none(*(kmap_pte-idx)))
 		BUG();
 #endif
@@ -48,7 +48,7 @@
 
 void kunmap_atomic(void *kvaddr, enum km_type type)
 {
-#if CONFIG_DEBUG_HIGHMEM
+#ifdef CONFIG_DEBUG_HIGHMEM
 	unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK;
 	enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id();
 
diff -Nru a/arch/i386/mm/hugetlbpage.c b/arch/i386/mm/hugetlbpage.c
--- a/arch/i386/mm/hugetlbpage.c	Sat Apr 19 23:22:35 2003
+++ b/arch/i386/mm/hugetlbpage.c	Wed May 14 23:43:48 2003
@@ -20,8 +20,6 @@
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
-#include <linux/sysctl.h>
-
 static long    htlbpagemem;
 int     htlbpage_max;
 static long    htlbzone_pages;
@@ -398,8 +396,6 @@
 {
 	int lcount;
 	struct page *page;
-	extern long htlbzone_pages;
-	extern struct list_head htlbpage_freelist;
 
 	if (count < 0)
 		lcount = count;
diff -Nru a/arch/i386/mm/init.c b/arch/i386/mm/init.c
--- a/arch/i386/mm/init.c	Sat May  3 18:36:22 2003
+++ b/arch/i386/mm/init.c	Mon May 12 11:09:21 2003
@@ -55,7 +55,7 @@
 {
 	pmd_t *pmd_table;
 		
-#if CONFIG_X86_PAE
+#ifdef CONFIG_X86_PAE
 	pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE);
 	set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT));
 	if (pmd_table != pmd_offset(pgd, 0)) 
@@ -188,7 +188,7 @@
 	return 0;
 }
 
-#if CONFIG_HIGHMEM
+#ifdef CONFIG_HIGHMEM
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
 
@@ -265,7 +265,7 @@
 	unsigned long vaddr;
 	pgd_t *pgd_base = swapper_pg_dir;
 
-#if CONFIG_X86_PAE
+#ifdef CONFIG_X86_PAE
 	int i;
 	/* Init entries of the first-level page table to the zero page */
 	for (i = 0; i < PTRS_PER_PGD; i++)
@@ -295,7 +295,7 @@
 
 	permanent_kmaps_init(pgd_base);
 
-#if CONFIG_X86_PAE
+#ifdef CONFIG_X86_PAE
 	/*
 	 * Add low memory identity-mappings - SMP needs it when
 	 * starting up on an AP from real-mode. In the non-PAE
@@ -317,7 +317,7 @@
 	 * us, because pgd_clear() is a no-op on i386.
 	 */
 	for (i = 0; i < USER_PTRS_PER_PGD; i++)
-#if CONFIG_X86_PAE
+#ifdef CONFIG_X86_PAE
 		set_pgd(swapper_pg_dir+i, __pgd(1 + __pa(empty_zero_page)));
 #else
 		set_pgd(swapper_pg_dir+i, __pgd(0));
@@ -363,7 +363,7 @@
 
 	load_cr3(swapper_pg_dir);
 
-#if CONFIG_X86_PAE
+#ifdef CONFIG_X86_PAE
 	/*
 	 * We will bail out later - printk doesn't work right now so
 	 * the user would just see a hanging kernel.
@@ -487,7 +487,7 @@
 		(unsigned long) (totalhigh_pages << (PAGE_SHIFT-10))
 	       );
 
-#if CONFIG_X86_PAE
+#ifdef CONFIG_X86_PAE
 	if (!cpu_has_pae)
 		panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!");
 #endif
@@ -505,7 +505,7 @@
 #endif
 }
 
-#if CONFIG_X86_PAE
+#ifdef CONFIG_X86_PAE
 struct kmem_cache_s *pae_pgd_cachep;
 
 void __init pgtable_cache_init(void)
diff -Nru a/arch/i386/mm/ioremap.c b/arch/i386/mm/ioremap.c
--- a/arch/i386/mm/ioremap.c	Thu Mar  6 06:34:47 2003
+++ b/arch/i386/mm/ioremap.c	Mon May 12 21:23:25 2003
@@ -222,7 +222,6 @@
 		return;
 	} 
 
-	unmap_vm_area(p);
 	if (p->flags && p->phys_addr < virt_to_phys(high_memory)) { 
 		change_page_attr(virt_to_page(__va(p->phys_addr)),
 				 p->size >> PAGE_SHIFT,
diff -Nru a/arch/i386/mm/pgtable.c b/arch/i386/mm/pgtable.c
--- a/arch/i386/mm/pgtable.c	Sat May  3 18:36:22 2003
+++ b/arch/i386/mm/pgtable.c	Mon May 12 11:11:38 2003
@@ -141,7 +141,7 @@
 {
 	struct page *pte;
 
-#if CONFIG_HIGHPTE
+#ifdef CONFIG_HIGHPTE
 	pte = alloc_pages(GFP_KERNEL|__GFP_HIGHMEM|__GFP_REPEAT, 0);
 #else
 	pte = alloc_pages(GFP_KERNEL|__GFP_REPEAT, 0);
@@ -151,7 +151,7 @@
 	return pte;
 }
 
-#if CONFIG_X86_PAE
+#ifdef CONFIG_X86_PAE
 
 pgd_t *pgd_alloc(struct mm_struct *mm)
 {
diff -Nru a/arch/i386/oprofile/init.c b/arch/i386/oprofile/init.c
--- a/arch/i386/oprofile/init.c	Mon Apr 28 17:17:00 2003
+++ b/arch/i386/oprofile/init.c	Mon May 12 21:23:26 2003
@@ -9,6 +9,7 @@
 
 #include <linux/oprofile.h>
 #include <linux/init.h>
+#include <linux/errno.h>
  
 /* We support CPUs that have performance counters like the Pentium Pro
  * with the NMI mode driver.
diff -Nru a/arch/i386/vmlinux.lds.S b/arch/i386/vmlinux.lds.S
--- a/arch/i386/vmlinux.lds.S	Wed Apr 30 01:07:08 2003
+++ b/arch/i386/vmlinux.lds.S	Tue May  6 06:54:06 2003
@@ -85,7 +85,11 @@
   __alt_instructions = .;
   .altinstructions : { *(.altinstructions) } 
   __alt_instructions_end = .; 
- .altinstr_replacement : { *(.altinstr_replacement) }
+ .altinstr_replacement : { *(.altinstr_replacement) } 
+  /* .exit.text is discard at runtime, not link time, to deal with references
+     from .altinstructions and .eh_frame */
+  .exit.text : { *(.exit.text) }
+  .exit.data : { *(.exit.data) }
   . = ALIGN(4096);
   __initramfs_start = .;
   .init.ramfs : { *(.init.ramfs) }
@@ -106,8 +110,6 @@
 
   /* Sections to be discarded */
   /DISCARD/ : {
-	*(.exit.text)
-	*(.exit.data)
 	*(.exitcall.exit)
 	}
 
diff -Nru a/arch/ia64/Kconfig b/arch/ia64/Kconfig
--- a/arch/ia64/Kconfig	Sun Apr 20 12:56:50 2003
+++ b/arch/ia64/Kconfig	Fri May  9 15:19:53 2003
@@ -381,6 +381,10 @@
 	depends on MCKINLEY
 	bool "4GB"
 
+config HUGETLB_PAGE_SIZE_1GB
+	depends on MCKINLEY
+	bool "1GB"
+
 config HUGETLB_PAGE_SIZE_256MB
 	bool "256MB"
 
diff -Nru a/arch/ia64/Makefile b/arch/ia64/Makefile
--- a/arch/ia64/Makefile	Wed Mar 26 08:30:43 2003
+++ b/arch/ia64/Makefile	Tue May  6 10:56:53 2003
@@ -23,6 +23,7 @@
 CFLAGS_KERNEL	:= -mconstant-gp
 
 GCC_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f1 -d'.')
+GCC_MINOR_VERSION=$(shell $(CC) -v 2>&1 | fgrep 'gcc version' | cut -f3 -d' ' | cut -f2 -d'.')
 
 GAS_STATUS=$(shell arch/ia64/scripts/check-gas $(CC) $(OBJDUMP))
 
@@ -35,7 +36,14 @@
 endif
 
 ifneq ($(GCC_VERSION),2)
-	cflags-y += -frename-registers --param max-inline-insns=5000
+	cflags-$(CONFIG_ITANIUM) += -frename-registers
+endif
+
+ifeq ($(GCC_VERSION),3)
+ ifeq ($(GCC_MINOR_VERSION),4)
+	cflags-$(CONFIG_ITANIUM) += -mtune=merced
+	cflags-$(CONFIG_MCKINLEY) += -mtune=mckinley
+ endif
 endif
 
 cflags-$(CONFIG_ITANIUM_BSTEP_SPECIFIC)	+= -mb-step
@@ -48,14 +56,14 @@
 core-y				+= arch/ia64/kernel/ arch/ia64/mm/
 core-$(CONFIG_IA32_SUPPORT)	+= arch/ia64/ia32/
 core-$(CONFIG_IA64_DIG) 	+= arch/ia64/dig/
-core-$(CONFIG_IA64_GENERIC) 	+= arch/ia64/dig/ arch/ia64/hp/common/ arch/ia64/hp/zx1/ \
-				   arch/ia64/hp/sim/
+core-$(CONFIG_IA64_GENERIC) 	+= arch/ia64/dig/
 core-$(CONFIG_IA64_HP_ZX1)	+= arch/ia64/dig/
 core-$(CONFIG_IA64_SGI_SN)	+= arch/ia64/sn/
 
 drivers-$(CONFIG_PCI)		+= arch/ia64/pci/
 drivers-$(CONFIG_IA64_HP_SIM)	+= arch/ia64/hp/sim/
 drivers-$(CONFIG_IA64_HP_ZX1)	+= arch/ia64/hp/common/ arch/ia64/hp/zx1/
+drivers-$(CONFIG_IA64_GENERIC)	+= arch/ia64/hp/common/ arch/ia64/hp/zx1/ arch/ia64/hp/sim/
 
 boot := arch/ia64/boot
 tools := arch/ia64/tools
diff -Nru a/arch/ia64/dig/machvec.c b/arch/ia64/dig/machvec.c
--- a/arch/ia64/dig/machvec.c	Tue Feb  5 09:40:31 2002
+++ b/arch/ia64/dig/machvec.c	Sat May 10 02:28:45 2003
@@ -1,2 +1,3 @@
-#define MACHVEC_PLATFORM_NAME	dig
+#define MACHVEC_PLATFORM_NAME		dig
+#define MACHVEC_PLATFORM_HEADER		<asm/machvec_dig.h>
 #include <asm/machvec_init.h>
diff -Nru a/arch/ia64/hp/common/sba_iommu.c b/arch/ia64/hp/common/sba_iommu.c
--- a/arch/ia64/hp/common/sba_iommu.c	Thu Apr  3 12:32:33 2003
+++ b/arch/ia64/hp/common/sba_iommu.c	Sat May 10 02:28:45 2003
@@ -1,9 +1,9 @@
 /*
 **  IA64 System Bus Adapter (SBA) I/O MMU manager
 **
-**	(c) Copyright 2002 Alex Williamson
-**	(c) Copyright 2002 Grant Grundler
-**	(c) Copyright 2002 Hewlett-Packard Company
+**	(c) Copyright 2002-2003 Alex Williamson
+**	(c) Copyright 2002-2003 Grant Grundler
+**	(c) Copyright 2002-2003 Hewlett-Packard Company
 **
 **	Portions (c) 2000 Grant Grundler (from parisc I/O MMU code)
 **	Portions (c) 1999 Dave S. Miller (from sparc64 I/O MMU code)
@@ -30,17 +30,39 @@
 #include <linux/string.h>
 #include <linux/pci.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/acpi.h>
 #include <linux/efi.h>
 
 #include <asm/delay.h>		/* ia64_get_itc() */
 #include <asm/io.h>
 #include <asm/page.h>		/* PAGE_OFFSET */
+#include <asm/dma.h>
+#include <asm/system.h>		/* wmb() */
 
+#include <asm/acpi-ext.h>
 
-#define DRIVER_NAME "SBA"
+#define PFX "IOC: "
 
+/*
+** This option allows cards capable of 64bit DMA to bypass the IOMMU.  If
+** not defined, all DMA will be 32bit and go through the TLB.
+*/
 #define ALLOW_IOV_BYPASS
+
+/*
+** If a device prefetches beyond the end of a valid pdir entry, it will cause
+** a hard failure, ie. MCA.  Version 3.0 and later of the zx1 LBA should
+** disconnect on 4k boundaries and prevent such issues.  If the device is
+** particularly agressive, this option will keep the entire pdir valid such
+** that prefetching will hit a valid address.  This could severely impact
+** error containment, and is therefore off by default.  The page that is
+** used for spill-over is poisoned, so that should help debugging somewhat.
+*/
+#undef FULL_VALID_PDIR
+
 #define ENABLE_MARK_CLEAN
+
 /*
 ** The number of debug flags is a clue - this code is fragile.
 */
@@ -52,6 +74,10 @@
 #undef DEBUG_LARGE_SG_ENTRIES
 #undef DEBUG_BYPASS
 
+#if defined(FULL_VALID_PDIR) && defined(ASSERT_PDIR_SANITY)
+#error FULL_VALID_PDIR and ASSERT_PDIR_SANITY are mutually exclusive
+#endif
+
 #define SBA_INLINE	__inline__
 /* #define SBA_INLINE */
 
@@ -96,12 +122,8 @@
 #define ASSERT(expr)
 #endif
 
-#define KB(x) ((x) * 1024)
-#define MB(x) (KB (KB (x)))
-#define GB(x) (MB (KB (x)))
-
 /*
-** The number of pdir entries to "free" before issueing
+** The number of pdir entries to "free" before issuing
 ** a read to PCOM register to flush out PCOM writes.
 ** Interacts with allocation granularity (ie 4 or 8 entries
 ** allocated and free'd/purged at a time might make this
@@ -109,30 +131,24 @@
 */
 #define DELAYED_RESOURCE_CNT	16
 
-#define DEFAULT_DMA_HINT_REG(d)	0
-
-#define ZX1_FUNC_ID_VALUE    ((PCI_DEVICE_ID_HP_ZX1_SBA << 16) | PCI_VENDOR_ID_HP)
-#define ZX1_MC_ID    ((PCI_DEVICE_ID_HP_ZX1_MC << 16) | PCI_VENDOR_ID_HP)
+#define DEFAULT_DMA_HINT_REG	0
 
-#define SBA_FUNC_ID	0x0000	/* function id */
-#define SBA_FCLASS	0x0008	/* function class, bist, header, rev... */
+#define ZX1_IOC_ID	((PCI_DEVICE_ID_HP_ZX1_IOC << 16) | PCI_VENDOR_ID_HP)
+#define REO_IOC_ID	((PCI_DEVICE_ID_HP_REO_IOC << 16) | PCI_VENDOR_ID_HP)
+#define SX1000_IOC_ID	((PCI_DEVICE_ID_HP_SX1000_IOC << 16) | PCI_VENDOR_ID_HP)
 
-#define SBA_FUNC_SIZE	0x10000   /* SBA configuration function reg set */
-
-unsigned int __initdata zx1_func_offsets[] = {0x1000, 0x4000, 0x8000,
-                                              0x9000, 0xa000, -1};
-
-#define SBA_IOC_OFFSET	0x1000
-
-#define MAX_IOC		1	/* we only have 1 for now*/
+#define ZX1_IOC_OFFSET	0x1000	/* ACPI reports SBA, we want IOC */
 
+#define IOC_FUNC_ID	0x000
+#define IOC_FCLASS	0x008	/* function class, bist, header, rev... */
 #define IOC_IBASE	0x300	/* IO TLB */
 #define IOC_IMASK	0x308
 #define IOC_PCOM	0x310
 #define IOC_TCNFG	0x318
 #define IOC_PDIR_BASE	0x320
 
-#define IOC_IOVA_SPACE_BASE	0x40000000 /* IOVA ranges start at 1GB */
+/* AGP GART driver looks for this */
+#define ZX1_SBA_IOMMU_COOKIE	0x0000badbadc0ffeeUL
 
 /*
 ** IOC supports 4/8/16/64KB page sizes (see TCNFG register)
@@ -152,7 +168,7 @@
 #define IOVP_MASK	PAGE_MASK
 
 struct ioc {
-	unsigned long	ioc_hpa;	/* I/O MMU base address */
+	void		*ioc_hpa;	/* I/O MMU base address */
 	char		*res_map;	/* resource map, bit == pdir entry */
 	u64		*pdir_base;	/* physical base address */
 	unsigned long	ibase;		/* pdir IOV Space base */
@@ -193,37 +209,37 @@
 #endif
 #endif
 
-	/* STUFF We don't need in performance path */
+	/* Stuff we don't need in performance path */
+	struct ioc	*next;		/* list of IOC's in system */
+	acpi_handle	handle;		/* for multiple IOC's */
+	const char 	*name;
+	unsigned int	func_id;
+	unsigned int	rev;		/* HW revision of chip */
+	u32		iov_size;
 	unsigned int	pdir_size;	/* in bytes, determined by IOV Space size */
+	struct pci_dev	*sac_only_dev;
 };
 
-struct sba_device {
-	struct sba_device	*next;	/* list of SBA's in system */
-	const char 		*name;
-	unsigned long		sba_hpa; /* base address */
-	spinlock_t		sba_lock;
-	unsigned int		flags;  /* state/functionality enabled */
-	unsigned int		hw_rev;  /* HW revision of chip */
-
-	unsigned int		num_ioc;  /* number of on-board IOC's */
-	struct ioc		ioc[MAX_IOC];
-};
+static struct ioc *ioc_list;
+static int reserve_sba_gart = 1;
 
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#define sba_sg_address(sg)	(page_address((sg)->page) + (sg)->offset)
+#else
+#define sba_sg_address(sg)	((sg)->address ? (sg)->address : \
+                                  page_address((sg)->page) + (sg)->offset)
+#endif
 
-static struct sba_device *sba_list;
-static int sba_count;
-static int reserve_sba_gart = 1;
-static struct pci_dev sac_only_dev;
+#ifdef FULL_VALID_PDIR
+static u64 prefetch_spill_page;
+#endif
 
-#define sba_sg_address(sg) (page_address((sg)->page) + (sg)->offset)
-#define sba_sg_len(sg) (sg->length)
-#define sba_sg_iova(sg) (sg->dma_address)
-#define sba_sg_iova_len(sg) (sg->dma_length)
-
-/* REVISIT - fix me for multiple SBAs/IOCs */
-#define GET_IOC(dev) (sba_list->ioc)
-#define SBA_SET_AGP(sba_dev) (sba_dev->flags |= 0x1)
-#define SBA_GET_AGP(sba_dev) (sba_dev->flags & 0x1)
+#ifdef CONFIG_PCI
+# define GET_IOC(dev)	(((dev)->bus == &pci_bus_type)						\
+			 ? ((struct ioc *) PCI_CONTROLLER(to_pci_dev(dev))->iommu) : NULL)
+#else
+# define GET_IOC(dev)	NULL
+#endif
 
 /*
 ** DMA_CHUNK_SIZE is used by the SCSI mid-layer to break up
@@ -232,10 +248,7 @@
 ** rather than the HW. I/O MMU allocation alogorithms can be
 ** faster with smaller size is (to some degree).
 */
-#define DMA_CHUNK_SIZE  (BITS_PER_LONG*IOVP_SIZE)
-
-/* Looks nice and keeps the compiler happy */
-#define SBA_DEV(d) ((struct sba_device *) (d))
+#define DMA_CHUNK_SIZE  (BITS_PER_LONG*PAGE_SIZE)
 
 #define ROUNDUP(x,y) ((x + ((y)-1)) & ~((y)-1))
 
@@ -255,7 +268,7 @@
  * sba_dump_tlb - debugging only - print IOMMU operating parameters
  * @hpa: base address of the IOMMU
  *
- * Print the size/location of the IO MMU Pdir.
+ * Print the size/location of the IO MMU PDIR.
  */
 static void
 sba_dump_tlb(char *hpa)
@@ -273,19 +286,19 @@
 #ifdef ASSERT_PDIR_SANITY
 
 /**
- * sba_dump_pdir_entry - debugging only - print one IOMMU Pdir entry
+ * sba_dump_pdir_entry - debugging only - print one IOMMU PDIR entry
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @msg: text to print ont the output line.
  * @pide: pdir index.
  *
- * Print one entry of the IO MMU Pdir in human readable form.
+ * Print one entry of the IO MMU PDIR in human readable form.
  */
 static void
 sba_dump_pdir_entry(struct ioc *ioc, char *msg, uint pide)
 {
 	/* start printing from lowest pde in rval */
-	u64 *ptr = &(ioc->pdir_base[pide  & ~(BITS_PER_LONG - 1)]);
-	unsigned long *rptr = (unsigned long *) &(ioc->res_map[(pide >>3) & ~(sizeof(unsigned long) - 1)]);
+	u64 *ptr = &ioc->pdir_base[pide  & ~(BITS_PER_LONG - 1)];
+	unsigned long *rptr = (unsigned long *) &ioc->res_map[(pide >>3) & -sizeof(unsigned long)];
 	uint rcnt;
 
 	printk(KERN_DEBUG "SBA: %s rp %p bit %d rval 0x%lx\n",
@@ -296,7 +309,7 @@
 		printk(KERN_DEBUG "%s %2d %p %016Lx\n",
 		       (rcnt == (pide & (BITS_PER_LONG - 1)))
 		       ? "    -->" : "       ",
-		       rcnt, ptr, *ptr );
+		       rcnt, ptr, (unsigned long long) *ptr );
 		rcnt++;
 		ptr++;
 	}
@@ -359,17 +372,18 @@
  * print the SG list so we can verify it's correct by hand.
  */
 static void
-sba_dump_sg(struct ioc *ioc, struct scatterlist *startsg, int nents)
+sba_dump_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
 {
 	while (nents-- > 0) {
 		printk(KERN_DEBUG " %d : DMA %08lx/%05x CPU %p\n", nents,
-		       (unsigned long) sba_sg_iova(startsg), sba_sg_iova_len(startsg),
+		       startsg->dma_address, startsg->dma_length,
 		       sba_sg_address(startsg));
 		startsg++;
 	}
 }
+
 static void
-sba_check_sg(struct ioc *ioc, struct scatterlist *startsg, int nents)
+sba_check_sg( struct ioc *ioc, struct scatterlist *startsg, int nents)
 {
 	struct scatterlist *the_sg = startsg;
 	int the_nents = nents;
@@ -398,9 +412,11 @@
 #define PAGES_PER_RANGE 1	/* could increase this to 4 or 8 if needed */
 
 /* Convert from IOVP to IOVA and vice versa. */
-#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset) | ((hint_reg)<<(ioc->hint_shift_pdir)))
+#define SBA_IOVA(ioc,iovp,offset,hint_reg) ((ioc->ibase) | (iovp) | (offset) |		\
+					    ((hint_reg)<<(ioc->hint_shift_pdir)))
 #define SBA_IOVP(ioc,iova) (((iova) & ioc->hint_mask_pdir) & ~(ioc->ibase))
 
+/* FIXME : review these macros to verify correctness and usage */
 #define PDIR_INDEX(iovp)   ((iovp)>>IOVP_SHIFT)
 
 #define RESMAP_MASK(n)    ~(~0UL << (n))
@@ -408,7 +424,7 @@
 
 
 /**
- * sba_search_bitmap - find free space in IO Pdir resource bitmap
+ * sba_search_bitmap - find free space in IO PDIR resource bitmap
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @bits_wanted: number of entries we need.
  *
@@ -445,7 +461,7 @@
 		** We need the alignment to invalidate I/O TLB using
 		** SBA HW features in the unmap path.
 		*/
-		unsigned long o = 1UL << get_order(bits_wanted << IOVP_SHIFT);
+		unsigned long o = 1 << get_order(bits_wanted << PAGE_SHIFT);
 		uint bitshiftcnt = ROUNDUP(ioc->res_bitshift, o);
 		unsigned long mask;
 
@@ -491,7 +507,7 @@
 
 
 /**
- * sba_alloc_range - find free bits and mark them in IO Pdir resource bitmap
+ * sba_alloc_range - find free bits and mark them in IO PDIR resource bitmap
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @size: number of bytes to create a mapping for
  *
@@ -520,7 +536,8 @@
 	if (pide >= (ioc->res_size << 3)) {
 		pide = sba_search_bitmap(ioc, pages_needed);
 		if (pide >= (ioc->res_size << 3))
-			panic(__FILE__ ": I/O MMU @ %lx is out of mapping resources\n", ioc->ioc_hpa);
+			panic(__FILE__ ": I/O MMU @ %p is out of mapping resources\n",
+			      ioc->ioc_hpa);
 	}
 
 #ifdef ASSERT_PDIR_SANITY
@@ -553,7 +570,7 @@
 
 
 /**
- * sba_free_range - unmark bits in IO Pdir resource bitmap
+ * sba_free_range - unmark bits in IO PDIR resource bitmap
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @iova: IO virtual address which was previously allocated.
  * @size: number of bytes to create a mapping for
@@ -600,14 +617,14 @@
 
 
 /**
- * sba_io_pdir_entry - fill in one IO Pdir entry
- * @pdir_ptr:  pointer to IO Pdir entry
- * @phys_page: phys CPU address of page to map
+ * sba_io_pdir_entry - fill in one IO PDIR entry
+ * @pdir_ptr:  pointer to IO PDIR entry
+ * @vba: Virtual CPU address of buffer to map
  *
  * SBA Mapping Routine
  *
- * Given a physical address (phys_page, arg1) sba_io_pdir_entry()
- * loads the I/O Pdir entry pointed to by pdir_ptr (arg0).
+ * Given a virtual address (vba, arg1) sba_io_pdir_entry()
+ * loads the I/O PDIR entry pointed to by pdir_ptr (arg0).
  * Each IO Pdir entry consists of 8 bytes as shown below
  * (LSB == bit 0):
  *
@@ -619,12 +636,21 @@
  *  V  == Valid Bit
  *  U  == Unused
  * PPN == Physical Page Number
+ *
+ * The physical address fields are filled with the results of virt_to_phys()
+ * on the vba.
  */
 
-#define SBA_VALID_MASK	0x80000000000000FFULL
-#define sba_io_pdir_entry(pdir_ptr, phys_page) *pdir_ptr = (phys_page | SBA_VALID_MASK)
-#define sba_io_page(pdir_ptr) (*pdir_ptr & ~SBA_VALID_MASK)
-
+#if 1
+#define sba_io_pdir_entry(pdir_ptr, vba) *pdir_ptr = ((vba & ~0xE000000000000FFFULL)	\
+						      | 0x8000000000000000ULL)
+#else
+void SBA_INLINE
+sba_io_pdir_entry(u64 *pdir_ptr, unsigned long vba)
+{
+	*pdir_ptr = ((vba & ~0xE000000000000FFFULL) | 0x80000000000000FFULL);
+}
+#endif
 
 #ifdef ENABLE_MARK_CLEAN
 /**
@@ -640,7 +666,7 @@
 	pg_addr = PAGE_ALIGN((unsigned long) addr);
 	end = (unsigned long) addr + size;
 	while (pg_addr + PAGE_SIZE <= end) {
-		struct page *page = virt_to_page(pg_addr);
+		struct page *page = virt_to_page((void *)pg_addr);
 		set_bit(PG_arch_1, &page->flags);
 		pg_addr += PAGE_SIZE;
 	}
@@ -648,12 +674,12 @@
 #endif
 
 /**
- * sba_mark_invalid - invalidate one or more IO Pdir entries
+ * sba_mark_invalid - invalidate one or more IO PDIR entries
  * @ioc: IO MMU structure which owns the pdir we are interested in.
  * @iova:  IO Virtual Address mapped earlier
  * @byte_cnt:  number of bytes this mapping covers.
  *
- * Marking the IO Pdir entry(ies) as Invalid and invalidate
+ * Marking the IO PDIR entry(ies) as Invalid and invalidate
  * corresponding IO TLB entry. The PCOM (Purge Command Register)
  * is to purge stale entries in the IO TLB when unmapping entries.
  *
@@ -687,15 +713,24 @@
 
 		iovp |= IOVP_SHIFT;     /* set "size" field for PCOM */
 
+#ifndef FULL_VALID_PDIR
 		/*
-		** clear I/O Pdir entry "valid" bit
+		** clear I/O PDIR entry "valid" bit
 		** Do NOT clear the rest - save it for debugging.
 		** We should only clear bits that have previously
 		** been enabled.
 		*/
-		ioc->pdir_base[off] &= ~SBA_VALID_MASK;
+		ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+		/*
+  		** If we want to maintain the PDIR as valid, put in
+		** the spill page so devices prefetching won't
+		** cause a hard fail.
+		*/
+		ioc->pdir_base[off] = (0x80000000000000FFULL | prefetch_spill_page);
+#endif
 	} else {
-		u32 t = get_order(byte_cnt) + IOVP_SHIFT;
+		u32 t = get_order(byte_cnt) + PAGE_SHIFT;
 
 		iovp |= t;
 		ASSERT(t <= 31);   /* 2GB! Max value of "size" field */
@@ -703,14 +738,18 @@
 		do {
 			/* verify this pdir entry is enabled */
 			ASSERT(ioc->pdir_base[off]  >> 63);
+#ifndef FULL_VALID_PDIR
 			/* clear I/O Pdir entry "valid" bit first */
-			ioc->pdir_base[off] &= ~SBA_VALID_MASK;
+			ioc->pdir_base[off] &= ~(0x80000000000000FFULL);
+#else
+			ioc->pdir_base[off] = (0x80000000000000FFULL | prefetch_spill_page);
+#endif
 			off++;
 			byte_cnt -= IOVP_SIZE;
 		} while (byte_cnt > 0);
 	}
 
-	WRITE_REG(iovp, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(iovp | ioc->ibase, ioc->ioc_hpa+IOC_PCOM);
 }
 
 /**
@@ -718,26 +757,23 @@
  * @dev: instance of PCI owned by the driver that's asking.
  * @addr:  driver buffer to map.
  * @size:  number of bytes to map in driver buffer.
- * @direction:  R/W or both.
+ * @dir:  R/W or both.
  *
  * See Documentation/DMA-mapping.txt
  */
 dma_addr_t
-sba_map_single(struct pci_dev *dev, void *addr, size_t size, int direction)
+sba_map_single(struct device *dev, void *addr, size_t size, int dir)
 {
 	struct ioc *ioc;
-	unsigned long flags; 
+	unsigned long flags;
 	dma_addr_t iovp;
 	dma_addr_t offset;
 	u64 *pdir_start;
 	int pide;
 #ifdef ALLOW_IOV_BYPASS
-	unsigned long phys_addr = virt_to_phys(addr);
+	unsigned long pci_addr = virt_to_phys(addr);
 #endif
 
-	if (!sba_list)
-		panic("sba_map_single: no SBA found!\n");
-
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
 
@@ -745,7 +781,7 @@
 	/*
  	** Check if the PCI device can DMA to ptr... if so, just return ptr
  	*/
-	if ((phys_addr & ~dev->dma_mask) == 0) {
+	if (dev && dev->dma_mask && (pci_addr & ~*dev->dma_mask) == 0) {
 		/*
  		** Device is bit capable of DMA'ing to the buffer...
 		** just return the PCI address of ptr
@@ -756,8 +792,8 @@
 		spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 		DBG_BYPASS("sba_map_single() bypass mask/addr: 0x%lx/0x%lx\n",
-		           dev->dma_mask, phys_addr);
-		return phys_addr;
+		           *dev->dma_mask, pci_addr);
+		return pci_addr;
 	}
 #endif
 
@@ -790,8 +826,7 @@
 
 	while (size > 0) {
 		ASSERT(((u8 *)pdir_start)[7] == 0); /* verify availability */
-
-		sba_io_pdir_entry(pdir_start, virt_to_phys(addr));
+		sba_io_pdir_entry(pdir_start, (unsigned long) addr);
 
 		DBG_RUN("     pdir 0x%p %lx\n", pdir_start, *pdir_start);
 
@@ -799,12 +834,15 @@
 		size -= IOVP_SIZE;
 		pdir_start++;
 	}
+	/* force pdir update */
+	wmb();
+
 	/* form complete address */
 #ifdef ASSERT_PDIR_SANITY
 	sba_check_pdir(ioc,"Check after sba_map_single()");
 #endif
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
-	return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG(direction));
+	return SBA_IOVA(ioc, iovp, offset, DEFAULT_DMA_HINT_REG);
 }
 
 /**
@@ -812,23 +850,19 @@
  * @dev: instance of PCI owned by the driver that's asking.
  * @iova:  IOVA of driver buffer previously mapped.
  * @size:  number of bytes mapped in driver buffer.
- * @direction:  R/W or both.
+ * @dir:  R/W or both.
  *
  * See Documentation/DMA-mapping.txt
  */
-void sba_unmap_single(struct pci_dev *dev, dma_addr_t iova, size_t size,
-		int direction)
+void sba_unmap_single(struct device *dev, dma_addr_t iova, size_t size, int dir)
 {
 	struct ioc *ioc;
 #if DELAYED_RESOURCE_CNT > 0
 	struct sba_dma_pair *d;
 #endif
-	unsigned long flags; 
+	unsigned long flags;
 	dma_addr_t offset;
 
-	if (!sba_list)
-		panic("sba_map_single: no SBA found!\n");
-
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
 
@@ -845,7 +879,7 @@
 		DBG_BYPASS("sba_unmap_single() bypass addr: 0x%lx\n", iova);
 
 #ifdef ENABLE_MARK_CLEAN
-		if (direction == PCI_DMA_FROMDEVICE) {
+		if (dir == DMA_FROM_DEVICE) {
 			mark_clean(phys_to_virt(iova), size);
 		}
 #endif
@@ -861,29 +895,6 @@
 	size += offset;
 	size = ROUNDUP(size, IOVP_SIZE);
 
-#ifdef ENABLE_MARK_CLEAN
-	/*
-	** Don't need to hold the spinlock while telling VM pages are "clean".
-	** The pages are "busy" in the resource map until we mark them free.
-	** But tell VM pages are clean *before* releasing the resource
-	** in order to avoid race conditions.
-	*/
-	if (direction == PCI_DMA_FROMDEVICE) {
-		u32 iovp = (u32) SBA_IOVP(ioc,iova);
-		unsigned int pide = PDIR_INDEX(iovp);
-		u64 *pdirp = &(ioc->pdir_base[pide]);
-		size_t byte_cnt = size;
-		void *addr;
-
-		do {
-			addr = phys_to_virt(sba_io_page(pdirp));
-			mark_clean(addr, min(byte_cnt, IOVP_SIZE));
-			pdirp++;
-			byte_cnt -= IOVP_SIZE;
-		} while (byte_cnt > 0);
-	}
-#endif
-
 	spin_lock_irqsave(&ioc->res_lock, flags);
 #ifdef CONFIG_PROC_FS
 	ioc->usingle_calls++;
@@ -909,7 +920,40 @@
 	sba_free_range(ioc, iova, size);
 	READ_REG(ioc->ioc_hpa+IOC_PCOM);	/* flush purges */
 #endif /* DELAYED_RESOURCE_CNT == 0 */
+#ifdef ENABLE_MARK_CLEAN
+	if (dir == DMA_FROM_DEVICE) {
+		u32 iovp = (u32) SBA_IOVP(ioc,iova);
+		int off = PDIR_INDEX(iovp);
+		void *addr;
+
+		if (size <= IOVP_SIZE) {
+			addr = phys_to_virt(ioc->pdir_base[off] &
+					    ~0xE000000000000FFFULL);
+			mark_clean(addr, size);
+		} else {
+			size_t byte_cnt = size;
+
+			do {
+				addr = phys_to_virt(ioc->pdir_base[off] &
+				                    ~0xE000000000000FFFULL);
+				mark_clean(addr, min(byte_cnt, IOVP_SIZE));
+				off++;
+				byte_cnt -= IOVP_SIZE;
+
+			   } while (byte_cnt > 0);
+		}
+	}
+#endif
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
+
+	/* XXX REVISIT for 2.5 Linux - need syncdma for zero-copy support.
+	** For Astro based systems this isn't a big deal WRT performance.
+	** As long as 2.4 kernels copyin/copyout data from/to userspace,
+	** we don't need the syncdma. The issue here is I/O MMU cachelines
+	** are *not* coherent in all cases.  May be hwrev dependent.
+	** Need to investigate more.
+	asm volatile("syncdma");
+	*/
 }
 
 
@@ -922,29 +966,25 @@
  * See Documentation/DMA-mapping.txt
  */
 void *
-sba_alloc_consistent(struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+sba_alloc_coherent (struct device *hwdev, size_t size, dma_addr_t *dma_handle, int flags)
 {
-	void *ret;
-
-	if (!hwdev) {
-		/* only support PCI */
-		*dma_handle = 0;
-		return 0;
-	}
+	struct ioc *ioc;
+	void *addr;
 
-        ret = (void *) __get_free_pages(GFP_ATOMIC, get_order(size));
+        addr = (void *) __get_free_pages(flags, get_order(size));
+	if (!addr)
+		return NULL;
 
-	if (ret) {
-		memset(ret, 0, size);
-		/*
-		 * REVISIT: if sba_map_single starts needing more
-		 * than dma_mask from the device, this needs to be
-		 * updated.
-		 */
-		*dma_handle = sba_map_single(&sac_only_dev, ret, size, 0);
-	}
+	/*
+	 * REVISIT: if sba_map_single starts needing more than dma_mask from the
+	 * device, this needs to be updated.
+	 */
+	ioc = GET_IOC(hwdev);
+	ASSERT(ioc);
+	*dma_handle = sba_map_single(&ioc->sac_only_dev->dev, addr, size, 0);
 
-	return ret;
+	memset(addr, 0, size);
+	return addr;
 }
 
 
@@ -957,117 +997,245 @@
  *
  * See Documentation/DMA-mapping.txt
  */
-void sba_free_consistent(struct pci_dev *hwdev, size_t size, void *vaddr,
-		dma_addr_t dma_handle)
+void sba_free_coherent (struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
 {
 	sba_unmap_single(hwdev, dma_handle, size, 0);
 	free_pages((unsigned long) vaddr, get_order(size));
 }
 
 
+/*
+** Since 0 is a valid pdir_base index value, can't use that
+** to determine if a value is valid or not. Use a flag to indicate
+** the SG list entry contains a valid pdir index.
+*/
+#define PIDE_FLAG 0x1UL
+
 #ifdef DEBUG_LARGE_SG_ENTRIES
 int dump_run_sg = 0;
 #endif
 
-#define SG_ENT_VIRT_PAGE(sg) page_address((sg)->page)
-#define SG_ENT_PHYS_PAGE(SG) virt_to_phys(SG_ENT_VIRT_PAGE(SG))
-
 
 /**
- * sba_coalesce_chunks - preprocess the SG list
+ * sba_fill_pdir - write allocated SG entries into IO PDIR
  * @ioc: IO MMU structure which owns the pdir we are interested in.
- * @startsg:  input=SG list	output=DMA addr/len pairs filled in
+ * @startsg:  list of IOVA/size pairs
  * @nents: number of entries in startsg list
- * @direction: R/W or both.
  *
- * Walk the SG list and determine where the breaks are in the DMA stream.
- * Allocate IO Pdir resources and fill them in separate loop.
- * Returns the number of DMA streams used for output IOVA list.
- * Note each DMA stream can consume multiple IO Pdir entries.
- *
- * Code is written assuming some coalescing is possible.
+ * Take preprocessed SG list and write corresponding entries
+ * in the IO PDIR.
  */
+
 static SBA_INLINE int
-sba_coalesce_chunks(struct ioc *ioc, struct scatterlist *startsg,
-	int nents, int direction)
+sba_fill_pdir(
+	struct ioc *ioc,
+	struct scatterlist *startsg,
+	int nents)
 {
-	struct scatterlist *dma_sg = startsg;	/* return array */
+	struct scatterlist *dma_sg = startsg;	/* pointer to current DMA */
 	int n_mappings = 0;
+	u64 *pdirp = 0;
+	unsigned long dma_offset = 0;
 
-	ASSERT(nents > 1);
+	dma_sg--;
+	while (nents-- > 0) {
+		int     cnt = startsg->dma_length;
+		startsg->dma_length = 0;
 
-	do {
-		unsigned int dma_cnt = 1; /* number of pages in DMA stream */
-		unsigned int pide;	/* index into IO Pdir array */
-		u64 *pdirp;		/* pointer into IO Pdir array */
-		unsigned long dma_offset, dma_len; /* cumulative DMA stream */
+#ifdef DEBUG_LARGE_SG_ENTRIES
+		if (dump_run_sg)
+			printk(" %2d : %08lx/%05x %p\n",
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
+#else
+		DBG_RUN_SG(" %d : %08lx/%05x %p\n",
+				nents, startsg->dma_address, cnt,
+				sba_sg_address(startsg));
+#endif
+		/*
+		** Look for the start of a new DMA stream
+		*/
+		if (startsg->dma_address & PIDE_FLAG) {
+			u32 pide = startsg->dma_address & ~PIDE_FLAG;
+			dma_offset = (unsigned long) pide & ~IOVP_MASK;
+			startsg->dma_address = 0;
+			dma_sg++;
+			dma_sg->dma_address = pide | ioc->ibase;
+			pdirp = &(ioc->pdir_base[pide >> IOVP_SHIFT]);
+			n_mappings++;
+		}
 
 		/*
-		** Prepare for first/next DMA stream
+		** Look for a VCONTIG chunk
 		*/
-		dma_len = sba_sg_len(startsg);
-		dma_offset = (unsigned long) sba_sg_address(startsg);
+		if (cnt) {
+			unsigned long vaddr = (unsigned long) sba_sg_address(startsg);
+			ASSERT(pdirp);
+
+			/* Since multiple Vcontig blocks could make up
+			** one DMA stream, *add* cnt to dma_len.
+			*/
+			dma_sg->dma_length += cnt;
+			cnt += dma_offset;
+			dma_offset=0;	/* only want offset on first chunk */
+			cnt = ROUNDUP(cnt, IOVP_SIZE);
+#ifdef CONFIG_PROC_FS
+			ioc->msg_pages += cnt >> IOVP_SHIFT;
+#endif
+			do {
+				sba_io_pdir_entry(pdirp, vaddr);
+				vaddr += IOVP_SIZE;
+				cnt -= IOVP_SIZE;
+				pdirp++;
+			} while (cnt > 0);
+		}
 		startsg++;
-		nents--;
+	}
+	/* force pdir update */
+	wmb();
+
+#ifdef DEBUG_LARGE_SG_ENTRIES
+	dump_run_sg = 0;
+#endif
+	return(n_mappings);
+}
+
+
+/*
+** Two address ranges are DMA contiguous *iff* "end of prev" and
+** "start of next" are both on a page boundry.
+**
+** (shift left is a quick trick to mask off upper bits)
+*/
+#define DMA_CONTIG(__X, __Y) \
+	(((((unsigned long) __X) | ((unsigned long) __Y)) << (BITS_PER_LONG - PAGE_SHIFT)) == 0UL)
+
+
+/**
+ * sba_coalesce_chunks - preprocess the SG list
+ * @ioc: IO MMU structure which owns the pdir we are interested in.
+ * @startsg:  list of IOVA/size pairs
+ * @nents: number of entries in startsg list
+ *
+ * First pass is to walk the SG list and determine where the breaks are
+ * in the DMA stream. Allocates PDIR entries but does not fill them.
+ * Returns the number of DMA chunks.
+ *
+ * Doing the fill seperate from the coalescing/allocation keeps the
+ * code simpler. Future enhancement could make one pass through
+ * the sglist do both.
+ */
+static SBA_INLINE int
+sba_coalesce_chunks( struct ioc *ioc,
+	struct scatterlist *startsg,
+	int nents)
+{
+	struct scatterlist *vcontig_sg;    /* VCONTIG chunk head */
+	unsigned long vcontig_len;         /* len of VCONTIG chunk */
+	unsigned long vcontig_end;
+	struct scatterlist *dma_sg;        /* next DMA stream head */
+	unsigned long dma_offset, dma_len; /* start/len of DMA stream */
+	int n_mappings = 0;
+
+	while (nents > 0) {
+		unsigned long vaddr = (unsigned long) sba_sg_address(startsg);
 
 		/*
-		** We want to know how many entries can be coalesced
-		** before trying to allocate IO Pdir space.
-		** IOVAs can then be allocated "naturally" aligned
-		** to take advantage of the block IO TLB flush.
+		** Prepare for first/next DMA stream
 		*/
-		while (nents) {
-			unsigned long end_offset = dma_offset + dma_len;
+		dma_sg = vcontig_sg = startsg;
+		dma_len = vcontig_len = vcontig_end = startsg->length;
+		vcontig_end +=  vaddr;
+		dma_offset = vaddr & ~IOVP_MASK;
 
-			/* prev entry must end on a page boundary */
-			if (end_offset & IOVP_MASK)
-				break;
+		/* PARANOID: clear entries */
+		startsg->dma_address = startsg->dma_length = 0;
 
-			/* next entry start on a page boundary? */
-			if (startsg->offset)
-				break;
+		/*
+		** This loop terminates one iteration "early" since
+		** it's always looking one "ahead".
+		*/
+		while (--nents > 0) {
+			unsigned long vaddr;	/* tmp */
+
+			startsg++;
+
+			/* PARANOID */
+			startsg->dma_address = startsg->dma_length = 0;
+
+			/* catch brokenness in SCSI layer */
+			ASSERT(startsg->length <= DMA_CHUNK_SIZE);
 
 			/*
-			** make sure current dma stream won't exceed
-			** DMA_CHUNK_SIZE if coalescing entries.
+			** First make sure current dma stream won't
+			** exceed DMA_CHUNK_SIZE if we coalesce the
+			** next entry.
 			*/
-			if (((end_offset + startsg->length + ~IOVP_MASK)
-								& IOVP_MASK)
-					> DMA_CHUNK_SIZE)
+			if (((dma_len + dma_offset + startsg->length + ~IOVP_MASK) & IOVP_MASK)
+			    > DMA_CHUNK_SIZE)
 				break;
 
-			dma_len += sba_sg_len(startsg);
-			startsg++;
-			nents--;
-			dma_cnt++;
-		}
+			/*
+			** Then look for virtually contiguous blocks.
+			**
+			** append the next transaction?
+			*/
+			vaddr = (unsigned long) sba_sg_address(startsg);
+			if  (vcontig_end == vaddr)
+			{
+				vcontig_len += startsg->length;
+				vcontig_end += startsg->length;
+				dma_len     += startsg->length;
+				continue;
+			}
 
-		ASSERT(dma_len <= DMA_CHUNK_SIZE);
+#ifdef DEBUG_LARGE_SG_ENTRIES
+			dump_run_sg = (vcontig_len > IOVP_SIZE);
+#endif
 
-		/* allocate IO Pdir resource.
-		** returns index into (u64) IO Pdir array.
-		** IOVA is formed from this.
-		*/
-		pide = sba_alloc_range(ioc, dma_cnt << IOVP_SHIFT);
-		pdirp = &(ioc->pdir_base[pide]);
+			/*
+			** Not virtually contigous.
+			** Terminate prev chunk.
+			** Start a new chunk.
+			**
+			** Once we start a new VCONTIG chunk, dma_offset
+			** can't change. And we need the offset from the first
+			** chunk - not the last one. Ergo Successive chunks
+			** must start on page boundaries and dove tail
+			** with it's predecessor.
+			*/
+			vcontig_sg->dma_length = vcontig_len;
 
-		/* fill_pdir: write stream into IO Pdir */
-		while (dma_cnt--) {
-			sba_io_pdir_entry(pdirp, SG_ENT_PHYS_PAGE(startsg));
-			startsg++;
-			pdirp++;
-		}
+			vcontig_sg = startsg;
+			vcontig_len = startsg->length;
 
-		/* "output" IOVA */
-		sba_sg_iova(dma_sg) = SBA_IOVA(ioc,
-					((dma_addr_t) pide << IOVP_SHIFT),
-					dma_offset,
-					DEFAULT_DMA_HINT_REG(direction));
-		sba_sg_iova_len(dma_sg) = dma_len;
+			/*
+			** 3) do the entries end/start on page boundaries?
+			**    Don't update vcontig_end until we've checked.
+			*/
+			if (DMA_CONTIG(vcontig_end, vaddr))
+			{
+				vcontig_end = vcontig_len + vaddr;
+				dma_len += vcontig_len;
+				continue;
+			} else {
+				break;
+			}
+		}
 
-		dma_sg++;
+		/*
+		** End of DMA Stream
+		** Terminate last VCONTIG block.
+		** Allocate space for DMA stream.
+		*/
+		vcontig_sg->dma_length = vcontig_len;
+		dma_len = (dma_len + dma_offset + ~IOVP_MASK) & IOVP_MASK;
+		ASSERT(dma_len <= DMA_CHUNK_SIZE);
+		dma_sg->dma_address = (dma_addr_t) (PIDE_FLAG
+			| (sba_alloc_range(ioc, dma_len) << IOVP_SHIFT)
+			| dma_offset);
 		n_mappings++;
-	} while (nents);
+	}
 
 	return n_mappings;
 }
@@ -1075,60 +1243,51 @@
 
 /**
  * sba_map_sg - map Scatter/Gather list
- * @dev: instance of PCI device owned by the driver that's asking.
+ * @dev: instance of PCI owned by the driver that's asking.
  * @sglist:  array of buffer/length pairs
  * @nents:  number of entries in list
- * @direction:  R/W or both.
+ * @dir:  R/W or both.
  *
  * See Documentation/DMA-mapping.txt
  */
-int sba_map_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents,
-		int direction)
+int sba_map_sg(struct device *dev, struct scatterlist *sglist, int nents, int dir)
 {
 	struct ioc *ioc;
-	int filled = 0;
+	int coalesced, filled = 0;
 	unsigned long flags;
 #ifdef ALLOW_IOV_BYPASS
 	struct scatterlist *sg;
 #endif
 
-	DBG_RUN_SG("%s() START %d entries, 0x%p,0x%x\n", __FUNCTION__, nents,
-		sba_sg_address(sglist), sba_sg_len(sglist));
-
-	if (!sba_list)
-		panic("sba_map_single: no SBA found!\n");
-
+	DBG_RUN_SG("%s() START %d entries\n", __FUNCTION__, nents);
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
 
 #ifdef ALLOW_IOV_BYPASS
-	if (dev->dma_mask >= ioc->dma_mask) {
-		for (sg = sglist ; filled < nents ; filled++, sg++) {
-			sba_sg_iova(sg) = virt_to_phys(sba_sg_address(sg));
-			sba_sg_iova_len(sg) = sba_sg_len(sg);
+	if (dev && dev->dma_mask && (ioc->dma_mask & ~*dev->dma_mask) == 0) {
+		for (sg = sglist ; filled < nents ; filled++, sg++){
+			sg->dma_length = sg->length;
+			sg->dma_address = virt_to_phys(sba_sg_address(sg));
 		}
 #ifdef CONFIG_PROC_FS
 		spin_lock_irqsave(&ioc->res_lock, flags);
 		ioc->msg_bypass++;
 		spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
-		DBG_RUN_SG("%s() DONE %d mappings bypassed\n", __FUNCTION__, filled);
 		return filled;
 	}
 #endif
 	/* Fast path single entry scatterlists. */
 	if (nents == 1) {
-		sba_sg_iova(sglist) = sba_map_single(dev,
-						     (void *) sba_sg_iova(sglist),
-						     sba_sg_len(sglist), direction);
-		sba_sg_iova_len(sglist) = sba_sg_len(sglist);
+		sglist->dma_length = sglist->length;
+		sglist->dma_address = sba_map_single(dev, sba_sg_address(sglist), sglist->length,
+						     dir);
 #ifdef CONFIG_PROC_FS
 		/*
 		** Should probably do some stats counting, but trying to
 		** be precise quickly starts wasting CPU time.
 		*/
 #endif
-		DBG_RUN_SG("%s() DONE 1 mapping\n", __FUNCTION__);
 		return 1;
 	}
 
@@ -1145,11 +1304,26 @@
 #ifdef CONFIG_PROC_FS
 	ioc->msg_calls++;
 #endif
- 
+
 	/*
-	** coalesce and program the I/O Pdir
+	** First coalesce the chunks and allocate I/O pdir space
+	**
+	** If this is one DMA stream, we can properly map using the
+	** correct virtual address associated with each DMA page.
+	** w/o this association, we wouldn't have coherent DMA!
+	** Access to the virtual address is what forces a two pass algorithm.
 	*/
-	filled = sba_coalesce_chunks(ioc, sglist, nents, direction);
+	coalesced = sba_coalesce_chunks(ioc, sglist, nents);
+
+	/*
+	** Program the I/O Pdir
+	**
+	** map the virtual addresses to the I/O Pdir
+	** o dma_address will contain the pdir index
+	** o dma_len will contain the number of bytes to map
+	** o address contains the virtual address.
+	*/
+	filled = sba_fill_pdir(ioc, sglist, nents);
 
 #ifdef ASSERT_PDIR_SANITY
 	if (sba_check_pdir(ioc,"Check after sba_map_sg()"))
@@ -1161,6 +1335,7 @@
 
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 
+	ASSERT(coalesced == filled);
 	DBG_RUN_SG("%s() DONE %d mappings\n", __FUNCTION__, filled);
 
 	return filled;
@@ -1172,23 +1347,19 @@
  * @dev: instance of PCI owned by the driver that's asking.
  * @sglist:  array of buffer/length pairs
  * @nents:  number of entries in list
- * @direction:  R/W or both.
+ * @dir:  R/W or both.
  *
  * See Documentation/DMA-mapping.txt
  */
-void sba_unmap_sg(struct pci_dev *dev, struct scatterlist *sglist, int nents,
-		int direction)
+void sba_unmap_sg (struct device *dev, struct scatterlist *sglist, int nents, int dir)
 {
 	struct ioc *ioc;
 #ifdef ASSERT_PDIR_SANITY
 	unsigned long flags;
 #endif
 
-	DBG_RUN_SG("%s() START %d entries, 0x%p,0x%x\n",
-		__FUNCTION__, nents, sba_sg_address(sglist), sba_sg_len(sglist));
-
-	if (!sba_list)
-		panic("sba_map_single: no SBA found!\n");
+	DBG_RUN_SG("%s() START %d entries,  %p,%x\n",
+		__FUNCTION__, nents, sba_sg_address(sglist), sglist->length);
 
 	ioc = GET_IOC(dev);
 	ASSERT(ioc);
@@ -1203,10 +1374,9 @@
 	spin_unlock_irqrestore(&ioc->res_lock, flags);
 #endif
 
-	while (sba_sg_len(sglist) && nents--) {
+	while (nents && sglist->dma_length) {
 
-		sba_unmap_single(dev, (dma_addr_t)sba_sg_iova(sglist),
-		                 sba_sg_iova_len(sglist), direction);
+		sba_unmap_single(dev, sglist->dma_address, sglist->dma_length, dir);
 #ifdef CONFIG_PROC_FS
 		/*
 		** This leaves inconsistent data in the stats, but we can't
@@ -1214,9 +1384,11 @@
 		** were coalesced to a single entry.  The stats are fun,
 		** but speed is more important.
 		*/
-		ioc->usg_pages += (((u64)sba_sg_iova(sglist) & ~IOVP_MASK) + sba_sg_len(sglist) + IOVP_SIZE - 1) >> IOVP_SHIFT;
+		ioc->usg_pages += ((sglist->dma_address & ~IOVP_MASK) + sglist->dma_length
+				   + IOVP_SIZE - 1) >> PAGE_SHIFT;
 #endif
-		++sglist;
+		sglist++;
+		nents--;
 	}
 
 	DBG_RUN_SG("%s() DONE (nents %d)\n", __FUNCTION__,  nents);
@@ -1229,87 +1401,76 @@
 
 }
 
-unsigned long
-sba_dma_address (struct scatterlist *sg)
-{
-	return ((unsigned long)sba_sg_iova(sg));
-}
-
-int
-sba_dma_supported (struct pci_dev *dev, u64 mask)
-{
-	return 1;
-}
-
 /**************************************************************
 *
 *   Initialization and claim
 *
 ***************************************************************/
 
-
-static void
-sba_ioc_init(struct sba_device *sba_dev, struct ioc *ioc, int ioc_num)
+static void __init
+ioc_iova_init(struct ioc *ioc)
 {
-	u32 iova_space_size, iova_space_mask;
-	void * pdir_base;
-	int pdir_size, iov_order, tcnfg;
+	u32 iova_space_mask;
+	int iov_order, tcnfg;
+	int agp_found = 0;
+	struct pci_dev *device;
+#ifdef FULL_VALID_PDIR
+	unsigned long index;
+#endif
 
 	/*
-	** Firmware programs the maximum IOV space size into the imask reg
+	** Firmware programs the base and size of a "safe IOVA space"
+	** (one that doesn't overlap memory or LMMIO space) in the
+	** IBASE and IMASK registers.
 	*/
-	iova_space_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;
+	ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & ~0x1UL;
+	ioc->iov_size = ~(READ_REG(ioc->ioc_hpa + IOC_IMASK) & 0xFFFFFFFFUL) + 1;
 
 	/*
 	** iov_order is always based on a 1GB IOVA space since we want to
 	** turn on the other half for AGP GART.
 	*/
-	iov_order = get_order(iova_space_size >> (IOVP_SHIFT-PAGE_SHIFT));
-	ioc->pdir_size = pdir_size = (iova_space_size/IOVP_SIZE) * sizeof(u64);
+	iov_order = get_order(ioc->iov_size >> (IOVP_SHIFT - PAGE_SHIFT));
+	ioc->pdir_size = (ioc->iov_size / IOVP_SIZE) * sizeof(u64);
 
-	DBG_INIT("%s() hpa 0x%lx IOV %dMB (%d bits) PDIR size 0x%0x\n",
-		__FUNCTION__, ioc->ioc_hpa, iova_space_size>>20,
-		iov_order + PAGE_SHIFT, ioc->pdir_size);
+	DBG_INIT("%s() hpa %p IOV %dMB (%d bits) PDIR size 0x%x\n",
+		 __FUNCTION__, ioc->ioc_hpa, ioc->iov_size >> 20,
+		 iov_order + PAGE_SHIFT, ioc->pdir_size);
 
-	/* XXX DMA HINTs not used */
+	/* FIXME : DMA HINTs not used */
 	ioc->hint_shift_pdir = iov_order + PAGE_SHIFT;
 	ioc->hint_mask_pdir = ~(0x3 << (iov_order + PAGE_SHIFT));
 
-	ioc->pdir_base = pdir_base =
-		(void *) __get_free_pages(GFP_KERNEL, get_order(pdir_size));
-	if (NULL == pdir_base)
-	{
-		panic(__FILE__ ":%s() could not allocate I/O Page Table\n", __FUNCTION__);
-	}
-	memset(pdir_base, 0, pdir_size);
+	ioc->pdir_base = (void *) __get_free_pages(GFP_KERNEL,
+						   get_order(ioc->pdir_size));
+	if (!ioc->pdir_base)
+		panic(PFX "Couldn't allocate I/O Page Table\n");
+
+	memset(ioc->pdir_base, 0, ioc->pdir_size);
 
 	DBG_INIT("%s() pdir %p size %x hint_shift_pdir %x hint_mask_pdir %lx\n",
-		__FUNCTION__, pdir_base, pdir_size,
+		__FUNCTION__, ioc->pdir_base, ioc->pdir_size,
 		ioc->hint_shift_pdir, ioc->hint_mask_pdir);
 
-	ASSERT((((unsigned long) pdir_base) & PAGE_MASK) == (unsigned long) pdir_base);
-	WRITE_REG(virt_to_phys(pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
+	ASSERT((((unsigned long) ioc->pdir_base) & PAGE_MASK) == (unsigned long) ioc->pdir_base);
+	WRITE_REG(virt_to_phys(ioc->pdir_base), ioc->ioc_hpa + IOC_PDIR_BASE);
 
-	DBG_INIT(" base %p\n", pdir_base);
+	DBG_INIT(" base %p\n", ioc->pdir_base);
 
 	/* build IMASK for IOC and Elroy */
 	iova_space_mask =  0xffffffff;
-	iova_space_mask <<= (iov_order + IOVP_SHIFT);
-
-	ioc->ibase = READ_REG(ioc->ioc_hpa + IOC_IBASE) & 0xFFFFFFFEUL;
-
-	ioc->imask = iova_space_mask;	/* save it */
+	iova_space_mask <<= (iov_order + PAGE_SHIFT);
+	ioc->imask = iova_space_mask;
 
 	DBG_INIT("%s() IOV base 0x%lx mask 0x%0lx\n",
 		__FUNCTION__, ioc->ibase, ioc->imask);
 
 	/*
-	** XXX DMA HINT registers are programmed with default hint
+	** FIXME: Hint registers are programmed with default hint
 	** values during boot, so hints should be sane even if we
 	** can't reprogram them the way drivers want.
 	*/
-
-	WRITE_REG(ioc->imask, ioc->ioc_hpa+IOC_IMASK);
+	WRITE_REG(ioc->imask, ioc->ioc_hpa + IOC_IMASK);
 
 	/*
 	** Setting the upper bits makes checking for bypass addresses
@@ -1317,34 +1478,30 @@
 	*/
 	ioc->imask |= 0xFFFFFFFF00000000UL;
 
-	/* Set I/O Pdir page size to system page size */
-	switch (IOVP_SHIFT) {
-		case 12: /* 4K */
-			tcnfg = 0;
-			break;
-		case 13: /* 8K */
-			tcnfg = 1;
-			break;
-		case 14: /* 16K */
-			tcnfg = 2;
-			break;
-		case 16: /* 64K */
-			tcnfg = 3;
+	/* Set I/O PDIR Page size to system page size */
+	switch (PAGE_SHIFT) {
+		case 12: tcnfg = 0; break;	/*  4K */
+		case 13: tcnfg = 1; break;	/*  8K */
+		case 14: tcnfg = 2; break;	/* 16K */
+		case 16: tcnfg = 3; break;	/* 64K */
+		default:
+			panic(PFX "Unsupported system page size %d",
+				1 << PAGE_SHIFT);
 			break;
 	}
-	WRITE_REG(tcnfg, ioc->ioc_hpa+IOC_TCNFG);
+	WRITE_REG(tcnfg, ioc->ioc_hpa + IOC_TCNFG);
 
 	/*
 	** Program the IOC's ibase and enable IOVA translation
 	** Bit zero == enable bit.
 	*/
-	WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa+IOC_IBASE);
+	WRITE_REG(ioc->ibase | 1, ioc->ioc_hpa + IOC_IBASE);
 
 	/*
 	** Clear I/O TLB of any possible entries.
 	** (Yes. This is a bit paranoid...but so what)
 	*/
-	WRITE_REG(0 | 31, ioc->ioc_hpa+IOC_PCOM);
+	WRITE_REG(ioc->ibase | (iov_order+PAGE_SHIFT), ioc->ioc_hpa + IOC_PCOM);
 
 	/*
 	** If an AGP device is present, only use half of the IOV space
@@ -1354,346 +1511,468 @@
 	** We program the next pdir index after we stop w/ a key for
 	** the GART code to handshake on.
 	*/
-	if (SBA_GET_AGP(sba_dev)) {
-		DBG_INIT("%s() AGP Device found, reserving 512MB for GART support\n", __FUNCTION__);
+	pci_for_each_dev(device)
+		agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP);
+
+	if (agp_found && reserve_sba_gart) {
+		DBG_INIT("%s: AGP device found, reserving half of IOVA for GART support\n",
+			 __FUNCTION__);
 		ioc->pdir_size /= 2;
-		((u64 *)pdir_base)[PDIR_INDEX(iova_space_size/2)] = 0x0000badbadc0ffeeULL;
+		((u64 *)ioc->pdir_base)[PDIR_INDEX(ioc->iov_size/2)] = ZX1_SBA_IOMMU_COOKIE;
 	}
+#ifdef FULL_VALID_PDIR
+	/*
+  	** Check to see if the spill page has been allocated, we don't need more than
+	** one across multiple SBAs.
+	*/
+	if (!prefetch_spill_page) {
+		char *spill_poison = "SBAIOMMU POISON";
+		int poison_size = 16;
+		void *poison_addr, *addr;
+
+		addr = (void *)__get_free_pages(GFP_KERNEL, get_order(IOVP_SIZE));
+		if (!addr)
+			panic(PFX "Couldn't allocate PDIR spill page\n");
+
+		poison_addr = addr;
+		for ( ; (u64) poison_addr < addr + IOVP_SIZE; poison_addr += poison_size)
+			memcpy(poison_addr, spill_poison, poison_size);
+
+		prefetch_spill_page = virt_to_phys(addr);
+
+		DBG_INIT("%s() prefetch spill addr: 0x%lx\n", __FUNCTION__, prefetch_spill_page);
+	}
+	/*
+  	** Set all the PDIR entries valid w/ the spill page as the target
+	*/
+	for (index = 0 ; index < (ioc->pdir_size / sizeof(u64)) ; index++)
+		((u64 *)ioc->pdir_base)[index] = (0x80000000000000FF | prefetch_spill_page);
+#endif
 
-	DBG_INIT("%s() DONE\n", __FUNCTION__);
 }
 
+static void __init
+ioc_resource_init(struct ioc *ioc)
+{
+	spin_lock_init(&ioc->res_lock);
 
+	/* resource map size dictated by pdir_size */
+	ioc->res_size = ioc->pdir_size / sizeof(u64); /* entries */
+	ioc->res_size >>= 3;  /* convert bit count to byte count */
+	DBG_INIT("%s() res_size 0x%x\n", __FUNCTION__, ioc->res_size);
 
-/**************************************************************************
-**
-**   SBA initialization code (HW and SW)
-**
-**   o identify SBA chip itself
-**   o FIXME: initialize DMA hints for reasonable defaults
-**
-**************************************************************************/
+	ioc->res_map = (char *) __get_free_pages(GFP_KERNEL,
+						 get_order(ioc->res_size));
+	if (!ioc->res_map)
+		panic(PFX "Couldn't allocate resource map\n");
 
-static void
-sba_hw_init(struct sba_device *sba_dev)
-{ 
-	int i;
-	int num_ioc;
-	u64 dma_mask;
-	u32 func_id;
+	memset(ioc->res_map, 0, ioc->res_size);
+	/* next available IOVP - circular search */
+	ioc->res_hint = (unsigned long *) ioc->res_map;
 
-	/*
-	** Identify the SBA so we can set the dma_mask.  We can make a virtual
-	** dma_mask of the memory subsystem such that devices not implmenting
-	** a full 64bit mask might still be able to bypass efficiently.
-	*/
-	func_id = READ_REG(sba_dev->sba_hpa + SBA_FUNC_ID);
+#ifdef ASSERT_PDIR_SANITY
+	/* Mark first bit busy - ie no IOVA 0 */
+	ioc->res_map[0] = 0x1;
+	ioc->pdir_base[0] = 0x8000000000000000ULL | ZX1_SBA_IOMMU_COOKIE;
+#endif
+#ifdef FULL_VALID_PDIR
+	/* Mark the last resource used so we don't prefetch beyond IOVA space */
+	ioc->res_map[ioc->res_size - 1] |= 0x80UL; /* res_map is chars */
+	ioc->pdir_base[(ioc->pdir_size / sizeof(u64)) - 1] = (0x80000000000000FF
+							      | prefetch_spill_page);
+#endif
 
-	if (func_id == ZX1_FUNC_ID_VALUE) {
-		dma_mask = 0xFFFFFFFFFFUL;
-	} else {
-		dma_mask = 0xFFFFFFFFFFFFFFFFUL;
-	}
+	DBG_INIT("%s() res_map %x %p\n", __FUNCTION__,
+		 ioc->res_size, (void *) ioc->res_map);
+}
+
+static void __init
+ioc_sac_init(struct ioc *ioc)
+{
+	struct pci_dev *sac = NULL;
+	struct pci_controller *controller = NULL;
 
-	DBG_INIT("%s(): ioc->dma_mask == 0x%lx\n", __FUNCTION__, dma_mask);
-	
 	/*
-	** Leaving in the multiple ioc code from parisc for the future,
-	** currently there are no muli-ioc mckinley sbas
-	*/
-	sba_dev->ioc[0].ioc_hpa = SBA_IOC_OFFSET;
-	num_ioc = 1;
+	 * pci_alloc_coherent() must return a DMA address which is
+	 * SAC (single address cycle) addressable, so allocate a
+	 * pseudo-device to enforce that.
+	 */
+	sac = kmalloc(sizeof(*sac), GFP_KERNEL);
+	if (!sac)
+		panic(PFX "Couldn't allocate struct pci_dev");
+	memset(sac, 0, sizeof(*sac));
 
-	sba_dev->num_ioc = num_ioc;
-	for (i = 0; i < num_ioc; i++) {
-		sba_dev->ioc[i].dma_mask = dma_mask;
-		sba_dev->ioc[i].ioc_hpa += sba_dev->sba_hpa;
-		sba_ioc_init(sba_dev, &(sba_dev->ioc[i]), i);
-	}
+	controller = kmalloc(sizeof(*controller), GFP_KERNEL);
+	if (!controller)
+		panic(PFX "Couldn't allocate struct pci_controller");
+	memset(controller, 0, sizeof(*controller));
+
+	controller->iommu = ioc;
+	sac->sysdata = controller;
+	sac->dma_mask = 0xFFFFFFFFUL;
+#ifdef CONFIG_PCI
+	sac->dev.bus = &pci_bus_type;
+#endif
+	ioc->sac_only_dev = sac;
 }
 
-static void
-sba_common_init(struct sba_device *sba_dev)
+static void __init
+ioc_zx1_init(struct ioc *ioc)
 {
-	int i;
+	if (ioc->rev < 0x20)
+		panic(PFX "IOC 2.0 or later required for IOMMU support\n");
 
-	/* add this one to the head of the list (order doesn't matter)
-	** This will be useful for debugging - especially if we get coredumps
-	*/
-	sba_dev->next = sba_list;
-	sba_list = sba_dev;
-	sba_count++;
-
-	for(i=0; i< sba_dev->num_ioc; i++) {
-		int res_size;
-
-		/* resource map size dictated by pdir_size */
-		res_size = sba_dev->ioc[i].pdir_size/sizeof(u64); /* entries */
-		res_size >>= 3;  /* convert bit count to byte count */
-		DBG_INIT("%s() res_size 0x%x\n",
-			__FUNCTION__, res_size);
-
-		sba_dev->ioc[i].res_size = res_size;
-		sba_dev->ioc[i].res_map = (char *) __get_free_pages(GFP_KERNEL, get_order(res_size));
-
-		if (NULL == sba_dev->ioc[i].res_map)
-		{
-			panic(__FILE__ ":%s() could not allocate resource map\n", __FUNCTION__ );
-		}
+	ioc->dma_mask = 0xFFFFFFFFFFUL;
+}
 
-		memset(sba_dev->ioc[i].res_map, 0, res_size);
-		/* next available IOVP - circular search */
-		if ((sba_dev->hw_rev & 0xFF) >= 0x20) {
-			sba_dev->ioc[i].res_hint = (unsigned long *)
-			    sba_dev->ioc[i].res_map;
-		} else {
-			u64 reserved_iov;
+typedef void (initfunc)(struct ioc *);
 
-			/* Yet another 1.x hack */
-			printk(KERN_DEBUG "zx1 1.x: Starting resource hint offset into "
-			       "IOV space to avoid initial zero value IOVA\n");
-			sba_dev->ioc[i].res_hint = (unsigned long *)
-			    &(sba_dev->ioc[i].res_map[L1_CACHE_BYTES]);
-
-			sba_dev->ioc[i].res_map[0] = 0x1;
-			sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL;
-
-			for (reserved_iov = 0xA0000 ; reserved_iov < 0xC0000 ; reserved_iov += IOVP_SIZE) {
-				u64 *res_ptr = (u64 *) sba_dev->ioc[i].res_map;
-				int index = PDIR_INDEX(reserved_iov);
-				int res_word;
-				u64 mask;
-
-				res_word = (int)(index / BITS_PER_LONG);
-				mask =  0x1UL << (index - (res_word * BITS_PER_LONG));
-				res_ptr[res_word] |= mask;
-				sba_dev->ioc[i].pdir_base[PDIR_INDEX(reserved_iov)] = (SBA_VALID_MASK | reserved_iov);
+struct ioc_iommu {
+	u32 func_id;
+	char *name;
+	initfunc *init;
+};
 
-			}
-		}
+static struct ioc_iommu ioc_iommu_info[] __initdata = {
+	{ ZX1_IOC_ID, "zx1", ioc_zx1_init },
+	{ REO_IOC_ID, "REO" },
+	{ SX1000_IOC_ID, "sx1000" },
+};
 
-#ifdef ASSERT_PDIR_SANITY
-		/* Mark first bit busy - ie no IOVA 0 */
-		sba_dev->ioc[i].res_map[0] = 0x1;
-		sba_dev->ioc[i].pdir_base[0] = 0x8000badbadc0ffeeULL;
-#endif
+static struct ioc * __init
+ioc_init(u64 hpa, void *handle)
+{
+	struct ioc *ioc;
+	struct ioc_iommu *info;
+
+	ioc = kmalloc(sizeof(*ioc), GFP_KERNEL);
+	if (!ioc)
+		return NULL;
+
+	memset(ioc, 0, sizeof(*ioc));
 
-		DBG_INIT("%s() %d res_map %x %p\n", __FUNCTION__,
-		         i, res_size, (void *)sba_dev->ioc[i].res_map);
+	ioc->next = ioc_list;
+	ioc_list = ioc;
+
+	ioc->handle = handle;
+	ioc->ioc_hpa = ioremap(hpa, 0x1000);
+
+	ioc->func_id = READ_REG(ioc->ioc_hpa + IOC_FUNC_ID);
+	ioc->rev = READ_REG(ioc->ioc_hpa + IOC_FCLASS) & 0xFFUL;
+	ioc->dma_mask = 0xFFFFFFFFFFFFFFFFUL;	/* conservative */
+
+	for (info = ioc_iommu_info; info < ioc_iommu_info + ARRAY_SIZE(ioc_iommu_info); info++) {
+		if (ioc->func_id == info->func_id) {
+			ioc->name = info->name;
+			if (info->init)
+				(info->init)(ioc);
+		}
 	}
 
-	sba_dev->sba_lock = SPIN_LOCK_UNLOCKED;
+	if (!ioc->name) {
+		ioc->name = kmalloc(24, GFP_KERNEL);
+		if (ioc->name)
+			sprintf((char *) ioc->name, "Unknown (%04x:%04x)",
+				ioc->func_id & 0xFFFF, (ioc->func_id >> 16) & 0xFFFF);
+		else
+			ioc->name = "Unknown";
+	}
+
+	ioc_iova_init(ioc);
+	ioc_resource_init(ioc);
+	ioc_sac_init(ioc);
+
+	printk(KERN_INFO PFX
+		"%s %d.%d HPA 0x%lx IOVA space %dMb at 0x%lx\n",
+		ioc->name, (ioc->rev >> 4) & 0xF, ioc->rev & 0xF,
+		hpa, ioc->iov_size >> 20, ioc->ibase);
+
+	return ioc;
 }
 
+
+
+/**************************************************************************
+**
+**   SBA initialization code (HW and SW)
+**
+**   o identify SBA chip itself
+**   o FIXME: initialize DMA hints for reasonable defaults
+**
+**************************************************************************/
+
 #ifdef CONFIG_PROC_FS
-static int sba_proc_info(char *buf, char **start, off_t offset, int len)
+static void *
+ioc_start(struct seq_file *s, loff_t *pos)
 {
-	struct sba_device *sba_dev;
 	struct ioc *ioc;
-	int total_pages;
+	loff_t n = *pos;
+
+	for (ioc = ioc_list; ioc; ioc = ioc->next)
+		if (!n--)
+			return ioc;
+
+	return NULL;
+}
+
+static void *
+ioc_next(struct seq_file *s, void *v, loff_t *pos)
+{
+	struct ioc *ioc = v;
+
+	++*pos;
+	return ioc->next;
+}
+
+static void
+ioc_stop(struct seq_file *s, void *v)
+{
+}
+
+static int
+ioc_show(struct seq_file *s, void *v)
+{
+	struct ioc *ioc = v;
+	int total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
 	unsigned long i = 0, avg = 0, min, max;
 
-	for (sba_dev = sba_list; sba_dev; sba_dev = sba_dev->next) {
-		ioc = &sba_dev->ioc[0];	/* FIXME: Multi-IOC support! */
-		total_pages = (int) (ioc->res_size << 3); /* 8 bits per byte */
-
-		sprintf(buf, "%s rev %d.%d\n", "Hewlett-Packard zx1 SBA",
-			((sba_dev->hw_rev >> 4) & 0xF), (sba_dev->hw_rev & 0xF));
-		sprintf(buf, "%sIO PDIR size    : %d bytes (%d entries)\n", buf,
-			(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */ total_pages);
-
-		sprintf(buf, "%sIO PDIR entries : %ld free  %ld used (%d%%)\n", buf,
-			total_pages - ioc->used_pages, ioc->used_pages,
-			(int) (ioc->used_pages * 100 / total_pages));
-
-		sprintf(buf, "%sResource bitmap : %d bytes (%d pages)\n", 
-			buf, ioc->res_size, ioc->res_size << 3);   /* 8 bits per byte */
-
-		min = max = ioc->avg_search[0];
-		for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
-			avg += ioc->avg_search[i];
-			if (ioc->avg_search[i] > max) max = ioc->avg_search[i];
-			if (ioc->avg_search[i] < min) min = ioc->avg_search[i];
-		}
-		avg /= SBA_SEARCH_SAMPLE;
-		sprintf(buf, "%s  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n",
-			buf, min, avg, max);
-
-		sprintf(buf, "%spci_map_single(): %12ld calls  %12ld pages (avg %d/1000)\n",
-			buf, ioc->msingle_calls, ioc->msingle_pages,
-			(int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
+	seq_printf(s, "Hewlett Packard %s IOC rev %d.%d\n",
+		ioc->name, ((ioc->rev >> 4) & 0xF), (ioc->rev & 0xF));
+	seq_printf(s, "IO PDIR size    : %d bytes (%d entries)\n",
+		(int) ((ioc->res_size << 3) * sizeof(u64)), /* 8 bits/byte */
+		total_pages);
+
+	seq_printf(s, "IO PDIR entries : %ld free  %ld used (%d%%)\n",
+		total_pages - ioc->used_pages, ioc->used_pages,
+		(int) (ioc->used_pages * 100 / total_pages));
+
+	seq_printf(s, "Resource bitmap : %d bytes (%d pages)\n",
+		ioc->res_size, ioc->res_size << 3);   /* 8 bits per byte */
+
+	min = max = ioc->avg_search[0];
+	for (i = 0; i < SBA_SEARCH_SAMPLE; i++) {
+		avg += ioc->avg_search[i];
+		if (ioc->avg_search[i] > max) max = ioc->avg_search[i];
+		if (ioc->avg_search[i] < min) min = ioc->avg_search[i];
+	}
+  	avg /= SBA_SEARCH_SAMPLE;
+	seq_printf(s, "  Bitmap search : %ld/%ld/%ld (min/avg/max CPU Cycles)\n", min, avg, max);
+
+	seq_printf(s, "pci_map_single(): %12ld calls  %12ld pages (avg %d/1000)\n",
+		   ioc->msingle_calls, ioc->msingle_pages,
+		   (int) ((ioc->msingle_pages * 1000)/ioc->msingle_calls));
 #ifdef ALLOW_IOV_BYPASS
-		sprintf(buf, "%spci_map_single(): %12ld bypasses\n",
-			buf, ioc->msingle_bypass);
+	seq_printf(s, "pci_map_single(): %12ld bypasses\n", ioc->msingle_bypass);
 #endif
 
-		sprintf(buf, "%spci_unmap_single: %12ld calls  %12ld pages (avg %d/1000)\n",
-			buf, ioc->usingle_calls, ioc->usingle_pages,
-			(int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls));
+	seq_printf(s, "pci_unmap_single: %12ld calls  %12ld pages (avg %d/1000)\n",
+		   ioc->usingle_calls, ioc->usingle_pages,
+		   (int) ((ioc->usingle_pages * 1000)/ioc->usingle_calls));
 #ifdef ALLOW_IOV_BYPASS
-		sprintf(buf, "%spci_unmap_single: %12ld bypasses\n",
-			buf, ioc->usingle_bypass);
+	seq_printf(s, "pci_unmap_single: %12ld bypasses\n", ioc->usingle_bypass);
 #endif
 
-		sprintf(buf, "%spci_map_sg()    : %12ld calls  %12ld pages (avg %d/1000)\n",
-			buf, ioc->msg_calls, ioc->msg_pages,
-			(int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
+	seq_printf(s, "pci_map_sg()    : %12ld calls  %12ld pages (avg %d/1000)\n",
+		   ioc->msg_calls, ioc->msg_pages,
+		   (int) ((ioc->msg_pages * 1000)/ioc->msg_calls));
 #ifdef ALLOW_IOV_BYPASS
-		sprintf(buf, "%spci_map_sg()    : %12ld bypasses\n",
-			buf, ioc->msg_bypass);
+	seq_printf(s, "pci_map_sg()    : %12ld bypasses\n", ioc->msg_bypass);
 #endif
 
-		sprintf(buf, "%spci_unmap_sg()  : %12ld calls  %12ld pages (avg %d/1000)\n",
-			buf, ioc->usg_calls, ioc->usg_pages,
-			(int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
-	}
-	return strlen(buf);
+	seq_printf(s, "pci_unmap_sg()  : %12ld calls  %12ld pages (avg %d/1000)\n",
+		   ioc->usg_calls, ioc->usg_pages, (int) ((ioc->usg_pages * 1000)/ioc->usg_calls));
+
+	return 0;
 }
 
+static struct seq_operations ioc_seq_ops = {
+	.start = ioc_start,
+	.next  = ioc_next,
+	.stop  = ioc_stop,
+	.show  = ioc_show
+};
+
 static int
-sba_resource_map(char *buf, char **start, off_t offset, int len)
+ioc_open(struct inode *inode, struct file *file)
 {
-	struct ioc *ioc = sba_list->ioc;	/* FIXME: Multi-IOC support! */
-	unsigned int *res_ptr;
-	int i;
+	return seq_open(file, &ioc_seq_ops);
+}
 
-	if (!ioc)
-		return 0;
+static struct file_operations ioc_fops = {
+	.open    = ioc_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release
+};
 
-	res_ptr = (unsigned int *)ioc->res_map;
-	buf[0] = '\0';
-	for(i = 0; i < (ioc->res_size / sizeof(unsigned int)); ++i, ++res_ptr) {
-		if ((i & 7) == 0)
-		    strcat(buf,"\n   ");
-		sprintf(buf, "%s %08x", buf, *res_ptr);
-	}
-	strcat(buf, "\n");
+static int
+ioc_map_show(struct seq_file *s, void *v)
+{
+	struct ioc *ioc = v;
+	unsigned int i, *res_ptr = (unsigned int *)ioc->res_map;
 
-	return strlen(buf);
+	for (i = 0; i < ioc->res_size / sizeof(unsigned int); ++i, ++res_ptr)
+		seq_printf(s, "%s%08x", (i & 7) ? " " : "\n   ", *res_ptr);
+	seq_printf(s, "\n");
+
+	return 0;
 }
-#endif
 
-/*
-** Determine if sba should claim this chip (return 0) or not (return 1).
-** If so, initialize the chip and tell other partners in crime they
-** have work to do.
-*/
-void __init sba_init(void)
+static struct seq_operations ioc_map_ops = {
+	.start = ioc_start,
+	.next  = ioc_next,
+	.stop  = ioc_stop,
+	.show  = ioc_map_show
+};
+
+static int
+ioc_map_open(struct inode *inode, struct file *file)
 {
-	struct sba_device *sba_dev;
-	u32 func_id, hw_rev;
-	u32 *func_offset = NULL;
-	int i, agp_found = 0;
-	static char sba_rev[6];
-	struct pci_dev *device = NULL;
-	u64 hpa = 0;
+	return seq_open(file, &ioc_map_ops);
+}
 
-	if (!(device = pci_find_device(PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_ZX1_SBA, NULL)))
-		return;
+static struct file_operations ioc_map_fops = {
+	.open    = ioc_map_open,
+	.read    = seq_read,
+	.llseek  = seq_lseek,
+	.release = seq_release
+};
 
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		if (pci_resource_flags(device, i) == IORESOURCE_MEM) {
-			hpa = (u64) ioremap(pci_resource_start(device, i),
-					    pci_resource_len(device, i));
-			break;
-		}
+static void __init
+ioc_proc_init(void)
+{
+	if (ioc_list) {
+		struct proc_dir_entry *dir, *entry;
+
+		dir = proc_mkdir("bus/mckinley", 0);
+		entry = create_proc_entry(ioc_list->name, 0, dir);
+		if (entry)
+			entry->proc_fops = &ioc_fops;
+
+		entry = create_proc_entry("bitmap", 0, dir);
+		if (entry)
+			entry->proc_fops = &ioc_map_fops;
 	}
+}
+#endif
 
-	func_id = READ_REG(hpa + SBA_FUNC_ID);
-	if (func_id != ZX1_FUNC_ID_VALUE)
-		return;
+void
+sba_connect_bus(struct pci_bus *bus)
+{
+	acpi_handle handle, parent;
+	acpi_status status;
+	struct ioc *ioc;
 
-	strcpy(sba_rev, "zx1");
-	func_offset = zx1_func_offsets;
+	if (!PCI_CONTROLLER(bus))
+		panic(PFX "no sysdata on bus %d!\n",bus->number);
 
-	/* Read HW Rev First */
-	hw_rev = READ_REG(hpa + SBA_FCLASS) & 0xFFUL;
+	if (PCI_CONTROLLER(bus)->iommu)
+		return;
+
+	handle = PCI_CONTROLLER(bus)->acpi_handle;
+	if (!handle)
+		return;
 
 	/*
-	 * Not all revision registers of the chipset are updated on every
-	 * turn.  Must scan through all functions looking for the highest rev
+	 * The IOC scope encloses PCI root bridges in the ACPI
+	 * namespace, so work our way out until we find an IOC we
+	 * claimed previously.
 	 */
-	if (func_offset) {
-		for (i = 0 ; func_offset[i] != -1 ; i++) {
-			u32 func_rev;
-
-			func_rev = READ_REG(hpa + SBA_FCLASS + func_offset[i]) & 0xFFUL;
-			DBG_INIT("%s() func offset: 0x%x rev: 0x%x\n",
-			         __FUNCTION__, func_offset[i], func_rev);
-			if (func_rev > hw_rev)
-				hw_rev = func_rev;
-		}
-	}
-
-	printk(KERN_INFO "%s found %s %d.%d at %s, HPA 0x%lx\n", DRIVER_NAME,
-	       sba_rev, ((hw_rev >> 4) & 0xF), (hw_rev & 0xF),
-	       device->slot_name, hpa);
+	do {
+		for (ioc = ioc_list; ioc; ioc = ioc->next)
+			if (ioc->handle == handle) {
+				PCI_CONTROLLER(bus)->iommu = ioc;
+				return;
+			}
 
-	if ((hw_rev & 0xFF) < 0x20) {
-		printk(KERN_INFO "%s: SBA rev less than 2.0 not supported", DRIVER_NAME);
-		return;
-	}
+		status = acpi_get_parent(handle, &parent);
+		handle = parent;
+	} while (ACPI_SUCCESS(status));
 
-	sba_dev = kmalloc(sizeof(struct sba_device), GFP_KERNEL);
-	if (NULL == sba_dev) {
-		printk(KERN_ERR DRIVER_NAME " - couldn't alloc sba_device\n");
-		return;
-	}
+	printk(KERN_WARNING "No IOC for PCI Bus %02x:%02x in ACPI\n", PCI_SEGMENT(bus), bus->number);
+}
 
-	memset(sba_dev, 0, sizeof(struct sba_device));
+static int __init
+acpi_sba_ioc_add(struct acpi_device *device)
+{
+	struct ioc *ioc;
+	acpi_status status;
+	u64 hpa, length;
+	struct acpi_device_info dev_info;
 
-	for(i=0; i<MAX_IOC; i++)
-		spin_lock_init(&(sba_dev->ioc[i].res_lock));
+	status = hp_acpi_csr_space(device->handle, &hpa, &length);
+	if (ACPI_FAILURE(status))
+		return 1;
 
-	sba_dev->hw_rev = hw_rev;
-	sba_dev->sba_hpa = hpa;
+	status = acpi_get_object_info(device->handle, &dev_info);
+	if (ACPI_FAILURE(status))
+		return 1;
 
 	/*
-	 * We pass this fake device from alloc_consistent to ensure
-	 * we only use SAC for alloc_consistent mappings.
+	 * For HWP0001, only SBA appears in ACPI namespace.  It encloses the PCI
+	 * root bridges, and its CSR space includes the IOC function.
 	 */
-	sac_only_dev.dma_mask = 0xFFFFFFFFUL;
+	if (strncmp("HWP0001", dev_info.hardware_id, 7) == 0)
+		hpa += ZX1_IOC_OFFSET;
 
-	/*
-	 * We need to check for an AGP device, if we find one, then only
-	 * use part of the IOVA space for PCI DMA, the rest is for GART.
-	 * REVISIT for multiple IOC.
-	 */
-	pci_for_each_dev(device)
-		agp_found |= pci_find_capability(device, PCI_CAP_ID_AGP);
+	ioc = ioc_init(hpa, device->handle);
+	if (!ioc)
+		return 1;
 
-	if (agp_found && reserve_sba_gart)
-		SBA_SET_AGP(sba_dev);
+	return 0;
+}
 
-	sba_hw_init(sba_dev);
-	sba_common_init(sba_dev);
+static struct acpi_driver acpi_sba_ioc_driver = {
+	name:		"IOC IOMMU Driver",
+	ids:		"HWP0001,HWP0004",
+	ops: {
+		add:	acpi_sba_ioc_add,
+	},
+};
 
-#ifdef CONFIG_PROC_FS
-	{
-		struct proc_dir_entry * proc_mckinley_root;
+static int __init
+sba_init(void)
+{
+	MAX_DMA_ADDRESS = ~0UL;
+
+	acpi_bus_register_driver(&acpi_sba_ioc_driver);
 
-		proc_mckinley_root = proc_mkdir("bus/mckinley",0);
-		create_proc_info_entry(sba_rev, 0, proc_mckinley_root, sba_proc_info);
-		create_proc_info_entry("bitmap", 0, proc_mckinley_root, sba_resource_map);
+#ifdef CONFIG_PCI
+	{
+		struct pci_bus *b;
+		pci_for_each_bus(b)
+			sba_connect_bus(b);
 	}
 #endif
+
+#ifdef CONFIG_PROC_FS
+	ioc_proc_init();
+#endif
+	return 0;
 }
 
+subsys_initcall(sba_init); /* must be initialized after ACPI etc., but before any drivers... */
+
 static int __init
-nosbagart (char *str)
+nosbagart(char *str)
 {
 	reserve_sba_gart = 0;
 	return 1;
 }
 
-__setup("nosbagart",nosbagart);
+int
+sba_dma_supported (struct device *dev, u64 mask)
+{
+	/* make sure it's at least 32bit capable */
+	return ((mask & 0xFFFFFFFFUL) == 0xFFFFFFFFUL);
+}
+
+__setup("nosbagart", nosbagart);
 
-EXPORT_SYMBOL(sba_init);
 EXPORT_SYMBOL(sba_map_single);
 EXPORT_SYMBOL(sba_unmap_single);
 EXPORT_SYMBOL(sba_map_sg);
 EXPORT_SYMBOL(sba_unmap_sg);
-EXPORT_SYMBOL(sba_dma_address);
 EXPORT_SYMBOL(sba_dma_supported);
-EXPORT_SYMBOL(sba_alloc_consistent);
-EXPORT_SYMBOL(sba_free_consistent);
+EXPORT_SYMBOL(sba_alloc_coherent);
+EXPORT_SYMBOL(sba_free_coherent);
diff -Nru a/arch/ia64/hp/sim/hpsim_console.c b/arch/ia64/hp/sim/hpsim_console.c
--- a/arch/ia64/hp/sim/hpsim_console.c	Thu Apr 24 03:30:40 2003
+++ b/arch/ia64/hp/sim/hpsim_console.c	Sat May 10 02:28:45 2003
@@ -59,7 +59,7 @@
 
 static struct tty_driver *simcons_console_device (struct console *c, int *index)
 {
-	extern struct tty_driver hp_serial_driver;
+	extern struct tty_driver hp_simserial_driver;
 	*index = c->index;
-	return &hp_serial_driver;
+	return &hp_simserial_driver;
 }
diff -Nru a/arch/ia64/hp/sim/hpsim_machvec.c b/arch/ia64/hp/sim/hpsim_machvec.c
--- a/arch/ia64/hp/sim/hpsim_machvec.c	Fri Apr  5 17:30:10 2002
+++ b/arch/ia64/hp/sim/hpsim_machvec.c	Sat May 10 02:28:45 2003
@@ -1,2 +1,3 @@
-#define MACHVEC_PLATFORM_NAME	hpsim
+#define MACHVEC_PLATFORM_NAME		hpsim
+#define MACHVEC_PLATFORM_HEADER		<asm/machvec_hpsim.h>
 #include <asm/machvec_init.h>
diff -Nru a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c
--- a/arch/ia64/hp/sim/simeth.c	Tue Feb 18 10:31:36 2003
+++ b/arch/ia64/hp/sim/simeth.c	Sat May 10 02:28:45 2003
@@ -55,7 +55,7 @@
 static int simeth_tx(struct sk_buff *skb, struct net_device *dev);
 static int simeth_rx(struct net_device *dev);
 static struct net_device_stats *simeth_get_stats(struct net_device *dev);
-static void simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs);
 static void set_multicast_list(struct net_device *dev);
 static int simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr);
 
@@ -494,20 +494,21 @@
 /*
  * Interrupt handler (Yes, we can do it too !!!)
  */
-static void
+static irqreturn_t
 simeth_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct net_device *dev = dev_id;
 
 	if ( dev == NULL ) {
 		printk(KERN_WARNING "simeth: irq %d for unknown device\n", irq);
-		return;
+		return IRQ_NONE;
 	}
 
 	/*
-	 * very simple loop because we get interrupts only when receving
+	 * very simple loop because we get interrupts only when receiving
 	 */
 	while (simeth_rx(dev));
+	return IRQ_HANDLED;
 }
 
 static struct net_device_stats *
diff -Nru a/arch/ia64/hp/sim/simscsi.c b/arch/ia64/hp/sim/simscsi.c
--- a/arch/ia64/hp/sim/simscsi.c	Wed Feb 12 00:11:32 2003
+++ b/arch/ia64/hp/sim/simscsi.c	Sun May  4 02:56:42 2003
@@ -386,6 +386,19 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = SIMSCSI;
-
+static Scsi_Host_Template driver_template = {
+	.name			= "simscsi",
+	.detect			= simscsi_detect,
+	.release		= simscsi_release,
+	.info			= simscsi_info,	
+	.queuecommand		= simscsi_queuecommand,
+	.eh_host_reset_handler	= simscsi_host_reset,
+	.bios_param		= simscsi_biosparam,
+	.can_queue		= SIMSCSI_REQ_QUEUE_LEN,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.max_sectors		= 1024,
+	.cmd_per_lun		= SIMSCSI_REQ_QUEUE_LEN,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
 #include "../drivers/scsi/scsi_module.c"
diff -Nru a/arch/ia64/hp/sim/simscsi.h b/arch/ia64/hp/sim/simscsi.h
--- a/arch/ia64/hp/sim/simscsi.h	Wed Dec  4 23:53:05 2002
+++ b/arch/ia64/hp/sim/simscsi.h	Sun May  4 02:56:42 2003
@@ -20,22 +20,4 @@
 extern int simscsi_biosparam (struct scsi_device *, struct block_device *,
 		sector_t, int[]);
 
-#define SIMSCSI {						\
-	.name			= "simscsi",			\
-	.detect			= simscsi_detect,		\
-	.release		= simscsi_release,		\
-	.info			= simscsi_info,			\
-	.queuecommand		= simscsi_queuecommand,		\
-	.eh_host_reset_handler	= simscsi_host_reset,		\
-	.bios_param		= simscsi_biosparam,		\
-	.can_queue		= SIMSCSI_REQ_QUEUE_LEN,	\
-	.this_id		= -1,				\
-	.sg_tablesize		= SG_ALL,			\
-	.max_sectors		= 1024,				\
-	.cmd_per_lun		= SIMSCSI_REQ_QUEUE_LEN,	\
-	.present		= 0,				\
-	.unchecked_isa_dma	= 0,				\
-	.use_clustering		= DISABLE_CLUSTERING		\
-}
-
 #endif /* SIMSCSI_H */
diff -Nru a/arch/ia64/hp/sim/simserial.c b/arch/ia64/hp/sim/simserial.c
--- a/arch/ia64/hp/sim/simserial.c	Thu Apr 24 03:30:40 2003
+++ b/arch/ia64/hp/sim/simserial.c	Sat May 10 02:28:45 2003
@@ -103,7 +103,8 @@
 	{ 0, 0}
 };
 
-static struct tty_driver hp_serial_driver, callout_driver;
+struct tty_driver hp_simserial_driver;
+static struct tty_driver callout_driver;
 static int serial_refcount;
 
 static struct async_struct *IRQ_ports[NR_IRQS];
@@ -184,7 +185,7 @@
 /*
  * This is the serial driver's interrupt routine for a single port
  */
-static void rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t rs_interrupt_single(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct async_struct * info;
 
@@ -195,13 +196,14 @@
 	info = IRQ_ports[irq];
 	if (!info || !info->tty) {
 		printk(KERN_INFO "simrs_interrupt_single: info|tty=0 info=%p problem\n", info);
-		return;
+		return IRQ_NONE;
 	}
 	/*
 	 * pretty simple in our case, because we only get interrupts
 	 * on inbound traffic
 	 */
 	receive_chars(info->tty, regs);
+	return IRQ_HANDLED;
 }
 
 /*
@@ -768,7 +770,7 @@
 {
 	unsigned long flags;
 	int	retval=0;
-	void (*handler)(int, void *, struct pt_regs *);
+	irqreturn_t (*handler)(int, void *, struct pt_regs *);
 	struct serial_state *state= info->state;
 	unsigned long page;
 
@@ -808,8 +810,7 @@
 		} else
 			handler = rs_interrupt_single;
 
-		retval = request_irq(state->irq, handler, IRQ_T(info),
-				     "simserial", NULL);
+		retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL);
 		if (retval) {
 			if (capable(CAP_SYS_ADMIN)) {
 				if (info->tty)
@@ -1028,43 +1029,43 @@
 
 	/* Initialize the tty_driver structure */
 
-	memset(&hp_serial_driver, 0, sizeof(struct tty_driver));
-	hp_serial_driver.magic = TTY_DRIVER_MAGIC;
-	hp_serial_driver.driver_name = "simserial";
-	hp_serial_driver.name = "ttyS";
-	hp_serial_driver.major = TTY_MAJOR;
-	hp_serial_driver.minor_start = 64;
-	hp_serial_driver.num = 1;
-	hp_serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
-	hp_serial_driver.subtype = SERIAL_TYPE_NORMAL;
-	hp_serial_driver.init_termios = tty_std_termios;
-	hp_serial_driver.init_termios.c_cflag =
+	memset(&hp_simserial_driver, 0, sizeof(struct tty_driver));
+	hp_simserial_driver.magic = TTY_DRIVER_MAGIC;
+	hp_simserial_driver.driver_name = "simserial";
+	hp_simserial_driver.name = "ttyS";
+	hp_simserial_driver.major = TTY_MAJOR;
+	hp_simserial_driver.minor_start = 64;
+	hp_simserial_driver.num = 1;
+	hp_simserial_driver.type = TTY_DRIVER_TYPE_SERIAL;
+	hp_simserial_driver.subtype = SERIAL_TYPE_NORMAL;
+	hp_simserial_driver.init_termios = tty_std_termios;
+	hp_simserial_driver.init_termios.c_cflag =
 		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	hp_serial_driver.flags = TTY_DRIVER_REAL_RAW;
-	hp_serial_driver.refcount = &serial_refcount;
-	hp_serial_driver.table = serial_table;
-	hp_serial_driver.termios = serial_termios;
-	hp_serial_driver.termios_locked = serial_termios_locked;
-
-	hp_serial_driver.open = rs_open;
-	hp_serial_driver.close = rs_close;
-	hp_serial_driver.write = rs_write;
-	hp_serial_driver.put_char = rs_put_char;
-	hp_serial_driver.flush_chars = rs_flush_chars;
-	hp_serial_driver.write_room = rs_write_room;
-	hp_serial_driver.chars_in_buffer = rs_chars_in_buffer;
-	hp_serial_driver.flush_buffer = rs_flush_buffer;
-	hp_serial_driver.ioctl = rs_ioctl;
-	hp_serial_driver.throttle = rs_throttle;
-	hp_serial_driver.unthrottle = rs_unthrottle;
-	hp_serial_driver.send_xchar = rs_send_xchar;
-	hp_serial_driver.set_termios = rs_set_termios;
-	hp_serial_driver.stop = rs_stop;
-	hp_serial_driver.start = rs_start;
-	hp_serial_driver.hangup = rs_hangup;
-	hp_serial_driver.break_ctl = rs_break;
-	hp_serial_driver.wait_until_sent = rs_wait_until_sent;
-	hp_serial_driver.read_proc = rs_read_proc;
+	hp_simserial_driver.flags = TTY_DRIVER_REAL_RAW;
+	hp_simserial_driver.refcount = &serial_refcount;
+	hp_simserial_driver.table = serial_table;
+	hp_simserial_driver.termios = serial_termios;
+	hp_simserial_driver.termios_locked = serial_termios_locked;
+
+	hp_simserial_driver.open = rs_open;
+	hp_simserial_driver.close = rs_close;
+	hp_simserial_driver.write = rs_write;
+	hp_simserial_driver.put_char = rs_put_char;
+	hp_simserial_driver.flush_chars = rs_flush_chars;
+	hp_simserial_driver.write_room = rs_write_room;
+	hp_simserial_driver.chars_in_buffer = rs_chars_in_buffer;
+	hp_simserial_driver.flush_buffer = rs_flush_buffer;
+	hp_simserial_driver.ioctl = rs_ioctl;
+	hp_simserial_driver.throttle = rs_throttle;
+	hp_simserial_driver.unthrottle = rs_unthrottle;
+	hp_simserial_driver.send_xchar = rs_send_xchar;
+	hp_simserial_driver.set_termios = rs_set_termios;
+	hp_simserial_driver.stop = rs_stop;
+	hp_simserial_driver.start = rs_start;
+	hp_simserial_driver.hangup = rs_hangup;
+	hp_simserial_driver.break_ctl = rs_break;
+	hp_simserial_driver.wait_until_sent = rs_wait_until_sent;
+	hp_simserial_driver.read_proc = rs_read_proc;
 
 	/*
 	 * Let's have a little bit of fun !
@@ -1087,14 +1088,14 @@
 	 * The callout device is just like normal device except for
 	 * major number and the subtype code.
 	 */
-	callout_driver = hp_serial_driver;
+	callout_driver = hp_simserial_driver;
 	callout_driver.name = "cua";
 	callout_driver.major = TTYAUX_MAJOR;
 	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
 	callout_driver.read_proc = 0;
 	callout_driver.proc_entry = 0;
 
-	if (tty_register_driver(&hp_serial_driver))
+	if (tty_register_driver(&hp_simserial_driver))
 		panic("Couldn't register simserial driver\n");
 
 	if (tty_register_driver(&callout_driver))
diff -Nru a/arch/ia64/hp/zx1/Makefile b/arch/ia64/hp/zx1/Makefile
--- a/arch/ia64/hp/zx1/Makefile	Mon Dec 16 15:41:30 2002
+++ b/arch/ia64/hp/zx1/Makefile	Fri Apr 11 18:05:22 2003
@@ -5,5 +5,4 @@
 # Copyright (C) Alex Williamson (alex_williamson@hp.com)
 #
 
-obj-y := hpzx1_misc.o
 obj-$(CONFIG_IA64_GENERIC) += hpzx1_machvec.o
diff -Nru a/arch/ia64/hp/zx1/hpzx1_machvec.c b/arch/ia64/hp/zx1/hpzx1_machvec.c
--- a/arch/ia64/hp/zx1/hpzx1_machvec.c	Thu Jun  6 03:37:14 2002
+++ b/arch/ia64/hp/zx1/hpzx1_machvec.c	Sat May 10 02:28:45 2003
@@ -1,2 +1,3 @@
-#define MACHVEC_PLATFORM_NAME	hpzx1
+#define MACHVEC_PLATFORM_NAME		hpzx1
+#define MACHVEC_PLATFORM_HEADER		<asm/machvec_hpzx1.h>
 #include <asm/machvec_init.h>
diff -Nru a/arch/ia64/hp/zx1/hpzx1_misc.c b/arch/ia64/hp/zx1/hpzx1_misc.c
--- a/arch/ia64/hp/zx1/hpzx1_misc.c	Fri Jan 24 11:56:49 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,348 +0,0 @@
-/*
- * Misc. support for HP zx1 chipset support
- *
- * Copyright (C) 2002-2003 Hewlett-Packard Co
- *	Alex Williamson <alex_williamson@hp.com>
- *	Bjorn Helgaas <bjorn_helgaas@hp.com>
- */
-
-
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/acpi.h>
-#include <linux/efi.h>
-
-#include <asm/dma.h>
-#include <asm/iosapic.h>
-
-extern acpi_status acpi_evaluate_integer (acpi_handle, acpi_string, struct acpi_object_list *,
-					  unsigned long *);
-
-#define PFX "hpzx1: "
-
-static int hpzx1_devices;
-
-struct fake_pci_dev {
-	struct fake_pci_dev *next;
-	struct pci_dev *pci_dev;
-	unsigned long csr_base;
-	unsigned long csr_size;
-	unsigned long mapped_csrs;	// ioremapped
-	int sizing;			// in middle of BAR sizing operation?
-} *fake_pci_dev_list;
-
-static struct pci_ops *orig_pci_ops;
-
-struct fake_pci_dev *
-lookup_fake_dev (struct pci_bus *bus, unsigned int devfn)
-{
-	struct fake_pci_dev *fake_dev;
-
-	for (fake_dev = fake_pci_dev_list; fake_dev; fake_dev = fake_dev->next)
-		if (fake_dev->pci_dev->bus == bus && fake_dev->pci_dev->devfn == devfn)
-			return fake_dev;
-	return NULL;
-}
-
-static int
-hp_cfg_read (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value)
-{
-	struct fake_pci_dev *fake_dev = lookup_fake_dev(bus, devfn);
-
-	if (!fake_dev)
-		return (*orig_pci_ops->read)(bus, devfn, where, size, value);
-
-	if (where == PCI_BASE_ADDRESS_0) {
-		if (fake_dev->sizing)
-			*value = ~(fake_dev->csr_size - 1);
-		else
-			*value = ((fake_dev->csr_base & PCI_BASE_ADDRESS_MEM_MASK)
-				  | PCI_BASE_ADDRESS_SPACE_MEMORY);
-		fake_dev->sizing = 0;
-		return PCIBIOS_SUCCESSFUL;
-	}
-	switch (size) {
-	      case 1: *value = readb(fake_dev->mapped_csrs + where); break;
-	      case 2: *value = readw(fake_dev->mapped_csrs + where); break;
-	      case 4: *value = readl(fake_dev->mapped_csrs + where); break;
-	      default:
-		printk(KERN_WARNING"hp_cfg_read: bad size = %d bytes", size);
-		break;
-	}
-	if (where == PCI_COMMAND)
-		*value |= PCI_COMMAND_MEMORY; /* SBA omits this */
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-hp_cfg_write (struct pci_bus *bus, unsigned int devfn, int where, int size, u32 value)
-{
-	struct fake_pci_dev *fake_dev = lookup_fake_dev(bus, devfn);
-
-	if (!fake_dev)
-		return (*orig_pci_ops->write)(bus, devfn, where, size, value);
-
-	if (where == PCI_BASE_ADDRESS_0) {
-		if (value == ((1UL << 8*size) - 1))
-			fake_dev->sizing = 1;
-		return PCIBIOS_SUCCESSFUL;
-	}
-	switch (size) {
-	      case 1: writeb(value, fake_dev->mapped_csrs + where); break;
-	      case 2: writew(value, fake_dev->mapped_csrs + where); break;
-	      case 4: writel(value, fake_dev->mapped_csrs + where); break;
-	      default:
-		printk(KERN_WARNING"hp_cfg_write: bad size = %d bytes", size);
-		break;
-	}
-	return PCIBIOS_SUCCESSFUL;
-}
-
-static struct pci_ops hp_pci_conf = {
-	.read =		hp_cfg_read,
-	.write =	hp_cfg_write
-};
-
-static void
-hpzx1_fake_pci_dev(char *name, unsigned int busnum, unsigned long addr, unsigned int size)
-{
-	struct fake_pci_dev *fake;
-	int slot, ret;
-	struct pci_dev *dev;
-	struct pci_bus *b, *bus = NULL;
-	u8 hdr;
-
-        fake = kmalloc(sizeof(*fake), GFP_KERNEL);
-	if (!fake) {
-		printk(KERN_ERR PFX "No memory for %s (0x%p) sysdata\n", name, (void *) addr);
-		return;
-	}
-
-	memset(fake, 0, sizeof(*fake));
-	fake->csr_base = addr;
-	fake->csr_size = size;
-	fake->mapped_csrs = (unsigned long) ioremap(addr, size);
-	fake->sizing = 0;
-
-	pci_for_each_bus(b)
-		if (busnum == b->number) {
-			bus = b;
-			break;
-		}
-
-	if (!bus) {
-		printk(KERN_ERR PFX "No host bus 0x%02x for %s (0x%p)\n",
-		       busnum, name, (void *) addr);
-		kfree(fake);
-		return;
-	}
-
-	for (slot = 0x1e; slot; slot--)
-		if (!pci_find_slot(busnum, PCI_DEVFN(slot, 0)))
-			break;
-
-	if (slot < 0) {
-		printk(KERN_ERR PFX "No space for %s (0x%p) on bus 0x%02x\n",
-		       name, (void *) addr, busnum);
-		kfree(fake);
-		return;
-	}
-
-        dev = kmalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		printk(KERN_ERR PFX "No memory for %s (0x%p)\n", name, (void *) addr);
-		kfree(fake);
-		return;
-	}
-
-	bus->ops = &hp_pci_conf;	// replace pci ops for this bus
-
-	fake->pci_dev = dev;
-	fake->next = fake_pci_dev_list;
-	fake_pci_dev_list = fake;
-
-	memset(dev, 0, sizeof(*dev));
-	dev->bus = bus;
-	dev->sysdata = fake;
-	dev->dev.parent = bus->dev;
-	dev->dev.bus = &pci_bus_type;
-	dev->devfn = PCI_DEVFN(slot, 0);
-	pci_read_config_word(dev, PCI_VENDOR_ID, &dev->vendor);
-	pci_read_config_word(dev, PCI_DEVICE_ID, &dev->device);
-	pci_read_config_byte(dev, PCI_HEADER_TYPE, &hdr);
-	dev->hdr_type = hdr & 0x7f;
-
-	pci_setup_device(dev);
-
-	// pci_insert_device() without running /sbin/hotplug
-	list_add_tail(&dev->bus_list, &bus->devices);
-	list_add_tail(&dev->global_list, &pci_devices);
-
-	strcpy(dev->dev.bus_id, dev->slot_name);
-	ret = device_register(&dev->dev);
-	if (ret < 0)
-		printk(KERN_INFO PFX "fake device registration failed (%d)\n", ret);
-
-	printk(KERN_INFO PFX "%s at 0x%lx; pci dev %s\n", name, addr, dev->slot_name);
-
-	hpzx1_devices++;
-}
-
-struct acpi_hp_vendor_long {
-	u8	guid_id;
-	u8	guid[16];
-	u8	csr_base[8];
-	u8	csr_length[8];
-};
-
-#define HP_CCSR_LENGTH	0x21
-#define HP_CCSR_TYPE	0x2
-#define HP_CCSR_GUID	EFI_GUID(0x69e9adf9, 0x924f, 0xab5f,				\
-				 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad)
-
-extern acpi_status acpi_get_crs(acpi_handle, struct acpi_buffer *);
-extern struct acpi_resource *acpi_get_crs_next(struct acpi_buffer *, int *);
-extern union acpi_resource_data *acpi_get_crs_type(struct acpi_buffer *, int *, int);
-extern void acpi_dispose_crs(struct acpi_buffer *);
-
-static acpi_status
-hp_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length)
-{
-	int i, offset = 0;
-	acpi_status status;
-	struct acpi_buffer buf;
-	struct acpi_resource_vendor *res;
-	struct acpi_hp_vendor_long *hp_res;
-	efi_guid_t vendor_guid;
-
-	*csr_base = 0;
-	*csr_length = 0;
-
-	status = acpi_get_crs(obj, &buf);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR PFX "Unable to get _CRS data on object\n");
-		return status;
-	}
-
-	res = (struct acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
-	if (!res) {
-		printk(KERN_ERR PFX "Failed to find config space for device\n");
-		acpi_dispose_crs(&buf);
-		return AE_NOT_FOUND;
-	}
-
-	hp_res = (struct acpi_hp_vendor_long *)(res->reserved);
-
-	if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
-		printk(KERN_ERR PFX "Unknown Vendor data\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
-	}
-
-	memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
-	if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
-		printk(KERN_ERR PFX "Vendor GUID does not match\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
-	}
-
-	for (i = 0 ; i < 8 ; i++) {
-		*csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
-		*csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
-	}
-
-	acpi_dispose_crs(&buf);
-
-	return AE_OK;
-}
-
-static acpi_status
-hpzx1_sba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
-{
-	u64 csr_base = 0, csr_length = 0;
-	acpi_status status;
-	char *name = context;
-	char fullname[16];
-
-	status = hp_csr_space(obj, &csr_base, &csr_length);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	/*
-	 * Only SBA shows up in ACPI namespace, so its CSR space
-	 * includes both SBA and IOC.  Make SBA and IOC show up
-	 * separately in PCI space.
-	 */
-	sprintf(fullname, "%s SBA", name);
-	hpzx1_fake_pci_dev(fullname, 0, csr_base, 0x1000);
-	sprintf(fullname, "%s IOC", name);
-	hpzx1_fake_pci_dev(fullname, 0, csr_base + 0x1000, 0x1000);
-
-	return AE_OK;
-}
-
-static acpi_status
-hpzx1_lba_probe(acpi_handle obj, u32 depth, void *context, void **ret)
-{
-	u64 csr_base = 0, csr_length = 0;
-	acpi_status status;
-	acpi_native_uint busnum;
-	char *name = context;
-	char fullname[32];
-
-	status = hp_csr_space(obj, &csr_base, &csr_length);
-	if (ACPI_FAILURE(status))
-		return status;
-
-	status = acpi_evaluate_integer(obj, METHOD_NAME__BBN, NULL, &busnum);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_WARNING PFX "evaluate _BBN fail=0x%x\n", status);
-		busnum = 0;	// no _BBN; stick it on bus 0
-	}
-
-	sprintf(fullname, "%s _BBN 0x%02x", name, (unsigned int) busnum);
-	hpzx1_fake_pci_dev(fullname, busnum, csr_base, csr_length);
-
-	return AE_OK;
-}
-
-static void
-hpzx1_acpi_dev_init(void)
-{
-	extern struct pci_ops *pci_root_ops;
-
-	orig_pci_ops = pci_root_ops;
-
-	/*
-	 * Make fake PCI devices for the following hardware in the
-	 * ACPI namespace.  This makes it more convenient for drivers
-	 * because they can claim these devices based on PCI
-	 * information, rather than needing to know about ACPI.  The
-	 * 64-bit "HPA" space for this hardware is available as BAR
-	 * 0/1.
-	 *
-	 * HWP0001: Single IOC SBA w/o IOC in namespace
-	 * HWP0002: LBA device
-	 * HWP0003: AGP LBA device
-	 */
-	acpi_get_devices("HWP0001", hpzx1_sba_probe, "HWP0001", NULL);
-	acpi_get_devices("HWP0002", hpzx1_lba_probe, "HWP0002 PCI LBA", NULL);
-	acpi_get_devices("HWP0003", hpzx1_lba_probe, "HWP0003 AGP LBA", NULL);
-}
-
-extern void sba_init(void);
-
-static int
-hpzx1_init (void)
-{
-	/* zx1 has a hardware I/O TLB which lets us DMA from any device to any address */
-	MAX_DMA_ADDRESS = ~0UL;
-
-	hpzx1_acpi_dev_init();
-	sba_init();
-	return 0;
-}
-
-subsys_initcall(hpzx1_init);
diff -Nru a/arch/ia64/ia32/binfmt_elf32.c b/arch/ia64/ia32/binfmt_elf32.c
--- a/arch/ia64/ia32/binfmt_elf32.c	Fri Jan 24 19:45:37 2003
+++ b/arch/ia64/ia32/binfmt_elf32.c	Wed May 14 23:43:46 2003
@@ -12,6 +12,7 @@
 #include <linux/config.h>
 
 #include <linux/types.h>
+#include <linux/mm.h>
 
 #include <asm/param.h>
 #include <asm/signal.h>
@@ -40,7 +41,6 @@
 #define CLOCKS_PER_SEC	IA32_CLOCKS_PER_SEC
 
 extern void ia64_elf32_init (struct pt_regs *regs);
-extern void put_dirty_page (struct task_struct * tsk, struct page *page, unsigned long address);
 
 static void elf32_set_personality (void);
 
@@ -200,7 +200,7 @@
 		struct page *page = bprm->page[i];
 		if (page) {
 			bprm->page[i] = NULL;
-			put_dirty_page(current, page, stack_base);
+			put_dirty_page(current, page, stack_base, PAGE_COPY);
 		}
 		stack_base += PAGE_SIZE;
 	}
diff -Nru a/arch/ia64/ia32/ia32_entry.S b/arch/ia64/ia32/ia32_entry.S
--- a/arch/ia64/ia32/ia32_entry.S	Wed Apr 30 08:47:35 2003
+++ b/arch/ia64/ia32/ia32_entry.S	Tue May  6 13:42:08 2003
@@ -273,9 +273,9 @@
 	data8 sys32_sigsuspend
 	data8 compat_sys_sigpending
 	data8 sys_sethostname
-	data8 sys32_setrlimit	  /* 75 */
-	data8 sys32_old_getrlimit
-	data8 sys32_getrusage
+	data8 compat_sys_setrlimit	  /* 75 */
+	data8 compat_sys_old_getrlimit
+	data8 compat_sys_getrusage
 	data8 sys32_gettimeofday
 	data8 sys32_settimeofday
 	data8 sys32_getgroups16	  /* 80 */
@@ -312,7 +312,7 @@
 	data8 sys_vhangup
 	data8 sys32_ni_syscall		/* used to be sys_idle */
 	data8 sys32_ni_syscall
-	data8 sys32_wait4
+	data8 compat_sys_wait4
 	data8 sys_swapoff	  /* 115 */
 	data8 sys32_sysinfo
 	data8 sys32_ipc
@@ -389,7 +389,7 @@
 	data8 sys32_ni_syscall		  /* streams1 */
 	data8 sys32_ni_syscall		  /* streams2 */
 	data8 sys32_vfork	  /* 190 */
-	data8 sys32_getrlimit
+	data8 compat_sys_getrlimit
 	data8 sys32_mmap2
 	data8 sys32_truncate64
 	data8 sys32_ftruncate64
diff -Nru a/arch/ia64/ia32/ia32_ioctl.c b/arch/ia64/ia32/ia32_ioctl.c
--- a/arch/ia64/ia32/ia32_ioctl.c	Wed Apr 30 08:47:35 2003
+++ b/arch/ia64/ia32/ia32_ioctl.c	Sat May 10 02:28:45 2003
@@ -3,13 +3,16 @@
  *
  * Copyright (C) 2000 VA Linux Co
  * Copyright (C) 2000 Don Dugger <n0ano@valinux.com>
- * Copyright (C) 2001-2002 Hewlett-Packard Co
+ * Copyright (C) 2001-2003 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
 #include <linux/types.h>
 #include <linux/dirent.h>
 #include <linux/fs.h>		/* argh, msdos_fs.h isn't self-contained... */
+#include <linux/signal.h>	/* argh, msdos_fs.h isn't self-contained... */
+
+#include <asm/ia32.h>
 
 #include <linux/msdos_fs.h>
 #include <linux/mtio.h>
@@ -32,8 +35,6 @@
 #include <scsi/scsi_ioctl.h>
 #define	__KERNEL__
 #include <scsi/sg.h>
-
-#include <asm/ia32.h>
 
 #include <../drivers/char/drm/drm.h>
 #include <../drivers/char/drm/mga_drm.h>
diff -Nru a/arch/ia64/ia32/ia32_traps.c b/arch/ia64/ia32/ia32_traps.c
--- a/arch/ia64/ia32/ia32_traps.c	Fri Mar 15 04:03:00 2002
+++ b/arch/ia64/ia32/ia32_traps.c	Tue Apr 22 19:45:53 2003
@@ -103,7 +103,7 @@
 			 * C1 reg you need in case of a stack fault, 0x040 is the stack
 			 * fault bit.  We should only be taking one exception at a time,
 			 * so if this combination doesn't produce any single exception,
-			 * then we have a bad program that isn't syncronizing its FPU usage
+			 * then we have a bad program that isn't synchronizing its FPU usage
 			 * and it will suffer the consequences since we won't be able to
 			 * fully reproduce the context of the exception
 			 */
diff -Nru a/arch/ia64/ia32/sys_ia32.c b/arch/ia64/ia32/sys_ia32.c
--- a/arch/ia64/ia32/sys_ia32.c	Sat Apr 19 23:22:56 2003
+++ b/arch/ia64/ia32/sys_ia32.c	Sat May 10 02:28:45 2003
@@ -53,10 +53,10 @@
 #include <asm/types.h>
 #include <asm/uaccess.h>
 #include <asm/semaphore.h>
+#include <asm/ia32.h>
 
 #include <net/scm.h>
 #include <net/sock.h>
-#include <asm/ia32.h>
 
 #define DEBUG	0
 
@@ -177,7 +177,7 @@
 {
 	int err;
 
-	if (stat->size > MAX_NON_LFS)
+	if ((u64) stat->size > MAX_NON_LFS)
 		return -EOVERFLOW;
 
 	if (clear_user(ubuf, sizeof(*ubuf)))
@@ -243,8 +243,7 @@
 		return -ENOMEM;
 
 	if (old_prot)
-		if (copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE))
-			return -EFAULT;
+		copy_from_user(page, (void *) PAGE_START(start), PAGE_SIZE);
 
 	down_write(&current->mm->mmap_sem);
 	{
@@ -837,8 +836,9 @@
 		}
 	}
 
+	size = FDS_BYTES(n);
 	ret = -EINVAL;
-	if (n < 0)
+	if (n < 0 || size < n)
 		goto out_nofds;
 
 	if (n > current->files->max_fdset)
@@ -850,7 +850,6 @@
 	 * long-words.
 	 */
 	ret = -ENOMEM;
-	size = FDS_BYTES(n);
 	bits = kmalloc(6 * size, GFP_KERNEL);
 	if (!bits)
 		goto out_nofds;
@@ -928,8 +927,7 @@
 static struct iovec *
 get_compat_iovec (struct compat_iovec *iov32, struct iovec *iov_buf, u32 count, int type)
 {
-	int i;
-	u32 buf, len;
+	u32 i, buf, len;
 	struct iovec *ivp, *iov;
 
 	/* Get the "struct iovec" from user memory */
@@ -1005,77 +1003,6 @@
 	return ret;
 }
 
-#define RLIM_INFINITY32	0x7fffffff
-#define RESOURCE32(x) ((x > RLIM_INFINITY32) ? RLIM_INFINITY32 : x)
-
-struct rlimit32 {
-	int	rlim_cur;
-	int	rlim_max;
-};
-
-extern asmlinkage long sys_getrlimit (unsigned int resource, struct rlimit *rlim);
-
-asmlinkage long
-sys32_old_getrlimit (unsigned int resource, struct rlimit32 *rlim)
-{
-	mm_segment_t old_fs = get_fs();
-	struct rlimit r;
-	int ret;
-
-	set_fs(KERNEL_DS);
-	ret = sys_getrlimit(resource, &r);
-	set_fs(old_fs);
-	if (!ret) {
-		ret = put_user(RESOURCE32(r.rlim_cur), &rlim->rlim_cur);
-		ret |= put_user(RESOURCE32(r.rlim_max), &rlim->rlim_max);
-	}
-	return ret;
-}
-
-asmlinkage long
-sys32_getrlimit (unsigned int resource, struct rlimit32 *rlim)
-{
-	mm_segment_t old_fs = get_fs();
-	struct rlimit r;
-	int ret;
-
-	set_fs(KERNEL_DS);
-	ret = sys_getrlimit(resource, &r);
-	set_fs(old_fs);
-	if (!ret) {
-		if (r.rlim_cur >= 0xffffffff)
-			r.rlim_cur = 0xffffffff;
-		if (r.rlim_max >= 0xffffffff)
-			r.rlim_max = 0xffffffff;
-		ret = put_user(r.rlim_cur, &rlim->rlim_cur);
-		ret |= put_user(r.rlim_max, &rlim->rlim_max);
-	}
-	return ret;
-}
-
-extern asmlinkage long sys_setrlimit (unsigned int resource, struct rlimit *rlim);
-
-asmlinkage long
-sys32_setrlimit (unsigned int resource, struct rlimit32 *rlim)
-{
-	struct rlimit r;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	if (resource >= RLIM_NLIMITS)
-		return -EINVAL;
-	if (get_user(r.rlim_cur, &rlim->rlim_cur) || get_user(r.rlim_max, &rlim->rlim_max))
-		return -EFAULT;
-	if (r.rlim_cur == RLIM_INFINITY32)
-		r.rlim_cur = RLIM_INFINITY;
-	if (r.rlim_max == RLIM_INFINITY32)
-		r.rlim_max = RLIM_INFINITY;
-	set_fs(KERNEL_DS);
-	ret = sys_setrlimit(resource, &r);
-	set_fs(old_fs);
-	return ret;
-}
-
 /*
  * sys32_ipc() is the de-multiplexer for the SysV IPC calls in 32bit emulation..
  *
@@ -1648,19 +1575,35 @@
 	return err;
 }
 
+extern int sem_ctls[];
+#define sc_semopm	(sem_ctls[2])
+
 static long
-semtimedop32(int semid, struct sembuf *tsems, int nsems,
-	     const struct compat_timespec *timeout32)
+semtimedop32(int semid, struct sembuf *tsops, int nsops,
+	     struct compat_timespec *timeout32)
 {
 	struct timespec t;
-	if (get_user (t.tv_sec, &timeout32->tv_sec) ||
-	    get_user (t.tv_nsec, &timeout32->tv_nsec))
+	mm_segment_t oldfs;
+	long ret;
+
+	/* parameter checking precedence should mirror sys_semtimedop() */
+	if (nsops < 1 || semid < 0)
+		return -EINVAL;
+	if (nsops > sc_semopm)
+		return -E2BIG;
+	if (!access_ok(VERIFY_READ, tsops, nsops * sizeof(struct sembuf)) ||
+	    get_compat_timespec(&t, timeout32))
 		return -EFAULT;
-	return sys_semtimedop(semid, tsems, nsems, &t);
+
+	oldfs = get_fs();
+	set_fs(KERNEL_DS);
+	ret = sys_semtimedop(semid, tsops, nsops, &t);
+	set_fs(oldfs);
+	return ret;
 }
 
 asmlinkage long
-sys32_ipc (u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth)
 {
 	int version;
 
@@ -1668,12 +1611,15 @@
 	call &= 0xffff;
 
 	switch (call) {
+	      case SEMTIMEDOP:
+		if (fifth)
+			return semtimedop32(first, (struct sembuf *)AA(ptr),
+				second, (struct compat_timespec *)AA(fifth));
+		/* else fall through for normal semop() */
 	      case SEMOP:
 		/* struct sembuf is the same on 32 and 64bit :)) */
-		return sys_semtimedop(first, (struct sembuf *)AA(ptr), second, NULL);
-	      case SEMTIMEDOP:
-		return semtimedop32(first, (struct sembuf *)AA(ptr), second,
-				    (const struct compat_timespec *)AA(fifth));
+		return sys_semtimedop(first, (struct sembuf *)AA(ptr), second,
+				      NULL);
 	      case SEMGET:
 		return sys_semget(first, second, third);
 	      case SEMCTL:
@@ -1724,98 +1670,10 @@
 	return i;
 }
 
-struct rusage32 {
-	struct compat_timeval ru_utime;
-	struct compat_timeval ru_stime;
-	int    ru_maxrss;
-	int    ru_ixrss;
-	int    ru_idrss;
-	int    ru_isrss;
-	int    ru_minflt;
-	int    ru_majflt;
-	int    ru_nswap;
-	int    ru_inblock;
-	int    ru_oublock;
-	int    ru_msgsnd;
-	int    ru_msgrcv;
-	int    ru_nsignals;
-	int    ru_nvcsw;
-	int    ru_nivcsw;
-};
-
-static int
-put_rusage (struct rusage32 *ru, struct rusage *r)
-{
-	int err;
-
-	if (!access_ok(VERIFY_WRITE, ru, sizeof(*ru)))
-		return -EFAULT;
-
-	err = __put_user (r->ru_utime.tv_sec, &ru->ru_utime.tv_sec);
-	err |= __put_user (r->ru_utime.tv_usec, &ru->ru_utime.tv_usec);
-	err |= __put_user (r->ru_stime.tv_sec, &ru->ru_stime.tv_sec);
-	err |= __put_user (r->ru_stime.tv_usec, &ru->ru_stime.tv_usec);
-	err |= __put_user (r->ru_maxrss, &ru->ru_maxrss);
-	err |= __put_user (r->ru_ixrss, &ru->ru_ixrss);
-	err |= __put_user (r->ru_idrss, &ru->ru_idrss);
-	err |= __put_user (r->ru_isrss, &ru->ru_isrss);
-	err |= __put_user (r->ru_minflt, &ru->ru_minflt);
-	err |= __put_user (r->ru_majflt, &ru->ru_majflt);
-	err |= __put_user (r->ru_nswap, &ru->ru_nswap);
-	err |= __put_user (r->ru_inblock, &ru->ru_inblock);
-	err |= __put_user (r->ru_oublock, &ru->ru_oublock);
-	err |= __put_user (r->ru_msgsnd, &ru->ru_msgsnd);
-	err |= __put_user (r->ru_msgrcv, &ru->ru_msgrcv);
-	err |= __put_user (r->ru_nsignals, &ru->ru_nsignals);
-	err |= __put_user (r->ru_nvcsw, &ru->ru_nvcsw);
-	err |= __put_user (r->ru_nivcsw, &ru->ru_nivcsw);
-	return err;
-}
-
-asmlinkage long
-sys32_wait4 (int pid, unsigned int *stat_addr, int options, struct rusage32 *ru)
-{
-	if (!ru)
-		return sys_wait4(pid, stat_addr, options, NULL);
-	else {
-		struct rusage r;
-		int ret;
-		unsigned int status;
-		mm_segment_t old_fs = get_fs();
-
-		set_fs(KERNEL_DS);
-		ret = sys_wait4(pid, stat_addr ? &status : NULL, options, &r);
-		set_fs(old_fs);
-		if (put_rusage(ru, &r))
-			return -EFAULT;
-		if (stat_addr && put_user(status, stat_addr))
-			return -EFAULT;
-		return ret;
-	}
-}
-
 asmlinkage long
 sys32_waitpid (int pid, unsigned int *stat_addr, int options)
 {
-	return sys32_wait4(pid, stat_addr, options, NULL);
-}
-
-
-extern asmlinkage long sys_getrusage (int who, struct rusage *ru);
-
-asmlinkage long
-sys32_getrusage (int who, struct rusage32 *ru)
-{
-	struct rusage r;
-	int ret;
-	mm_segment_t old_fs = get_fs();
-
-	set_fs(KERNEL_DS);
-	ret = sys_getrusage(who, &r);
-	set_fs(old_fs);
-	if (put_rusage (ru, &r))
-		return -EFAULT;
-	return ret;
+	return compat_sys_wait4(pid, stat_addr, options, NULL);
 }
 
 static unsigned int
@@ -2211,7 +2069,7 @@
 			ret = -EIO;
 			break;
 		}
-		for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
+		for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) {
 			put_user(getreg(child, i), (unsigned int *) A(data));
 			data += sizeof(int);
 		}
@@ -2223,7 +2081,7 @@
 			ret = -EIO;
 			break;
 		}
-		for (i = 0; i < 17*sizeof(int); i += sizeof(int) ) {
+		for (i = 0; i < (int) (17*sizeof(int)); i += sizeof(int) ) {
 			get_user(tmp, (unsigned int *) A(data));
 			putreg(child, i, tmp);
 			data += sizeof(int);
@@ -2299,7 +2157,7 @@
 		return(-EINVAL);
 	/* Trying to gain more privileges? */
 	asm volatile ("mov %0=ar.eflag ;;" : "=r"(old));
-	if (level > ((old >> 12) & 3)) {
+	if ((unsigned int) level > ((old >> 12) & 3)) {
 		if (!capable(CAP_SYS_RAWIO))
 			return -EPERM;
 	}
diff -Nru a/arch/ia64/kernel/Makefile b/arch/ia64/kernel/Makefile
--- a/arch/ia64/kernel/Makefile	Tue Apr  8 12:03:13 2003
+++ b/arch/ia64/kernel/Makefile	Fri Apr 11 18:05:22 2003
@@ -11,6 +11,8 @@
 obj-$(CONFIG_EFI_VARS)		+= efivars.o
 obj-$(CONFIG_FSYS)		+= fsys.o
 obj-$(CONFIG_IA64_BRL_EMU)	+= brl_emu.o
+obj-$(CONFIG_IA64_GENERIC)	+= acpi-ext.o
+obj-$(CONFIG_IA64_HP_ZX1)	+= acpi-ext.o
 obj-$(CONFIG_IA64_MCA)		+= mca.o mca_asm.o
 obj-$(CONFIG_IA64_PALINFO)	+= palinfo.o
 obj-$(CONFIG_IOSAPIC)		+= iosapic.o
diff -Nru a/arch/ia64/kernel/acpi-ext.c b/arch/ia64/kernel/acpi-ext.c
--- a/arch/ia64/kernel/acpi-ext.c	Thu Apr  3 12:32:33 2003
+++ b/arch/ia64/kernel/acpi-ext.c	Fri Apr 25 11:13:59 2003
@@ -3,69 +3,99 @@
  *
  * Copyright (C) 2003 Hewlett-Packard
  * Copyright (C) Alex Williamson
+ * Copyright (C) Bjorn Helgaas
  *
- * Vendor specific extensions to ACPI.  These are used by both
- * HP and NEC.
+ * Vendor specific extensions to ACPI.
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/acpi.h>
 #include <linux/efi.h>
 
 #include <asm/acpi-ext.h>
 
-/*
- * Note: Strictly speaking, this is only needed for HP and NEC machines.
- *	 However, NEC machines identify themselves as DIG-compliant, so there is
- *	 no easy way to #ifdef this out.
- */
+struct acpi_vendor_descriptor {
+	u8				guid_id;
+	efi_guid_t			guid;
+};
+
+struct acpi_vendor_info {
+	struct acpi_vendor_descriptor	*descriptor;
+	u8				*data;
+	u32				length;
+};
+
 acpi_status
-hp_acpi_csr_space (acpi_handle obj, u64 *csr_base, u64 *csr_length)
+acpi_vendor_resource_match(struct acpi_resource *resource, void *context)
 {
-	int i, offset = 0;
-	acpi_status status;
-	struct acpi_buffer buf;
-	struct acpi_resource_vendor *res;
-	struct acpi_hp_vendor_long *hp_res;
-	efi_guid_t vendor_guid;
-
-	*csr_base = 0;
-	*csr_length = 0;
-
-	status = acpi_get_crs(obj, &buf);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
-		return status;
-	}
-
-	res = (struct acpi_resource_vendor *)acpi_get_crs_type(&buf, &offset, ACPI_RSTYPE_VENDOR);
-	if (!res) {
-		printk(KERN_ERR PREFIX "Failed to find config space for device\n");
-		acpi_dispose_crs(&buf);
+	struct acpi_vendor_info *info = (struct acpi_vendor_info *) context;
+	struct acpi_resource_vendor *vendor;
+	struct acpi_vendor_descriptor *descriptor;
+	u32 length;
+
+	if (resource->id != ACPI_RSTYPE_VENDOR)
+		return AE_OK;
+
+	vendor = (struct acpi_resource_vendor *) &resource->data;
+	descriptor = (struct acpi_vendor_descriptor *) vendor->reserved;
+	if (vendor->length <= sizeof(*info->descriptor) ||
+	    descriptor->guid_id != info->descriptor->guid_id ||
+	    efi_guidcmp(descriptor->guid, info->descriptor->guid))
+		return AE_OK;
+
+	length = vendor->length - sizeof(struct acpi_vendor_descriptor);
+	info->data = acpi_os_allocate(length);
+	if (!info->data)
+		return AE_NO_MEMORY;
+
+	memcpy(info->data, vendor->reserved + sizeof(struct acpi_vendor_descriptor), length);
+	info->length = length;
+	return AE_CTRL_TERMINATE;
+}
+
+acpi_status
+acpi_find_vendor_resource(acpi_handle obj, struct acpi_vendor_descriptor *id,
+		u8 **data, u32 *length)
+{
+	struct acpi_vendor_info info;
+
+	info.descriptor = id;
+	info.data = 0;
+
+	acpi_walk_resources(obj, METHOD_NAME__CRS, acpi_vendor_resource_match, &info);
+	if (!info.data)
 		return AE_NOT_FOUND;
-	}
 
-	hp_res = (struct acpi_hp_vendor_long *)(res->reserved);
+	*data = info.data;
+	*length = info.length;
+	return AE_OK;
+}
+
+struct acpi_vendor_descriptor hp_ccsr_descriptor = {
+	.guid_id = 2,
+	.guid    = EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad)
+};
+
+acpi_status
+hp_acpi_csr_space(acpi_handle obj, u64 *csr_base, u64 *csr_length)
+{
+	acpi_status status;
+	u8 *data;
+	u32 length;
+	int i;
+
+	status = acpi_find_vendor_resource(obj, &hp_ccsr_descriptor, &data, &length);
 
-	if (res->length != HP_CCSR_LENGTH || hp_res->guid_id != HP_CCSR_TYPE) {
-		printk(KERN_ERR PREFIX "Unknown Vendor data\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
-	}
-
-	memcpy(&vendor_guid, hp_res->guid, sizeof(efi_guid_t));
-	if (efi_guidcmp(vendor_guid, HP_CCSR_GUID) != 0) {
-		printk(KERN_ERR PREFIX "Vendor GUID does not match\n");
-		acpi_dispose_crs(&buf);
-		return AE_TYPE; /* Revisit error? */
-	}
-
-	for (i = 0 ; i < 8 ; i++) {
-		*csr_base |= ((u64)(hp_res->csr_base[i]) << (i * 8));
-		*csr_length |= ((u64)(hp_res->csr_length[i]) << (i * 8));
-	}
+	if (ACPI_FAILURE(status) || length != 16)
+		return AE_NOT_FOUND;
+
+	memcpy(csr_base, data, sizeof(*csr_base));
+	memcpy(csr_length, data + 8, sizeof(*csr_length));
+	acpi_os_free(data);
 
-	acpi_dispose_crs(&buf);
 	return AE_OK;
 }
+
+EXPORT_SYMBOL(hp_acpi_csr_space);
diff -Nru a/arch/ia64/kernel/acpi.c b/arch/ia64/kernel/acpi.c
--- a/arch/ia64/kernel/acpi.c	Tue Apr  1 07:20:36 2003
+++ b/arch/ia64/kernel/acpi.c	Sat May 10 02:28:45 2003
@@ -115,134 +115,6 @@
 #endif
 }
 
-#ifdef CONFIG_ACPI
-
-/**
- * acpi_get_crs - Return the current resource settings for a device
- * obj: A handle for this device
- * buf: A buffer to be populated by this call.
- *
- * Pass a valid handle, typically obtained by walking the namespace and a
- * pointer to an allocated buffer, and this function will fill in the buffer
- * with a list of acpi_resource structures.
- */
-acpi_status
-acpi_get_crs (acpi_handle obj, struct acpi_buffer *buf)
-{
-	acpi_status result;
-	buf->length = 0;
-	buf->pointer = NULL;
-
-	result = acpi_get_current_resources(obj, buf);
-	if (result != AE_BUFFER_OVERFLOW)
-		return result;
-	buf->pointer = kmalloc(buf->length, GFP_KERNEL);
-	if (!buf->pointer)
-		return -ENOMEM;
-
-	return acpi_get_current_resources(obj, buf);
-}
-
-struct acpi_resource *
-acpi_get_crs_next (struct acpi_buffer *buf, int *offset)
-{
-	struct acpi_resource *res;
-
-	if (*offset >= buf->length)
-		return NULL;
-
-	res = buf->pointer + *offset;
-	*offset += res->length;
-	return res;
-}
-
-union acpi_resource_data *
-acpi_get_crs_type (struct acpi_buffer *buf, int *offset, int type)
-{
-	for (;;) {
-		struct acpi_resource *res = acpi_get_crs_next(buf, offset);
-		if (!res)
-			return NULL;
-		if (res->id == type)
-			return &res->data;
-	}
-}
-
-void
-acpi_dispose_crs (struct acpi_buffer *buf)
-{
-	kfree(buf->pointer);
-}
-
-void
-acpi_get_crs_addr (struct acpi_buffer *buf, int type, u64 *base, u64 *size, u64 *tra)
-{
-	int offset = 0;
-	struct acpi_resource_address16 *addr16;
-	struct acpi_resource_address32 *addr32;
-	struct acpi_resource_address64 *addr64;
-
-	for (;;) {
-		struct acpi_resource *res = acpi_get_crs_next(buf, &offset);
-		if (!res)
-			return;
-		switch (res->id) {
-			case ACPI_RSTYPE_ADDRESS16:
-				addr16 = (struct acpi_resource_address16 *) &res->data;
-
-				if (type == addr16->resource_type) {
-					*base = addr16->min_address_range;
-					*size = addr16->address_length;
-					*tra = addr16->address_translation_offset;
-					return;
-				}
-				break;
-			case ACPI_RSTYPE_ADDRESS32:
-				addr32 = (struct acpi_resource_address32 *) &res->data;
-				if (type == addr32->resource_type) {
-					*base = addr32->min_address_range;
-					*size = addr32->address_length;
-					*tra = addr32->address_translation_offset;
-					return;
-				}
-				break;
-			case ACPI_RSTYPE_ADDRESS64:
-				addr64 = (struct acpi_resource_address64 *) &res->data;
-				if (type == addr64->resource_type) {
-					*base = addr64->min_address_range;
-					*size = addr64->address_length;
-					*tra = addr64->address_translation_offset;
-					return;
-				}
-				break;
-		}
-	}
-}
-
-int
-acpi_get_addr_space(void *obj, u8 type, u64 *base, u64 *length, u64 *tra)
-{
-	acpi_status status;
-	struct acpi_buffer buf;
-
-	*base = 0;
-	*length = 0;
-	*tra = 0;
-
-	status = acpi_get_crs((acpi_handle)obj, &buf);
-	if (ACPI_FAILURE(status)) {
-		printk(KERN_ERR PREFIX "Unable to get _CRS data on object\n");
-		return status;
-	}
-
-	acpi_get_crs_addr(&buf, type, base, length, tra);
-
-	acpi_dispose_crs(&buf);
-
-	return AE_OK;
-}
-#endif /* CONFIG_ACPI */
-
 #ifdef CONFIG_ACPI_BOOT
 
 #define ACPI_MAX_PLATFORM_INTERRUPTS	256
@@ -324,7 +196,8 @@
 		printk(" enabled");
 #ifdef CONFIG_SMP
 		smp_boot_data.cpu_phys_id[total_cpus] = (lsapic->id << 8) | lsapic->eid;
-		if (hard_smp_processor_id() == smp_boot_data.cpu_phys_id[total_cpus])
+		if (hard_smp_processor_id()
+		    == (unsigned int) smp_boot_data.cpu_phys_id[total_cpus])
 			printk(" (BSP)");
 #endif
 	}
@@ -918,8 +791,7 @@
 		return 0;
 
 	/* Turn it on */
-	vector = iosapic_register_intr (gsi, polarity ? IOSAPIC_POL_HIGH : IOSAPIC_POL_LOW,
-			trigger ? IOSAPIC_EDGE : IOSAPIC_LEVEL);
+	vector = iosapic_register_intr (gsi, polarity, trigger);
 	return vector;
 }
 
diff -Nru a/arch/ia64/kernel/brl_emu.c b/arch/ia64/kernel/brl_emu.c
--- a/arch/ia64/kernel/brl_emu.c	Tue Feb  4 17:06:07 2003
+++ b/arch/ia64/kernel/brl_emu.c	Wed Apr 16 16:32:50 2003
@@ -59,7 +59,7 @@
 	unsigned long next_ip;
 	struct siginfo siginfo;
 	struct illegal_op_return rv;
-	int tmp_taken, unimplemented_address;
+	long tmp_taken, unimplemented_address;
 
 	rv.fkt = (unsigned long) -1;
 
diff -Nru a/arch/ia64/kernel/efi.c b/arch/ia64/kernel/efi.c
--- a/arch/ia64/kernel/efi.c	Tue Feb  4 17:06:07 2003
+++ b/arch/ia64/kernel/efi.c	Sat May 10 02:28:45 2003
@@ -203,16 +203,16 @@
 STUB_RESET_SYSTEM(virt, )
 
 void
-efi_gettimeofday (struct timeval *tv)
+efi_gettimeofday (struct timespec *ts)
 {
 	efi_time_t tm;
 
-	memset(tv, 0, sizeof(tv));
+	memset(ts, 0, sizeof(ts));
 	if ((*efi.get_time)(&tm, 0) != EFI_SUCCESS)
 		return;
 
-	tv->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
-	tv->tv_usec = tm.nanosecond / 1000;
+	ts->tv_sec = mktime(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
+	ts->tv_nsec = tm.nanosecond;
 }
 
 static int
@@ -512,7 +512,7 @@
 	/* Show what we know for posterity */
 	c16 = __va(efi.systab->fw_vendor);
 	if (c16) {
-		for (i = 0;i < sizeof(vendor) && *c16; ++i)
+		for (i = 0;i < (int) sizeof(vendor) && *c16; ++i)
 			vendor[i] = *c16++;
 		vendor[i] = '\0';
 	}
@@ -520,7 +520,7 @@
 	printk(KERN_INFO "EFI v%u.%.02u by %s:",
 	       efi.systab->hdr.revision >> 16, efi.systab->hdr.revision & 0xffff, vendor);
 
-	for (i = 0; i < efi.systab->nr_tables; i++) {
+	for (i = 0; i < (int) efi.systab->nr_tables; i++) {
 		if (efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID) == 0) {
 			efi.mps = __va(config_tables[i].table);
 			printk(" MPS=0x%lx", config_tables[i].table);
diff -Nru a/arch/ia64/kernel/efivars.c b/arch/ia64/kernel/efivars.c
--- a/arch/ia64/kernel/efivars.c	Fri Dec 13 16:20:51 2002
+++ b/arch/ia64/kernel/efivars.c	Sat May 10 02:28:45 2003
@@ -138,8 +138,7 @@
 static inline unsigned long
 utf8_strsize(efi_char16_t *data, unsigned long maxlength)
 {
-	return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) *
-		sizeof(efi_char16_t);
+	return utf8_strlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
 }
 
 
@@ -170,8 +169,7 @@
 			 efi_guid_t *vendor_guid)
 {
 
-	int i, short_name_size = variable_name_size /
-		sizeof(efi_char16_t) + 38;
+	int i, short_name_size = variable_name_size / sizeof(efi_char16_t) + 38;
 	char *short_name;
 	efivar_entry_t *new_efivar;
 
@@ -192,7 +190,7 @@
 
 	/* Convert Unicode to normal chars (assume top bits are 0),
 	   ala UTF-8 */
-	for (i=0; i<variable_name_size / sizeof(efi_char16_t); i++) {
+	for (i=0; i< (int) (variable_name_size / sizeof(efi_char16_t)); i++) {
 		short_name[i] = variable_name[i] & 0xFF;
 	}
 
diff -Nru a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S
--- a/arch/ia64/kernel/entry.S	Wed Mar 26 09:14:34 2003
+++ b/arch/ia64/kernel/entry.S	Mon May 12 18:59:21 2003
@@ -838,7 +838,7 @@
 	rsm psr.i		// disable interrupts
 	;;
 	adds r17=TI_FLAGS+IA64_TASK_SIZE,r13
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 (pKStk)	adds r20=TI_PRE_COUNT+IA64_TASK_SIZE,r13
 	;;
 (pKStk)	st4 [r20]=r0		// preempt_count() <- 0
diff -Nru a/arch/ia64/kernel/fw-emu.c b/arch/ia64/kernel/fw-emu.c
--- a/arch/ia64/kernel/fw-emu.c	Wed Nov  6 15:41:27 2002
+++ b/arch/ia64/kernel/fw-emu.c	Sat May 10 02:28:45 2003
@@ -37,7 +37,7 @@
 		    + NUM_MEM_DESCS*(sizeof(efi_memory_desc_t))
 		    + 1024)] __attribute__ ((aligned (8)));
 
-#ifdef CONFIG_IA64_HP_SIM
+#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC)
 
 /* Simulator system calls: */
 
@@ -233,7 +233,7 @@
 static efi_status_t
 efi_get_time (efi_time_t *tm, efi_time_cap_t *tc)
 {
-#ifdef CONFIG_IA64_HP_SIM
+#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC)
 	struct {
 		int tv_sec;	/* must be 32bits to work */
 		int tv_usec;
@@ -255,7 +255,7 @@
 static void
 efi_reset_system (int reset_type, efi_status_t status, unsigned long data_size, efi_char16_t *data)
 {
-#ifdef CONFIG_IA64_HP_SIM
+#if defined(CONFIG_IA64_HP_SIM) || defined(CONFIG_IA64_GENERIC)
 	ssc(status, 0, 0, 0, SSC_EXIT);
 #else
 #	error Not implemented yet...
diff -Nru a/arch/ia64/kernel/gate.S b/arch/ia64/kernel/gate.S
--- a/arch/ia64/kernel/gate.S	Mon Feb 10 18:28:00 2003
+++ b/arch/ia64/kernel/gate.S	Mon May 12 18:59:21 2003
@@ -17,7 +17,7 @@
 .start_gate:
 
 
-#if CONFIG_FSYS
+#ifdef CONFIG_FSYS
 
 #include <asm/errno.h>
 
diff -Nru a/arch/ia64/kernel/head.S b/arch/ia64/kernel/head.S
--- a/arch/ia64/kernel/head.S	Tue Mar 11 17:51:47 2003
+++ b/arch/ia64/kernel/head.S	Tue May  6 10:56:54 2003
@@ -733,3 +733,82 @@
 SET_REG(b5);
 
 #endif /* CONFIG_IA64_BRL_EMU */
+
+#ifdef CONFIG_SMP
+	/*
+	 * This routine handles spinlock contention.  It uses a non-standard calling
+	 * convention to avoid converting leaf routines into interior routines.  Because
+	 * of this special convention, there are several restrictions:
+	 *
+	 * - do not use gp relative variables, this code is called from the kernel
+	 *   and from modules, r1 is undefined.
+	 * - do not use stacked registers, the caller owns them.
+	 * - do not use the scratch stack space, the caller owns it.
+	 * - do not use any registers other than the ones listed below
+	 *
+	 * Inputs:
+	 *   ar.pfs - saved CFM of caller
+	 *   ar.ccv - 0 (and available for use)
+	 *   r28    - available for use.
+	 *   r29    - available for use.
+	 *   r30    - available for use.
+	 *   r31    - address of lock, available for use.
+	 *   b7     - return address
+	 *   p14    - available for use.
+	 *
+	 * If you patch this code to use more registers, do not forget to update
+	 * the clobber lists for spin_lock() in include/asm-ia64/spinlock.h.
+	 */
+
+#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
+
+GLOBAL_ENTRY(ia64_spinlock_contention_pre3_4)
+	.prologue
+	.save ar.pfs, r0	// this code effectively has a zero frame size
+	.save rp, r28
+	.body
+	nop 0
+	nop 0
+	.restore sp		// pop existing prologue after next insn
+	mov b6 = r28
+	.prologue
+	.save ar.pfs, r0
+	.altrp b6
+	.body
+.wait:
+	// exponential backoff, kdb, lockmeter etc. go in here
+	hint @pause
+	ld4.bias r30=[r31]
+	nop 0
+	;;
+	cmp4.eq p14,p0=r30,r0
+(p14)	br.cond.sptk.few b6	// lock is now free, try to acquire
+	br.cond.sptk.few .wait
+END(ia64_spinlock_contention_pre3_4)
+
+#else
+
+GLOBAL_ENTRY(ia64_spinlock_contention)
+	.prologue
+	.altrp b6
+	.body
+.wait:
+	// exponential backoff, kdb, lockmeter etc. go in here
+	hint @pause
+	ld4.bias r30=[r31]
+	;;
+	cmp4.ne p14,p0=r30,r0
+	mov r30 = 1
+(p14)	br.cond.sptk.few .wait
+	;;
+	cmpxchg4.acq r30=[r31], r30, ar.ccv
+	;;
+	cmp4.ne p14,p0=r0,r30
+(p14)	br.cond.sptk.few .wait
+
+	br.ret.sptk.many b6	// lock is now taken
+END(ia64_spinlock_contention)
+
+#endif
+
+#endif /* CONFIG_SMP */
diff -Nru a/arch/ia64/kernel/ia64_ksyms.c b/arch/ia64/kernel/ia64_ksyms.c
--- a/arch/ia64/kernel/ia64_ksyms.c	Thu Apr  3 00:35:03 2003
+++ b/arch/ia64/kernel/ia64_ksyms.c	Sat May 10 03:13:39 2003
@@ -46,6 +46,7 @@
 EXPORT_SYMBOL(__ia64_memcpy_fromio);
 EXPORT_SYMBOL(__ia64_memcpy_toio);
 EXPORT_SYMBOL(__ia64_memset_c_io);
+EXPORT_SYMBOL(io_space);
 
 #include <asm/semaphore.h>
 EXPORT_SYMBOL_NOVERS(__down);
@@ -56,6 +57,12 @@
 #include <asm/page.h>
 EXPORT_SYMBOL(clear_page);
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+#include <asm/pgtable.h>
+EXPORT_SYMBOL(vmalloc_end);
+EXPORT_SYMBOL(ia64_pfn_valid);
+#endif
+
 #include <asm/processor.h>
 EXPORT_SYMBOL(cpu_info__per_cpu);
 EXPORT_SYMBOL(kernel_thread);
@@ -161,3 +168,11 @@
 EXPORT_SYMBOL(unw_access_fr);
 EXPORT_SYMBOL(unw_access_ar);
 EXPORT_SYMBOL(unw_access_pr);
+
+#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
+extern void ia64_spinlock_contention_pre3_4 (void);
+EXPORT_SYMBOL(ia64_spinlock_contention_pre3_4);
+#else
+extern void ia64_spinlock_contention (void);
+EXPORT_SYMBOL(ia64_spinlock_contention);
+#endif
diff -Nru a/arch/ia64/kernel/iosapic.c b/arch/ia64/kernel/iosapic.c
--- a/arch/ia64/kernel/iosapic.c	Wed Feb 19 14:07:24 2003
+++ b/arch/ia64/kernel/iosapic.c	Sat May 10 02:28:45 2003
@@ -581,9 +581,8 @@
 	register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, polarity, trigger);
 
 	DBG("ISA: IRQ %u -> GSI 0x%x (%s,%s) -> CPU 0x%04x vector %d\n",
-	    isa_irq, gsi,
-	    polarity == IOSAPIC_POL_HIGH ? "high" : "low", trigger == IOSAPIC_EDGE ? "edge" : "level",
-	    dest, vector);
+	    isa_irq, gsi, polarity == IOSAPIC_POL_HIGH ? "high" : "low",
+	    trigger == IOSAPIC_EDGE ? "edge" : "level", dest, vector);
 
 	/* program the IOSAPIC routing table */
 	set_rte(vector, dest);
@@ -635,7 +634,6 @@
 	       (ver & 0xf0) >> 4, (ver & 0x0f), phys_addr, gsi_base, gsi_base + num_rte - 1);
 
 	if ((gsi_base == 0) && pcat_compat) {
-
 		/*
 		 * Map the legacy ISA devices into the IOSAPIC data.  Some of these may
 		 * get reprogrammed later on with data from the ACPI Interrupt Source
@@ -646,20 +644,11 @@
 	}
 }
 
-static void __init
-fixup_vector (int vector, unsigned int gsi, const char *pci_id)
+void
+iosapic_enable_intr (unsigned int vector)
 {
-	struct hw_interrupt_type *irq_type = &irq_type_iosapic_level;
-	irq_desc_t *idesc;
 	unsigned int dest;
 
-	idesc = irq_desc(vector);
-	if (idesc->handler != irq_type) {
-		if (idesc->handler != &no_irq_type)
-			printk(KERN_INFO "IOSAPIC: changing vector %d from %s to %s\n",
-			       vector, idesc->handler->typename, irq_type->typename);
-		idesc->handler = irq_type;
-	}
 #ifdef CONFIG_SMP
 	/*
 	 * For platforms that do not support interrupt redirect via the XTP interface, we
@@ -687,10 +676,12 @@
 #endif
 	set_rte(vector, dest);
 
-	printk(KERN_INFO "IOSAPIC: %s -> GSI 0x%x -> CPU 0x%04x vector %d\n",
-	       pci_id, gsi, dest, vector);
+	printk(KERN_INFO "IOSAPIC: vector %d -> CPU 0x%04x, enabled\n",
+	       vector, dest);
 }
 
+#ifdef CONFIG_ACPI_PCI
+
 void __init
 iosapic_parse_prt (void)
 {
@@ -699,6 +690,8 @@
 	unsigned int gsi;
 	int vector;
 	char pci_id[16];
+	struct hw_interrupt_type *irq_type = &irq_type_iosapic_level;
+	irq_desc_t *idesc;
 
 	list_for_each(node, &acpi_prt.entries) {
 		entry = list_entry(node, struct acpi_prt_entry, node);
@@ -711,6 +704,9 @@
 
 		vector = gsi_to_vector(gsi);
 		if (vector < 0) {
+			if (find_iosapic(gsi) < 0)
+				continue;
+
 			/* allocate a vector for this interrupt line */
 			if (pcat_compat && (gsi < 16))
 				vector = isa_irq_to_vector(gsi);
@@ -718,11 +714,22 @@
 				/* new GSI; allocate a vector for it */
 				vector = ia64_alloc_vector();
 
-			register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW, IOSAPIC_LEVEL);
+			register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
+				      IOSAPIC_LEVEL);
 		}
 		snprintf(pci_id, sizeof(pci_id), "%02x:%02x:%02x[%c]",
 			 entry->id.segment, entry->id.bus, entry->id.device, 'A' + entry->pin);
 
-		fixup_vector(vector, gsi, pci_id);
+		/*
+		 * If vector was previously initialized to a different
+		 * handler, re-initialize.
+		 */
+		idesc = irq_desc(vector);
+		if (idesc->handler != irq_type)
+			register_intr(gsi, vector, IOSAPIC_LOWEST_PRIORITY, IOSAPIC_POL_LOW,
+				      IOSAPIC_LEVEL);
+
 	}
 }
+
+#endif /* CONFIG_ACPI */
diff -Nru a/arch/ia64/kernel/irq.c b/arch/ia64/kernel/irq.c
--- a/arch/ia64/kernel/irq.c	Sat Mar  8 14:50:43 2003
+++ b/arch/ia64/kernel/irq.c	Mon May 12 18:59:21 2003
@@ -18,7 +18,6 @@
  */
 
 #include <linux/config.h>
-#include <linux/ptrace.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -33,6 +32,7 @@
 #include <linux/irq.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
+#include <linux/kallsyms.h>
 
 #include <asm/atomic.h>
 #include <asm/io.h>
@@ -50,7 +50,7 @@
  * Linux has a controller-independent x86 interrupt architecture.
  * every controller has a 'controller-template', that is used
  * by the main code to do the right thing. Each driver-visible
- * interrupt source is transparently wired to the apropriate
+ * interrupt source is transparently wired to the appropriate
  * controller. Thus drivers need not be aware of the
  * interrupt-controller.
  *
@@ -91,7 +91,8 @@
  * Special irq handlers.
  */
 
-void no_action(int cpl, void *dev_id, struct pt_regs *regs) { }
+irqreturn_t no_action(int cpl, void *dev_id, struct pt_regs *regs)
+{ return IRQ_NONE; }
 
 /*
  * Generic no controller code
@@ -107,7 +108,7 @@
  * each architecture has to answer this themselves, it doesn't deserve
  * a generic callback i think.
  */
-#if CONFIG_X86
+#ifdef CONFIG_X86
 	printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq);
 #ifdef CONFIG_X86_LOCAL_APIC
 	/*
@@ -121,7 +122,7 @@
 	ack_APIC_irq();
 #endif
 #endif
-#if CONFIG_IA64
+#ifdef CONFIG_IA64
 	printk(KERN_ERR "Unexpected irq vector 0x%x on CPU %u!\n", irq, smp_processor_id());
 #endif
 }
@@ -141,9 +142,11 @@
 };
 
 atomic_t irq_err_count;
-#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG)
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
 atomic_t irq_mis_count;
 #endif
+#endif
 
 /*
  * Generic, controller-independent functions:
@@ -178,9 +181,10 @@
 #endif
 		seq_printf(p, " %14s", idesc->handler->typename);
 		seq_printf(p, "  %s", action->name);
+
 		for (action=action->next; action; action = action->next)
 			seq_printf(p, ", %s", action->name);
-		
+
 		seq_putc(p, '\n');
 skip:
 		spin_unlock_irqrestore(&idesc->lock, flags);
@@ -190,21 +194,23 @@
 		if (cpu_online(j))
 			seq_printf(p, "%10u ", nmi_count(j));
 	seq_putc(p, '\n');
-#if defined(CONFIG_SMP) && defined(CONFIG_X86)
+#ifdef CONFIG_X86_LOCAL_APIC
 	seq_puts(p, "LOC: ");
 	for (j = 0; j < NR_CPUS; j++)
 		if (cpu_online(j))
-			seq_printf(p, "%10u ", apic_timer_irqs[j]);
+			seq_printf(p, "%10u ", irq_stat[j].apic_timer_irqs);
 	seq_putc(p, '\n');
 #endif
 	seq_printf(p, "ERR: %10u\n", atomic_read(&irq_err_count));
-#if defined(CONFIG_X86) && defined(CONFIG_X86_IO_APIC) && defined(APIC_MISMATCH_DEBUG)
+#ifdef CONFIG_X86_IO_APIC
+#ifdef APIC_MISMATCH_DEBUG
 	seq_printf(p, "MIS: %10u\n", atomic_read(&irq_mis_count));
 #endif
+#endif
 	return 0;
 }
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 inline void synchronize_irq(unsigned int irq)
 {
 	while (irq_desc(irq)->status & IRQ_INPROGRESS)
@@ -219,21 +225,46 @@
  * waste of time and is not what some drivers would
  * prefer.
  */
-int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, struct irqaction * action)
+int handle_IRQ_event(unsigned int irq,
+		struct pt_regs *regs, struct irqaction *action)
 {
 	int status = 1;	/* Force the "do bottom halves" bit */
+	int retval = 0;
+	struct irqaction *first_action = action;
 
 	if (!(action->flags & SA_INTERRUPT))
 		local_irq_enable();
 
 	do {
 		status |= action->flags;
-		action->handler(irq, action->dev_id, regs);
+		retval |= action->handler(irq, action->dev_id, regs);
 		action = action->next;
 	} while (action);
 	if (status & SA_SAMPLE_RANDOM)
 		add_interrupt_randomness(irq);
 	local_irq_disable();
+	if (retval != 1) {
+		static int count = 100;
+		if (count) {
+			count--;
+			if (retval) {
+				printk("irq event %d: bogus retval mask %x\n",
+					irq, retval);
+			} else {
+				printk("irq %d: nobody cared!\n", irq);
+			}
+			dump_stack();
+			printk("handlers:\n");
+			action = first_action;
+			do {
+				printk("[<%p>]", action->handler);
+				print_symbol(" (%s)",
+					(unsigned long)action->handler);
+				printk("\n");
+				action = action->next;
+			} while (action);
+		}
+	}
 
 	return status;
 }
@@ -455,7 +486,7 @@
  */
 
 int request_irq(unsigned int irq,
-		void (*handler)(int, void *, struct pt_regs *),
+		irqreturn_t (*handler)(int, void *, struct pt_regs *),
 		unsigned long irqflags,
 		const char * devname,
 		void *dev_id)
@@ -482,7 +513,7 @@
 		return -EINVAL;
 
 	action = (struct irqaction *)
-			kmalloc(sizeof(struct irqaction), GFP_KERNEL);
+			kmalloc(sizeof(struct irqaction), GFP_ATOMIC);
 	if (!action)
 		return -ENOMEM;
 
@@ -511,10 +542,7 @@
  *	does not return until any executing interrupts for this IRQ
  *	have completed.
  *
- *	This function may be called from interrupt context. 
- *
- *	Bugs: Attempting to free an irq in a handler for the same irq hangs
- *	      the machine.
+ *	This function must not be called from interrupt context.
  */
 
 void free_irq(unsigned int irq, void *dev_id)
@@ -545,11 +573,8 @@
 			}
 			spin_unlock_irqrestore(&desc->lock,flags);
 
-#ifdef CONFIG_SMP
 			/* Wait to make sure it's not being used on another CPU */
-			while (desc->status & IRQ_INPROGRESS)
-				synchronize_irq(irq);
-#endif
+			synchronize_irq(irq);
 			kfree(action);
 			return;
 		}
@@ -664,7 +689,6 @@
  *	only return ISA irq numbers - just so that we reset them
  *	all to a known state.
  */
-
 unsigned int probe_irq_mask(unsigned long val)
 {
 	int i;
@@ -705,7 +729,7 @@
  *	The interrupt probe logic state is returned to its previous
  *	value.
  *
- *	BUGS: When used in a module (which arguably shouldnt happen)
+ *	BUGS: When used in a module (which arguably shouldn't happen)
  *	nothing prevents two IRQ probe callers from overlapping. The
  *	results of this are non-optimal.
  */
@@ -748,6 +772,8 @@
 	struct irqaction *old, **p;
 	irq_desc_t *desc = irq_desc(irq);
 
+	if (desc->handler == &no_irq_type)
+		return -ENOSYS;
 	/*
 	 * Some drivers like serial.c use request_irq() heavily,
 	 * so we have to be careful not to interfere with a
@@ -808,11 +834,11 @@
 
 #define HEX_DIGITS 8
 
-static int parse_hex_value (const char *buffer, unsigned long count, unsigned long *ret)
+static unsigned int parse_hex_value (const char *buffer,
+		unsigned long count, unsigned long *ret)
 {
 	unsigned char hexnum [HEX_DIGITS];
-	unsigned long value;
-	int i;
+	unsigned long value, i;
 
 	if (!count)
 		return -EINVAL;
@@ -844,7 +870,7 @@
 	return 0;
 }
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 
 static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
 
@@ -947,15 +973,16 @@
 	/* create /proc/irq/1234 */
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	{
 		struct proc_dir_entry *entry;
+
 		/* create /proc/irq/1234/smp_affinity */
 		entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]);
 
 		if (entry) {
 			entry->nlink = 1;
-			entry->data = (void *)(unsigned long)irq;
+			entry->data = (void *)(long)irq;
 			entry->read_proc = irq_affinity_read_proc;
 			entry->write_proc = irq_affinity_write_proc;
 		}
diff -Nru a/arch/ia64/kernel/irq_ia64.c b/arch/ia64/kernel/irq_ia64.c
--- a/arch/ia64/kernel/irq_ia64.c	Mon Jan  6 17:05:37 2003
+++ b/arch/ia64/kernel/irq_ia64.c	Sat May 10 02:28:45 2003
@@ -145,7 +145,7 @@
 }
 
 #ifdef CONFIG_SMP
-extern void handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t handle_IPI (int irq, void *dev_id, struct pt_regs *regs);
 
 static struct irqaction ipi_irqaction = {
 	.handler =	handle_IPI,
diff -Nru a/arch/ia64/kernel/machvec.c b/arch/ia64/kernel/machvec.c
--- a/arch/ia64/kernel/machvec.c	Thu Feb 20 02:35:33 2003
+++ b/arch/ia64/kernel/machvec.c	Sat May 10 02:28:46 2003
@@ -1,12 +1,14 @@
 #include <linux/config.h>
 
+#include <asm/system.h>
+
 #ifdef CONFIG_IA64_GENERIC
 
 #include <linux/kernel.h>
 #include <linux/string.h>
 
-#include <asm/page.h>
 #include <asm/machvec.h>
+#include <asm/page.h>
 
 struct ia64_machine_vector ia64_mv;
 
@@ -42,4 +44,10 @@
 void
 machvec_noop (void)
 {
+}
+
+void
+machvec_memory_fence (void)
+{
+	mb();
 }
diff -Nru a/arch/ia64/kernel/mca.c b/arch/ia64/kernel/mca.c
--- a/arch/ia64/kernel/mca.c	Thu Apr  3 13:24:33 2003
+++ b/arch/ia64/kernel/mca.c	Sat May 10 02:28:46 2003
@@ -3,6 +3,9 @@
  * Purpose:	Generic MCA handling layer
  *
  * Updated for latest kernel
+ * Copyright (C) 2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *
  * Copyright (C) 2002 Dell Computer Corporation
  * Copyright (C) Matt Domsch (Matt_Domsch@dell.com)
  *
@@ -18,6 +21,7 @@
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
  *
+ * 03/04/15 D. Mosberger Added INIT backtrace support.
  * 02/03/25 M. Domsch	GUID cleanups
  *
  * 02/01/04 J. Hall	Aligned MCA stack to 16 bytes, added platform vs. CPU
@@ -39,6 +43,7 @@
 #include <linux/sched.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/kallsyms.h>
 #include <linux/smp_lock.h>
 #include <linux/bootmem.h>
 #include <linux/acpi.h>
@@ -47,6 +52,7 @@
 #include <linux/kernel.h>
 #include <linux/smp.h>
 
+#include <asm/delay.h>
 #include <asm/machvec.h>
 #include <asm/page.h>
 #include <asm/ptrace.h>
@@ -139,7 +145,7 @@
 
 	/* Get the MCA error record */
 	if (!ia64_log_get(sal_info_type, (prfunc_t)printk))
-		return platform_err;                 // no record retrieved
+		return platform_err;		/* no record retrieved */
 
 	/* TODO:
 	 * 1. analyze error logs to determine recoverability
@@ -166,7 +172,7 @@
 
 }
 
-void
+irqreturn_t
 ia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs)
 {
 	IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. CPU:%d vector = %#x\n",
@@ -174,20 +180,186 @@
 
 	/* Get the CMC error record and log it */
 	ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE, 0);
+	return IRQ_HANDLED;
+}
+
+static void
+show_min_state (pal_min_state_area_t *minstate)
+{
+	u64 iip = minstate->pmsa_iip + ((struct ia64_psr *)(&minstate->pmsa_ipsr))->ri;
+	u64 xip = minstate->pmsa_xip + ((struct ia64_psr *)(&minstate->pmsa_xpsr))->ri;
+
+	printk("NaT bits\t%016lx\n", minstate->pmsa_nat_bits);
+	printk("pr\t\t%016lx\n", minstate->pmsa_pr);
+	printk("b0\t\t%016lx ", minstate->pmsa_br0); print_symbol("%s\n", minstate->pmsa_br0);
+	printk("ar.rsc\t\t%016lx\n", minstate->pmsa_rsc);
+	printk("cr.iip\t\t%016lx ", iip); print_symbol("%s\n", iip);
+	printk("cr.ipsr\t\t%016lx\n", minstate->pmsa_ipsr);
+	printk("cr.ifs\t\t%016lx\n", minstate->pmsa_ifs);
+	printk("xip\t\t%016lx ", xip); print_symbol("%s\n", xip);
+	printk("xpsr\t\t%016lx\n", minstate->pmsa_xpsr);
+	printk("xfs\t\t%016lx\n", minstate->pmsa_xfs);
+	printk("b1\t\t%016lx ", minstate->pmsa_br1);
+	print_symbol("%s\n", minstate->pmsa_br1);
+
+	printk("\nstatic registers r0-r15:\n");
+	printk(" r0- 3 %016lx %016lx %016lx %016lx\n",
+	       0UL, minstate->pmsa_gr[0], minstate->pmsa_gr[1], minstate->pmsa_gr[2]);
+	printk(" r4- 7 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_gr[3], minstate->pmsa_gr[4],
+	       minstate->pmsa_gr[5], minstate->pmsa_gr[6]);
+	printk(" r8-11 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_gr[7], minstate->pmsa_gr[8],
+	       minstate->pmsa_gr[9], minstate->pmsa_gr[10]);
+	printk("r12-15 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_gr[11], minstate->pmsa_gr[12],
+	       minstate->pmsa_gr[13], minstate->pmsa_gr[14]);
+
+	printk("\nbank 0:\n");
+	printk("r16-19 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_bank0_gr[0], minstate->pmsa_bank0_gr[1],
+	       minstate->pmsa_bank0_gr[2], minstate->pmsa_bank0_gr[3]);
+	printk("r20-23 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_bank0_gr[4], minstate->pmsa_bank0_gr[5],
+	       minstate->pmsa_bank0_gr[6], minstate->pmsa_bank0_gr[7]);
+	printk("r24-27 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_bank0_gr[8], minstate->pmsa_bank0_gr[9],
+	       minstate->pmsa_bank0_gr[10], minstate->pmsa_bank0_gr[11]);
+	printk("r28-31 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_bank0_gr[12], minstate->pmsa_bank0_gr[13],
+	       minstate->pmsa_bank0_gr[14], minstate->pmsa_bank0_gr[15]);
+
+	printk("\nbank 1:\n");
+	printk("r16-19 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_bank1_gr[0], minstate->pmsa_bank1_gr[1],
+	       minstate->pmsa_bank1_gr[2], minstate->pmsa_bank1_gr[3]);
+	printk("r20-23 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_bank1_gr[4], minstate->pmsa_bank1_gr[5],
+	       minstate->pmsa_bank1_gr[6], minstate->pmsa_bank1_gr[7]);
+	printk("r24-27 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_bank1_gr[8], minstate->pmsa_bank1_gr[9],
+	       minstate->pmsa_bank1_gr[10], minstate->pmsa_bank1_gr[11]);
+	printk("r28-31 %016lx %016lx %016lx %016lx\n",
+	       minstate->pmsa_bank1_gr[12], minstate->pmsa_bank1_gr[13],
+	       minstate->pmsa_bank1_gr[14], minstate->pmsa_bank1_gr[15]);
+}
+
+static void
+fetch_min_state (pal_min_state_area_t *ms, struct pt_regs *pt, struct switch_stack *sw)
+{
+	u64 *dst_banked, *src_banked, bit, shift, nat_bits;
+	int i;
+
+	/*
+	 * First, update the pt-regs and switch-stack structures with the contents stored
+	 * in the min-state area:
+	 */
+	if (((struct ia64_psr *) &ms->pmsa_ipsr)->ic == 0) {
+		pt->cr_ipsr = ms->pmsa_xpsr;
+		pt->cr_iip = ms->pmsa_xip;
+		pt->cr_ifs = ms->pmsa_xfs;
+	} else {
+		pt->cr_ipsr = ms->pmsa_ipsr;
+		pt->cr_iip = ms->pmsa_iip;
+		pt->cr_ifs = ms->pmsa_ifs;
+	}
+	pt->ar_rsc = ms->pmsa_rsc;
+	pt->pr = ms->pmsa_pr;
+	pt->r1 = ms->pmsa_gr[0];
+	pt->r2 = ms->pmsa_gr[1];
+	pt->r3 = ms->pmsa_gr[2];
+	sw->r4 = ms->pmsa_gr[3];
+	sw->r5 = ms->pmsa_gr[4];
+	sw->r6 = ms->pmsa_gr[5];
+	sw->r7 = ms->pmsa_gr[6];
+	pt->r8 = ms->pmsa_gr[7];
+	pt->r9 = ms->pmsa_gr[8];
+	pt->r10 = ms->pmsa_gr[9];
+	pt->r11 = ms->pmsa_gr[10];
+	pt->r12 = ms->pmsa_gr[11];
+	pt->r13 = ms->pmsa_gr[12];
+	pt->r14 = ms->pmsa_gr[13];
+	pt->r15 = ms->pmsa_gr[14];
+	dst_banked = &pt->r16;		/* r16-r31 are contiguous in struct pt_regs */
+	src_banked = ms->pmsa_bank1_gr;
+	for (i = 0; i < 16; ++i)
+		dst_banked[i] = src_banked[i];
+	pt->b0 = ms->pmsa_br0;
+	sw->b1 = ms->pmsa_br1;
+
+	/* construct the NaT bits for the pt-regs structure: */
+#	define PUT_NAT_BIT(dst, addr)					\
+	do {								\
+		bit = nat_bits & 1; nat_bits >>= 1;			\
+		shift = ((unsigned long) addr >> 3) & 0x3f;		\
+		dst = ((dst) & ~(1UL << shift)) | (bit << shift);	\
+	} while (0)
+
+	/* Rotate the saved NaT bits such that bit 0 corresponds to pmsa_gr[0]: */
+	shift = ((unsigned long) &ms->pmsa_gr[0] >> 3) & 0x3f;
+	nat_bits = (ms->pmsa_nat_bits >> shift) | (ms->pmsa_nat_bits << (64 - shift));
+
+	PUT_NAT_BIT(sw->caller_unat, &pt->r1);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r2);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r3);
+	PUT_NAT_BIT(sw->ar_unat, &sw->r4);
+	PUT_NAT_BIT(sw->ar_unat, &sw->r5);
+	PUT_NAT_BIT(sw->ar_unat, &sw->r6);
+	PUT_NAT_BIT(sw->ar_unat, &sw->r7);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r8);	PUT_NAT_BIT(sw->caller_unat, &pt->r9);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r10);	PUT_NAT_BIT(sw->caller_unat, &pt->r11);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r12);	PUT_NAT_BIT(sw->caller_unat, &pt->r13);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r14);	PUT_NAT_BIT(sw->caller_unat, &pt->r15);
+	nat_bits >>= 16;	/* skip over bank0 NaT bits */
+	PUT_NAT_BIT(sw->caller_unat, &pt->r16);	PUT_NAT_BIT(sw->caller_unat, &pt->r17);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r18);	PUT_NAT_BIT(sw->caller_unat, &pt->r19);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r20);	PUT_NAT_BIT(sw->caller_unat, &pt->r21);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r22);	PUT_NAT_BIT(sw->caller_unat, &pt->r23);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r24);	PUT_NAT_BIT(sw->caller_unat, &pt->r25);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r26);	PUT_NAT_BIT(sw->caller_unat, &pt->r27);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r28);	PUT_NAT_BIT(sw->caller_unat, &pt->r29);
+	PUT_NAT_BIT(sw->caller_unat, &pt->r30);	PUT_NAT_BIT(sw->caller_unat, &pt->r31);
 }
 
-/*
- * This routine will be used to deal with platform specific handling
- * of the init, i.e. drop into the kernel debugger on server machine,
- * or if the processor is part of some parallel machine without a
- * console, then we would call the appropriate debug hooks here.
- */
 void
-init_handler_platform (struct pt_regs *regs)
+init_handler_platform (sal_log_processor_info_t *proc_ptr,
+		       struct pt_regs *pt, struct switch_stack *sw)
 {
+	struct unw_frame_info info;
+
 	/* if a kernel debugger is available call it here else just dump the registers */
 
-	show_regs(regs);		/* dump the state info */
+	/*
+	 * Wait for a bit.  On some machines (e.g., HP's zx2000 and zx6000, INIT can be
+	 * generated via the BMC's command-line interface, but since the console is on the
+	 * same serial line, the user will need some time to switch out of the BMC before
+	 * the dump begins.
+	 */
+	printk("Delaying for 5 seconds...\n");
+	udelay(5*1000000);
+	show_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area);
+
+	printk("Backtrace of current task (pid %d, %s)\n", current->pid, current->comm);
+	fetch_min_state(&SAL_LPI_PSI_INFO(proc_ptr)->min_state_area, pt, sw);
+	unw_init_from_interruption(&info, current, pt, sw);
+	ia64_do_show_stack(&info, NULL);
+
+	if (!tasklist_lock.write_lock)
+		read_lock(&tasklist_lock);
+	{
+		struct task_struct *g, *t;
+		do_each_thread (g, t) {
+			if (t == current)
+				continue;
+
+			printk("\nBacktrace of pid %d (%s)\n", t->pid, t->comm);
+			show_stack(t);
+		} while_each_thread (g, t);
+	}
+	if (!tasklist_lock.write_lock)
+		read_unlock(&tasklist_lock);
+
+	printk("\nINIT dump complete.  Please reboot now.\n");
 	while (1);			/* hang city if no debugger */
 }
 
@@ -263,7 +435,6 @@
 /*
  * routine to process and prepare to dump min_state_save
  * information for debugging purposes.
- *
  */
 void
 ia64_process_min_state_save (pal_min_state_area_t *pmss)
@@ -272,8 +443,6 @@
 	u64 *tpmss_ptr = (u64 *)pmss;
 	u64 *return_min_state_ptr = ia64_mca_min_state_save_info;
 
-	/* dump out the min_state_area information */
-
 	for (i=0;i<max;i++) {
 
 		/* copy min-state register info for eventual return to PAL */
@@ -676,7 +845,7 @@
  *  Inputs  :   None
  *  Outputs :   None
  */
-void
+irqreturn_t
 ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
 {
 	unsigned long flags;
@@ -699,6 +868,7 @@
 
 	/* Enable all interrupts */
 	local_irq_restore(flags);
+	return IRQ_HANDLED;
 }
 
 
@@ -717,10 +887,10 @@
  *  Outputs :   None
  *
  */
-void
+irqreturn_t
 ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs)
 {
-
+	return IRQ_HANDLED;
 }
 
 /*
@@ -815,7 +985,7 @@
  * Outputs
  *	None
  */
-void
+irqreturn_t
 ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
 {
 	static unsigned long	cmc_history[CMC_HISTORY_LENGTH];
@@ -832,7 +1002,7 @@
 	if (!cmc_polling_enabled) {
 		int i, count = 1; /* we know 1 happened now */
 		unsigned long now = jiffies;
-		
+
 		for (i = 0; i < CMC_HISTORY_LENGTH; i++) {
 			if (now - cmc_history[i] <= HZ)
 				count++;
@@ -867,12 +1037,12 @@
 			 * something is generating more than we can handle.
 			 */
 			printk(KERN_WARNING "ia64_mca_cmc_int_handler: WARNING: Switching to polling CMC handler, error records may be lost\n");
-			
+
 
 			mod_timer(&cmc_poll_timer, jiffies + CMC_POLL_INTERVAL);
 
 			/* lock already released, get out now */
-			return;
+			return IRQ_HANDLED;
 		} else {
 			cmc_history[index++] = now;
 			if (index == CMC_HISTORY_LENGTH)
@@ -880,6 +1050,7 @@
 		}
 	}
 	spin_unlock(&cmc_history_lock);
+	return IRQ_HANDLED;
 }
 
 /*
@@ -944,7 +1115,7 @@
 static void
 ia64_mca_cmc_poll (unsigned long dummy)
 {
-	int start_count;
+	unsigned long start_count;
 
 	start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CMC);
 
@@ -986,7 +1157,7 @@
  *  ia64_mca_cpe_poll
  *
  *	Poll for Corrected Platform Errors (CPEs), dynamically adjust
- *	polling interval based on occurance of an event.
+ *	polling interval based on occurrence of an event.
  *
  * Inputs   :   dummy(unused)
  * Outputs  :   None
@@ -995,7 +1166,7 @@
 static void
 ia64_mca_cpe_poll (unsigned long dummy)
 {
-	int start_count;
+	unsigned long start_count;
 	static int poll_time = MAX_CPE_POLL_INTERVAL;
 
 	start_count = IA64_LOG_COUNT(SAL_INFO_TYPE_CPE);
@@ -1062,7 +1233,7 @@
  *
  */
 void
-ia64_init_handler (struct pt_regs *regs)
+ia64_init_handler (struct pt_regs *pt, struct switch_stack *sw)
 {
 	sal_log_processor_info_t *proc_ptr;
 	ia64_err_rec_t *plog_ptr;
@@ -1089,7 +1260,7 @@
 	/* Clear the INIT SAL logs now that they have been saved in the OS buffer */
 	ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT);
 
-	init_handler_platform(regs);              /* call platform specific routines */
+	init_handler_platform(proc_ptr, pt, sw);	/* call platform specific routines */
 }
 
 /*
@@ -1112,7 +1283,8 @@
 static void
 ia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc)
 {
-	int i, j;
+	unsigned long i;
+	int j;
 
 	if (!p)
 		return;
@@ -1960,7 +2132,7 @@
 {
 	sal_log_section_hdr_t       *slsh;
 	int                         n_sects;
-	int                         ercd_pos;
+	u32                         ercd_pos;
 
 	if (!lh)
 		return;
@@ -2022,7 +2194,7 @@
 {
 	sal_log_section_hdr_t	*slsh;
 	int			n_sects;
-	int			ercd_pos;
+	u32			ercd_pos;
 	int			platform_err = 0;
 
 	if (!lh)
@@ -2139,7 +2311,8 @@
 	switch(sal_info_type) {
 	      case SAL_INFO_TYPE_MCA:
 		prfunc("+BEGIN HARDWARE ERROR STATE AT MCA\n");
-		platform_err = ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type), prfunc);
+		platform_err = ia64_log_platform_info_print(IA64_LOG_CURR_BUFFER(sal_info_type),
+							    prfunc);
 		prfunc("+END HARDWARE ERROR STATE AT MCA\n");
 		break;
 	      case SAL_INFO_TYPE_INIT:
diff -Nru a/arch/ia64/kernel/mca_asm.S b/arch/ia64/kernel/mca_asm.S
--- a/arch/ia64/kernel/mca_asm.S	Tue May 14 10:17:01 2002
+++ b/arch/ia64/kernel/mca_asm.S	Tue Apr 15 13:16:39 2003
@@ -766,8 +766,6 @@
 	// stash the information the SAL passed to os
 	SAL_TO_OS_MCA_HANDOFF_STATE_SAVE(r2)
 	;;
-
-// now we want to save information so we can dump registers
 	SAVE_MIN_WITH_COVER
 	;;
 	mov r8=cr.ifa
@@ -798,10 +796,12 @@
 	//
 	// Let's call the C handler to get the rest of the state info
 	//
-	alloc r14=ar.pfs,0,0,1,0		// now it's safe (must be first in insn group!)
-	;;					//
+	alloc r14=ar.pfs,0,0,2,0		// now it's safe (must be first in insn group!)
+	;;
 	adds out0=16,sp				// out0 = pointer to pt_regs
 	;;
+	DO_SAVE_SWITCH_STACK
+	adds out1=16,sp				// out0 = pointer to switch_stack
 
 	br.call.sptk.many rp=ia64_init_handler
 .ret1:
diff -Nru a/arch/ia64/kernel/palinfo.c b/arch/ia64/kernel/palinfo.c
--- a/arch/ia64/kernel/palinfo.c	Thu Mar 27 10:36:54 2003
+++ b/arch/ia64/kernel/palinfo.c	Sat May 10 02:28:46 2003
@@ -91,7 +91,7 @@
 	"eager loads and stores"
 };
 
-#define RSE_HINTS_COUNT (sizeof(rse_hints)/sizeof(const char *))
+#define RSE_HINTS_COUNT ARRAY_SIZE(rse_hints)
 
 static const char *mem_attrib[]={
 	"WB",		/* 000 */
@@ -192,15 +192,15 @@
 
 	for (i=0; i < 8 ; i++ ) {
 		if (halt_info[i].pal_power_mgmt_info_s.im == 1) {
-			p += sprintf(p,	"Power level %d:\n" \
-					"\tentry_latency       : %d cycles\n" \
-					"\texit_latency        : %d cycles\n" \
-					"\tpower consumption   : %d mW\n" \
-					"\tCache+TLB coherency : %s\n", i,
-				halt_info[i].pal_power_mgmt_info_s.entry_latency,
-				halt_info[i].pal_power_mgmt_info_s.exit_latency,
-				halt_info[i].pal_power_mgmt_info_s.power_consumption,
-				halt_info[i].pal_power_mgmt_info_s.co ? "Yes" : "No");
+			p += sprintf(p,	"Power level %d:\n"
+				     "\tentry_latency       : %d cycles\n"
+				     "\texit_latency        : %d cycles\n"
+				     "\tpower consumption   : %d mW\n"
+				     "\tCache+TLB coherency : %s\n", i,
+				     halt_info[i].pal_power_mgmt_info_s.entry_latency,
+				     halt_info[i].pal_power_mgmt_info_s.exit_latency,
+				     halt_info[i].pal_power_mgmt_info_s.power_consumption,
+				     halt_info[i].pal_power_mgmt_info_s.co ? "Yes" : "No");
 		} else {
 			p += sprintf(p,"Power level %d: not implemented\n",i);
 		}
@@ -212,9 +212,9 @@
 cache_info(char *page)
 {
 	char *p = page;
-	u64 levels, unique_caches;
+	u64 i, levels, unique_caches;
 	pal_cache_config_info_t cci;
-	int i,j, k;
+	int j, k;
 	s64 status;
 
 	if ((status = ia64_pal_cache_summary(&levels, &unique_caches)) != 0) {
@@ -232,48 +232,50 @@
 			if ((status=ia64_pal_cache_config_info(i,j, &cci)) != 0) {
 				continue;
 			}
-			p += sprintf(p, "%s Cache level %d:\n" \
-					"\tSize           : %ld bytes\n" \
-					"\tAttributes     : ",
-					cache_types[j+cci.pcci_unified], i+1,
-					cci.pcci_cache_size);
+			p += sprintf(p,
+				     "%s Cache level %lu:\n"
+				     "\tSize           : %lu bytes\n"
+				     "\tAttributes     : ",
+				     cache_types[j+cci.pcci_unified], i+1,
+				     cci.pcci_cache_size);
 
 			if (cci.pcci_unified) p += sprintf(p, "Unified ");
 
 			p += sprintf(p, "%s\n", cache_mattrib[cci.pcci_cache_attr]);
 
-			p += sprintf(p, "\tAssociativity  : %d\n" \
-					"\tLine size      : %d bytes\n" \
-					"\tStride         : %d bytes\n",
-					cci.pcci_assoc,
-					1<<cci.pcci_line_size,
-					1<<cci.pcci_stride);
+			p += sprintf(p,
+				     "\tAssociativity  : %d\n"
+				     "\tLine size      : %d bytes\n"
+				     "\tStride         : %d bytes\n",
+				     cci.pcci_assoc, 1<<cci.pcci_line_size, 1<<cci.pcci_stride);
 			if (j == 1)
 				p += sprintf(p, "\tStore latency  : N/A\n");
 			else
 				p += sprintf(p, "\tStore latency  : %d cycle(s)\n",
 						cci.pcci_st_latency);
 
-			p += sprintf(p, "\tLoad latency   : %d cycle(s)\n" \
-					"\tStore hints    : ",
-					cci.pcci_ld_latency);
+			p += sprintf(p,
+				     "\tLoad latency   : %d cycle(s)\n"
+				     "\tStore hints    : ", cci.pcci_ld_latency);
 
 			for(k=0; k < 8; k++ ) {
-				if ( cci.pcci_st_hints & 0x1) p += sprintf(p, "[%s]", cache_st_hints[k]);
+				if ( cci.pcci_st_hints & 0x1)
+					p += sprintf(p, "[%s]", cache_st_hints[k]);
 				cci.pcci_st_hints >>=1;
 			}
 			p += sprintf(p, "\n\tLoad hints     : ");
 
 			for(k=0; k < 8; k++ ) {
-				if ( cci.pcci_ld_hints & 0x1) p += sprintf(p, "[%s]", cache_ld_hints[k]);
+				if (cci.pcci_ld_hints & 0x1)
+					p += sprintf(p, "[%s]", cache_ld_hints[k]);
 				cci.pcci_ld_hints >>=1;
 			}
-			p += sprintf(p, "\n\tAlias boundary : %d byte(s)\n" \
-					"\tTag LSB        : %d\n" \
-					"\tTag MSB        : %d\n",
-					1<<cci.pcci_alias_boundary,
-					cci.pcci_tag_lsb,
-					cci.pcci_tag_msb);
+			p += sprintf(p,
+				     "\n\tAlias boundary : %d byte(s)\n"
+				     "\tTag LSB        : %d\n"
+				     "\tTag MSB        : %d\n",
+				     1<<cci.pcci_alias_boundary, cci.pcci_tag_lsb,
+				     cci.pcci_tag_msb);
 
 			/* when unified, data(j=2) is enough */
 			if (cci.pcci_unified) break;
@@ -303,20 +305,20 @@
 	}
 
 
-	p += sprintf(p, "Physical Address Space         : %d bits\n" \
-			"Virtual Address Space          : %d bits\n" \
-			"Protection Key Registers(PKR)  : %d\n" \
-			"Implemented bits in PKR.key    : %d\n" \
-			"Hash Tag ID                    : 0x%x\n" \
-			"Size of RR.rid                 : %d\n",
-			vm_info_1.pal_vm_info_1_s.phys_add_size,
-			vm_info_2.pal_vm_info_2_s.impl_va_msb+1,
-			vm_info_1.pal_vm_info_1_s.max_pkr+1,
-			vm_info_1.pal_vm_info_1_s.key_size,
-			vm_info_1.pal_vm_info_1_s.hash_tag_id,
-			vm_info_2.pal_vm_info_2_s.rid_size);
+	p += sprintf(p,
+		     "Physical Address Space         : %d bits\n"
+		     "Virtual Address Space          : %d bits\n"
+		     "Protection Key Registers(PKR)  : %d\n"
+		     "Implemented bits in PKR.key    : %d\n"
+		     "Hash Tag ID                    : 0x%x\n"
+		     "Size of RR.rid                 : %d\n",
+		     vm_info_1.pal_vm_info_1_s.phys_add_size,
+		     vm_info_2.pal_vm_info_2_s.impl_va_msb+1, vm_info_1.pal_vm_info_1_s.max_pkr+1,
+		     vm_info_1.pal_vm_info_1_s.key_size, vm_info_1.pal_vm_info_1_s.hash_tag_id,
+		     vm_info_2.pal_vm_info_2_s.rid_size);
 
-	if (ia64_pal_mem_attrib(&attrib) != 0) return 0;
+	if (ia64_pal_mem_attrib(&attrib) != 0)
+		return 0;
 
 	p += sprintf(p, "Supported memory attributes    : ");
 	sep = "";
@@ -333,13 +335,14 @@
 		return 0;
 	}
 
-	p += sprintf(p, "\nTLB walker                     : %simplemented\n" \
-			"Number of DTR                  : %d\n" \
-			"Number of ITR                  : %d\n" \
-			"TLB insertable page sizes      : ",
-			vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
-			vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
-			vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
+	p += sprintf(p,
+		     "\nTLB walker                     : %simplemented\n"
+		     "Number of DTR                  : %d\n"
+		     "Number of ITR                  : %d\n"
+		     "TLB insertable page sizes      : ",
+		     vm_info_1.pal_vm_info_1_s.vw ? "" : "not ",
+		     vm_info_1.pal_vm_info_1_s.max_dtr_entry+1,
+		     vm_info_1.pal_vm_info_1_s.max_itr_entry+1);
 
 
 	p = bitvector_process(p, tr_pages);
@@ -353,21 +356,19 @@
 		return 0;
 	}
 
-	p += sprintf(p, "\nPurge base address             : 0x%016lx\n" \
-			"Purge outer loop count         : %d\n" \
-			"Purge inner loop count         : %d\n" \
-			"Purge outer loop stride        : %d\n" \
-			"Purge inner loop stride        : %d\n",
-			ptce.base,
-			ptce.count[0],
-			ptce.count[1],
-			ptce.stride[0],
-			ptce.stride[1]);
-
-	p += sprintf(p, "TC Levels                      : %d\n" \
-			"Unique TC(s)                   : %d\n",
-			vm_info_1.pal_vm_info_1_s.num_tc_levels,
-			vm_info_1.pal_vm_info_1_s.max_unique_tcs);
+	p += sprintf(p,
+		     "\nPurge base address             : 0x%016lx\n"
+		     "Purge outer loop count         : %d\n"
+		     "Purge inner loop count         : %d\n"
+		     "Purge outer loop stride        : %d\n"
+		     "Purge inner loop stride        : %d\n",
+		     ptce.base, ptce.count[0], ptce.count[1], ptce.stride[0], ptce.stride[1]);
+
+	p += sprintf(p,
+		     "TC Levels                      : %d\n"
+		     "Unique TC(s)                   : %d\n",
+		     vm_info_1.pal_vm_info_1_s.num_tc_levels,
+		     vm_info_1.pal_vm_info_1_s.max_unique_tcs);
 
 	for(i=0; i < vm_info_1.pal_vm_info_1_s.num_tc_levels; i++) {
 		for (j=2; j>0 ; j--) {
@@ -379,15 +380,14 @@
 				continue;
 			}
 
-			p += sprintf(p, "\n%s Translation Cache Level %d:\n" \
-					"\tHash sets           : %d\n" \
-					"\tAssociativity       : %d\n" \
-					"\tNumber of entries   : %d\n" \
-					"\tFlags               : ",
-					cache_types[j+tc_info.tc_unified], i+1,
-					tc_info.tc_num_sets,
-					tc_info.tc_associativity,
-					tc_info.tc_num_entries);
+			p += sprintf(p,
+				     "\n%s Translation Cache Level %d:\n"
+				     "\tHash sets           : %d\n"
+				     "\tAssociativity       : %d\n"
+				     "\tNumber of entries   : %d\n"
+				     "\tFlags               : ",
+				     cache_types[j+tc_info.tc_unified], i+1, tc_info.tc_num_sets,
+				     tc_info.tc_associativity, tc_info.tc_num_entries);
 
 			if (tc_info.tc_pf) p += sprintf(p, "PreferredPageSizeOptimized ");
 			if (tc_info.tc_unified) p += sprintf(p, "Unified ");
@@ -436,17 +436,18 @@
 
 	if (ia64_pal_rse_info(&phys_stacked, &hints) != 0) return 0;
 
-	p += sprintf(p, "RSE stacked physical registers   : %ld\n" \
-			"RSE load/store hints             : %ld (%s)\n",
-			phys_stacked,
-			hints.ph_data,
-			hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)");
-
-	if (ia64_pal_debug_info(&iregs, &dregs)) return 0;
-
-	p += sprintf(p, "Instruction debug register pairs : %ld\n" \
-			"Data debug register pairs        : %ld\n",
-			iregs, dregs);
+	p += sprintf(p,
+		     "RSE stacked physical registers   : %ld\n"
+		     "RSE load/store hints             : %ld (%s)\n",
+		     phys_stacked, hints.ph_data,
+		     hints.ph_data < RSE_HINTS_COUNT ? rse_hints[hints.ph_data]: "(\?\?)");
+
+	if (ia64_pal_debug_info(&iregs, &dregs))
+		return 0;
+
+	p += sprintf(p,
+		     "Instruction debug register pairs : %ld\n"
+		     "Data debug register pairs        : %ld\n", iregs, dregs);
 
 	return p - page;
 }
@@ -563,26 +564,21 @@
 	 */
 	if (ia64_pal_version(&min_ver, &cur_ver) != 0) return 0;
 
-	p += sprintf(p, "PAL_vendor : 0x%02x (min=0x%02x)\n" \
-			"PAL_A      : %x.%x.%x (min=%x.%x.%x)\n" \
-			"PAL_B      : %x.%x.%x (min=%x.%x.%x)\n",
-			cur_ver.pal_version_s.pv_pal_vendor,
-			min_ver.pal_version_s.pv_pal_vendor,
-
-			cur_ver.pal_version_s.pv_pal_a_model>>4,
-			cur_ver.pal_version_s.pv_pal_a_model&0xf,
-			cur_ver.pal_version_s.pv_pal_a_rev,
-			min_ver.pal_version_s.pv_pal_a_model>>4,
-			min_ver.pal_version_s.pv_pal_a_model&0xf,
-			min_ver.pal_version_s.pv_pal_a_rev,
-
-			cur_ver.pal_version_s.pv_pal_b_model>>4,
-			cur_ver.pal_version_s.pv_pal_b_model&0xf,
-			cur_ver.pal_version_s.pv_pal_b_rev,
-			min_ver.pal_version_s.pv_pal_b_model>>4,
-			min_ver.pal_version_s.pv_pal_b_model&0xf,
-			min_ver.pal_version_s.pv_pal_b_rev);
-
+	p += sprintf(p,
+		     "PAL_vendor : 0x%02x (min=0x%02x)\n"
+		     "PAL_A      : %x.%x.%x (min=%x.%x.%x)\n"
+		     "PAL_B      : %x.%x.%x (min=%x.%x.%x)\n",
+		     cur_ver.pal_version_s.pv_pal_vendor, min_ver.pal_version_s.pv_pal_vendor,
+
+		     cur_ver.pal_version_s.pv_pal_a_model>>4,
+		     cur_ver.pal_version_s.pv_pal_a_model&0xf, cur_ver.pal_version_s.pv_pal_a_rev,
+		     min_ver.pal_version_s.pv_pal_a_model>>4,
+		     min_ver.pal_version_s.pv_pal_a_model&0xf, min_ver.pal_version_s.pv_pal_a_rev,
+
+		     cur_ver.pal_version_s.pv_pal_b_model>>4,
+		     cur_ver.pal_version_s.pv_pal_b_model&0xf, cur_ver.pal_version_s.pv_pal_b_rev,
+		     min_ver.pal_version_s.pv_pal_b_model>>4,
+		     min_ver.pal_version_s.pv_pal_b_model&0xf, min_ver.pal_version_s.pv_pal_b_rev);
 	return p - page;
 }
 
@@ -595,26 +591,20 @@
 
 	if (ia64_pal_perf_mon_info(pm_buffer, &pm_info) != 0) return 0;
 
-	p += sprintf(p, "PMC/PMD pairs                 : %d\n" \
-			"Counter width                 : %d bits\n" \
-			"Cycle event number            : %d\n" \
-			"Retired event number          : %d\n" \
-			"Implemented PMC               : ",
-			pm_info.pal_perf_mon_info_s.generic,
-			pm_info.pal_perf_mon_info_s.width,
-			pm_info.pal_perf_mon_info_s.cycles,
-			pm_info.pal_perf_mon_info_s.retired);
+	p += sprintf(p,
+		     "PMC/PMD pairs                 : %d\n"
+		     "Counter width                 : %d bits\n"
+		     "Cycle event number            : %d\n"
+		     "Retired event number          : %d\n"
+		     "Implemented PMC               : ",
+		     pm_info.pal_perf_mon_info_s.generic, pm_info.pal_perf_mon_info_s.width,
+		     pm_info.pal_perf_mon_info_s.cycles, pm_info.pal_perf_mon_info_s.retired);
 
 	p = bitregister_process(p, pm_buffer, 256);
-
 	p += sprintf(p, "\nImplemented PMD               : ");
-
 	p = bitregister_process(p, pm_buffer+4, 256);
-
 	p += sprintf(p, "\nCycles count capable          : ");
-
 	p = bitregister_process(p, pm_buffer+8, 256);
-
 	p += sprintf(p, "\nRetired bundles count capable : ");
 
 #ifdef CONFIG_ITANIUM
@@ -646,12 +636,11 @@
 
 	if (ia64_pal_freq_ratios(&proc, &bus, &itc) != 0) return 0;
 
-	p += sprintf(p, "Processor/Clock ratio   : %ld/%ld\n" \
-			"Bus/Clock ratio         : %ld/%ld\n" \
-			"ITC/Clock ratio         : %ld/%ld\n",
-			proc.num, proc.den,
-			bus.num, bus.den,
-			itc.num, itc.den);
+	p += sprintf(p,
+		     "Processor/Clock ratio   : %ld/%ld\n"
+		     "Bus/Clock ratio         : %ld/%ld\n"
+		     "ITC/Clock ratio         : %ld/%ld\n",
+		     proc.num, proc.den, bus.num, bus.den, itc.num, itc.den);
 
 	return p - page;
 }
@@ -665,7 +654,7 @@
 	u64 tr_buffer[4];
 	pal_vm_info_1_u_t vm_info_1;
 	pal_vm_info_2_u_t vm_info_2;
-	int i, j;
+	u64 i, j;
 	u64 max[3], pgm;
 	struct ifa_reg {
 		u64 valid:1;
@@ -711,7 +700,7 @@
 
 		status = ia64_pal_tr_read(j, i, tr_buffer, &tr_valid);
 		if (status != 0) {
-			printk(KERN_ERR "palinfo: pal call failed on tr[%d:%d]=%ld\n",
+			printk(KERN_ERR "palinfo: pal call failed on tr[%lu:%lu]=%ld\n",
 			       i, j, status);
 			continue;
 		}
@@ -725,34 +714,29 @@
 		rid_reg  = (struct rid_reg *)&tr_buffer[3];
 
 		pgm	 = -1 << (itir_reg->ps - 12);
-		p += sprintf(p, "%cTR%d: av=%d pv=%d dv=%d mv=%d\n" \
-				"\tppn  : 0x%lx\n" \
-				"\tvpn  : 0x%lx\n" \
-				"\tps   : ",
-
-				"ID"[i],
-				j,
-				tr_valid.pal_tr_valid_s.access_rights_valid,
-				tr_valid.pal_tr_valid_s.priv_level_valid,
-				tr_valid.pal_tr_valid_s.dirty_bit_valid,
-				tr_valid.pal_tr_valid_s.mem_attr_valid,
-				(gr_reg->ppn & pgm)<< 12,
-				(ifa_reg->vpn & pgm)<< 12);
+		p += sprintf(p,
+			     "%cTR%lu: av=%d pv=%d dv=%d mv=%d\n"
+			     "\tppn  : 0x%lx\n"
+			     "\tvpn  : 0x%lx\n"
+			     "\tps   : ",
+			     "ID"[i], j,
+			     tr_valid.pal_tr_valid_s.access_rights_valid,
+			     tr_valid.pal_tr_valid_s.priv_level_valid,
+			     tr_valid.pal_tr_valid_s.dirty_bit_valid,
+			     tr_valid.pal_tr_valid_s.mem_attr_valid,
+			     (gr_reg->ppn & pgm)<< 12, (ifa_reg->vpn & pgm)<< 12);
 
 		p = bitvector_process(p, 1<< itir_reg->ps);
 
-		p += sprintf(p, "\n\tpl   : %d\n" \
-				"\tar   : %d\n" \
-				"\trid  : %x\n" \
-				"\tp    : %d\n" \
-				"\tma   : %d\n" \
-				"\td    : %d\n",
-				gr_reg->pl,
-				gr_reg->ar,
-				rid_reg->rid,
-				gr_reg->p,
-				gr_reg->ma,
-				gr_reg->d);
+		p += sprintf(p,
+			     "\n\tpl   : %d\n"
+			     "\tar   : %d\n"
+			     "\trid  : %x\n"
+			     "\tp    : %d\n"
+			     "\tma   : %d\n"
+			     "\td    : %d\n",
+			     gr_reg->pl, gr_reg->ar, rid_reg->rid, gr_reg->p, gr_reg->ma,
+			     gr_reg->d);
 		}
 	}
 	return p - page;
@@ -776,7 +760,7 @@
 	{ "tr_info",		tr_info, }
 };
 
-#define NR_PALINFO_ENTRIES	(sizeof(palinfo_entries)/sizeof(palinfo_entry_t))
+#define NR_PALINFO_ENTRIES	(int) ARRAY_SIZE(palinfo_entries)
 
 /*
  * this array is used to keep track of the proc entries we create. This is
diff -Nru a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
--- a/arch/ia64/kernel/perfmon.c	Thu Apr 24 03:37:07 2003
+++ b/arch/ia64/kernel/perfmon.c	Sat May 10 02:28:46 2003
@@ -2,7 +2,7 @@
  * This file implements the perfmon subsystem which is used
  * to program the IA-64 Performance Monitoring Unit (PMU).
  *
- * Originaly Written by Ganesh Venkitachalam, IBM Corp.
+ * Originally Written by Ganesh Venkitachalam, IBM Corp.
  * Copyright (C) 1999 Ganesh Venkitachalam <venkitac@us.ibm.com>
  *
  * Modifications by Stephane Eranian, Hewlett-Packard Co.
@@ -224,8 +224,9 @@
 	unsigned int protected:1;	/* allow access to creator of context only */
 	unsigned int using_dbreg:1;	/* using range restrictions (debug registers) */
 	unsigned int excl_idle:1;	/* exclude idle task in system wide session */
+	unsigned int unsecure:1;	/* sp = 0 for non self-monitored task */
 	unsigned int trap_reason:2;	/* reason for going into pfm_block_ovfl_reset() */
-	unsigned int reserved:21;
+	unsigned int reserved:20;
 } pfm_context_flags_t;
 
 #define PFM_TRAP_REASON_NONE		0x0	/* default value */
@@ -278,6 +279,7 @@
 #define ctx_fl_using_dbreg	ctx_flags.using_dbreg
 #define ctx_fl_excl_idle	ctx_flags.excl_idle
 #define ctx_fl_trap_reason	ctx_flags.trap_reason
+#define ctx_fl_unsecure		ctx_flags.unsecure
 
 /*
  * global information about all sessions
@@ -362,8 +364,9 @@
 
 #define PFM_CMD_IDX(cmd)	(cmd)
 
-#define PFM_CMD_IS_VALID(cmd)	((PFM_CMD_IDX(cmd) >= 0) && (PFM_CMD_IDX(cmd) < PFM_CMD_COUNT) \
-				  && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL)
+#define PFM_CMD_IS_VALID(cmd)	((PFM_CMD_IDX(cmd) >= 0)				\
+				 && (PFM_CMD_IDX(cmd) < (int) PFM_CMD_COUNT)		\
+				 && pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_func != NULL)
 
 #define PFM_CMD_USE_PID(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_PID) != 0)
 #define PFM_CMD_READ_ARG(cmd)	((pfm_cmd_tab[PFM_CMD_IDX(cmd)].cmd_flags & PFM_CMD_ARG_READ) != 0)
@@ -646,7 +649,7 @@
 
 /*
  * This function is called from pfm_destroy_context() and also from pfm_inherit()
- * to explicitely remove the sampling buffer mapping from the user level address space.
+ * to explicitly remove the sampling buffer mapping from the user level address space.
  */
 static int
 pfm_remove_smpl_mapping(struct task_struct *task)
@@ -724,8 +727,7 @@
 static unsigned long
 pfm_smpl_entry_size(unsigned long *which, unsigned long size)
 {
-	unsigned long res = 0;
-	int i;
+	unsigned long i, res = 0;
 
 	for (i=0; i < size; i++, which++) res += hweight64(*which);
 
@@ -1076,10 +1078,15 @@
 		 * and it must be a valid CPU
 		 */
 		cpu = ffz(~pfx->ctx_cpu_mask);
+#ifdef CONFIG_SMP
 		if (cpu_online(cpu) == 0) {
+#else
+		if (cpu != 0) {
+#endif
 			DBprintk(("CPU%d is not online\n", cpu));
 			return -EINVAL;
 		}
+
 		/*
 		 * check for pre-existing pinning, if conflicting reject
 		 */
@@ -1225,6 +1232,7 @@
 	ctx->ctx_fl_block     = (ctx_flags & PFM_FL_NOTIFY_BLOCK) ? 1 : 0;
 	ctx->ctx_fl_system    = (ctx_flags & PFM_FL_SYSTEM_WIDE) ? 1: 0;
 	ctx->ctx_fl_excl_idle = (ctx_flags & PFM_FL_EXCL_IDLE) ? 1: 0;
+	ctx->ctx_fl_unsecure  = (ctx_flags & PFM_FL_UNSECURE) ? 1: 0;
 	ctx->ctx_fl_frozen    = 0;
 	ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE;
 
@@ -1251,9 +1259,11 @@
 	DBprintk(("context=%p, pid=%d notify_task=%p\n",
 			(void *)ctx, task->pid, ctx->ctx_notify_task));
 
-	DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d\n", 
+	DBprintk(("context=%p, pid=%d flags=0x%x inherit=%d block=%d system=%d excl_idle=%d unsecure=%d\n", 
 			(void *)ctx, task->pid, ctx_flags, ctx->ctx_fl_inherit, 
-			ctx->ctx_fl_block, ctx->ctx_fl_system, ctx->ctx_fl_excl_idle));
+			ctx->ctx_fl_block, ctx->ctx_fl_system, 
+			ctx->ctx_fl_excl_idle,
+			ctx->ctx_fl_unsecure));
 
 	/*
 	 * when no notification is required, we can make this visible at the last moment
@@ -1659,7 +1669,7 @@
 		if (!PMD_IS_IMPL(cnum)) goto abort_mission;
 		/*
 		 * we can only read the register that we use. That includes
-		 * the one we explicitely initialize AND the one we want included
+		 * the one we explicitly initialize AND the one we want included
 		 * in the sampling buffer (smpl_regs).
 		 *
 		 * Having this restriction allows optimization in the ctxsw routine
@@ -1871,7 +1881,7 @@
 	 * if blocking, then post the semaphore.
 	 * if non-blocking, then we ensure that the task will go into
 	 * pfm_overflow_must_block() before returning to user mode. 
-	 * We cannot explicitely reset another task, it MUST always
+	 * We cannot explicitly reset another task, it MUST always
 	 * be done by the task itself. This works for system wide because
 	 * the tool that is controlling the session is doing "self-monitoring".
 	 *
@@ -1882,7 +1892,10 @@
 		DBprintk(("unblocking %d \n", task->pid));
 		up(sem);
 	} else {
+		struct thread_info *info = (struct thread_info *) ((char *) task + IA64_TASK_SIZE);
 		task->thread.pfm_ovfl_block_reset = 1;
+		ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_RESET;
+		set_bit(TIF_NOTIFY_RESUME, &info->flags);
 	}
 #if 0
 	/*
@@ -2051,7 +2064,7 @@
 	/*
 	 * reinforce secure monitoring: cannot toggle psr.up
 	 */
-	ia64_psr(regs)->sp = 1;
+	if (ctx->ctx_fl_unsecure == 0) ia64_psr(regs)->sp = 1;
 
 	return 0;
 }
@@ -2159,11 +2172,11 @@
 		 * never leaves the current CPU and the state
 		 * is shared by all processes running on it
 	 	 */
-		for (i=0; i < pmu_conf.num_ibrs; i++) {
+		for (i=0; i < (int) pmu_conf.num_ibrs; i++) {
 			ia64_set_ibr(i, 0UL);
 		}
 		ia64_srlz_i();
-		for (i=0; i < pmu_conf.num_dbrs; i++) {
+		for (i=0; i < (int) pmu_conf.num_dbrs; i++) {
 			ia64_set_dbr(i, 0UL);
 		}
 		ia64_srlz_d();
@@ -2505,7 +2518,7 @@
 /* 33 */{ pfm_write_dbrs, PFM_CMD_PID|PFM_CMD_CTX|PFM_CMD_ARG_RW, PFM_CMD_ARG_MANY, sizeof(pfarg_dbreg_t)}
 #endif
 };
-#define PFM_CMD_COUNT	(sizeof(pfm_cmd_tab)/sizeof(pfm_cmd_desc_t))
+#define PFM_CMD_COUNT	ARRAY_SIZE(pfm_cmd_tab)
 
 static int
 check_task_state(struct task_struct *task)
@@ -2732,12 +2745,13 @@
 	 * again
 	 */
 	th->pfm_ovfl_block_reset = 0;
+	clear_thread_flag(TIF_NOTIFY_RESUME);
 
 	/*
 	 * do some sanity checks first
 	 */
 	if (!ctx) {
-		printk(KERN_DEBUG "perfmon: [%d] has no PFM context\n", current->pid);
+		printk(KERN_ERR "perfmon: [%d] has no PFM context\n", current->pid);
 		return;
 	}
 	/*
@@ -2899,15 +2913,18 @@
 
 /*
  * main overflow processing routine.
- * it can be called from the interrupt path or explicitely during the context switch code
+ * it can be called from the interrupt path or explicitly during the context switch code
+ * Arguments:
+ *	mode: 0=coming from PMU interrupt, 1=coming from ctxsw 
+ *	
  * Return:
  *	new value of pmc[0]. if 0x0 then unfreeze, else keep frozen
  */
 static unsigned long
-pfm_overflow_handler(struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs)
+pfm_overflow_handler(int mode, struct task_struct *task, pfm_context_t *ctx, u64 pmc0, struct pt_regs *regs)
 {
-	unsigned long mask;
 	struct thread_struct *t;
+	unsigned long mask;
 	unsigned long old_val;
 	unsigned long ovfl_notify = 0UL, ovfl_pmds = 0UL;
 	int i;
@@ -2998,10 +3015,10 @@
 	/*
 	 * check for sampling buffer
 	 *
-	 * if present, record sample. We propagate notification ONLY when buffer
-	 * becomes full.
+	 * if present, record sample only when a 64-bit counter has overflowed.
+	 * We propagate notification ONLY when buffer becomes full.
 	 */
-	if(CTX_HAS_SMPL(ctx)) {
+	if(CTX_HAS_SMPL(ctx) && ovfl_pmds) {
 		ret = pfm_record_sample(task, ctx, ovfl_pmds, regs);
 		if (ret == 1) {
 			/*
@@ -3046,12 +3063,55 @@
 	 * ctx_notify_task could already be NULL, checked in pfm_notify_user() 
 	 */
 	if (CTX_OVFL_NOBLOCK(ctx) == 0 && ctx->ctx_notify_task != task) {
-		t->pfm_ovfl_block_reset = 1; /* will cause blocking */
 		ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_BLOCKSIG;
 	} else {
-		t->pfm_ovfl_block_reset = 1; /* will cause blocking */
 		ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_SIG;
 	}
+	/*
+	 * we cannot block in system wide mode and we do not go
+	 * through the PMU ctxsw code. Therefore we can generate
+	 * the notification here. In system wide mode, the current
+	 * task maybe different from the task controlling the session
+	 * on this CPU, therefore owner can be different from current.
+	 *
+	 * In per-process mode, this function gets called from 
+	 * the interrupt handler or pfm_load_regs(). The mode argument
+	 * tells where we are coming from. When coming from the interrupt
+	 * handler, it is safe to notify (send signal) right here because
+	 * we do not hold any runqueue locks needed by send_sig_info(). 
+	 *
+	 * However when coming from ctxsw, we cannot send the signal here.
+	 * It must be deferred until we are sure we do not hold any runqueue
+	 * related locks. The current task maybe different from the owner
+	 * only in UP mode. The deferral is implemented using the 
+	 * TIF_NOTIFY_RESUME mechanism. In this case, the pending work
+	 * is checked when the task is about to leave the kernel (see
+	 * entry.S). As of this version of perfmon, a kernel only
+	 * task cannot be monitored in per-process mode. Therefore,
+	 * when this function gets called from pfm_load_regs(), we know
+	 * we have a user level task which will eventually either exit
+	 * or leave the kernel, and thereby go through the checkpoint
+	 * for TIF_*.
+	 */
+	if (ctx->ctx_fl_system || mode == 0) {
+		pfm_notify_user(ctx);
+		ctx->ctx_fl_trap_reason = PFM_TRAP_REASON_NONE;
+	} else {
+		struct thread_info *info;
+
+		/*
+		 * given that TIF_NOTIFY_RESUME is not specific to
+		 * perfmon, we need to have a second level check to
+		 * verify the source of the notification.
+		 */
+		task->thread.pfm_ovfl_block_reset = 1;
+		/*
+		 * when coming from ctxsw, current still points to the
+		 * previous task, therefore we must work with task and not current.
+		 */
+		info = ((struct thread_info *) ((char *) task + IA64_TASK_SIZE));
+		set_bit(TIF_NOTIFY_RESUME, &info->flags);
+	}
 
 	/*
 	 * keep the PMU frozen until either pfm_restart() or 
@@ -3059,7 +3119,10 @@
 	 */
 	ctx->ctx_fl_frozen = 1;
 
-	DBprintk_ovfl(("return pmc0=0x%x must_block=%ld reason=%d\n",
+	DBprintk_ovfl(("current [%d] owner [%d] mode=%d return pmc0=0x%x must_block=%ld reason=%d\n",
+		current->pid, 
+		PMU_OWNER() ? PMU_OWNER()->pid : -1,
+		mode,
 		ctx->ctx_fl_frozen ? 0x1 : 0x0, 
 		t->pfm_ovfl_block_reset,
 		ctx->ctx_fl_trap_reason));
@@ -3068,7 +3131,7 @@
 	return 0x1UL;
 }
 
-static void
+static irqreturn_t
 pfm_interrupt_handler(int irq, void *arg, struct pt_regs *regs)
 {
 	u64 pmc0;
@@ -3083,7 +3146,7 @@
 	if (pfm_alternate_intr_handler) {
 		(*pfm_alternate_intr_handler->handler)(irq, arg, regs);
 		put_cpu();
-		return;
+		return IRQ_HANDLED;
 	}
 
 	/* 
@@ -3108,19 +3171,21 @@
 			printk(KERN_DEBUG "perfmon: Spurious overflow interrupt: process %d has "
 			       "no PFM context\n", task->pid);
 			put_cpu();
-			return;
+			return IRQ_HANDLED;
 		}
 
 		/* 
 		 * assume PMC[0].fr = 1 at this point 
 		 */
-		pmc0 = pfm_overflow_handler(task, ctx, pmc0, regs);
+		pmc0 = pfm_overflow_handler(0, task, ctx, pmc0, regs);
 		/*
 		 * we can only update pmc0 when the overflow
-		 * is for the current context. In UP the current
-		 * task may not be the one owning the PMU
+		 * is for the current context or we are in system
+		 * wide mode. In UP (per-task) the current
+		 * task may not be the one owning the PMU,
+		 * same thing for system-wide.
 		 */
-		if (task == current) {
+		if (task == current || ctx->ctx_fl_system) {
 			/*
 		 	 * We always clear the overflow status bits and either unfreeze
 		 	 * or keep the PMU frozen.
@@ -3134,6 +3199,7 @@
 		pfm_stats[smp_processor_id()].pfm_spurious_ovfl_intr_count++;
 	}
 	put_cpu_no_resched();
+	return IRQ_HANDLED;
 }
 
 /* for debug only */
@@ -3387,11 +3453,11 @@
 	 * in the next version of perfmon.
 	 */
 	if (ctx->ctx_fl_using_dbreg) {
-		for (i=0; i < pmu_conf.num_ibrs; i++) {
+		for (i=0; i < (int) pmu_conf.num_ibrs; i++) {
 			ia64_set_ibr(i, t->ibr[i]);
 		}
 		ia64_srlz_i();
-		for (i=0; i < pmu_conf.num_dbrs; i++) {
+		for (i=0; i < (int) pmu_conf.num_dbrs; i++) {
 			ia64_set_dbr(i, t->dbr[i]);
 		}
 		ia64_srlz_d();
@@ -3402,7 +3468,7 @@
 	 * this path cannot be used in SMP
 	 */
 	if (owner == task) {
-		if (atomic_read(&ctx->ctx_last_cpu) != smp_processor_id())
+		if ((unsigned int) atomic_read(&ctx->ctx_last_cpu) != smp_processor_id())
 			DBprintk(("invalid last_cpu=%d for [%d]\n", 
 				atomic_read(&ctx->ctx_last_cpu), task->pid));
 
@@ -3454,7 +3520,7 @@
 	 * Side effect on ctx_fl_frozen is possible.
 	 */
 	if (t->pmc[0] & ~0x1) {
-		t->pmc[0] = pfm_overflow_handler(task, ctx, t->pmc[0], NULL);
+		t->pmc[0] = pfm_overflow_handler(1, task, ctx, t->pmc[0], NULL);
 	}
 
 	/*
@@ -3676,7 +3742,7 @@
 	 *
 	 */
 
-	if (atomic_read(&ctx->ctx_last_cpu) != smp_processor_id())
+	if ((unsigned int) atomic_read(&ctx->ctx_last_cpu) != smp_processor_id())
 		printk(KERN_DEBUG "perfmon: [%d] last_cpu=%d\n",
 		       task->pid, atomic_read(&ctx->ctx_last_cpu));
 
@@ -3754,16 +3820,20 @@
 
 	preempt_disable();
 	/*
-	 * make sure child cannot mess up the monitoring session
+	 * for secure sessions, make sure child cannot mess up 
+	 * the monitoring session.
 	 */
-	 ia64_psr(regs)->sp = 1;
-	 DBprintk(("enabling psr.sp for [%d]\n", task->pid));
-
+	if (ctx->ctx_fl_unsecure == 0) {
+		ia64_psr(regs)->sp = 1;
+	 	DBprintk(("enabling psr.sp for [%d]\n", task->pid));
+	} else {
+	 	DBprintk(("psr.sp=%d [%d]\n", ia64_psr(regs)->sp, task->pid));
+	}
 
 	/*
 	 * if there was a virtual mapping for the sampling buffer
 	 * the mapping is NOT inherited across fork() (see VM_DONTCOPY), 
-	 * so we don't have to explicitely remove it here. 
+	 * so we don't have to explicitly remove it here. 
 	 *
 	 *
 	 * Part of the clearing of fields is also done in
diff -Nru a/arch/ia64/kernel/perfmon_mckinley.h b/arch/ia64/kernel/perfmon_mckinley.h
--- a/arch/ia64/kernel/perfmon_mckinley.h	Tue Feb  4 17:06:13 2003
+++ b/arch/ia64/kernel/perfmon_mckinley.h	Thu Apr 10 06:46:37 2003
@@ -25,8 +25,8 @@
 /* pmc5  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(5),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
 /* pmc6  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(6),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
 /* pmc7  */ { PFM_REG_COUNTING, 6, 0x0UL, 0xfffff7fUL, NULL,  pfm_mck_reserved, {RDEP(7),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xffffffff3fffffffUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
-/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xffffffff3ffffffcUL, 0xffffffff9fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc8  */ { PFM_REG_CONFIG  , 0, 0xffffffff3fffffffUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
+/* pmc9  */ { PFM_REG_CONFIG  , 0, 0xffffffff3ffffffcUL, 0xffffffff3fffffffUL, NULL, pfm_mck_pmc_check, {0UL,0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
 /* pmc10 */ { PFM_REG_MONITOR , 4, 0x0UL, 0xffffUL, NULL, pfm_mck_reserved, {RDEP(0)|RDEP(1),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
 /* pmc11 */ { PFM_REG_MONITOR , 6, 0x0UL, 0x30f01cf, NULL,  pfm_mck_reserved, {RDEP(2)|RDEP(3)|RDEP(17),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
 /* pmc12 */ { PFM_REG_MONITOR , 6, 0x0UL, 0xffffUL, NULL,  pfm_mck_reserved, {RDEP(8)|RDEP(9)|RDEP(10)|RDEP(11)|RDEP(12)|RDEP(13)|RDEP(14)|RDEP(15)|RDEP(16),0UL, 0UL, 0UL}, {0UL,0UL, 0UL, 0UL}},
@@ -143,10 +143,7 @@
 		case  8: val8 = *val;
 			 val13 = th->pmc[13];
 			 val14 = th->pmc[14];
-			 *val |= 1UL << 2; /* bit 2 must always be 1 */
 			 check_case1 = 1;
-			 break;
-		case  9: *val |= 1UL << 2; /* bit 2 must always be 1 */
 			 break;
 		case 13: val8  = th->pmc[8];
 			 val13 = *val;
diff -Nru a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c
--- a/arch/ia64/kernel/process.c	Thu Mar 27 02:29:02 2003
+++ b/arch/ia64/kernel/process.c	Sat May 10 02:28:46 2003
@@ -43,8 +43,8 @@
 
 #include "sigframe.h"
 
-static void
-do_show_stack (struct unw_frame_info *info, void *arg)
+void
+ia64_do_show_stack (struct unw_frame_info *info, void *arg)
 {
 	unsigned long ip, sp, bsp;
 	char buf[80];			/* don't make it so big that it overflows the stack! */
@@ -57,7 +57,7 @@
 
 		unw_get_sp(info, &sp);
 		unw_get_bsp(info, &bsp);
-		snprintf(buf, sizeof(buf), " [<%016lx>] %%s sp=0x%016lx bsp=0x%016lx\n",
+		snprintf(buf, sizeof(buf), " [<%016lx>] %%s\n\t\t\t\tsp=%016lx bsp=%016lx\n",
 			 ip, sp, bsp);
 		print_symbol(buf, ip);
 	} while (unw_unwind(info) >= 0);
@@ -73,12 +73,12 @@
 show_stack (struct task_struct *task)
 {
 	if (!task)
-		unw_init_running(do_show_stack, 0);
+		unw_init_running(ia64_do_show_stack, 0);
 	else {
 		struct unw_frame_info info;
 
 		unw_init_from_blocked_task(&info, task);
-		do_show_stack(&info, 0);
+		ia64_do_show_stack(&info, 0);
 	}
 }
 
@@ -123,8 +123,8 @@
 
 	if (user_mode(regs)) {
 		/* print the stacked registers */
-		unsigned long val, sof, *bsp, ndirty;
-		int i, is_nat = 0;
+		unsigned long val, *bsp, ndirty;
+		int i, sof, is_nat = 0;
 
 		sof = regs->cr_ifs & 0x7f;	/* size of frame */
 		ndirty = (regs->loadrs >> 19);
@@ -135,7 +135,7 @@
 			       ((i == sof - 1) || (i % 3) == 2) ? "\n" : " ");
 		}
 	} else
-		show_stack(0);
+		show_stack(NULL);
 }
 
 void
@@ -379,6 +379,7 @@
 #	define THREAD_FLAGS_TO_SET	0
 	p->thread.flags = ((current->thread.flags & ~THREAD_FLAGS_TO_CLEAR)
 			   | THREAD_FLAGS_TO_SET);
+	p->thread.last_fph_cpu = -1;
 #ifdef CONFIG_IA32_SUPPORT
 	/*
 	 * If we're cloning an IA32 task then save the IA32 extra
diff -Nru a/arch/ia64/kernel/ptrace.c b/arch/ia64/kernel/ptrace.c
--- a/arch/ia64/kernel/ptrace.c	Thu Mar  6 14:56:33 2003
+++ b/arch/ia64/kernel/ptrace.c	Sat May 10 02:28:46 2003
@@ -202,17 +202,16 @@
 get_rnat (struct pt_regs *pt, struct switch_stack *sw,
 	  unsigned long *krbs, unsigned long *urnat_addr)
 {
-	unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, kmask = ~0UL;
+	unsigned long rnat0 = 0, rnat1 = 0, urnat = 0, *slot0_kaddr, umask = 0UL;
 	unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift;
 	long num_regs;
 
 	kbsp = (unsigned long *) sw->ar_bspstore;
 	ubspstore = (unsigned long *) pt->ar_bspstore;
 	/*
-	 * First, figure out which bit number slot 0 in user-land maps
-	 * to in the kernel rnat.  Do this by figuring out how many
-	 * register slots we're beyond the user's backingstore and
-	 * then computing the equivalent address in kernel space.
+	 * First, figure out which bit number slot 0 in user-land maps to in the kernel
+	 * rnat.  Do this by figuring out how many register slots we're beyond the user's
+	 * backingstore and then computing the equivalent address in kernel space.
 	 */
 	num_regs = ia64_rse_num_regs(ubspstore, urnat_addr + 1);
 	slot0_kaddr = ia64_rse_skip_regs(krbs, num_regs);
@@ -222,8 +221,8 @@
 
 	if (ubspstore + 63 > urnat_addr) {
 		/* some bits need to be merged in from pt->ar_rnat */
-		kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1);
-		urnat = (pt->ar_rnat & ~kmask);
+		umask = ((1UL << ia64_rse_slot_num(ubspstore)) - 1);
+		urnat = (pt->ar_rnat & umask);
 	}
 	if (rnat0_kaddr >= kbsp) {
 		rnat0 = sw->ar_rnat;
@@ -235,7 +234,7 @@
 	} else if (rnat1_kaddr > krbs) {
 		rnat1 = *rnat1_kaddr;
 	}
-	urnat |= ((rnat1 << (63 - shift)) | (rnat0 >> shift)) & kmask;
+	urnat |= ((rnat1 << (63 - shift)) | (rnat0 >> shift)) & ~umask;
 	return urnat;
 }
 
@@ -246,17 +245,19 @@
 put_rnat (struct pt_regs *pt, struct switch_stack *sw,
 	  unsigned long *krbs, unsigned long *urnat_addr, unsigned long urnat)
 {
-	unsigned long rnat0 = 0, rnat1 = 0, rnat = 0, *slot0_kaddr, kmask = ~0UL, mask;
-	unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift;
-	long num_regs;
+	unsigned long rnat0 = 0, rnat1 = 0, *slot0_kaddr, umask = 0, mask, m;
+	unsigned long *kbsp, *ubspstore, *rnat0_kaddr, *rnat1_kaddr, shift, slot, ndirty;
+	long num_regs, nbits;
+
+	ndirty = ia64_rse_num_regs(krbs, krbs + (pt->loadrs >> 19));
+	nbits = ndirty % 63;
 
 	kbsp = (unsigned long *) sw->ar_bspstore;
 	ubspstore = (unsigned long *) pt->ar_bspstore;
 	/*
-	 * First, figure out which bit number slot 0 in user-land maps
-	 * to in the kernel rnat.  Do this by figuring out how many
-	 * register slots we're beyond the user's backingstore and
-	 * then computing the equivalent address in kernel space.
+	 * First, figure out which bit number slot 0 in user-land maps to in the kernel
+	 * rnat.  Do this by figuring out how many register slots we're beyond the user's
+	 * backingstore and then computing the equivalent address in kernel space.
 	 */
 	num_regs = (long) ia64_rse_num_regs(ubspstore, urnat_addr + 1);
 	slot0_kaddr = ia64_rse_skip_regs(krbs, num_regs);
@@ -264,29 +265,37 @@
 	rnat1_kaddr = ia64_rse_rnat_addr(slot0_kaddr);
 	rnat0_kaddr = rnat1_kaddr - 64;
 
+printk("%s: ubspstore=%p urnat_addr=%p\n", __FUNCTION__, ubspstore, urnat_addr);
 	if (ubspstore + 63 > urnat_addr) {
 		/* some bits need to be place in pt->ar_rnat: */
-		kmask = ~((1UL << ia64_rse_slot_num(ubspstore)) - 1);
-		pt->ar_rnat = (pt->ar_rnat & kmask) | (rnat & ~kmask);
+		slot = ia64_rse_slot_num(ubspstore);
+		umask = ((1UL << slot) - 1);
+		pt->ar_rnat = (pt->ar_rnat & ~umask) | (urnat & umask);
+		nbits -= slot;
+		if (nbits <= 0)
+			return;
 	}
+	mask = (1UL << nbits) - 1;
 	/*
 	 * Note: Section 11.1 of the EAS guarantees that bit 63 of an
 	 * rnat slot is ignored. so we don't have to clear it here.
 	 */
 	rnat0 = (urnat << shift);
-	mask = ~0UL << shift;
+	m = mask << shift;
+printk("%s: rnat0=%016lx, m=%016lx, rnat0_kaddr=%p kbsp=%p\n", __FUNCTION__, rnat0, m, rnat0_kaddr, kbsp);
 	if (rnat0_kaddr >= kbsp) {
-		sw->ar_rnat = (sw->ar_rnat & ~mask) | (rnat0 & mask);
+		sw->ar_rnat = (sw->ar_rnat & ~m) | (rnat0 & m);
 	} else if (rnat0_kaddr > krbs) {
-		*rnat0_kaddr = ((*rnat0_kaddr & ~mask) | (rnat0 & mask));
+		*rnat0_kaddr = ((*rnat0_kaddr & ~m) | (rnat0 & m));
 	}
 
 	rnat1 = (urnat >> (63 - shift));
-	mask = ~0UL >> (63 - shift);
+	m = mask >> (63 - shift);
+printk("%s: rnat1=%016lx, m=%016lx, rnat1_kaddr=%p kbsp=%p\n", __FUNCTION__, rnat1, m, rnat1_kaddr, kbsp);
 	if (rnat1_kaddr >= kbsp) {
-		sw->ar_rnat = (sw->ar_rnat & ~mask) | (rnat1 & mask);
+		sw->ar_rnat = (sw->ar_rnat & ~m) | (rnat1 & m);
 	} else if (rnat1_kaddr > krbs) {
-		*rnat1_kaddr = ((*rnat1_kaddr & ~mask) | (rnat1 & mask));
+		*rnat1_kaddr = ((*rnat1_kaddr & ~m) | (rnat1 & m));
 	}
 }
 
@@ -589,6 +598,7 @@
 		psr->mfh = 0;
 		ia64_save_fpu(&task->thread.fph[0]);
 		task->thread.flags |= IA64_THREAD_FPH_VALID;
+		task->thread.last_fph_cpu = smp_processor_id();
 	}
 }
 
@@ -608,12 +618,11 @@
 	ia64_flush_fph(task);
 	if (!(task->thread.flags & IA64_THREAD_FPH_VALID)) {
 		task->thread.flags |= IA64_THREAD_FPH_VALID;
+		task->thread.last_fph_cpu = -1;		/* force reload */
 		memset(&task->thread.fph, 0, sizeof(task->thread.fph));
 	}
-#ifndef CONFIG_SMP
 	if (ia64_get_fpu_owner() == task)
 		ia64_set_fpu_owner(0);
-#endif
 	psr->dfh = 1;
 }
 
@@ -702,7 +711,9 @@
 		      case PT_R4: case PT_R5: case PT_R6: case PT_R7:
 			if (write_access) {
 				/* read NaT bit first: */
-				ret = unw_get_gr(&info, (addr - PT_R4)/8 + 4, data, &nat);
+				unsigned long dummy;
+
+				ret = unw_get_gr(&info, (addr - PT_R4)/8 + 4, &dummy, &nat);
 				if (ret < 0)
 					return ret;
 			}
diff -Nru a/arch/ia64/kernel/sal.c b/arch/ia64/kernel/sal.c
--- a/arch/ia64/kernel/sal.c	Tue Feb  4 17:06:14 2003
+++ b/arch/ia64/kernel/sal.c	Tue Apr 22 19:45:56 2003
@@ -116,7 +116,7 @@
 	p = (char *) (systab + 1);
 	for (i = 0; i < systab->entry_count; i++) {
 		/*
-		 * The first byte of each entry type contains the type desciptor.
+		 * The first byte of each entry type contains the type descriptor.
 		 */
 		switch (*p) {
 		      case SAL_DESC_ENTRY_POINT:
diff -Nru a/arch/ia64/kernel/salinfo.c b/arch/ia64/kernel/salinfo.c
--- a/arch/ia64/kernel/salinfo.c	Sun Dec  1 22:17:31 2002
+++ b/arch/ia64/kernel/salinfo.c	Sat May 10 02:28:46 2003
@@ -38,7 +38,7 @@
 	{ "itc_drift",		IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT, },
 };
 
-#define NR_SALINFO_ENTRIES (sizeof(salinfo_entries)/sizeof(salinfo_entry_t))
+#define NR_SALINFO_ENTRIES ARRAY_SIZE(salinfo_entries)
 
 /*
  * One for each feature and one more for the directory entry...
diff -Nru a/arch/ia64/kernel/setup.c b/arch/ia64/kernel/setup.c
--- a/arch/ia64/kernel/setup.c	Sun Apr 20 09:14:40 2003
+++ b/arch/ia64/kernel/setup.c	Sat May 10 02:28:46 2003
@@ -59,7 +59,10 @@
 struct ia64_boot_param *ia64_boot_param;
 struct screen_info screen_info;
 
+unsigned long ia64_max_cacheline_size;
 unsigned long ia64_iobase;	/* virtual address for I/O accesses */
+struct io_space io_space[MAX_IO_SPACES];
+unsigned int num_io_spaces;
 
 unsigned char aux_device_present = 0xaa;        /* XXX remove this when legacy I/O is gone */
 
@@ -412,6 +415,11 @@
 	}
 	ia64_iobase = (unsigned long) ioremap(phys_iobase, 0);
 
+	/* setup legacy IO port space */
+	io_space[0].mmio_base = ia64_iobase;
+	io_space[0].sparse = 1;
+	num_io_spaces = 1;
+
 #ifdef CONFIG_SMP
 	cpu_physical_id(0) = hard_smp_processor_id();
 #endif
@@ -421,7 +429,7 @@
 #ifdef CONFIG_ACPI_BOOT
 	acpi_boot_init();
 #endif
-#ifdef CONFIG_SERIAL_HCDP
+#ifdef CONFIG_SERIAL_8250_HCDP
 	if (efi.hcdp) {
 		void setup_serial_hcdp(void *);
 
@@ -494,7 +502,7 @@
 	memcpy(features, " standard", 10);
 	cp = features;
 	sep = 0;
-	for (i = 0; i < sizeof(feature_bits)/sizeof(feature_bits[0]); ++i) {
+	for (i = 0; i < (int) ARRAY_SIZE(feature_bits); ++i) {
 		if (mask & feature_bits[i].mask) {
 			if (sep)
 				*cp++ = sep;
@@ -625,6 +633,39 @@
 	/* start_kernel() requires this... */
 }
 
+static void
+get_max_cacheline_size (void)
+{
+	unsigned long line_size, max = 1;
+	u64 l, levels, unique_caches;
+        pal_cache_config_info_t cci;
+        s64 status;
+
+        status = ia64_pal_cache_summary(&levels, &unique_caches);
+        if (status != 0) {
+                printk(KERN_ERR "%s: ia64_pal_cache_summary() failed (status=%ld)\n",
+                       __FUNCTION__, status);
+                max = SMP_CACHE_BYTES;
+		goto out;
+        }
+
+	for (l = 0; l < levels; ++l) {
+		status = ia64_pal_cache_config_info(l, /* cache_type (data_or_unified)= */ 2,
+						    &cci);
+		if (status != 0) {
+			printk(KERN_ERR
+			       "%s: ia64_pal_cache_config_info(l=%lu) failed (status=%ld)\n",
+			       __FUNCTION__, l, status);
+			max = SMP_CACHE_BYTES;
+		}
+		line_size = 1 << cci.pcci_line_size;
+		if (line_size > max)
+			max = line_size;
+        }
+  out:
+	if (max > ia64_max_cacheline_size)
+		ia64_max_cacheline_size = max;
+}
 
 /*
  * cpu_init() initializes state that is per-CPU.  This function acts
@@ -667,6 +708,8 @@
 #ifdef CONFIG_NUMA
 	cpu_info->node_data = get_node_data_ptr();
 #endif
+
+	get_max_cacheline_size();
 
 	/*
 	 * We can't pass "local_cpu_data" to identify_cpu() because we haven't called
diff -Nru a/arch/ia64/kernel/signal.c b/arch/ia64/kernel/signal.c
--- a/arch/ia64/kernel/signal.c	Fri Mar  7 04:39:25 2003
+++ b/arch/ia64/kernel/signal.c	Sat May 10 02:28:46 2003
@@ -142,8 +142,13 @@
 
 		__copy_from_user(current->thread.fph, &sc->sc_fr[32], 96*16);
 		psr->mfh = 0;	/* drop signal handler's fph contents... */
-		if (!psr->dfh)
+		if (psr->dfh)
+			current->thread.last_fph_cpu = -1;
+		else {
 			__ia64_load_fpu(current->thread.fph);
+			ia64_set_fpu_owner(current);
+			current->thread.last_fph_cpu = smp_processor_id();
+		}
 	}
 	return err;
 }
@@ -523,7 +528,7 @@
 			else
 				errno = -errno;
 		}
-	} else if (scr->pt.r10 != -1)
+	} else if ((long) scr->pt.r10 != -1)
 		/*
 		 * A system calls has to be restarted only if one of the error codes
 		 * ERESTARTNOHAND, ERESTARTSYS, or ERESTARTNOINTR is returned.  If r10
diff -Nru a/arch/ia64/kernel/smp.c b/arch/ia64/kernel/smp.c
--- a/arch/ia64/kernel/smp.c	Thu Mar  6 11:40:52 2003
+++ b/arch/ia64/kernel/smp.c	Sat May 10 02:28:46 2003
@@ -2,7 +2,7 @@
  * SMP Support
  *
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999, 2001 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999, 2001, 2003 David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * Lots of stuff stolen from arch/alpha/kernel/smp.c
  *
@@ -87,7 +87,7 @@
 	cpu_halt();
 }
 
-void
+irqreturn_t
 handle_IPI (int irq, void *dev_id, struct pt_regs *regs)
 {
 	int this_cpu = get_cpu();
@@ -147,10 +147,11 @@
 		mb();	/* Order data access and bit testing. */
 	}
 	put_cpu();
+	return IRQ_HANDLED;
 }
 
 /*
- * Called with preeemption disabled 
+ * Called with preeemption disabled.
  */
 static inline void
 send_IPI_single (int dest_cpu, int op)
@@ -160,12 +161,12 @@
 }
 
 /*
- * Called with preeemption disabled 
+ * Called with preeemption disabled.
  */
 static inline void
 send_IPI_allbutself (int op)
 {
-	int i;
+	unsigned int i;
 
 	for (i = 0; i < NR_CPUS; i++) {
 		if (cpu_online(i) && i != smp_processor_id())
@@ -174,7 +175,7 @@
 }
 
 /*
- * Called with preeemption disabled 
+ * Called with preeemption disabled.
  */
 static inline void
 send_IPI_all (int op)
@@ -187,7 +188,7 @@
 }
 
 /*
- * Called with preeemption disabled 
+ * Called with preeemption disabled.
  */
 static inline void
 send_IPI_self (int op)
@@ -196,7 +197,7 @@
 }
 
 /*
- * Called with preeemption disabled 
+ * Called with preeemption disabled.
  */
 void
 smp_send_reschedule (int cpu)
diff -Nru a/arch/ia64/kernel/smpboot.c b/arch/ia64/kernel/smpboot.c
--- a/arch/ia64/kernel/smpboot.c	Tue Mar 25 22:19:17 2003
+++ b/arch/ia64/kernel/smpboot.c	Sat May 10 02:28:46 2003
@@ -192,6 +192,7 @@
 {
 	long i, delta, adj, adjust_latency = 0, done = 0;
 	unsigned long flags, rt, master_time_stamp, bound;
+	extern void ia64_cpu_local_tick (void);
 #if DEBUG_ITC_SYNC
 	struct {
 		long rt;	/* roundtrip time */
@@ -246,6 +247,16 @@
 
 	printk(KERN_INFO "CPU %d: synchronized ITC with CPU %u (last diff %ld cycles, "
 	       "maxerr %lu cycles)\n", smp_processor_id(), master, delta, rt);
+
+	/*
+	 * Check whether we sync'd the itc ahead of the next timer interrupt.  If so, just
+	 * reset it.
+	 */
+	if (time_after(ia64_get_itc(), local_cpu_data->itm_next)) {
+		Dprintk("CPU %d: oops, jumped a timer tick; resetting timer.\n",
+			smp_processor_id());
+		ia64_cpu_local_tick();
+	}
 }
 
 /*
@@ -279,15 +290,6 @@
 
 	smp_setup_percpu_timer();
 
-	if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
-		/*
-		 * Synchronize the ITC with the BP
-		 */
-		Dprintk("Going to syncup ITC with BP.\n");
-
-		ia64_sync_itc(0);
-	}
-
 	/*
 	 * Get our bogomips.
 	 */
@@ -310,6 +312,18 @@
 	local_irq_enable();
 	calibrate_delay();
 	local_cpu_data->loops_per_jiffy = loops_per_jiffy;
+
+	if (!(sal_platform_features & IA64_SAL_PLATFORM_FEATURE_ITC_DRIFT)) {
+		/*
+		 * Synchronize the ITC with the BP.  Need to do this after irqs are
+		 * enabled because ia64_sync_itc() calls smp_call_function_single(), which
+		 * calls spin_unlock_bh(), which calls spin_unlock_bh(), which calls
+		 * local_bh_enable(), which bugs out if irqs are not enabled...
+		 */
+		Dprintk("Going to syncup ITC with BP.\n");
+		ia64_sync_itc(0);
+	}
+
 	/*
 	 * Allow the master to continue.
 	 */
@@ -394,13 +408,26 @@
 	return 0;
 }
 
-unsigned long cache_decay_ticks;	/* # of ticks an idle task is considered cache-hot */
+static int __init
+decay (char *str)
+{
+	int ticks;
+	get_option (&str, &ticks);
+	cache_decay_ticks = ticks;
+	return 1;
+}
+
+__setup("decay=", decay);
+
+/*
+ * # of ticks an idle task is considered cache-hot.  Highly application-dependent.  There
+ * are apps out there which are known to suffer significantly with values >= 4.
+ */
+unsigned long cache_decay_ticks = 10;	/* equal to MIN_TIMESLICE */
 
 static void
 smp_tune_scheduling (void)
 {
-	cache_decay_ticks = 10;	/* XXX base this on PAL info and cache-bandwidth estimate */
-
 	printk(KERN_INFO "task migration cache decay timeout: %ld msecs.\n",
 	       (cache_decay_ticks + 1) * 1000 / HZ);
 }
diff -Nru a/arch/ia64/kernel/time.c b/arch/ia64/kernel/time.c
--- a/arch/ia64/kernel/time.c	Wed Mar 26 02:48:05 2003
+++ b/arch/ia64/kernel/time.c	Sat May 10 02:28:47 2003
@@ -83,11 +83,26 @@
 	return (elapsed_cycles*local_cpu_data->nsec_per_cyc) >> IA64_NSEC_PER_CYC_SHIFT;
 }
 
+static inline void
+set_normalized_timespec (struct timespec *ts, time_t sec, long nsec)
+{
+	while (nsec > NSEC_PER_SEC) {
+		nsec -= NSEC_PER_SEC;
+		++sec;
+	}
+	while (nsec < 0) {
+		nsec += NSEC_PER_SEC;
+		--sec;
+	}
+	ts->tv_sec = sec;
+	ts->tv_nsec = nsec;
+}
+
 void
 do_settimeofday (struct timeval *tv)
 {
-	time_t sec = tv->tv_sec;
-	long nsec = tv->tv_usec * 1000;
+	time_t wtm_sec, sec = tv->tv_sec;
+	long wtm_nsec, nsec = tv->tv_usec * 1000;
 
 	write_seqlock_irq(&xtime_lock);
 	{
@@ -99,13 +114,12 @@
 		 */
 		nsec -= gettimeoffset();
 
-		while (nsec < 0) {
-			nsec += 1000000000;
-			sec--;
-		}
+		wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
+		wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
+
+		set_normalized_timespec(&xtime, sec, nsec);
+		set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
 
-		xtime.tv_sec = sec;
-		xtime.tv_nsec = nsec;
 		time_adjust = 0;		/* stop active adjtime() */
 		time_status |= STA_UNSYNC;
 		time_maxerror = NTP_PHASE_LIMIT;
@@ -166,8 +180,8 @@
 
 	usec = (nsec + offset) / 1000;
 
-	while (unlikely(usec >= 1000000)) {
-		usec -= 1000000;
+	while (unlikely(usec >= USEC_PER_SEC)) {
+		usec -= USEC_PER_SEC;
 		++sec;
 	}
 
@@ -175,8 +189,8 @@
 	tv->tv_usec = usec;
 }
 
-static void
-timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned long new_itm;
 
@@ -221,7 +235,7 @@
 	do {
 	    /*
 	     * If we're too close to the next clock tick for comfort, we increase the
-	     * saftey margin by intentionally dropping the next tick(s).  We do NOT update
+	     * safety margin by intentionally dropping the next tick(s).  We do NOT update
 	     * itm.next because that would force us to call do_timer() which in turn would
 	     * let our clock run too fast (with the potentially devastating effect of
 	     * losing monotony of time).
@@ -231,12 +245,13 @@
 	    ia64_set_itm(new_itm);
 	    /* double check, in case we got hit by a (slow) PMI: */
 	} while (time_after_eq(ia64_get_itc(), new_itm));
+	return IRQ_HANDLED;
 }
 
 /*
  * Encapsulate access to the itm structure for SMP.
  */
-void __init
+void
 ia64_cpu_local_tick (void)
 {
 	int cpu = smp_processor_id();
@@ -281,7 +296,7 @@
 	if (status != 0) {
 		/* invent "random" values */
 		printk(KERN_ERR
-		       "SAL/PAL failed to obtain frequency info---inventing reasonably values\n");
+		       "SAL/PAL failed to obtain frequency info---inventing reasonable values\n");
 		platform_base_freq = 100000000;
 		itc_ratio.num = 3;
 		itc_ratio.den = 1;
@@ -305,8 +320,8 @@
 
 	local_cpu_data->proc_freq = (platform_base_freq*proc_ratio.num)/proc_ratio.den;
 	local_cpu_data->itc_freq = itc_freq;
-	local_cpu_data->cyc_per_usec = (itc_freq + 500000) / 1000000;
-	local_cpu_data->nsec_per_cyc = ((1000000000UL<<IA64_NSEC_PER_CYC_SHIFT)
+	local_cpu_data->cyc_per_usec = (itc_freq + USEC_PER_SEC/2) / USEC_PER_SEC;
+	local_cpu_data->nsec_per_cyc = ((NSEC_PER_SEC<<IA64_NSEC_PER_CYC_SHIFT)
 					+ itc_freq/2)/itc_freq;
 
 	/* Setup the CPU local timer tick */
@@ -323,6 +338,12 @@
 time_init (void)
 {
 	register_percpu_irq(IA64_TIMER_VECTOR, &timer_irqaction);
-	efi_gettimeofday((struct timeval *) &xtime);
+	efi_gettimeofday(&xtime);
 	ia64_init_itm();
+
+	/*
+	 * Initialize wall_to_monotonic such that adding it to xtime will yield zero, the
+	 * tv_nsec field must be normalized (i.e., 0 <= nsec < NSEC_PER_SEC).
+	 */
+	set_normalized_timespec(&wall_to_monotonic, -xtime.tv_sec, -xtime.tv_nsec);
 }
diff -Nru a/arch/ia64/kernel/traps.c b/arch/ia64/kernel/traps.c
--- a/arch/ia64/kernel/traps.c	Tue Apr  8 12:03:13 2003
+++ b/arch/ia64/kernel/traps.c	Tue May  6 10:56:54 2003
@@ -94,7 +94,7 @@
 {
 	static struct {
 		spinlock_t lock;
-		int lock_owner;
+		u32 lock_owner;
 		int lock_owner_depth;
 	} die = {
 		.lock =			SPIN_LOCK_UNLOCKED,
diff -Nru a/arch/ia64/kernel/unaligned.c b/arch/ia64/kernel/unaligned.c
--- a/arch/ia64/kernel/unaligned.c	Fri Jan 24 11:56:49 2003
+++ b/arch/ia64/kernel/unaligned.c	Tue Apr 22 19:46:02 2003
@@ -789,7 +789,7 @@
 	 *
 	 * ldX.a (advanced load):
 	 *	- suppose ldX.a r1=[r3]. If we get to the unaligned trap it's because the
-	 *	  address doesn't match requested size alignement. This means that we would
+	 *	  address doesn't match requested size alignment. This means that we would
 	 *	  possibly need more than one load to get the result.
 	 *
 	 *	  The load part can be handled just like a normal load, however the difficult
diff -Nru a/arch/ia64/kernel/unwind.c b/arch/ia64/kernel/unwind.c
--- a/arch/ia64/kernel/unwind.c	Tue Mar 25 04:49:15 2003
+++ b/arch/ia64/kernel/unwind.c	Sat May 10 02:28:47 2003
@@ -682,7 +682,7 @@
 	 * First, resolve implicit register save locations (see Section "11.4.2.3 Rules
 	 * for Using Unwind Descriptors", rule 3):
 	 */
-	for (i = 0; i < (int) sizeof(unw.save_order)/sizeof(unw.save_order[0]); ++i) {
+	for (i = 0; i < (int) ARRAY_SIZE(unw.save_order); ++i) {
 		reg = sr->curr.reg + unw.save_order[i];
 		if (reg->where == UNW_WHERE_GR_SAVE) {
 			reg->where = UNW_WHERE_GR;
@@ -698,7 +698,7 @@
 	 */
 	if (sr->imask) {
 		unsigned char kind, mask = 0, *cp = sr->imask;
-		unsigned long t;
+		int t;
 		static const unsigned char limit[3] = {
 			UNW_REG_F31, UNW_REG_R7, UNW_REG_B5
 		};
@@ -1214,13 +1214,13 @@
 	spin_unlock(&unw.lock);
 
 	/*
-	 * XXX We'll deadlock here if we interrupt a thread that is
-	 * holding a read lock on script->lock.  A try_write_lock()
-	 * might be mighty handy here...  Alternatively, we could
-	 * disable interrupts whenever we hold a read-lock, but that
-	 * seems silly.
+	 * We'd deadlock here if we interrupted a thread that is holding a read lock on
+	 * script->lock.  Thus, if the write_trylock() fails, we simply bail out.  The
+	 * alternative would be to disable interrupts whenever we hold a read-lock, but
+	 * that seems silly.
 	 */
-	write_lock(&script->lock);
+	if (!write_trylock(&script->lock))
+		return NULL;
 
 	spin_lock(&unw.lock);
 	{
@@ -1888,22 +1888,21 @@
 	return -1;
 }
 
-void
-unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw)
+static void
+init_frame_info (struct unw_frame_info *info, struct task_struct *t,
+		 struct switch_stack *sw, unsigned long stktop)
 {
-	unsigned long rbslimit, rbstop, stklimit, stktop, sol;
+	unsigned long rbslimit, rbstop, stklimit;
 	STAT(unsigned long start, flags;)
 
 	STAT(local_irq_save(flags); ++unw.stat.api.inits; start = ia64_get_itc());
 
 	/*
-	 * Subtle stuff here: we _could_ unwind through the
-	 * switch_stack frame but we don't want to do that because it
-	 * would be slow as each preserved register would have to be
-	 * processed.  Instead, what we do here is zero out the frame
-	 * info and start the unwind process at the function that
-	 * created the switch_stack frame.  When a preserved value in
-	 * switch_stack needs to be accessed, run_script() will
+	 * Subtle stuff here: we _could_ unwind through the switch_stack frame but we
+	 * don't want to do that because it would be slow as each preserved register would
+	 * have to be processed.  Instead, what we do here is zero out the frame info and
+	 * start the unwind process at the function that created the switch_stack frame.
+	 * When a preserved value in switch_stack needs to be accessed, run_script() will
 	 * initialize the appropriate pointer on demand.
 	 */
 	memset(info, 0, sizeof(*info));
@@ -1914,7 +1913,6 @@
 		rbstop = rbslimit;
 
 	stklimit = (unsigned long) t + IA64_STK_OFFSET;
-	stktop   = (unsigned long) sw - 16;
 	if (stktop <= rbstop)
 		stktop = rbstop;
 
@@ -1924,34 +1922,58 @@
 	info->memstk.top   = stktop;
 	info->task = t;
 	info->sw  = sw;
-	info->sp = info->psp = (unsigned long) (sw + 1) - 16;
-	info->pt = 0;
+	info->sp = info->psp = stktop;
+	info->pr = sw->pr;
+	UNW_DPRINT(3, "unwind.%s:\n"
+		   "  task   0x%lx\n"
+		   "  rbs = [0x%lx-0x%lx)\n"
+		   "  stk = [0x%lx-0x%lx)\n"
+		   "  pr     0x%lx\n"
+		   "  sw     0x%lx\n"
+		   "  sp     0x%lx\n",
+		   __FUNCTION__, (unsigned long) t, rbslimit, rbstop, stktop, stklimit,
+		   info->pr, (unsigned long) info->sw, info->sp);
+	STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
+}
+
+void
+unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t,
+			    struct pt_regs *pt, struct switch_stack *sw)
+{
+	unsigned long sof;
+
+	init_frame_info(info, t, sw, pt->r12);
+	info->cfm_loc = &pt->cr_ifs;
+	info->unat_loc = &pt->ar_unat;
+	info->pfs_loc = &pt->ar_pfs;
+	sof = *info->cfm_loc & 0x7f;
+	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sof);
+	info->ip = pt->cr_iip + ia64_psr(pt)->ri;
+	info->pt = (unsigned long) pt;
+	UNW_DPRINT(3, "unwind.%s:\n"
+		   "  bsp    0x%lx\n"
+		   "  sof    0x%lx\n"
+		   "  ip     0x%lx\n",
+		   __FUNCTION__, info->bsp, sof, info->ip);
+	find_save_locs(info);
+}
+
+void
+unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t, struct switch_stack *sw)
+{
+	unsigned long sol;
+
+	init_frame_info(info, t, sw, (unsigned long) (sw + 1) - 16);
 	info->cfm_loc = &sw->ar_pfs;
 	sol = (*info->cfm_loc >> 7) & 0x7f;
 	info->bsp = (unsigned long) ia64_rse_skip_regs((unsigned long *) info->regstk.top, -sol);
 	info->ip = sw->b0;
-	info->pr = sw->pr;
-	UNW_DPRINT(3,
-			"unwind.%s\n"
-			"  rbslimit 0x%lx\n"
-			"  rbstop   0x%lx\n"
-			"  stklimit 0x%lx\n"
-			"  stktop   0x%lx\n"
-			"  task     0x%lx\n"
-			"  sw       0x%lx\n",
-			__FUNCTION__, rbslimit, rbstop, stklimit, stktop,
-			(unsigned long)(info->task),
-			(unsigned long)(info->sw));
-	UNW_DPRINT(3,
-			"  sp/psp   0x%lx\n"
-			"  sol      0x%lx\n"
-			"  bsp      0x%lx\n"
-			"  ip       0x%lx\n"
-			"  pr       0x%lx\n",
-			info->sp, sol, info->bsp, info->ip, info->pr);
-
+	UNW_DPRINT(3, "unwind.%s:\n"
+		   "  bsp    0x%lx\n"
+		   "  sol    0x%lx\n"
+		   "  ip     0x%lx\n",
+		   __FUNCTION__, info->bsp, sol, info->ip);
 	find_save_locs(info);
-	STAT(unw.stat.api.init_time += ia64_get_itc() - start; local_irq_restore(flags));
 }
 
 void
diff -Nru a/arch/ia64/lib/copy_user.S b/arch/ia64/lib/copy_user.S
--- a/arch/ia64/lib/copy_user.S	Wed Jul 24 09:46:27 2002
+++ b/arch/ia64/lib/copy_user.S	Tue Apr 22 19:45:51 2003
@@ -316,7 +316,7 @@
 	// Beginning of long mempcy (i.e. > 16 bytes)
 	//
 .long_copy_user:
-	tbit.nz p6,p7=src1,0	// odd alignement
+	tbit.nz p6,p7=src1,0	// odd alignment
 	and tmp=7,tmp
 	;;
 	cmp.eq p10,p8=r0,tmp
diff -Nru a/arch/ia64/lib/do_csum.S b/arch/ia64/lib/do_csum.S
--- a/arch/ia64/lib/do_csum.S	Tue Feb 25 09:44:09 2003
+++ b/arch/ia64/lib/do_csum.S	Tue Apr 22 19:45:52 2003
@@ -137,7 +137,7 @@
 	mov saved_pr=pr		// preserve predicates (rotation)
 (p6)	br.ret.spnt.many rp	// return if zero or negative length
 
-	mov hmask=-1		// intialize head mask
+	mov hmask=-1		// initialize head mask
 	tbit.nz p15,p0=buf,0	// is buf an odd address?
 	and first1=-8,buf	// 8-byte align down address of first1 element
 
diff -Nru a/arch/ia64/lib/io.c b/arch/ia64/lib/io.c
--- a/arch/ia64/lib/io.c	Thu Mar 27 07:52:21 2003
+++ b/arch/ia64/lib/io.c	Sat May 10 02:28:47 2003
@@ -51,84 +51,79 @@
 
 #ifdef CONFIG_IA64_GENERIC
 
+#undef __ia64_inb
+#undef __ia64_inw
+#undef __ia64_inl
+#undef __ia64_outb
+#undef __ia64_outw
+#undef __ia64_outl
+#undef __ia64_readb
+#undef __ia64_readw
+#undef __ia64_readl
+#undef __ia64_readq
+#undef __ia64_writeb
+#undef __ia64_writew
+#undef __ia64_writel
+#undef __ia64_writeq
+
 unsigned int
-ia64_inb (unsigned long port)
+__ia64_inb (unsigned long port)
 {
-	return __ia64_inb(port);
+	return ___ia64_inb(port);
 }
 
 unsigned int
-ia64_inw (unsigned long port)
+__ia64_inw (unsigned long port)
 {
-	return __ia64_inw(port);
+	return ___ia64_inw(port);
 }
 
 unsigned int
-ia64_inl (unsigned long port)
+__ia64_inl (unsigned long port)
 {
-	return __ia64_inl(port);
+	return ___ia64_inl(port);
 }
 
 void
-ia64_outb (unsigned char val, unsigned long port)
+__ia64_outb (unsigned char val, unsigned long port)
 {
-	__ia64_outb(val, port);
+	___ia64_outb(val, port);
 }
 
 void
-ia64_outw (unsigned short val, unsigned long port)
+__ia64_outw (unsigned short val, unsigned long port)
 {
-	__ia64_outw(val, port);
+	___ia64_outw(val, port);
 }
 
 void
-ia64_outl (unsigned int val, unsigned long port)
+__ia64_outl (unsigned int val, unsigned long port)
 {
-	__ia64_outl(val, port);
+	___ia64_outl(val, port);
 }
 
 unsigned char
-ia64_readb (void *addr)
+__ia64_readb (void *addr)
 {
-	return __ia64_readb (addr);
+	return ___ia64_readb (addr);
 }
 
 unsigned short
-ia64_readw (void *addr)
+__ia64_readw (void *addr)
 {
-	return __ia64_readw (addr);
+	return ___ia64_readw (addr);
 }
 
 unsigned int
-ia64_readl (void *addr)
+__ia64_readl (void *addr)
 {
-	return __ia64_readl (addr);
+	return ___ia64_readl (addr);
 }
 
 unsigned long
-ia64_readq (void *addr)
+__ia64_readq (void *addr)
 {
-	return __ia64_readq (addr)
+	return ___ia64_readq (addr);
 }
-
-
-/* define aliases: */
-
-asm (".global __ia64_inb, __ia64_inw, __ia64_inl");
-asm ("__ia64_inb = ia64_inb");
-asm ("__ia64_inw = ia64_inw");
-asm ("__ia64_inl = ia64_inl");
-
-asm (".global __ia64_outb, __ia64_outw, __ia64_outl");
-asm ("__ia64_outb = ia64_outb");
-asm ("__ia64_outw = ia64_outw");
-asm ("__ia64_outl = ia64_outl");
-
-asm (".global __ia64_readb, __ia64_readw, __ia64_readl, __ia64_readq");
-asm ("__ia64_readb = ia64_readb");
-asm ("__ia64_readw = ia64_readw");
-asm ("__ia64_readl = ia64_readl");
-asm ("__ia64_readq = ia64_readq");
-
 
 #endif /* CONFIG_IA64_GENERIC */
diff -Nru a/arch/ia64/lib/swiotlb.c b/arch/ia64/lib/swiotlb.c
--- a/arch/ia64/lib/swiotlb.c	Tue Apr  1 01:19:53 2003
+++ b/arch/ia64/lib/swiotlb.c	Sat May 10 02:28:47 2003
@@ -5,7 +5,10 @@
  * I/O TLBs (aka DMA address translation hardware).
  * Copyright (C) 2000 Asit Mallick <Asit.K.Mallick@intel.com>
  * Copyright (C) 2000 Goutham Rao <goutham.rao@intel.com>
+ * Copyright (C) 2000, 2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
+ * 03/05/07 davidm	Switch from PCI-DMA to generic device DMA API.
  * 00/12/13 davidm	Rename to swiotlb.c and add mark_clean() to avoid
  *			unnecessary i-cache flushing.
  */
@@ -92,7 +95,7 @@
 void
 swiotlb_init (void)
 {
-	int i;
+	unsigned long i;
 
 	/*
 	 * Get IO TLB memory from the low pages
@@ -121,7 +124,7 @@
  * Allocates bounce buffer and returns its kernel virtual address.
  */
 static void *
-map_single (struct pci_dev *hwdev, char *buffer, size_t size, int direction)
+map_single (struct device *hwdev, char *buffer, size_t size, int dir)
 {
 	unsigned long flags;
 	char *dma_addr;
@@ -161,7 +164,7 @@
 			if (io_tlb_list[index] >= nslots) {
 				int count = 0;
 
-				for (i = index; i < index + nslots; i++)
+				for (i = index; i < (int) (index + nslots); i++)
 					io_tlb_list[i] = 0;
 				for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1)
 				       && io_tlb_list[i]; i--)
@@ -195,7 +198,7 @@
 	 * needed when we sync the memory.  Then we sync the buffer if needed.
 	 */
 	io_tlb_orig_addr[index] = buffer;
-	if (direction == PCI_DMA_TODEVICE || direction == PCI_DMA_BIDIRECTIONAL)
+	if (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL)
 		memcpy(dma_addr, buffer, size);
 
 	return dma_addr;
@@ -205,7 +208,7 @@
  * dma_addr is the kernel virtual address of the bounce buffer to unmap.
  */
 static void
-unmap_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction)
+unmap_single (struct device *hwdev, char *dma_addr, size_t size, int dir)
 {
 	unsigned long flags;
 	int i, nslots = ALIGN(size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
@@ -215,7 +218,7 @@
 	/*
 	 * First, sync the memory before unmapping the entry
 	 */
-	if ((direction == PCI_DMA_FROMDEVICE) || (direction == PCI_DMA_BIDIRECTIONAL))
+	if ((dir == DMA_FROM_DEVICE) || (dir == DMA_BIDIRECTIONAL))
 		/*
 		 * bounce... copy the data back into the original buffer * and delete the
 		 * bounce buffer.
@@ -239,7 +242,7 @@
 		for (i = index + nslots - 1; i >= index; i--)
 			io_tlb_list[i] = ++count;
 		/*
-		 * Step 2: merge the returned slots with the preceeding slots, if
+		 * Step 2: merge the returned slots with the preceding slots, if
 		 * available (non zero)
 		 */
 		for (i = index - 1;  (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) &&
@@ -250,49 +253,46 @@
 }
 
 static void
-sync_single (struct pci_dev *hwdev, char *dma_addr, size_t size, int direction)
+sync_single (struct device *hwdev, char *dma_addr, size_t size, int dir)
 {
 	int index = (dma_addr - io_tlb_start) >> IO_TLB_SHIFT;
 	char *buffer = io_tlb_orig_addr[index];
 
 	/*
 	 * bounce... copy the data back into/from the original buffer
-	 * XXX How do you handle PCI_DMA_BIDIRECTIONAL here ?
+	 * XXX How do you handle DMA_BIDIRECTIONAL here ?
 	 */
-	if (direction == PCI_DMA_FROMDEVICE)
+	if (dir == DMA_FROM_DEVICE)
 		memcpy(buffer, dma_addr, size);
-	else if (direction == PCI_DMA_TODEVICE)
+	else if (dir == DMA_TO_DEVICE)
 		memcpy(dma_addr, buffer, size);
 	else
 		BUG();
 }
 
 void *
-swiotlb_alloc_consistent (struct pci_dev *hwdev, size_t size, dma_addr_t *dma_handle)
+swiotlb_alloc_coherent (struct device *hwdev, size_t size, dma_addr_t *dma_handle, int flags)
 {
-	unsigned long pci_addr;
-	int gfp = GFP_ATOMIC;
+	unsigned long dev_addr;
 	void *ret;
 
-	/*
-	 * Alloc_consistent() is defined to return memory < 4GB, no matter what the DMA
-	 * mask says.
-	 */
-	gfp |= GFP_DMA; /* XXX fix me: should change this to GFP_32BIT or ZONE_32BIT */
-	ret = (void *)__get_free_pages(gfp, get_order(size));
+	/* XXX fix me: the DMA API should pass us an explicit DMA mask instead: */
+	flags |= GFP_DMA;
+
+	ret = (void *)__get_free_pages(flags, get_order(size));
 	if (!ret)
 		return NULL;
 
 	memset(ret, 0, size);
-	pci_addr = virt_to_phys(ret);
-	if (hwdev && (pci_addr & ~hwdev->dma_mask) != 0)
-		panic("swiotlb_alloc_consistent: allocated memory is out of range for PCI device");
-	*dma_handle = pci_addr;
+	dev_addr = virt_to_phys(ret);
+	if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0)
+		panic("swiotlb_alloc_consistent: allocated memory is out of range for device");
+	*dma_handle = dev_addr;
 	return ret;
 }
 
 void
-swiotlb_free_consistent (struct pci_dev *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
+swiotlb_free_coherent (struct device *hwdev, size_t size, void *vaddr, dma_addr_t dma_handle)
 {
 	free_pages((unsigned long) vaddr, get_order(size));
 }
@@ -305,34 +305,34 @@
  * swiotlb_unmap_single or swiotlb_dma_sync_single is performed.
  */
 dma_addr_t
-swiotlb_map_single (struct pci_dev *hwdev, void *ptr, size_t size, int direction)
+swiotlb_map_single (struct device *hwdev, void *ptr, size_t size, int dir)
 {
-	unsigned long pci_addr = virt_to_phys(ptr);
+	unsigned long dev_addr = virt_to_phys(ptr);
 
-	if (direction == PCI_DMA_NONE)
+	if (dir == DMA_NONE)
 		BUG();
 	/*
 	 * Check if the PCI device can DMA to ptr... if so, just return ptr
 	 */
-	if ((pci_addr & ~hwdev->dma_mask) == 0)
+	if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) == 0)
 		/*
 		 * Device is bit capable of DMA'ing to the buffer... just return the PCI
 		 * address of ptr
 		 */
-		return pci_addr;
+		return dev_addr;
 
 	/*
 	 * get a bounce buffer:
 	 */
-	pci_addr = virt_to_phys(map_single(hwdev, ptr, size, direction));
+	dev_addr = virt_to_phys(map_single(hwdev, ptr, size, dir));
 
 	/*
 	 * Ensure that the address returned is DMA'ble:
 	 */
-	if ((pci_addr & ~hwdev->dma_mask) != 0)
+	if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0)
 		panic("map_single: bounce buffer is not DMA'ble");
 
-	return pci_addr;
+	return dev_addr;
 }
 
 /*
@@ -363,15 +363,15 @@
  * device wrote there.
  */
 void
-swiotlb_unmap_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction)
+swiotlb_unmap_single (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir)
 {
-	char *dma_addr = phys_to_virt(pci_addr);
+	char *dma_addr = phys_to_virt(dev_addr);
 
-	if (direction == PCI_DMA_NONE)
+	if (dir == DMA_NONE)
 		BUG();
 	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
-		unmap_single(hwdev, dma_addr, size, direction);
-	else if (direction == PCI_DMA_FROMDEVICE)
+		unmap_single(hwdev, dma_addr, size, dir);
+	else if (dir == DMA_FROM_DEVICE)
 		mark_clean(dma_addr, size);
 }
 
@@ -385,21 +385,21 @@
  * again owns the buffer.
  */
 void
-swiotlb_sync_single (struct pci_dev *hwdev, dma_addr_t pci_addr, size_t size, int direction)
+swiotlb_sync_single (struct device *hwdev, dma_addr_t dev_addr, size_t size, int dir)
 {
-	char *dma_addr = phys_to_virt(pci_addr);
+	char *dma_addr = phys_to_virt(dev_addr);
 
-	if (direction == PCI_DMA_NONE)
+	if (dir == DMA_NONE)
 		BUG();
 	if (dma_addr >= io_tlb_start && dma_addr < io_tlb_end)
-		sync_single(hwdev, dma_addr, size, direction);
-	else if (direction == PCI_DMA_FROMDEVICE)
+		sync_single(hwdev, dma_addr, size, dir);
+	else if (dir == DMA_FROM_DEVICE)
 		mark_clean(dma_addr, size);
 }
 
 /*
  * Map a set of buffers described by scatterlist in streaming mode for DMA.  This is the
- * scather-gather version of the above swiotlb_map_single interface.  Here the scatter
+ * scatter-gather version of the above swiotlb_map_single interface.  Here the scatter
  * gather list elements are each tagged with the appropriate dma address and length.  They
  * are obtained via sg_dma_{address,length}(SG).
  *
@@ -412,23 +412,22 @@
  * Device ownership issues as mentioned above for swiotlb_map_single are the same here.
  */
 int
-swiotlb_map_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+swiotlb_map_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int dir)
 {
 	void *addr;
-	unsigned long pci_addr;
+	unsigned long dev_addr;
 	int i;
 
-	if (direction == PCI_DMA_NONE)
+	if (dir == DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++) {
 		addr = SG_ENT_VIRT_ADDRESS(sg);
-		pci_addr = virt_to_phys(addr);
-		if ((pci_addr & ~hwdev->dma_mask) != 0)
-			sg->dma_address = (dma_addr_t)
-				map_single(hwdev, addr, sg->length, direction);
+		dev_addr = virt_to_phys(addr);
+		if (hwdev && hwdev->dma_mask && (dev_addr & ~*hwdev->dma_mask) != 0)
+			sg->dma_address = (dma_addr_t) map_single(hwdev, addr, sg->length, dir);
 		else
-			sg->dma_address = pci_addr;
+			sg->dma_address = dev_addr;
 		sg->dma_length = sg->length;
 	}
 	return nelems;
@@ -439,17 +438,17 @@
  * here are the same as for swiotlb_unmap_single() above.
  */
 void
-swiotlb_unmap_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+swiotlb_unmap_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int dir)
 {
 	int i;
 
-	if (direction == PCI_DMA_NONE)
+	if (dir == DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
 		if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
-			unmap_single(hwdev, (void *) sg->dma_address, sg->dma_length, direction);
-		else if (direction == PCI_DMA_FROMDEVICE)
+			unmap_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir);
+		else if (dir == DMA_FROM_DEVICE)
 			mark_clean(SG_ENT_VIRT_ADDRESS(sg), sg->dma_length);
 }
 
@@ -461,16 +460,16 @@
  * usage.
  */
 void
-swiotlb_sync_sg (struct pci_dev *hwdev, struct scatterlist *sg, int nelems, int direction)
+swiotlb_sync_sg (struct device *hwdev, struct scatterlist *sg, int nelems, int dir)
 {
 	int i;
 
-	if (direction == PCI_DMA_NONE)
+	if (dir == DMA_NONE)
 		BUG();
 
 	for (i = 0; i < nelems; i++, sg++)
 		if (sg->dma_address != SG_ENT_PHYS_ADDRESS(sg))
-			sync_single(hwdev, (void *) sg->dma_address, sg->dma_length, direction);
+			sync_single(hwdev, (void *) sg->dma_address, sg->dma_length, dir);
 }
 
 /*
@@ -479,7 +478,7 @@
  * you would pass 0x00ffffff as the mask to this function.
  */
 int
-swiotlb_pci_dma_supported (struct pci_dev *hwdev, u64 mask)
+swiotlb_dma_supported (struct device *hwdev, u64 mask)
 {
 	return 1;
 }
@@ -491,6 +490,6 @@
 EXPORT_SYMBOL(swiotlb_unmap_sg);
 EXPORT_SYMBOL(swiotlb_sync_single);
 EXPORT_SYMBOL(swiotlb_sync_sg);
-EXPORT_SYMBOL(swiotlb_alloc_consistent);
-EXPORT_SYMBOL(swiotlb_free_consistent);
-EXPORT_SYMBOL(swiotlb_pci_dma_supported);
+EXPORT_SYMBOL(swiotlb_alloc_coherent);
+EXPORT_SYMBOL(swiotlb_free_coherent);
+EXPORT_SYMBOL(swiotlb_dma_supported);
diff -Nru a/arch/ia64/mm/fault.c b/arch/ia64/mm/fault.c
--- a/arch/ia64/mm/fault.c	Wed Apr  9 11:51:34 2003
+++ b/arch/ia64/mm/fault.c	Sat May 10 03:13:39 2003
@@ -58,6 +58,18 @@
 	if (in_atomic() || !mm)
 		goto no_context;
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+	/*
+	 * If fault is in region 5 and we are in the kernel, we may already
+	 * have the mmap_sem (pfn_valid macro is called during mmap). There
+	 * is no vma for region 5 addr's anyway, so skip getting the semaphore
+	 * and go directly to the exception handling code.
+	 */
+
+	if ((REGION_NUMBER(address) == 5) && !user_mode(regs))
+		goto bad_area_no_up;
+#endif
+
 	down_read(&mm->mmap_sem);
 
 	vma = find_vma_prev(mm, address, &prev_vma);
@@ -139,6 +151,9 @@
 
   bad_area:
 	up_read(&mm->mmap_sem);
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+  bad_area_no_up:
+#endif
 	if ((isr & IA64_ISR_SP)
 	    || ((isr & IA64_ISR_NA) && (isr & IA64_ISR_CODE_MASK) == IA64_ISR_CODE_LFETCH))
 	{
diff -Nru a/arch/ia64/mm/hugetlbpage.c b/arch/ia64/mm/hugetlbpage.c
--- a/arch/ia64/mm/hugetlbpage.c	Thu Mar  6 13:34:27 2003
+++ b/arch/ia64/mm/hugetlbpage.c	Wed May 14 23:43:48 2003
@@ -12,13 +12,12 @@
 #include <linux/pagemap.h>
 #include <linux/smp_lock.h>
 #include <linux/slab.h>
+#include <linux/sysctl.h>
 #include <asm/mman.h>
 #include <asm/pgalloc.h>
 #include <asm/tlb.h>
 #include <asm/tlbflush.h>
 
-#include <linux/sysctl.h>
-
 #define TASK_HPAGE_BASE (REGION_HPAGE << REGION_SHIFT)
 
 static long    htlbpagemem;
@@ -392,8 +391,6 @@
 {
 	int  lcount;
 	struct page *page ;
-	extern long htlbzone_pages;
-	extern struct list_head htlbpage_freelist;
 
 	if (count < 0)
 		lcount = count;
diff -Nru a/arch/ia64/mm/init.c b/arch/ia64/mm/init.c
--- a/arch/ia64/mm/init.c	Sat Apr 12 16:21:01 2003
+++ b/arch/ia64/mm/init.c	Sat May 10 03:13:39 2003
@@ -38,6 +38,13 @@
 
 unsigned long MAX_DMA_ADDRESS = PAGE_OFFSET + 0x100000000UL;
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+# define LARGE_GAP	0x40000000	/* Use virtual mem map if hole is > than this */
+  unsigned long vmalloc_end = VMALLOC_END_INIT;
+  static struct page *vmem_map;
+  static unsigned long num_dma_physpages;
+#endif
+
 static int pgt_cache_water[2] = { 25, 50 };
 
 void
@@ -48,13 +55,13 @@
 	low = pgt_cache_water[0];
 	high = pgt_cache_water[1];
 
-	if (pgtable_cache_size > high) {
+	if (pgtable_cache_size > (u64) high) {
 		do {
 			if (pgd_quicklist)
 				free_page((unsigned long)pgd_alloc_one_fast(0));
 			if (pmd_quicklist)
 				free_page((unsigned long)pmd_alloc_one_fast(0, 0));
-		} while (pgtable_cache_size > low);
+		} while (pgtable_cache_size > (u64) low);
 	}
 }
 
@@ -337,6 +344,139 @@
 	ia64_tlb_init();
 }
 
+#ifdef CONFIG_VIRTUAL_MEM_MAP
+
+static int
+create_mem_map_page_table (u64 start, u64 end, void *arg)
+{
+	unsigned long address, start_page, end_page;
+	struct page *map_start, *map_end;
+	pgd_t *pgd;
+	pmd_t *pmd;
+	pte_t *pte;
+
+	map_start = vmem_map + (__pa(start) >> PAGE_SHIFT);
+	map_end   = vmem_map + (__pa(end) >> PAGE_SHIFT);
+
+	start_page = (unsigned long) map_start & PAGE_MASK;
+	end_page = PAGE_ALIGN((unsigned long) map_end);
+
+	for (address = start_page; address < end_page; address += PAGE_SIZE) {
+		pgd = pgd_offset_k(address);
+		if (pgd_none(*pgd))
+			pgd_populate(&init_mm, pgd, alloc_bootmem_pages(PAGE_SIZE));
+		pmd = pmd_offset(pgd, address);
+
+		if (pmd_none(*pmd))
+			pmd_populate_kernel(&init_mm, pmd, alloc_bootmem_pages(PAGE_SIZE));
+		pte = pte_offset_kernel(pmd, address);
+
+		if (pte_none(*pte))
+			set_pte(pte, pfn_pte(__pa(alloc_bootmem_pages(PAGE_SIZE)) >> PAGE_SHIFT,
+					     PAGE_KERNEL));
+	}
+	return 0;
+}
+
+struct memmap_init_callback_data {
+	struct page *start;
+	struct page *end;
+	int nid;
+	unsigned long zone;
+};
+
+static int
+virtual_memmap_init (u64 start, u64 end, void *arg)
+{
+	struct memmap_init_callback_data *args;
+	struct page *map_start, *map_end;
+
+	args = (struct memmap_init_callback_data *) arg;
+
+	map_start = vmem_map + (__pa(start) >> PAGE_SHIFT);
+	map_end   = vmem_map + (__pa(end) >> PAGE_SHIFT);
+
+	if (map_start < args->start)
+		map_start = args->start;
+	if (map_end > args->end)
+		map_end = args->end;
+
+	/*
+	 * We have to initialize "out of bounds" struct page elements that fit completely
+	 * on the same pages that were allocated for the "in bounds" elements because they
+	 * may be referenced later (and found to be "reserved").
+	 */
+	map_start -= ((unsigned long) map_start & (PAGE_SIZE - 1)) / sizeof(struct page);
+	map_end += ((PAGE_ALIGN((unsigned long) map_end) - (unsigned long) map_end)
+		    / sizeof(struct page));
+
+	if (map_start < map_end)
+		memmap_init_zone(map_start, (unsigned long) (map_end - map_start),
+				 args->nid, args->zone, page_to_pfn(map_start));
+	return 0;
+}
+
+void
+memmap_init (struct page *start, unsigned long size, int nid,
+	     unsigned long zone, unsigned long start_pfn)
+{
+	if (!vmem_map)
+		memmap_init_zone(start, size, nid, zone, start_pfn);
+	else {
+		struct memmap_init_callback_data args;
+
+		args.start = start;
+		args.end = start + size;
+		args.nid = nid;
+		args.zone = zone;
+
+		efi_memmap_walk(virtual_memmap_init, &args);
+	}
+}
+
+int
+ia64_pfn_valid (unsigned long pfn)
+{
+	char byte;
+
+	return __get_user(byte, (char *) pfn_to_page(pfn)) == 0;
+}
+
+static int
+count_dma_pages (u64 start, u64 end, void *arg)
+{
+	unsigned long *count = arg;
+
+	if (end <= MAX_DMA_ADDRESS)
+		*count += (end - start) >> PAGE_SHIFT;
+	return 0;
+}
+
+static int
+find_largest_hole (u64 start, u64 end, void *arg)
+{
+	u64 *max_gap = arg;
+
+	static u64 last_end = PAGE_OFFSET;
+
+	/* NOTE: this algorithm assumes efi memmap table is ordered */
+
+	if (*max_gap < (start - last_end))
+		*max_gap = start - last_end;
+	last_end = end;
+	return 0;
+}
+#endif /* CONFIG_VIRTUAL_MEM_MAP */
+
+static int
+count_pages (u64 start, u64 end, void *arg)
+{
+	unsigned long *count = arg;
+
+	*count += (end - start) >> PAGE_SHIFT;
+	return 0;
+}
+
 /*
  * Set up the page tables.
  */
@@ -348,18 +488,70 @@
 	extern void discontig_paging_init(void);
 
 	discontig_paging_init();
+	efi_memmap_walk(count_pages, &num_physpages);
 }
 #else /* !CONFIG_DISCONTIGMEM */
 void
 paging_init (void)
 {
-	unsigned long max_dma, zones_size[MAX_NR_ZONES];
+	unsigned long max_dma;
+	unsigned long zones_size[MAX_NR_ZONES];
+#  ifdef CONFIG_VIRTUAL_MEM_MAP
+	unsigned long zholes_size[MAX_NR_ZONES];
+	unsigned long max_gap;
+#  endif
 
 	/* initialize mem_map[] */
 
 	memset(zones_size, 0, sizeof(zones_size));
 
+	num_physpages = 0;
+	efi_memmap_walk(count_pages, &num_physpages);
+
 	max_dma = virt_to_phys((void *) MAX_DMA_ADDRESS) >> PAGE_SHIFT;
+
+#  ifdef CONFIG_VIRTUAL_MEM_MAP
+	memset(zholes_size, 0, sizeof(zholes_size));
+
+	num_dma_physpages = 0;
+	efi_memmap_walk(count_dma_pages, &num_dma_physpages);
+
+	if (max_low_pfn < max_dma) {
+		zones_size[ZONE_DMA] = max_low_pfn;
+		zholes_size[ZONE_DMA] = max_low_pfn - num_dma_physpages;
+	} else {
+		zones_size[ZONE_DMA] = max_dma;
+		zholes_size[ZONE_DMA] = max_dma - num_dma_physpages;
+		if (num_physpages > num_dma_physpages) {
+			zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
+			zholes_size[ZONE_NORMAL] = ((max_low_pfn - max_dma)
+						    - (num_physpages - num_dma_physpages));
+		}
+	}
+
+	max_gap = 0;
+	efi_memmap_walk(find_largest_hole, (u64 *)&max_gap);
+	if (max_gap < LARGE_GAP) {
+		vmem_map = (struct page *) 0;
+		free_area_init_node(0, &contig_page_data, NULL, zones_size, 0, zholes_size);
+		mem_map = contig_page_data.node_mem_map;
+	}
+	else {
+		unsigned long map_size;
+
+		/* allocate virtual_mem_map */
+
+		map_size = PAGE_ALIGN(max_low_pfn * sizeof(struct page));
+		vmalloc_end -= map_size;
+		vmem_map = (struct page *) vmalloc_end;
+		efi_memmap_walk(create_mem_map_page_table, 0);
+
+		free_area_init_node(0, &contig_page_data, vmem_map, zones_size, 0, zholes_size);
+
+		mem_map = contig_page_data.node_mem_map;
+		printk("Virtual mem_map starts at 0x%p\n", mem_map);
+	}
+#  else /* !CONFIG_VIRTUAL_MEM_MAP */
 	if (max_low_pfn < max_dma)
 		zones_size[ZONE_DMA] = max_low_pfn;
 	else {
@@ -367,19 +559,11 @@
 		zones_size[ZONE_NORMAL] = max_low_pfn - max_dma;
 	}
 	free_area_init(zones_size);
+#  endif /* !CONFIG_VIRTUAL_MEM_MAP */
 }
 #endif /* !CONFIG_DISCONTIGMEM */
 
 static int
-count_pages (u64 start, u64 end, void *arg)
-{
-	unsigned long *count = arg;
-
-	*count += (end - start) >> PAGE_SHIFT;
-	return 0;
-}
-
-static int
 count_reserved_pages (u64 start, u64 end, void *arg)
 {
 	unsigned long num_reserved = 0;
@@ -406,7 +590,7 @@
 	 * any drivers that may need the PCI DMA interface are initialized or bootmem has
 	 * been freed.
 	 */
-	platform_pci_dma_init();
+	platform_dma_init();
 #endif
 
 #ifndef CONFIG_DISCONTIGMEM
@@ -415,9 +599,6 @@
 	max_mapnr = max_low_pfn;
 #endif
 
-	num_physpages = 0;
-	efi_memmap_walk(count_pages, &num_physpages);
-
 	high_memory = __va(max_low_pfn * PAGE_SIZE);
 
 	for_each_pgdat(pgdat)
@@ -445,7 +626,7 @@
 	num_pgt_pages = nr_free_pages() / PTRS_PER_PGD + NUM_TASKS;
 	if (num_pgt_pages > nr_free_pages() / 10)
 		num_pgt_pages = nr_free_pages() / 10;
-	if (num_pgt_pages > pgt_cache_water[1])
+	if (num_pgt_pages > (u64) pgt_cache_water[1])
 		pgt_cache_water[1] = num_pgt_pages;
 
 	/* install the gate page in the global page table: */
diff -Nru a/arch/ia64/pci/pci.c b/arch/ia64/pci/pci.c
--- a/arch/ia64/pci/pci.c	Tue Apr  8 12:03:13 2003
+++ b/arch/ia64/pci/pci.c	Thu Apr 24 13:46:26 2003
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2002 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *	Bjorn Helgaas <bjorn_helgaas@hp.com>
  *
  * Note: Above list of copyright holders is incomplete...
  */
@@ -116,31 +117,10 @@
 
 subsys_initcall(pci_acpi_init);
 
-static void __init
-pcibios_fixup_resource(struct resource *res, u64 offset)
-{
-	res->start += offset;
-	res->end += offset;
-}
-
-void __init
-pcibios_fixup_device_resources(struct pci_dev *dev, struct pci_bus *bus)
-{
-	int i;
-
-	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-		if (!dev->resource[i].start)
-			continue;
-		if (dev->resource[i].flags & IORESOURCE_MEM)
-			pcibios_fixup_resource(&dev->resource[i],
-			                       PCI_CONTROLLER(dev)->mem_offset);
-	}
-}
-
 /* Called by ACPI when it finds a new root bus.  */
 
 static struct pci_controller *
-alloc_pci_controller(int seg)
+alloc_pci_controller (int seg)
 {
 	struct pci_controller *controller;
 
@@ -153,8 +133,8 @@
 	return controller;
 }
 
-struct pci_bus *
-scan_root_bus(int bus, struct pci_ops *ops, void *sysdata)
+static struct pci_bus *
+scan_root_bus (int bus, struct pci_ops *ops, void *sysdata)
 {
 	struct pci_bus *b;
 
@@ -184,23 +164,185 @@
 	return b;
 }
 
+static int
+alloc_resource (char *name, struct resource *root, unsigned long start, unsigned long end, unsigned long flags)
+{
+	struct resource *res;
+
+	res = kmalloc(sizeof(*res), GFP_KERNEL);
+	if (!res)
+		return -ENOMEM;
+
+	memset(res, 0, sizeof(*res));
+	res->name = name;
+	res->start = start;
+	res->end = end;
+	res->flags = flags;
+
+	if (request_resource(root, res))
+		return -EBUSY;
+
+	return 0;
+}
+
+static u64
+add_io_space (struct acpi_resource_address64 *addr)
+{
+	u64 offset;
+	int sparse = 0;
+	int i;
+
+	if (addr->address_translation_offset == 0)
+		return IO_SPACE_BASE(0);	/* part of legacy IO space */
+
+	if (addr->attribute.io.translation_attribute == ACPI_SPARSE_TRANSLATION)
+		sparse = 1;
+
+	offset = (u64) ioremap(addr->address_translation_offset, 0);
+	for (i = 0; i < num_io_spaces; i++)
+		if (io_space[i].mmio_base == offset &&
+		    io_space[i].sparse == sparse)
+			return IO_SPACE_BASE(i);
+
+	if (num_io_spaces == MAX_IO_SPACES) {
+		printk("Too many IO port spaces\n");
+		return ~0;
+	}
+
+	i = num_io_spaces++;
+	io_space[i].mmio_base = offset;
+	io_space[i].sparse = sparse;
+
+	return IO_SPACE_BASE(i);
+}
+
+static acpi_status
+count_window (struct acpi_resource *resource, void *data)
+{
+	unsigned int *windows = (unsigned int *) data;
+	struct acpi_resource_address64 addr;
+	acpi_status status;
+
+	status = acpi_resource_to_address64(resource, &addr);
+	if (ACPI_SUCCESS(status))
+		if (addr.resource_type == ACPI_MEMORY_RANGE ||
+		    addr.resource_type == ACPI_IO_RANGE)
+			(*windows)++;
+
+	return AE_OK;
+}
+
+struct pci_root_info {
+	struct pci_controller *controller;
+	char *name;
+};
+
+static acpi_status
+add_window (struct acpi_resource *res, void *data)
+{
+	struct pci_root_info *info = (struct pci_root_info *) data;
+	struct pci_window *window;
+	struct acpi_resource_address64 addr;
+	acpi_status status;
+	unsigned long flags, offset = 0;
+	struct resource *root;
+
+	status = acpi_resource_to_address64(res, &addr);
+	if (ACPI_SUCCESS(status)) {
+		if (addr.resource_type == ACPI_MEMORY_RANGE) {
+			flags = IORESOURCE_MEM;
+			root = &iomem_resource;
+			offset = addr.address_translation_offset;
+		} else if (addr.resource_type == ACPI_IO_RANGE) {
+			flags = IORESOURCE_IO;
+			root = &ioport_resource;
+			offset = add_io_space(&addr);
+			if (offset == ~0)
+				return AE_OK;
+		} else
+			return AE_OK;
+
+		window = &info->controller->window[info->controller->windows++];
+		window->resource.flags |= flags;
+		window->resource.start  = addr.min_address_range;
+		window->resource.end    = addr.max_address_range;
+		window->offset		= offset;
+
+		if (alloc_resource(info->name, root, addr.min_address_range + offset,
+			addr.max_address_range + offset, flags))
+			printk(KERN_ERR "alloc 0x%lx-0x%lx from %s for %s failed\n",
+				addr.min_address_range + offset, addr.max_address_range + offset,
+				root->name, info->name);
+	}
+
+	return AE_OK;
+}
+
 struct pci_bus *
-pcibios_scan_root(void *handle, int seg, int bus)
+pcibios_scan_root (void *handle, int seg, int bus)
 {
+	struct pci_root_info info;
 	struct pci_controller *controller;
-	u64 base, size, offset;
+	unsigned int windows = 0;
+	char *name;
 
 	printk("PCI: Probing PCI hardware on bus (%02x:%02x)\n", seg, bus);
 	controller = alloc_pci_controller(seg);
 	if (!controller)
-		return NULL;
+		goto out1;
 
 	controller->acpi_handle = handle;
 
-	acpi_get_addr_space(handle, ACPI_MEMORY_RANGE, &base, &size, &offset);
-	controller->mem_offset = offset;
+	acpi_walk_resources(handle, METHOD_NAME__CRS, count_window, &windows);
+	controller->window = kmalloc(sizeof(*controller->window) * windows, GFP_KERNEL);
+	if (!controller->window)
+		goto out2;
+
+	name = kmalloc(16, GFP_KERNEL);
+	if (!name)
+		goto out3;
+
+	sprintf(name, "PCI Bus %02x:%02x", seg, bus);
+	info.controller = controller;
+	info.name = name;
+	acpi_walk_resources(handle, METHOD_NAME__CRS, add_window, &info);
 
 	return scan_root_bus(bus, pci_root_ops, controller);
+
+out3:
+	kfree(controller->window);
+out2:
+	kfree(controller);
+out1:
+	return NULL;
+}
+
+void __init
+pcibios_fixup_device_resources (struct pci_dev *dev, struct pci_bus *bus)
+{
+	struct pci_controller *controller = PCI_CONTROLLER(dev);
+	struct pci_window *window;
+	int i, j;
+
+	for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+		if (!dev->resource[i].start)
+			continue;
+
+#define contains(win, res)	((res)->start >= (win)->start && \
+				 (res)->end   <= (win)->end)
+
+		for (j = 0; j < controller->windows; j++) {
+			window = &controller->window[j];
+			if (((dev->resource[i].flags & IORESOURCE_MEM &&
+			      window->resource.flags & IORESOURCE_MEM) ||
+			     (dev->resource[i].flags & IORESOURCE_IO &&
+			      window->resource.flags & IORESOURCE_IO)) &&
+			    contains(&window->resource, &dev->resource[i])) {
+				dev->resource[i].start += window->offset;
+				dev->resource[i].end   += window->offset;
+			}
+		}
+	}
 }
 
 /*
diff -Nru a/arch/ia64/sn/kernel/machvec.c b/arch/ia64/sn/kernel/machvec.c
--- a/arch/ia64/sn/kernel/machvec.c	Tue Dec  3 10:07:29 2002
+++ b/arch/ia64/sn/kernel/machvec.c	Sat May 10 02:28:47 2003
@@ -33,9 +33,11 @@
 #include <linux/config.h>
 
 #ifdef CONFIG_IA64_SGI_SN1
-#define MACHVEC_PLATFORM_NAME	sn1
+#define MACHVEC_PLATFORM_NAME		sn1
+#define MACHVEC_PLATFORM_HEADER		<asm/machvec_sn1.h>
 #else CONFIG_IA64_SGI_SN1
-#define MACHVEC_PLATFORM_NAME	sn2
+#define MACHVEC_PLATFORM_NAME		sn2
+#define MACHVEC_PLATFORM_HEADER		<asm/machvec_sn2.h>
 #else
 #error "unknown platform"
 #endif
diff -Nru a/arch/ia64/tools/print_offsets.c b/arch/ia64/tools/print_offsets.c
--- a/arch/ia64/tools/print_offsets.c	Fri Feb 28 15:27:56 2003
+++ b/arch/ia64/tools/print_offsets.c	Sat May 10 02:28:47 2003
@@ -193,7 +193,7 @@
   printf ("/*\n * DO NOT MODIFY\n *\n * This file was generated by "
 	  "arch/ia64/tools/print_offsets.\n *\n */\n\n");
 
-  for (i = 0; i < sizeof (tab) / sizeof (tab[0]); ++i)
+  for (i = 0; i < (int) (sizeof (tab) / sizeof (tab[0])); ++i)
     {
       if (tab[i].name[0] == '\0')
 	printf ("\n");
diff -Nru a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S
--- a/arch/m68k/kernel/entry.S	Tue Feb 25 07:35:49 2003
+++ b/arch/m68k/kernel/entry.S	Mon May 12 18:59:21 2003
@@ -188,7 +188,7 @@
 
 
 #if 0
-#if CONFIG_AMIGA
+#ifdef CONFIG_AMIGA
 ami_inthandler:
 	addql	#1,irq_stat+CPUSTAT_LOCAL_IRQ_COUNT
 	SAVE_ALL_INT
diff -Nru a/arch/m68k/sun3/prom/init.c b/arch/m68k/sun3/prom/init.c
--- a/arch/m68k/sun3/prom/init.c	Tue Feb  5 09:40:28 2002
+++ b/arch/m68k/sun3/prom/init.c	Mon May 12 18:59:21 2003
@@ -32,7 +32,7 @@
 
 void __init prom_init(struct linux_romvec *rp)
 {
-#if CONFIG_AP1000
+#ifdef CONFIG_AP1000
 	extern struct linux_romvec *ap_prom_init(void);
 	rp = ap_prom_init();
 #endif
diff -Nru a/arch/m68k/sun3/prom/printf.c b/arch/m68k/sun3/prom/printf.c
--- a/arch/m68k/sun3/prom/printf.c	Tue Feb  5 09:40:28 2002
+++ b/arch/m68k/sun3/prom/printf.c	Mon May 12 18:59:21 2003
@@ -38,7 +38,7 @@
 
 	bptr = ppbuf;
 
-#if CONFIG_AP1000
+#ifdef CONFIG_AP1000
         ap_write(1,bptr,strlen(bptr));
 #else
 
diff -Nru a/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S b/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S
--- a/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S	Fri Nov  1 07:19:55 2002
+++ b/arch/m68knommu/platform/5249/MOTOROLA/crt0_ram.S	Mon May 12 18:59:22 2003
@@ -93,7 +93,7 @@
 	move.l  %d0, 0x180(%a1)			/* Set PLL register */
 	nop
 
-#if CONFIG_CLOCK_140MHz
+#ifdef CONFIG_CLOCK_140MHz
 	/*
 	 *	Set initial clock frequency. This assumes M5249C3 board
 	 *	is fitted with 11.2896MHz crystal. It will program the
diff -Nru a/arch/mips/arc/misc.c b/arch/mips/arc/misc.c
--- a/arch/mips/arc/misc.c	Mon Feb  4 23:41:17 2002
+++ b/arch/mips/arc/misc.c	Mon May 12 18:59:21 2003
@@ -19,7 +19,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	romvec->halt();
@@ -29,7 +29,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	romvec->pdown();
@@ -40,7 +40,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	romvec->restart();
@@ -50,7 +50,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	romvec->reboot();
@@ -60,7 +60,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	romvec->imode();
diff -Nru a/arch/mips/au1000/common/serial.c b/arch/mips/au1000/common/serial.c
--- a/arch/mips/au1000/common/serial.c	Thu Apr 24 03:30:40 2003
+++ b/arch/mips/au1000/common/serial.c	Wed May  7 15:51:55 2003
@@ -2681,8 +2681,8 @@
 		       (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
 		       state->port, state->irq,
 		       uart_config[state->type].name);
-		tty_register_device(&serial_driver, state->line);
-		tty_register_device(&callout_driver, state->line);
+		tty_register_device(&serial_driver, state->line, NULL);
+		tty_register_device(&callout_driver, state->line, NULL);
 	}
 	return 0;
 }
@@ -2769,8 +2769,8 @@
 	      state->iomem_base ? "iomem" : "port",
 	      state->iomem_base ? (unsigned long)state->iomem_base :
 	      state->port, state->irq, uart_config[state->type].name);
-	tty_register_device(&serial_driver, state->line); 
-	tty_register_device(&callout_driver, state->line);
+	tty_register_device(&serial_driver, state->line, NULL); 
+	tty_register_device(&callout_driver, state->line, NULL);
 	return state->line + SERIAL_DEV_OFFSET;
 }
 
diff -Nru a/arch/mips64/arc/misc.c b/arch/mips64/arc/misc.c
--- a/arch/mips64/arc/misc.c	Mon Feb  4 23:45:04 2002
+++ b/arch/mips64/arc/misc.c	Mon May 12 18:59:21 2003
@@ -29,7 +29,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	ARC_CALL0(halt);
@@ -41,7 +41,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	ARC_CALL0(pdown);
@@ -54,7 +54,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	ARC_CALL0(restart);
@@ -66,7 +66,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	ARC_CALL0(reboot);
@@ -78,7 +78,7 @@
 {
 	bc_disable();
 	cli();
-#if CONFIG_SCSI_SGIWD93
+#ifdef CONFIG_SCSI_SGIWD93
 	reset_wd33c93(sgiwd93_host);
 #endif
 	ARC_CALL0(imode);
diff -Nru a/arch/parisc/hpux/wrappers.S b/arch/parisc/hpux/wrappers.S
--- a/arch/parisc/hpux/wrappers.S	Fri Oct 18 01:25:07 2002
+++ b/arch/parisc/hpux/wrappers.S	Mon May 12 20:04:07 2003
@@ -129,7 +129,7 @@
 	/* Set the return value for the child */
 
 hpux_child_return:
-#if CONFIG_SMP || CONFIG_PREEMPT
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 	bl	schedule_tail, %r2
 	nop
 #endif
diff -Nru a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c
--- a/arch/parisc/kernel/module.c	Sun Mar  2 15:58:28 2003
+++ b/arch/parisc/kernel/module.c	Mon May 12 21:23:07 2003
@@ -568,3 +568,7 @@
 #endif
 	return 0;
 }
+
+void module_arch_cleanup(struct module *mod)
+{
+}
diff -Nru a/arch/ppc/kernel/module.c b/arch/ppc/kernel/module.c
--- a/arch/ppc/kernel/module.c	Mon Jan 13 09:46:25 2003
+++ b/arch/ppc/kernel/module.c	Mon May 12 21:23:07 2003
@@ -269,3 +269,7 @@
 {
 	return 0;
 }
+
+void module_arch_cleanup(struct module *mod)
+{
+}
diff -Nru a/arch/ppc/kernel/process.c b/arch/ppc/kernel/process.c
--- a/arch/ppc/kernel/process.c	Wed Mar 12 03:28:50 2003
+++ b/arch/ppc/kernel/process.c	Mon May 19 11:32:25 2003
@@ -445,33 +445,26 @@
 	      void *child_threadptr, int *child_tidp, int p6,
 	      struct pt_regs *regs)
 {
- 	struct task_struct *p;
-
 	CHECK_FULL_REGS(regs);
 	if (usp == 0)
 		usp = regs->gpr[1];	/* stack pointer for child */
- 	p = do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0,
-		    parent_tidp, child_tidp);
- 	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+ 	return do_fork(clone_flags & ~CLONE_IDLETASK, usp, regs, 0,
+			parent_tidp, child_tidp);
 }
 
 int sys_fork(int p1, int p2, int p3, int p4, int p5, int p6,
 	     struct pt_regs *regs)
 {
-	struct task_struct *p;
 	CHECK_FULL_REGS(regs);
-	p = do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL);
 }
 
 int sys_vfork(int p1, int p2, int p3, int p4, int p5, int p6,
 	      struct pt_regs *regs)
 {
-	struct task_struct *p;
 	CHECK_FULL_REGS(regs);
-	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs,
-		    0, NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1],
+			regs, 0, NULL, NULL);
 }
 
 int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
@@ -524,7 +517,7 @@
 	while (count < 16 && sp > prev_sp && sp < stack_top && (sp & 3) == 0) {
 		if (count == 0) {
 			printk("Call trace:");
-#if CONFIG_KALLSYMS
+#ifdef CONFIG_KALLSYMS
 			printk("\n");
 #endif
 		} else {
@@ -534,7 +527,7 @@
 			} else
 				ret = *(unsigned long *)(sp + 4);
 			printk(" [%08lx] ", ret);
-#if CONFIG_KALLSYMS
+#ifdef CONFIG_KALLSYMS
 			print_symbol("%s", ret);
 			printk("\n");
 #endif
diff -Nru a/arch/ppc/kernel/smp.c b/arch/ppc/kernel/smp.c
--- a/arch/ppc/kernel/smp.c	Wed Apr 30 05:41:43 2003
+++ b/arch/ppc/kernel/smp.c	Mon May 19 11:33:32 2003
@@ -403,7 +403,7 @@
 	/* create a process for the processor */
 	/* only regs.msr is actually used, and 0 is OK for it */
 	memset(&regs, 0, sizeof(struct pt_regs));
-	p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+	p = copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
 	if (IS_ERR(p))
 		panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
 
diff -Nru a/arch/ppc64/kernel/LparData.c b/arch/ppc64/kernel/LparData.c
--- a/arch/ppc64/kernel/LparData.c	Mon Nov 11 05:21:11 2002
+++ b/arch/ppc64/kernel/LparData.c	Tue Mar 25 20:30:58 2003
@@ -61,7 +61,7 @@
 	0xc8a5d9c4,	/* desc = "HvRD" ebcdic */
 	sizeof(struct HvReleaseData),
 	offsetof(struct naca_struct, xItVpdAreas),
-	(struct naca_struct *)(KERNELBASE+0x4000), /* 64-bit Naca address */
+	(struct naca_struct *)(NACA_VIRT_ADDR), /* 64-bit Naca address */
 	0x6000,		/* offset of LparMap within loadarea (see head.S) */
 	0,
 	1,		/* tags inactive       */
diff -Nru a/arch/ppc64/kernel/Makefile b/arch/ppc64/kernel/Makefile
--- a/arch/ppc64/kernel/Makefile	Sun Mar  9 14:15:54 2003
+++ b/arch/ppc64/kernel/Makefile	Tue Mar 25 20:30:58 2003
@@ -15,7 +15,7 @@
 			     iSeries_IoMmTable.o iSeries_irq.o \
 			     iSeries_VpdInfo.o   XmPciLpEvent.o \
 			     HvCall.o HvLpConfig.o LparData.o mf_proc.o \
-			     proc_pmc.o iSeries_setup.o ItLpQueue.o hvCall.o \
+			     iSeries_setup.o ItLpQueue.o hvCall.o \
 			     mf.o HvLpEvent.o iSeries_proc.o 
 
 obj-$(CONFIG_PPC_PSERIES) += pSeries_pci.o pSeries_lpar.o pSeries_hvCall.o \
@@ -25,6 +25,7 @@
 obj-y			  += open_pic.o xics.o pSeries_htab.o rtas.o \
 			     chrp_setup.o i8259.o ras.o prom.o 
 
+obj-$(CONFIG_PROC_FS)		+= proc_ppc64.o
 obj-$(CONFIG_RTAS_FLASH)	+= rtas_flash.o
 obj-$(CONFIG_SMP)		+= smp.o
 obj-$(CONFIG_MODULES)		+= module.o ppc_ksyms.o
diff -Nru a/arch/ppc64/kernel/align.c b/arch/ppc64/kernel/align.c
--- a/arch/ppc64/kernel/align.c	Thu Feb 20 19:55:52 2003
+++ b/arch/ppc64/kernel/align.c	Mon Mar 31 11:43:44 2003
@@ -237,7 +237,7 @@
 	dsisr = regs->dsisr;
 
 	/* Power4 doesn't set DSISR for an alignment interrupt */
-	if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+	if (!cpu_alignexc_sets_dsisr()) {
 		unsigned int real_instr;
 		if (__get_user(real_instr, (unsigned int *)regs->nip))
 			return 0;
@@ -309,6 +309,7 @@
 				/* Doing stfs, have to convert to single */
 				enable_kernel_fp();
 				cvt_df(&current->thread.fpr[reg], (float *)&data.v[4], &current->thread.fpscr);
+				disable_kernel_fp();
 			}
 			else
 				data.dd = current->thread.fpr[reg];
@@ -342,6 +343,7 @@
 				/* Doing lfs, have to convert to double */
 				enable_kernel_fp();
 				cvt_fd((float *)&data.v[4], &current->thread.fpr[reg], &current->thread.fpscr);
+				disable_kernel_fp();
 			}
 			else
 				current->thread.fpr[reg] = data.dd;
diff -Nru a/arch/ppc64/kernel/asm-offsets.c b/arch/ppc64/kernel/asm-offsets.c
--- a/arch/ppc64/kernel/asm-offsets.c	Sat Oct 26 14:47:45 2002
+++ b/arch/ppc64/kernel/asm-offsets.c	Tue Mar 25 20:30:58 2003
@@ -59,14 +59,14 @@
 
 	/* naca */
         DEFINE(PACA, offsetof(struct naca_struct, paca));
-	DEFINE(DCACHEL1LINESIZE, offsetof(struct naca_struct, dCacheL1LineSize));
+	DEFINE(DCACHEL1LINESIZE, offsetof(struct systemcfg, dCacheL1LineSize));
         DEFINE(DCACHEL1LOGLINESIZE, offsetof(struct naca_struct, dCacheL1LogLineSize));
         DEFINE(DCACHEL1LINESPERPAGE, offsetof(struct naca_struct, dCacheL1LinesPerPage));
-        DEFINE(ICACHEL1LINESIZE, offsetof(struct naca_struct, iCacheL1LineSize));
+        DEFINE(ICACHEL1LINESIZE, offsetof(struct systemcfg, iCacheL1LineSize));
         DEFINE(ICACHEL1LOGLINESIZE, offsetof(struct naca_struct, iCacheL1LogLineSize));
         DEFINE(ICACHEL1LINESPERPAGE, offsetof(struct naca_struct, iCacheL1LinesPerPage));
 	DEFINE(SLBSIZE, offsetof(struct naca_struct, slb_size));
-	DEFINE(PLATFORM, offsetof(struct naca_struct, platform));
+	DEFINE(PLATFORM, offsetof(struct systemcfg, platform));
 
 	/* paca */
         DEFINE(PACA_SIZE, sizeof(struct paca_struct));
diff -Nru a/arch/ppc64/kernel/chrp_setup.c b/arch/ppc64/kernel/chrp_setup.c
--- a/arch/ppc64/kernel/chrp_setup.c	Thu Apr 24 03:30:41 2003
+++ b/arch/ppc64/kernel/chrp_setup.c	Fri Apr 25 13:27:32 2003
@@ -263,6 +263,8 @@
 	char *os;
 	static int display_character, set_indicator;
 	static int max_width;
+	static spinlock_t progress_lock = SPIN_LOCK_UNLOCKED;
+	static int pending_newline = 0;  /* did last write end with unprinted newline? */
 
 	if (!rtas.base)
 		return;
@@ -278,34 +280,79 @@
 		display_character = rtas_token("display-character");
 		set_indicator = rtas_token("set-indicator");
 	}
-	if (display_character == RTAS_UNKNOWN_SERVICE) {
-		/* use hex display */
-		if (set_indicator == RTAS_UNKNOWN_SERVICE)
-			return;
-		rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex);
+
+	if(display_character == RTAS_UNKNOWN_SERVICE) {
+		/* use hex display if available */
+		if(set_indicator != RTAS_UNKNOWN_SERVICE)
+			rtas_call(set_indicator, 3, 1, NULL, 6, 0, hex);
 		return;
 	}
 
-	rtas_call(display_character, 1, 1, NULL, '\r');
+	spin_lock(&progress_lock);
 
+	/* Last write ended with newline, but we didn't print it since
+	 * it would just clear the bottom line of output. Print it now
+	 * instead.
+	 *
+	 * If no newline is pending, print a CR to start output at the
+	 * beginning of the line.
+	 */
+	if(pending_newline) {
+		rtas_call(display_character, 1, 1, NULL, '\r');
+		rtas_call(display_character, 1, 1, NULL, '\n');
+		pending_newline = 0;
+	} else
+		rtas_call(display_character, 1, 1, NULL, '\r');
+ 
 	width = max_width;
 	os = s;
-	while ( *os )
-	{
-		if ( (*os == '\n') || (*os == '\r') )
+	while (*os) {
+		if(*os == '\n' || *os == '\r') {
+			/* Blank to end of line. */
+			while(width-- > 0)
+				rtas_call(display_character, 1, 1, NULL, ' ');
+ 
+			/* If newline is the last character, save it
+			 * until next call to avoid bumping up the
+			 * display output.
+			 */
+			if(*os == '\n' && !os[1]) {
+				pending_newline = 1;
+				spin_unlock(&progress_lock);
+				return;
+			}
+ 
+			/* RTAS wants CR-LF, not just LF */
+ 
+			if(*os == '\n') {
+				rtas_call(display_character, 1, 1, NULL, '\r');
+				rtas_call(display_character, 1, 1, NULL, '\n');
+			} else {
+				/* CR might be used to re-draw a line, so we'll
+				 * leave it alone and not add LF.
+				 */
+				rtas_call(display_character, 1, 1, NULL, *os);
+			}
+ 
 			width = max_width;
-		else
+		} else {
 			width--;
-		rtas_call(display_character, 1, 1, NULL, *os++ );
+			rtas_call(display_character, 1, 1, NULL, *os);
+		}
+ 
+		os++;
+ 
 		/* if we overwrite the screen length */
-		if ( width == 0 )
+		if ( width <= 0 )
 			while ( (*os != 0) && (*os != '\n') && (*os != '\r') )
 				os++;
 	}
-
+ 
 	/* Blank to end of line. */
 	while ( width-- > 0 )
 		rtas_call(display_character, 1, 1, NULL, ' ' );
+
+	spin_unlock(&progress_lock);
 }
 
 extern void setup_default_decr(void);
diff -Nru a/arch/ppc64/kernel/entry.S b/arch/ppc64/kernel/entry.S
--- a/arch/ppc64/kernel/entry.S	Sat Feb 22 18:35:54 2003
+++ b/arch/ppc64/kernel/entry.S	Thu May  1 19:04:21 2003
@@ -225,10 +225,6 @@
 	bl	.sys32_rt_sigreturn
 	b	80f
 
-_GLOBAL(ppc64_sigreturn)
-	bl	.sys_sigreturn
-	b	80f
-
 _GLOBAL(ppc64_rt_sigreturn)
 	bl	.sys_rt_sigreturn
 
@@ -412,11 +408,6 @@
 	ld	r4,GPR4(r1)
 	ld	r1,GPR1(r1)
 
-	/*
-	 *  What if we took an exception and stole this segment, we may
-	 * fault on the above addresses and globber SRR0/1. Should check RI
-	 * bit and repeat - Anton
-	 */
 	rfid
 
 /* Note: this must change if we start using the  TIF_NOTIFY_RESUME bit */
diff -Nru a/arch/ppc64/kernel/head.S b/arch/ppc64/kernel/head.S
--- a/arch/ppc64/kernel/head.S	Sun Mar  2 14:39:15 2003
+++ b/arch/ppc64/kernel/head.S	Thu May  1 19:04:21 2003
@@ -29,6 +29,8 @@
 #include <asm/processor.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
+#include <asm/naca.h>
+#include <asm/systemcfg.h>
 #include <asm/ppc_asm.h>
 #include <asm/offsets.h>
 #include <asm/bug.h>
@@ -49,8 +51,9 @@
  * 0x0100 - 0x2fff : pSeries Interrupt prologs
  * 0x3000 - 0x3fff : Interrupt support
  * 0x4000 - 0x4fff : NACA
- * 0x5000 - 0x5fff : Initial segment table
+ * 0x5000 - 0x5fff : SystemCfg
  * 0x6000          : iSeries and common interrupt prologs
+ * 0x9000 - 0x9fff : Initial segment table
  */
 
 /*
@@ -123,6 +126,10 @@
  * All of it must fit below the first exception vector at 0x100.
  */
 _GLOBAL(__secondary_hold)
+	mfmsr	r24
+	ori	r24,r24,MSR_RI
+	mtmsrd	r24			/* RI on */
+
 	/* Grab our linux cpu number */
 	mr      r24,r3
 
@@ -362,11 +369,11 @@
 	STD_EXCEPTION_PSERIES( 0x1300, InstructionBreakpoint )
 
 	/* Space for the naca.  Architected to be located at real address
-	 * 0x4000.  Various tools rely on this location being fixed.
+	 * NACA_PHYS_ADDR.  Various tools rely on this location being fixed.
 	 * The first dword of the naca is required by iSeries LPAR to
 	 * point to itVpdAreas.  On pSeries native, this value is not used.
 	 */
-	. = 0x4000
+	. = NACA_PHYS_ADDR
 	.globl __end_interrupts
 	.globl __start_naca
 __end_interrupts:
@@ -380,21 +387,14 @@
 	.llong 0x0
 	.llong paca
 
-	/*
-	 * Space for the initial segment table
-	 * For LPAR, the hypervisor must fill in at least one entry
-	 * before we get control (with relocate on)
-	 */
-	. = 0x5000
+	. = SYSTEMCFG_PHYS_ADDR
 	.globl __end_naca
-	.globl __start_stab
+	.globl __start_systemcfg
 __end_naca:
-__start_stab:
-
-
-	. = 0x6000
-	.globl __end_stab
-__end_stab:
+__start_systemcfg:
+	. = (SYSTEMCFG_PHYS_ADDR + PAGE_SIZE)
+	.globl __end_systemcfg
+__end_systemcfg:
 
 #ifdef CONFIG_PPC_ISERIES
 	/*
@@ -408,7 +408,7 @@
 
 	.llong	1		/* # ESIDs to be mapped by hypervisor         */
 	.llong	1		/* # memory ranges to be mapped by hypervisor */
-	.llong	5		/* Page # of segment table within load area   */
+	.llong	STAB0_PAGE	/* Page # of segment table within load area   */
 	.llong	0		/* Reserved */
 	.llong  0		/* Reserved */
 	.llong  0		/* Reserved */
@@ -529,6 +529,20 @@
 MachineCheck_FWNMI:
 	EXCEPTION_PROLOG_PSERIES(0x200, MachineCheck_common)
 
+	/*
+	 * Space for the initial segment table
+	 * For LPAR, the hypervisor must fill in at least one entry
+	 * before we get control (with relocate on)
+	 */
+	. = STAB0_PHYS_ADDR
+	.globl __start_stab
+__start_stab:
+
+	. = (STAB0_PHYS_ADDR + PAGE_SIZE)
+	.globl __end_stab
+__end_stab:
+
+
 /*** Common interrupt handlers ***/
 
 	STD_EXCEPTION_COMMON( 0x100, SystemReset, .SystemResetException )
@@ -782,11 +796,16 @@
 FPUnavailable_common:
 	EXCEPTION_PROLOG_COMMON
 	bne	.load_up_fpu		/* if from user, just load it up */
-	li	r20,0
+	addi	r3,r1,STACK_FRAME_OVERHEAD
+#ifdef DO_SOFT_DISABLE
+	ld	r20,SOFTE(r1)
+#else
+	rldicl	r20,r23,49,63   	/* copy EE bit from saved MSR */
+#endif
 	li	r6,0x800
-	bl      .save_remaining_regs    /* if from kernel, take a trap */
-	bl      .KernelFP
-	b       .ret_from_except
+	bl      .save_remaining_regs
+	bl      .KernelFPUnavailableException
+	BUG_OPCODE
 
 	.globl SystemCall_common
 SystemCall_common:
@@ -1032,7 +1051,7 @@
 	slbmfee	r23,r22
 	rldicl  r23,r23,37,63
 	cmpwi   r23,0
-	beq     3f              /* Found an invalid entry              */
+	beq     4f              /* Found an invalid entry              */
 
 	addi	r22,r22,1
 	cmpldi	r22,64
@@ -1041,18 +1060,37 @@
 	/* No free entry - just take the next entry, round-robin */
 	/* XXX we should get the number of SLB entries from the naca */
 SLB_NUM_ENTRIES = 64
-	mfspr	r21,SPRG3
+2:	mfspr	r21,SPRG3
 	ld	r22,PACASTABRR(r21)
 	addi	r23,r22,1
 	cmpdi	r23,SLB_NUM_ENTRIES
-	blt	2f
+	blt	3f
 	li	r23,1
-2:	std	r23,PACASTABRR(r21)
+3:	std	r23,PACASTABRR(r21)
 
 	/* r20 = vsid, r22 = entry */
-3:
+
+	/* 
+	 * Never cast out the segment for our kernel stack. Since we
+	 * dont invalidate the ERAT we could have a valid translation
+	 * for the kernel stack during the first part of exception exit 
+	 * which gets invalidated due to a tlbie from another cpu at a
+	 * non recoverable point (after setting srr0/1) - Anton
+	 */
+	slbmfee	r23,r22
+	srdi	r23,r23,28
+	/*
+	 * This is incorrect (r1 is not the kernel stack) if we entered
+	 * from userspace but there is no critical window from userspace
+	 * so this should be OK. Also if we cast out the userspace stack
+	 * segment while in userspace we will fault it straight back in.
+	 */
+	srdi	r21,r1,28
+	cmpd	r21,r23
+	beq-	2b
+
 	/* Put together the vsid portion of the entry. */
-	li      r21,0
+4:	li      r21,0
 	rldimi  r21,r20,12,0
 	ori     r20,r21,1024
 	ori	r20,r20,128    /* set class bit for kernel region */
@@ -1060,17 +1098,6 @@
 	ori	r20,r20,256    /* map kernel region with large ptes */
 #endif
 
-	/*
-	 * XXX we should handle this in the exception exit path in 2.5,
-	 * we need to make this path quick - Anton
-	 */
-	/* Invalidate the old entry */
-	slbmfee	r21,r22
-	lis	r23,-2049
-	ori	r23,r23,65535
-	and	r21,r21,r23
-	slbie	r21
-
 	/* Put together the esid portion of the entry. */
 	mfspr	r21,DAR        /* Get the new esid                     */
 	rldicl  r21,r21,36,28  /* Permits a full 36b of ESID           */
@@ -1252,9 +1279,12 @@
 	addi	r2,r2,0x4000
 	addi	r2,r2,0x4000
 
+	LOADADDR(r9,systemcfg)
+	SET_REG_TO_CONST(r4, SYSTEMCFG_VIRT_ADDR)
+	std	r4,0(r9)		/* set the systemcfg pointer */
+
 	LOADADDR(r9,naca)
-	SET_REG_TO_CONST(r4, KERNELBASE)
-	addi	r4,r4,0x4000
+	SET_REG_TO_CONST(r4, NACA_VIRT_ADDR)
 	std	r4,0(r9)		/* set the naca pointer */
 
 	/* Get the pointer to the segment table */
@@ -1285,13 +1315,18 @@
 	/* Relocate the TOC from a virt addr to a real addr */
 	sub	r2,r2,r3
 
+	/* setup the systemcfg pointer which is needed by prom_init       */
+	LOADADDR(r9,systemcfg)
+	sub	r9,r9,r3                /* addr of the variable systemcfg */
+	SET_REG_TO_CONST(r4, SYSTEMCFG_VIRT_ADDR)
+	sub	r4,r4,r3
+	std	r4,0(r9)		/* set the value of systemcfg     */
+
 	/* setup the naca pointer which is needed by prom_init            */
 	LOADADDR(r9,naca)
 	sub	r9,r9,r3                /* addr of the variable naca      */
-
-	SET_REG_TO_CONST(r4, KERNELBASE)
+	SET_REG_TO_CONST(r4, NACA_VIRT_ADDR)
 	sub	r4,r4,r3
-	addi	r4,r4,0x4000
 	std	r4,0(r9)		/* set the value of naca          */
 
 	/* DRENG / PPPBBB Fix the following comment!!! -Peter */
@@ -1410,11 +1445,13 @@
 copy_to_here:
 
 /*
+ * load_up_fpu(unused, unused, tsk)
  * Disable FP for the task which had the FPU previously,
  * and save its floating-point registers in its thread_struct.
  * Enables the FPU for use in the kernel on return.
  * On SMP we know the fpu is free, since we give it up every
- * switch.  -- Cort
+ * switch (ie, no lazy save of the FP registers).
+ * On entry: r13 == 'current' && last_task_used_math != 'current'
  */
 _STATIC(load_up_fpu)
 	mfmsr	r5                      /* grab the current MSR */
@@ -1432,27 +1469,30 @@
 	ld	r4,last_task_used_math@l(r3)
 	cmpi	0,r4,0
 	beq	1f
-	addi	r4,r4,THREAD	       /* want THREAD of last_task_used_math */
+	/* Save FP state to last_task_used_math's THREAD struct */
+	addi	r4,r4,THREAD
 	SAVE_32FPRS(0, r4)
 	mffs	fr0
 	stfd	fr0,THREAD_FPSCR(r4)
+	/* Disable FP for last_task_used_math */
 	ld	r5,PT_REGS(r4)
 	ld	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 	li	r20,MSR_FP|MSR_FE0|MSR_FE1
-	andc	r4,r4,r20		/* disable FP for previous task */
+	andc	r4,r4,r20
 	std	r4,_MSR-STACK_FRAME_OVERHEAD(r5)
 1:
 #endif /* CONFIG_SMP */
 	/* enable use of FP after return */
 	ld	r4,PACACURRENT(r13)
 	addi	r5,r4,THREAD		/* Get THREAD */
-	lwz	r4,THREAD_FPEXC_MODE(r5)
+	ld	r4,THREAD_FPEXC_MODE(r5)
 	ori	r23,r23,MSR_FP
 	or	r23,r23,r4
 	lfd	fr0,THREAD_FPSCR(r5)
 	mtfsf	0xff,fr0
 	REST_32FPRS(0, r5)
 #ifndef CONFIG_SMP
+	/* Update last_task_used_math to 'current' */
 	subi	r4,r5,THREAD		/* Back to 'current' */
 	std	r4,last_task_used_math@l(r3)
 #endif /* CONFIG_SMP */
@@ -1460,19 +1500,16 @@
 	b	fast_exception_return
 
 /*
- * FP unavailable trap from kernel - print a message, but let
- * the task use FP in the kernel until it returns to user mode.
+ * disable_kernel_fp()
+ * Disable the FPU.
  */
-_GLOBAL(KernelFP)
-	ld	r3,_MSR(r1)
-	ori	r3,r3,MSR_FP
-	std	r3,_MSR(r1)		/* enable use of FP after return */
-	LOADADDR(r3,86f)
-	ld	r4,PACACURRENT(r13)	/* current */
-	ld	r5,_NIP(r1)
-	b	.ret_from_except
-86:	.string	"floating point used in kernel (task=%p, pc=%x)\n"
-	.align	4
+_GLOBAL(disable_kernel_fp)
+	mfmsr   r3
+	rldicl  r0,r3,(63-MSR_FP_LG),1
+	rldicl  r3,r0,(MSR_FP_LG+1),0
+	mtmsrd  r3			/* disable use of fpu now */
+	isync
+	blr
 
 /*
  * giveup_fpu(tsk)
@@ -1562,8 +1599,8 @@
 	sc				/* HvCall_setASR */
 #else
 	/* set the ASR */
-	addi	r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,SYSTEMCFG_PHYS_ADDR	/* r3 = ptr to systemcfg  */
+	lwz   	r3,PLATFORM(r3)		/* r3 = platform flags */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne   	98f
 	mfspr	r3,PVR
@@ -1642,10 +1679,20 @@
 	bl	.reloc_offset
 	mr	r26,r3
 
+	mfmsr	r6
+	ori	r6,r6,MSR_RI
+	mtmsrd	r6			/* RI on */
+
+	/* setup the systemcfg pointer which is needed by *tab_initialize  */
+	LOADADDR(r6,systemcfg)
+	sub	r6,r6,r26                /* addr of the variable systemcfg */
+	li	r27,SYSTEMCFG_PHYS_ADDR
+	std	r27,0(r6)	 	 /* set the value of systemcfg     */
+
 	/* setup the naca pointer which is needed by *tab_initialize       */
 	LOADADDR(r6,naca)
 	sub	r6,r6,r26                /* addr of the variable naca      */
-	li	r27,0x4000
+	li	r27,NACA_PHYS_ADDR
 	std	r27,0(r6)	 	 /* set the value of naca          */
 
 #ifdef CONFIG_HMT
@@ -1709,15 +1756,12 @@
 	sub	r13,r13,r26		/* convert to physical addr         */
 
 	mtspr	SPRG3,r13		/* PPPBBB: Temp... -Peter */
-	li	r3,0x5000
-	std	r3,PACASTABREAL(r13)
-	LOADADDR(r24, __start_stab)
-	std	r24,PACASTABVIRT(r13)
+	ld	r3,PACASTABREAL(r13)
 	ori	r4,r3,1			/* turn on valid bit                */
 	
 	/* set the ASR */
-	addi	r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   	r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,SYSTEMCFG_PHYS_ADDR	/* r3 = ptr to systemcfg */
+	lwz   	r3,PLATFORM(r3)		/* r3 = platform flags */
 	cmpldi 	r3,PLATFORM_PSERIES_LPAR
 	bne   	98f
 	mfspr	r3,PVR
@@ -1741,8 +1785,8 @@
 	bl	.stab_initialize
 	bl	.htab_initialize
 
-	addi  r3,0,0x4000     /* r3 = ptr to naca */
-	lhz   r3,PLATFORM(r3) /* r3 = platform flags */
+	li	r3,SYSTEMCFG_PHYS_ADDR	/* r3 = ptr to systemcfg */
+	lwz	r3,PLATFORM(r3)		/* r3 = platform flags */
 	cmpldi r3,PLATFORM_PSERIES
 	bne    98f
 	LOADADDR(r6,_SDR1)		/* Only if NOT LPAR */
@@ -1791,11 +1835,14 @@
 	addi    r2,r2,0x4000
 	addi    r2,r2,0x4000
 
-	/* setup the naca pointer                                         */
-	LOADADDR(r9,naca)
+	/* setup the systemcfg pointer */
+	LOADADDR(r9,systemcfg)
+	SET_REG_TO_CONST(r8, SYSTEMCFG_VIRT_ADDR)
+	std	r8,0(r9)
 
-	SET_REG_TO_CONST(r8, KERNELBASE)
-	addi	r8,r8,0x4000
+	/* setup the naca pointer */
+	LOADADDR(r9,naca)
+	SET_REG_TO_CONST(r8, NACA_VIRT_ADDR)
 	std	r8,0(r9)		/* set the value of the naca ptr  */
 
 	LOADADDR(r26, boot_cpuid)
@@ -1946,7 +1993,7 @@
 hardware_int_paca0:
 	.space	8*4096
 
-/* 1 page segment table per cpu (max 48) */
+/* 1 page segment table per cpu (max 48, cpu0 allocated at STAB0_PHYS_ADDR) */
 	.globl	stab_array
 stab_array:
         .space	4096 * 48
diff -Nru a/arch/ppc64/kernel/htab.c b/arch/ppc64/kernel/htab.c
--- a/arch/ppc64/kernel/htab.c	Wed Mar 12 15:19:15 2003
+++ b/arch/ppc64/kernel/htab.c	Tue Mar 25 20:30:58 2003
@@ -101,7 +101,7 @@
 
 		hpteg = ((hash & htab_data.htab_hash_mask)*HPTES_PER_GROUP);
 
-		if (naca->platform == PLATFORM_PSERIES_LPAR)
+		if (systemcfg->platform == PLATFORM_PSERIES_LPAR)
 			ret = pSeries_lpar_hpte_insert(hpteg, va,
 				(unsigned long)__v2a(addr) >> PAGE_SHIFT,
 				0, mode, 1, large);
@@ -140,7 +140,7 @@
 	htab_data.htab_num_ptegs = pteg_count;
 	htab_data.htab_hash_mask = pteg_count - 1;
 
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 		/* Find storage for the HPT.  Must be contiguous in
 		 * the absolute address space.
 		 */
@@ -165,15 +165,15 @@
 	mode_rw = _PAGE_ACCESSED | _PAGE_COHERENT | PP_RWXX;
 
 	/* XXX we currently map kernel text rw, should fix this */
-	if (cpu_has_largepage() && naca->physicalMemorySize > 256*MB) {
+	if (cpu_has_largepage() && systemcfg->physicalMemorySize > 256*MB) {
 		create_pte_mapping((unsigned long)KERNELBASE, 
 				   KERNELBASE + 256*MB, mode_rw, 0);
 		create_pte_mapping((unsigned long)KERNELBASE + 256*MB, 
-				   KERNELBASE + (naca->physicalMemorySize), 
+				   KERNELBASE + (systemcfg->physicalMemorySize), 
 				   mode_rw, 1);
 	} else {
 		create_pte_mapping((unsigned long)KERNELBASE, 
-				   KERNELBASE+(naca->physicalMemorySize), 
+				   KERNELBASE+(systemcfg->physicalMemorySize), 
 				   mode_rw, 0);
 	}
 }
diff -Nru a/arch/ppc64/kernel/iSeries_setup.c b/arch/ppc64/kernel/iSeries_setup.c
--- a/arch/ppc64/kernel/iSeries_setup.c	Sun Apr 20 09:14:41 2003
+++ b/arch/ppc64/kernel/iSeries_setup.c	Wed Apr 23 23:53:25 2003
@@ -561,13 +561,13 @@
 	 * which should be equal to 
 	 *   nextPhysChunk
 	 */
-	naca->physicalMemorySize = chunk_to_addr(nextPhysChunk);
+	systemcfg->physicalMemorySize = chunk_to_addr(nextPhysChunk);
 
 	/* Bolt kernel mappings for all of memory */
-	iSeries_bolt_kernel( 0, naca->physicalMemorySize );
+	iSeries_bolt_kernel( 0, systemcfg->physicalMemorySize );
 
 	lmb_init();
-	lmb_add( 0, naca->physicalMemorySize );
+	lmb_add( 0, systemcfg->physicalMemorySize );
 	lmb_analyze();	/* ?? */
 	lmb_reserve( 0, __pa(klimit));
 
@@ -584,29 +584,28 @@
 
 static void __init setup_iSeries_cache_sizes(void)
 {
-	unsigned i,n;
-	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
+	unsigned int i, n;
+	unsigned int procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
+
+	systemcfg->iCacheL1Size = xIoHriProcessorVpd[procIx].xInstCacheSize * 1024;
+	systemcfg->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
+	systemcfg->dCacheL1Size = xIoHriProcessorVpd[procIx].xDataL1CacheSizeKB * 1024;
+	systemcfg->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
+	naca->iCacheL1LinesPerPage = PAGE_SIZE / systemcfg->iCacheL1LineSize;
+	naca->dCacheL1LinesPerPage = PAGE_SIZE / systemcfg->dCacheL1LineSize;
 
-	naca->iCacheL1LineSize = xIoHriProcessorVpd[procIx].xInstCacheOperandSize;
-	naca->dCacheL1LineSize = xIoHriProcessorVpd[procIx].xDataCacheOperandSize;
-	naca->iCacheL1LinesPerPage = PAGE_SIZE / naca->iCacheL1LineSize;
-	naca->dCacheL1LinesPerPage = PAGE_SIZE / naca->dCacheL1LineSize;
-	i = naca->iCacheL1LineSize;
+	i = systemcfg->iCacheL1LineSize;
 	n = 0;
 	while ((i=(i/2))) ++n;
 	naca->iCacheL1LogLineSize = n;
-	i = naca->dCacheL1LineSize;
+
+	i = systemcfg->dCacheL1LineSize;
 	n = 0;
 	while ((i=(i/2))) ++n;
 	naca->dCacheL1LogLineSize = n;
 
-	printk( "D-cache line size = %d  (log = %d)\n",
-			(unsigned)naca->dCacheL1LineSize,
-			(unsigned)naca->dCacheL1LogLineSize );
-	printk( "I-cache line size = %d  (log = %d)\n",
-			(unsigned)naca->iCacheL1LineSize,
-			(unsigned)naca->iCacheL1LogLineSize );
-	
+	printk( "D-cache line size = %d\n", (unsigned int)systemcfg->dCacheL1LineSize);
+	printk( "I-cache line size = %d\n", (unsigned int)systemcfg->iCacheL1LineSize);
 }
 
 /*
@@ -648,6 +647,11 @@
 	void *	eventStack;
 	unsigned procIx = get_paca()->xLpPaca.xDynHvPhysicalProcIndex;
 
+	/* Add an eye catcher and the systemcfg layout version number */
+	strcpy(systemcfg->eye_catcher, "SYSTEMCFG:PPC64");
+	systemcfg->version.major = SYSTEMCFG_MAJOR;
+	systemcfg->version.minor = SYSTEMCFG_MINOR;
+
 	/* Setup the Lp Event Queue */
 
 	/* Allocate a page for the Event Stack
@@ -696,8 +700,8 @@
 	printk("Time base frequency = %lu.%02lu\n",
 			tbFreqMhz,
 			tbFreqMhzHundreths );
-	printk("Processor version = %x\n",
-			xIoHriProcessorVpd[procIx].xPVR );
+	systemcfg->processor = xIoHriProcessorVpd[procIx].xPVR;
+	printk("Processor version = %x\n", systemcfg->processor);
 
 }
 
@@ -726,9 +730,9 @@
 	seq_printf(m,"time base\t: %lu.%02luMHz\n",
 		tbFreqMhz, tbFreqMhzHundreths );
 	seq_printf(m,"i-cache\t\t: %d\n",
-		naca->iCacheL1LineSize);
+		systemcfg->iCacheL1LineSize);
 	seq_printf(m,"d-cache\t\t: %d\n",
-		naca->dCacheL1LineSize);
+		systemcfg->dCacheL1LineSize);
 
 }
 
diff -Nru a/arch/ppc64/kernel/ioctl32.c b/arch/ppc64/kernel/ioctl32.c
--- a/arch/ppc64/kernel/ioctl32.c	Wed Apr 30 08:47:36 2003
+++ b/arch/ppc64/kernel/ioctl32.c	Mon May 19 23:31:53 2003
@@ -23,6 +23,7 @@
 #include <linux/config.h>
 #include <linux/types.h>
 #include <linux/compat.h>
+#include <linux/ioctl32.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
@@ -50,6 +51,7 @@
 #include <linux/cdrom.h>
 #include <linux/loop.h>
 #include <linux/auto_fs.h>
+#include <linux/auto_fs4.h>
 #include <linux/devfs_fs.h>
 #include <linux/tty.h>
 #include <linux/vt_kern.h>
@@ -577,6 +579,17 @@
 		len += sizeof(struct ethtool_regs);
 		break;
 	}
+	case ETHTOOL_GEEPROM: 
+	case ETHTOOL_SEEPROM: { 
+		struct ethtool_eeprom *promaddr = (struct ethtool_eeprom *)A(data); 
+		/* darned variable size arguments */ 
+		if (get_user(len, (u32 *)&promaddr->len)) { 
+			err = -EFAULT; 
+			goto out; 
+		} 
+		len += sizeof(struct ethtool_eeprom); 
+		break; 
+	} 
 	case ETHTOOL_GSET:
 	case ETHTOOL_SSET:	len = sizeof(struct ethtool_cmd); break;
 	default:
@@ -659,6 +672,32 @@
 	return err;
 }
 
+int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+	struct ifreq *u_ifreq64;
+	struct ifreq32 *u_ifreq32 = (struct ifreq32 *) arg;
+	char tmp_buf[IFNAMSIZ];
+	void __user *data64;
+	u32 data32;
+
+	if (copy_from_user(&tmp_buf[0], &(u_ifreq32->ifr_ifrn.ifrn_name[0]),
+			   IFNAMSIZ))
+		return -EFAULT;
+	if (__get_user(data32, &u_ifreq32->ifr_ifru.ifru_data))
+		return -EFAULT;
+	data64 = A(data32);
+
+	u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64));
+
+	/* Don't check these user accesses, just let that get trapped
+	 * in the ioctl handler instead.
+	 */
+	copy_to_user(&u_ifreq64->ifr_ifrn.ifrn_name[0], &tmp_buf[0], IFNAMSIZ);
+	__put_user(data64, &u_ifreq64->ifr_ifru.ifru_data);
+
+	return sys_ioctl(fd, cmd, (unsigned long) u_ifreq64);
+}
+
 static int dev_ifsioc(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifreq ifr;
@@ -3643,670 +3682,32 @@
 #define BNEPGETCONNLIST	_IOR('B', 210, int)
 #define BNEPGETCONNINFO	_IOR('B', 211, int)
 
-struct ioctl_trans {
-	unsigned long cmd;
-	unsigned long handler;
-	unsigned long next;
-};
-
-#define COMPATIBLE_IOCTL(cmd) { cmd, (unsigned long)sys_ioctl, 0 },
+#define HANDLE_IOCTL(cmd,handler) { cmd, (ioctl_trans_handler_t)handler, 0 },
+#define COMPATIBLE_IOCTL(cmd) HANDLE_IOCTL(cmd,sys_ioctl)
 
-#define HANDLE_IOCTL(cmd,handler) { cmd, (unsigned long)handler, 0 },
+#define IOCTL_TABLE_START \
+	struct ioctl_trans ioctl_start[] = {
+#define IOCTL_TABLE_END \
+	}; struct ioctl_trans ioctl_end[0];
 
 #define AUTOFS_IOC_SETTIMEOUT32 _IOWR(0x93,0x64,unsigned int)
 #define SMB_IOC_GETMOUNTUID_32 _IOR('u', 1, compat_uid_t)
 
-static struct ioctl_trans ioctl_translations[] = {
-    /* List here explicitly which ioctl's need translation,
-     * all others default to calling sys_ioctl().
-     */
-/* Big T */
-COMPATIBLE_IOCTL(TCGETA)
-COMPATIBLE_IOCTL(TCSETA)
-COMPATIBLE_IOCTL(TCSETAW)
-COMPATIBLE_IOCTL(TCSETAF)
-COMPATIBLE_IOCTL(TCSBRK)
+IOCTL_TABLE_START
+#include <linux/compat_ioctl.h>
 COMPATIBLE_IOCTL(TCSBRKP)
-COMPATIBLE_IOCTL(TCXONC)
-COMPATIBLE_IOCTL(TCFLSH)
-COMPATIBLE_IOCTL(TCGETS)
-COMPATIBLE_IOCTL(TCSETS)
-COMPATIBLE_IOCTL(TCSETSW)
-COMPATIBLE_IOCTL(TCSETSF)
-COMPATIBLE_IOCTL(TIOCLINUX)
 COMPATIBLE_IOCTL(TIOCSTART)
 COMPATIBLE_IOCTL(TIOCSTOP)
-/* Little t */
-COMPATIBLE_IOCTL(TIOCGETD)
-COMPATIBLE_IOCTL(TIOCSETD)
-COMPATIBLE_IOCTL(TIOCEXCL)
-COMPATIBLE_IOCTL(TIOCNXCL)
-COMPATIBLE_IOCTL(TIOCCONS)
-COMPATIBLE_IOCTL(TIOCGSOFTCAR)
-COMPATIBLE_IOCTL(TIOCSSOFTCAR)
-COMPATIBLE_IOCTL(TIOCSWINSZ)
-COMPATIBLE_IOCTL(TIOCGWINSZ)
-COMPATIBLE_IOCTL(TIOCMGET)
-COMPATIBLE_IOCTL(TIOCMBIC)
-COMPATIBLE_IOCTL(TIOCMBIS)
-COMPATIBLE_IOCTL(TIOCMSET)
-COMPATIBLE_IOCTL(TIOCPKT)
-COMPATIBLE_IOCTL(TIOCNOTTY)
-COMPATIBLE_IOCTL(TIOCSTI)
-COMPATIBLE_IOCTL(TIOCOUTQ)
-COMPATIBLE_IOCTL(TIOCSPGRP)
-COMPATIBLE_IOCTL(TIOCGPGRP)
-COMPATIBLE_IOCTL(TIOCSCTTY)
-COMPATIBLE_IOCTL(TIOCGPTN)
-COMPATIBLE_IOCTL(TIOCSPTLCK)
 COMPATIBLE_IOCTL(TIOCGSERIAL)
 COMPATIBLE_IOCTL(TIOCSSERIAL)
-COMPATIBLE_IOCTL(TIOCSERGETLSR)
 COMPATIBLE_IOCTL(TIOCSLTC)
-/* Big F */
-COMPATIBLE_IOCTL(FBIOGET_VSCREENINFO)
-COMPATIBLE_IOCTL(FBIOPUT_VSCREENINFO)
-COMPATIBLE_IOCTL(FBIOPAN_DISPLAY)
-COMPATIBLE_IOCTL(FBIOGET_CON2FBMAP)
-COMPATIBLE_IOCTL(FBIOPUT_CON2FBMAP)
 #if 0
 COMPATIBLE_IOCTL(FBIOBLANK)
 #endif
-/* Little f */
-COMPATIBLE_IOCTL(FIOCLEX)
-COMPATIBLE_IOCTL(FIONCLEX)
-COMPATIBLE_IOCTL(FIOASYNC)
-COMPATIBLE_IOCTL(FIONBIO)
-COMPATIBLE_IOCTL(FIONREAD)  /* This is also TIOCINQ */
-/* 0x00 */
-COMPATIBLE_IOCTL(FIBMAP)
-COMPATIBLE_IOCTL(FIGETBSZ)
-/* 0x03 -- HD/IDE ioctl's used by hdparm and friends.
- *         Some need translations, these do not.
- */
-COMPATIBLE_IOCTL(HDIO_GET_IDENTITY)
-COMPATIBLE_IOCTL(HDIO_SET_DMA)
-COMPATIBLE_IOCTL(HDIO_SET_UNMASKINTR)
-COMPATIBLE_IOCTL(HDIO_SET_NOWERR)
-COMPATIBLE_IOCTL(HDIO_SET_32BIT)
-COMPATIBLE_IOCTL(HDIO_SET_MULTCOUNT)
-COMPATIBLE_IOCTL(HDIO_DRIVE_CMD)
-COMPATIBLE_IOCTL(HDIO_SET_PIO_MODE)
-COMPATIBLE_IOCTL(HDIO_SET_NICE)
-/* 0x02 -- Floppy ioctls */
-COMPATIBLE_IOCTL(FDMSGON)
-COMPATIBLE_IOCTL(FDMSGOFF)
-COMPATIBLE_IOCTL(FDSETEMSGTRESH)
-COMPATIBLE_IOCTL(FDFLUSH)
-COMPATIBLE_IOCTL(FDWERRORCLR)
-COMPATIBLE_IOCTL(FDSETMAXERRS)
-COMPATIBLE_IOCTL(FDGETMAXERRS)
-COMPATIBLE_IOCTL(FDGETDRVTYP)
-COMPATIBLE_IOCTL(FDEJECT)
-COMPATIBLE_IOCTL(FDCLRPRM)
-COMPATIBLE_IOCTL(FDFMTBEG)
-COMPATIBLE_IOCTL(FDFMTEND)
-COMPATIBLE_IOCTL(FDRESET)
-COMPATIBLE_IOCTL(FDTWADDLE)
-COMPATIBLE_IOCTL(FDFMTTRK)
-COMPATIBLE_IOCTL(FDRAWCMD)
-/* 0x12 */
-COMPATIBLE_IOCTL(BLKROSET)
-COMPATIBLE_IOCTL(BLKROGET)
-COMPATIBLE_IOCTL(BLKRRPART)
-COMPATIBLE_IOCTL(BLKFLSBUF)
-COMPATIBLE_IOCTL(BLKSECTSET)
-COMPATIBLE_IOCTL(BLKSSZGET)
-COMPATIBLE_IOCTL(BLKRASET)
-COMPATIBLE_IOCTL(BLKFRASET)
-/* RAID */
-COMPATIBLE_IOCTL(RAID_VERSION)
-COMPATIBLE_IOCTL(GET_ARRAY_INFO)
-COMPATIBLE_IOCTL(GET_DISK_INFO)
-COMPATIBLE_IOCTL(PRINT_RAID_DEBUG)
-COMPATIBLE_IOCTL(CLEAR_ARRAY)
-COMPATIBLE_IOCTL(ADD_NEW_DISK)
-COMPATIBLE_IOCTL(HOT_REMOVE_DISK)
-COMPATIBLE_IOCTL(SET_ARRAY_INFO)
-COMPATIBLE_IOCTL(SET_DISK_INFO)
-COMPATIBLE_IOCTL(WRITE_RAID_INFO)
-COMPATIBLE_IOCTL(UNPROTECT_ARRAY)
-COMPATIBLE_IOCTL(PROTECT_ARRAY)
-COMPATIBLE_IOCTL(HOT_ADD_DISK)
-COMPATIBLE_IOCTL(SET_DISK_FAULTY)
-COMPATIBLE_IOCTL(RUN_ARRAY)
-COMPATIBLE_IOCTL(START_ARRAY)
-COMPATIBLE_IOCTL(STOP_ARRAY)
-COMPATIBLE_IOCTL(STOP_ARRAY_RO)
-COMPATIBLE_IOCTL(RESTART_ARRAY_RW)
-/* Big K */
-COMPATIBLE_IOCTL(PIO_FONT)
-COMPATIBLE_IOCTL(GIO_FONT)
-COMPATIBLE_IOCTL(KDSIGACCEPT)
-COMPATIBLE_IOCTL(KDGETKEYCODE)
-COMPATIBLE_IOCTL(KDSETKEYCODE)
-COMPATIBLE_IOCTL(KIOCSOUND)
-COMPATIBLE_IOCTL(KDMKTONE)
-COMPATIBLE_IOCTL(KDGKBTYPE)
-COMPATIBLE_IOCTL(KDSETMODE)
-COMPATIBLE_IOCTL(KDGETMODE)
-COMPATIBLE_IOCTL(KDSKBMODE)
-COMPATIBLE_IOCTL(KDGKBMODE)
-COMPATIBLE_IOCTL(KDSKBMETA)
-COMPATIBLE_IOCTL(KDGKBMETA)
-COMPATIBLE_IOCTL(KDGKBENT)
-COMPATIBLE_IOCTL(KDSKBENT)
-COMPATIBLE_IOCTL(KDGKBSENT)
-COMPATIBLE_IOCTL(KDSKBSENT)
-COMPATIBLE_IOCTL(KDGKBDIACR)
-COMPATIBLE_IOCTL(KDKBDREP)
-COMPATIBLE_IOCTL(KDSKBDIACR)
-COMPATIBLE_IOCTL(KDGKBLED)
-COMPATIBLE_IOCTL(KDSKBLED)
-COMPATIBLE_IOCTL(KDGETLED)
-COMPATIBLE_IOCTL(KDSETLED)
-COMPATIBLE_IOCTL(GIO_SCRNMAP)
-COMPATIBLE_IOCTL(PIO_SCRNMAP)
-COMPATIBLE_IOCTL(GIO_UNISCRNMAP)
-COMPATIBLE_IOCTL(PIO_UNISCRNMAP)
-COMPATIBLE_IOCTL(PIO_FONTRESET)
-COMPATIBLE_IOCTL(PIO_UNIMAPCLR)
-/* Big S */
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN)
-COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK)
-COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY)
-COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE)
-COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE)
-COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER)
-COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND)
-/* Big T */
-COMPATIBLE_IOCTL(TUNSETNOCSUM)
-COMPATIBLE_IOCTL(TUNSETDEBUG)
-COMPATIBLE_IOCTL(TUNSETIFF)
-COMPATIBLE_IOCTL(TUNSETPERSIST)
-COMPATIBLE_IOCTL(TUNSETOWNER)
-/* Big V */
-COMPATIBLE_IOCTL(VT_SETMODE)
-COMPATIBLE_IOCTL(VT_GETMODE)
-COMPATIBLE_IOCTL(VT_GETSTATE)
-COMPATIBLE_IOCTL(VT_OPENQRY)
-COMPATIBLE_IOCTL(VT_ACTIVATE)
-COMPATIBLE_IOCTL(VT_WAITACTIVE)
-COMPATIBLE_IOCTL(VT_RELDISP)
-COMPATIBLE_IOCTL(VT_DISALLOCATE)
-COMPATIBLE_IOCTL(VT_RESIZE)
-COMPATIBLE_IOCTL(VT_RESIZEX)
-COMPATIBLE_IOCTL(VT_LOCKSWITCH)
-COMPATIBLE_IOCTL(VT_UNLOCKSWITCH)
-/* Little v, the video4linux ioctls */
-COMPATIBLE_IOCTL(VIDIOCGCAP)
-COMPATIBLE_IOCTL(VIDIOCGCHAN)
-COMPATIBLE_IOCTL(VIDIOCSCHAN)
-COMPATIBLE_IOCTL(VIDIOCGPICT)
-COMPATIBLE_IOCTL(VIDIOCSPICT)
-COMPATIBLE_IOCTL(VIDIOCCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCKEY)
-COMPATIBLE_IOCTL(VIDIOCGAUDIO)
-COMPATIBLE_IOCTL(VIDIOCSAUDIO)
-COMPATIBLE_IOCTL(VIDIOCSYNC)
-COMPATIBLE_IOCTL(VIDIOCMCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCGMBUF)
-COMPATIBLE_IOCTL(VIDIOCGUNIT)
-COMPATIBLE_IOCTL(VIDIOCGCAPTURE)
-COMPATIBLE_IOCTL(VIDIOCSCAPTURE)
-/* BTTV specific... */
-COMPATIBLE_IOCTL(_IOW('v',  BASE_VIDIOCPRIVATE+0, char [256]))
-COMPATIBLE_IOCTL(_IOR('v',  BASE_VIDIOCPRIVATE+1, char [256]))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int))
-COMPATIBLE_IOCTL(_IOW('v' , BASE_VIDIOCPRIVATE+3, char [16])) /* struct bttv_pll_info */
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+4, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+5, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+6, int))
-COMPATIBLE_IOCTL(_IOR('v' , BASE_VIDIOCPRIVATE+7, int))
 /* Little p (/dev/rtc, /dev/envctrl, etc.) */
 COMPATIBLE_IOCTL(_IOR('p', 20, int[7])) /* RTCGET */
 COMPATIBLE_IOCTL(_IOW('p', 21, int[7])) /* RTCSET */
-COMPATIBLE_IOCTL(RTC_AIE_ON)
-COMPATIBLE_IOCTL(RTC_AIE_OFF)
-COMPATIBLE_IOCTL(RTC_UIE_ON)
-COMPATIBLE_IOCTL(RTC_UIE_OFF)
-COMPATIBLE_IOCTL(RTC_PIE_ON)
-COMPATIBLE_IOCTL(RTC_PIE_OFF)
-COMPATIBLE_IOCTL(RTC_WIE_ON)
-COMPATIBLE_IOCTL(RTC_WIE_OFF)
-COMPATIBLE_IOCTL(RTC_ALM_SET)
-COMPATIBLE_IOCTL(RTC_ALM_READ)
-COMPATIBLE_IOCTL(RTC_RD_TIME)
-COMPATIBLE_IOCTL(RTC_SET_TIME)
-COMPATIBLE_IOCTL(RTC_WKALM_SET)
-COMPATIBLE_IOCTL(RTC_WKALM_RD)
-/* Little m */
-COMPATIBLE_IOCTL(MTIOCTOP)
-/* Socket level stuff */
-COMPATIBLE_IOCTL(FIOSETOWN)
-COMPATIBLE_IOCTL(SIOCSPGRP)
-COMPATIBLE_IOCTL(FIOGETOWN)
-COMPATIBLE_IOCTL(SIOCGPGRP)
-COMPATIBLE_IOCTL(SIOCATMARK)
-COMPATIBLE_IOCTL(SIOCSIFLINK)
-COMPATIBLE_IOCTL(SIOCSIFENCAP)
-COMPATIBLE_IOCTL(SIOCGIFENCAP)
-COMPATIBLE_IOCTL(SIOCSIFBR)
-COMPATIBLE_IOCTL(SIOCGIFBR)
-COMPATIBLE_IOCTL(SIOCSARP)
-COMPATIBLE_IOCTL(SIOCGARP)
-COMPATIBLE_IOCTL(SIOCDARP)
-COMPATIBLE_IOCTL(SIOCSRARP)
-COMPATIBLE_IOCTL(SIOCGRARP)
-COMPATIBLE_IOCTL(SIOCDRARP)
-COMPATIBLE_IOCTL(SIOCADDDLCI)
-COMPATIBLE_IOCTL(SIOCDELDLCI)
-COMPATIBLE_IOCTL(SIOCGMIIPHY)
-COMPATIBLE_IOCTL(SIOCGMIIREG)
-COMPATIBLE_IOCTL(SIOCSMIIREG)
-COMPATIBLE_IOCTL(SIOCGIFVLAN)
-COMPATIBLE_IOCTL(SIOCSIFVLAN)
-/* SG stuff */
-COMPATIBLE_IOCTL(SG_SET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_GET_TIMEOUT)
-COMPATIBLE_IOCTL(SG_EMULATED_HOST)
-COMPATIBLE_IOCTL(SG_SET_TRANSFORM)
-COMPATIBLE_IOCTL(SG_GET_TRANSFORM)
-COMPATIBLE_IOCTL(SG_SET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_RESERVED_SIZE)
-COMPATIBLE_IOCTL(SG_GET_SCSI_ID)
-COMPATIBLE_IOCTL(SG_SET_FORCE_LOW_DMA)
-COMPATIBLE_IOCTL(SG_GET_LOW_DMA)
-COMPATIBLE_IOCTL(SG_SET_FORCE_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_PACK_ID)
-COMPATIBLE_IOCTL(SG_GET_NUM_WAITING)
-COMPATIBLE_IOCTL(SG_SET_DEBUG)
-COMPATIBLE_IOCTL(SG_GET_SG_TABLESIZE)
-COMPATIBLE_IOCTL(SG_GET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_SET_COMMAND_Q)
-COMPATIBLE_IOCTL(SG_GET_VERSION_NUM)
-COMPATIBLE_IOCTL(SG_NEXT_CMD_LEN)
-COMPATIBLE_IOCTL(SG_SCSI_RESET)
-COMPATIBLE_IOCTL(SG_GET_REQUEST_TABLE)
-COMPATIBLE_IOCTL(SG_SET_KEEP_ORPHAN)
-COMPATIBLE_IOCTL(SG_GET_KEEP_ORPHAN)
-/* PPP stuff */
-COMPATIBLE_IOCTL(PPPIOCGFLAGS)
-COMPATIBLE_IOCTL(PPPIOCSFLAGS)
-COMPATIBLE_IOCTL(PPPIOCGASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCGUNIT)
-COMPATIBLE_IOCTL(PPPIOCGRASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCSRASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCGMRU)
-COMPATIBLE_IOCTL(PPPIOCSMRU)
-COMPATIBLE_IOCTL(PPPIOCSMAXCID)
-COMPATIBLE_IOCTL(PPPIOCGXASYNCMAP)
-COMPATIBLE_IOCTL(LPGETSTATUS)
-COMPATIBLE_IOCTL(PPPIOCSXASYNCMAP)
-COMPATIBLE_IOCTL(PPPIOCXFERUNIT)
-COMPATIBLE_IOCTL(PPPIOCGNPMODE)
-COMPATIBLE_IOCTL(PPPIOCSNPMODE)
-COMPATIBLE_IOCTL(PPPIOCGDEBUG)
-COMPATIBLE_IOCTL(PPPIOCSDEBUG)
-COMPATIBLE_IOCTL(PPPIOCNEWUNIT)
-COMPATIBLE_IOCTL(PPPIOCATTACH)
-COMPATIBLE_IOCTL(PPPIOCDETACH)
-COMPATIBLE_IOCTL(PPPIOCSMRRU)
-COMPATIBLE_IOCTL(PPPIOCCONNECT)
-COMPATIBLE_IOCTL(PPPIOCDISCONN)
-COMPATIBLE_IOCTL(PPPIOCATTCHAN)
-COMPATIBLE_IOCTL(PPPIOCGCHAN)
-/* PPPOX */
-COMPATIBLE_IOCTL(PPPOEIOCSFWD)
-COMPATIBLE_IOCTL(PPPOEIOCDFWD)
-/* CDROM stuff */
-COMPATIBLE_IOCTL(CDROMPAUSE)
-COMPATIBLE_IOCTL(CDROMRESUME)
-COMPATIBLE_IOCTL(CDROMPLAYMSF)
-COMPATIBLE_IOCTL(CDROMPLAYTRKIND)
-COMPATIBLE_IOCTL(CDROMREADTOCHDR)
-COMPATIBLE_IOCTL(CDROMREADTOCENTRY)
-COMPATIBLE_IOCTL(CDROMSTOP)
-COMPATIBLE_IOCTL(CDROMSTART)
-COMPATIBLE_IOCTL(CDROMEJECT)
-COMPATIBLE_IOCTL(CDROMVOLCTRL)
-COMPATIBLE_IOCTL(CDROMSUBCHNL)
-COMPATIBLE_IOCTL(CDROMEJECT_SW)
-COMPATIBLE_IOCTL(CDROMMULTISESSION)
-COMPATIBLE_IOCTL(CDROM_GET_MCN)
-COMPATIBLE_IOCTL(CDROMRESET)
-COMPATIBLE_IOCTL(CDROMVOLREAD)
-COMPATIBLE_IOCTL(CDROMSEEK)
-COMPATIBLE_IOCTL(CDROMPLAYBLK)
-COMPATIBLE_IOCTL(CDROMCLOSETRAY)
-COMPATIBLE_IOCTL(CDROM_SET_OPTIONS)
-COMPATIBLE_IOCTL(CDROM_CLEAR_OPTIONS)
-COMPATIBLE_IOCTL(CDROM_SELECT_SPEED)
-COMPATIBLE_IOCTL(CDROM_SELECT_DISC)
-COMPATIBLE_IOCTL(CDROM_MEDIA_CHANGED)
-COMPATIBLE_IOCTL(CDROM_DRIVE_STATUS)
-COMPATIBLE_IOCTL(CDROM_DISC_STATUS)
-COMPATIBLE_IOCTL(CDROM_CHANGER_NSLOTS)
-COMPATIBLE_IOCTL(CDROM_LOCKDOOR)
-COMPATIBLE_IOCTL(CDROM_DEBUG)
-COMPATIBLE_IOCTL(CDROM_GET_CAPABILITY)
-/* DVD ioctls */
-COMPATIBLE_IOCTL(DVD_READ_STRUCT)
-COMPATIBLE_IOCTL(DVD_WRITE_STRUCT)
-COMPATIBLE_IOCTL(DVD_AUTH)
-/* Big L */
-COMPATIBLE_IOCTL(LOOP_SET_FD)
-COMPATIBLE_IOCTL(LOOP_CLR_FD)
-/* Big Q for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_SEQ_RESET)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_SYNC)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_INFO)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_CTRLRATE)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETOUTCOUNT)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETINCOUNT)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_PERCMODE)
-COMPATIBLE_IOCTL(SNDCTL_FM_LOAD_INSTR)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_TESTMIDI)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_RESETSAMPLES)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_NRSYNTHS)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_NRMIDIS)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_INFO)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_THRESHOLD)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_MEMAVL)
-COMPATIBLE_IOCTL(SNDCTL_FM_4OP_ENABLE)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_PANIC)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_OUTOFBAND)
-COMPATIBLE_IOCTL(SNDCTL_SEQ_GETTIME)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_ID)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_CONTROL)
-COMPATIBLE_IOCTL(SNDCTL_SYNTH_REMOVESAMPLE)
-/* Big T for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_TMR_TIMEBASE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_START)
-COMPATIBLE_IOCTL(SNDCTL_TMR_STOP)
-COMPATIBLE_IOCTL(SNDCTL_TMR_CONTINUE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_TEMPO)
-COMPATIBLE_IOCTL(SNDCTL_TMR_SOURCE)
-COMPATIBLE_IOCTL(SNDCTL_TMR_METRONOME)
-COMPATIBLE_IOCTL(SNDCTL_TMR_SELECT)
-/* Little m for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_MIDI_PRETIME)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUMODE)
-COMPATIBLE_IOCTL(SNDCTL_MIDI_MPUCMD)
-/* Big P for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_DSP_RESET)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SYNC)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SPEED)
-COMPATIBLE_IOCTL(SNDCTL_DSP_STEREO)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETBLKSIZE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_CHANNELS)
-COMPATIBLE_IOCTL(SOUND_PCM_WRITE_FILTER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_POST)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SUBDIVIDE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETFRAGMENT)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETFMTS)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETFMT)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETOSPACE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETISPACE)
-COMPATIBLE_IOCTL(SNDCTL_DSP_NONBLOCK)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETCAPS)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETTRIGGER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETTRIGGER)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETIPTR)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETOPTR)
-/* SNDCTL_DSP_MAPINBUF,  XXX needs translation */
-/* SNDCTL_DSP_MAPOUTBUF,  XXX needs translation */
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETSYNCRO)
-COMPATIBLE_IOCTL(SNDCTL_DSP_SETDUPLEX)
-COMPATIBLE_IOCTL(SNDCTL_DSP_GETODELAY)
-COMPATIBLE_IOCTL(SNDCTL_DSP_PROFILE)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_RATE)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_CHANNELS)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_BITS)
-COMPATIBLE_IOCTL(SOUND_PCM_READ_FILTER)
-/* Big C for sound/OSS */
-COMPATIBLE_IOCTL(SNDCTL_COPR_RESET)
-COMPATIBLE_IOCTL(SNDCTL_COPR_LOAD)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RDATA)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RCODE)
-COMPATIBLE_IOCTL(SNDCTL_COPR_WDATA)
-COMPATIBLE_IOCTL(SNDCTL_COPR_WCODE)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RUN)
-COMPATIBLE_IOCTL(SNDCTL_COPR_HALT)
-COMPATIBLE_IOCTL(SNDCTL_COPR_SENDMSG)
-COMPATIBLE_IOCTL(SNDCTL_COPR_RCVMSG)
-/* Big M for sound/OSS */
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_VOLUME)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_BASS)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_TREBLE)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_SYNTH)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_PCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_SPEAKER)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_MIC)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_CD)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_IMIX)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_ALTPCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECLEV)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_IGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_OGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_LINE3)
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL1))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL2))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_DIGITAL3))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEIN))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_PHONEOUT))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_VIDEO))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_RADIO))
-COMPATIBLE_IOCTL(MIXER_READ(SOUND_MIXER_MONITOR))
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_MUTE)
-/* SOUND_MIXER_READ_ENHANCE,  same value as READ_MUTE */
-/* SOUND_MIXER_READ_LOUD,  same value as READ_MUTE */
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECSRC)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_DEVMASK)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_RECMASK)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_STEREODEVS)
-COMPATIBLE_IOCTL(SOUND_MIXER_READ_CAPS)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_VOLUME)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_BASS)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_TREBLE)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SYNTH)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_PCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_SPEAKER)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MIC)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_CD)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IMIX)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_ALTPCM)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECLEV)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_IGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_OGAIN)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_LINE3)
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL1))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL2))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_DIGITAL3))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEIN))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_PHONEOUT))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_VIDEO))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_RADIO))
-COMPATIBLE_IOCTL(MIXER_WRITE(SOUND_MIXER_MONITOR))
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_MUTE)
-/* SOUND_MIXER_WRITE_ENHANCE,  same value as WRITE_MUTE */
-/* SOUND_MIXER_WRITE_LOUD,  same value as WRITE_MUTE */
-COMPATIBLE_IOCTL(SOUND_MIXER_WRITE_RECSRC)
-COMPATIBLE_IOCTL(SOUND_MIXER_INFO)
-COMPATIBLE_IOCTL(SOUND_OLD_MIXER_INFO)
-COMPATIBLE_IOCTL(SOUND_MIXER_ACCESS)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE1)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE2)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE3)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE4)
-COMPATIBLE_IOCTL(SOUND_MIXER_PRIVATE5)
-COMPATIBLE_IOCTL(SOUND_MIXER_GETLEVELS)
-COMPATIBLE_IOCTL(SOUND_MIXER_SETLEVELS)
-COMPATIBLE_IOCTL(OSS_GETVERSION)
-/* AUTOFS */
-COMPATIBLE_IOCTL(AUTOFS_IOC_READY)
-COMPATIBLE_IOCTL(AUTOFS_IOC_FAIL)
-COMPATIBLE_IOCTL(AUTOFS_IOC_CATATONIC)
-COMPATIBLE_IOCTL(AUTOFS_IOC_PROTOVER)
-COMPATIBLE_IOCTL(AUTOFS_IOC_EXPIRE)
-/* DEVFS */
-COMPATIBLE_IOCTL(DEVFSDIOC_GET_PROTO_REV)
-COMPATIBLE_IOCTL(DEVFSDIOC_SET_EVENT_MASK)
-COMPATIBLE_IOCTL(DEVFSDIOC_RELEASE_EVENT_QUEUE)
-COMPATIBLE_IOCTL(DEVFSDIOC_SET_DEBUG_MASK)
-/* Raw devices */
-COMPATIBLE_IOCTL(RAW_SETBIND)
-COMPATIBLE_IOCTL(RAW_GETBIND)
-/* SMB ioctls which do not need any translations */
-COMPATIBLE_IOCTL(SMB_IOC_NEWCONN)
-/* NCP ioctls which do not need any translations */
-COMPATIBLE_IOCTL(NCP_IOC_CONN_LOGGED_IN)
-COMPATIBLE_IOCTL(NCP_IOC_SIGN_INIT)
-COMPATIBLE_IOCTL(NCP_IOC_SIGN_WANTED)
-COMPATIBLE_IOCTL(NCP_IOC_SET_SIGN_WANTED)
-COMPATIBLE_IOCTL(NCP_IOC_LOCKUNLOCK)
-COMPATIBLE_IOCTL(NCP_IOC_GETROOT)
-COMPATIBLE_IOCTL(NCP_IOC_SETROOT)
-COMPATIBLE_IOCTL(NCP_IOC_GETCHARSETS)
-COMPATIBLE_IOCTL(NCP_IOC_SETCHARSETS)
-COMPATIBLE_IOCTL(NCP_IOC_GETDENTRYTTL)
-COMPATIBLE_IOCTL(NCP_IOC_SETDENTRYTTL)
-/* Little a */
-COMPATIBLE_IOCTL(ATMSIGD_CTRL)
-COMPATIBLE_IOCTL(ATMARPD_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_CTRL)
-COMPATIBLE_IOCTL(ATMLEC_MCAST)
-COMPATIBLE_IOCTL(ATMLEC_DATA)
-COMPATIBLE_IOCTL(ATM_SETSC)
-COMPATIBLE_IOCTL(SIOCSIFATMTCP)
-COMPATIBLE_IOCTL(SIOCMKCLIP)
-COMPATIBLE_IOCTL(ATMARP_MKIP)
-COMPATIBLE_IOCTL(ATMARP_SETENTRY)
-COMPATIBLE_IOCTL(ATMARP_ENCAP)
-COMPATIBLE_IOCTL(ATMTCP_CREATE)
-COMPATIBLE_IOCTL(ATMTCP_REMOVE)
-COMPATIBLE_IOCTL(ATMMPC_CTRL)
-COMPATIBLE_IOCTL(ATMMPC_DATA)
-#if defined(CONFIG_DRM) || defined(CONFIG_DRM_MODULE)
-COMPATIBLE_IOCTL(DRM_IOCTL_GET_MAGIC)
-COMPATIBLE_IOCTL(DRM_IOCTL_IRQ_BUSID)
-COMPATIBLE_IOCTL(DRM_IOCTL_AUTH_MAGIC)
-COMPATIBLE_IOCTL(DRM_IOCTL_BLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_UNBLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_CONTROL)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_BUFS)
-COMPATIBLE_IOCTL(DRM_IOCTL_MARK_BUFS)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_RM_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_MOD_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_GET_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_SWITCH_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_NEW_CTX)
-COMPATIBLE_IOCTL(DRM_IOCTL_ADD_DRAW)
-COMPATIBLE_IOCTL(DRM_IOCTL_RM_DRAW)
-COMPATIBLE_IOCTL(DRM_IOCTL_LOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_UNLOCK)
-COMPATIBLE_IOCTL(DRM_IOCTL_FINISH)
-#endif /* DRM */
-/* Big W */
-/* WIOC_GETSUPPORT not yet implemented -E */
-COMPATIBLE_IOCTL(WDIOC_GETSTATUS)
-COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS)
-COMPATIBLE_IOCTL(WDIOC_GETTEMP)
-COMPATIBLE_IOCTL(WDIOC_SETOPTIONS)
-COMPATIBLE_IOCTL(WDIOC_KEEPALIVE)
-/* Big R */
-COMPATIBLE_IOCTL(RNDGETENTCNT)
-COMPATIBLE_IOCTL(RNDADDTOENTCNT)
-COMPATIBLE_IOCTL(RNDGETPOOL)
-COMPATIBLE_IOCTL(RNDADDENTROPY)
-COMPATIBLE_IOCTL(RNDZAPENTCNT)
-COMPATIBLE_IOCTL(RNDCLEARPOOL)
-/* Bluetooth ioctls */
-COMPATIBLE_IOCTL(HCIDEVUP)
-COMPATIBLE_IOCTL(HCIDEVDOWN)
-COMPATIBLE_IOCTL(HCIDEVRESET)
-COMPATIBLE_IOCTL(HCIDEVRESTAT)
-COMPATIBLE_IOCTL(HCIGETDEVLIST)
-COMPATIBLE_IOCTL(HCIGETDEVINFO)
-COMPATIBLE_IOCTL(HCIGETCONNLIST)
-COMPATIBLE_IOCTL(HCIGETCONNINFO)
-COMPATIBLE_IOCTL(HCISETRAW)
-COMPATIBLE_IOCTL(HCISETSCAN)
-COMPATIBLE_IOCTL(HCISETAUTH)
-COMPATIBLE_IOCTL(HCISETENCRYPT)
-COMPATIBLE_IOCTL(HCISETPTYPE)
-COMPATIBLE_IOCTL(HCISETLINKPOL)
-COMPATIBLE_IOCTL(HCISETLINKMODE)
-COMPATIBLE_IOCTL(HCISETACLMTU)
-COMPATIBLE_IOCTL(HCISETSCOMTU)
-COMPATIBLE_IOCTL(HCIINQUIRY)
-COMPATIBLE_IOCTL(HCIUARTSETPROTO)
-COMPATIBLE_IOCTL(HCIUARTGETPROTO)
-COMPATIBLE_IOCTL(RFCOMMCREATEDEV)
-COMPATIBLE_IOCTL(RFCOMMRELEASEDEV)
-COMPATIBLE_IOCTL(RFCOMMGETDEVLIST)
-COMPATIBLE_IOCTL(RFCOMMGETDEVINFO)
-COMPATIBLE_IOCTL(RFCOMMSTEALDLC)
-COMPATIBLE_IOCTL(BNEPCONNADD)
-COMPATIBLE_IOCTL(BNEPCONNDEL)
-COMPATIBLE_IOCTL(BNEPGETCONNLIST)
-COMPATIBLE_IOCTL(BNEPGETCONNINFO)
-COMPATIBLE_IOCTL(PCIIOC_CONTROLLER)
-COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_IO)
-COMPATIBLE_IOCTL(PCIIOC_MMAP_IS_MEM)
-COMPATIBLE_IOCTL(PCIIOC_WRITE_COMBINE)
-/* USB */
-COMPATIBLE_IOCTL(USBDEVFS_RESETEP)
-COMPATIBLE_IOCTL(USBDEVFS_SETINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_SETCONFIGURATION)
-COMPATIBLE_IOCTL(USBDEVFS_GETDRIVER)
-COMPATIBLE_IOCTL(USBDEVFS_DISCARDURB)
-COMPATIBLE_IOCTL(USBDEVFS_CLAIMINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_RELEASEINTERFACE)
-COMPATIBLE_IOCTL(USBDEVFS_CONNECTINFO)
-COMPATIBLE_IOCTL(USBDEVFS_HUB_PORTINFO)
-COMPATIBLE_IOCTL(USBDEVFS_RESET)
-COMPATIBLE_IOCTL(USBDEVFS_CLEAR_HALT)
-/* MTD */
-COMPATIBLE_IOCTL(MEMGETINFO)
-COMPATIBLE_IOCTL(MEMERASE)
-COMPATIBLE_IOCTL(MEMLOCK)
-COMPATIBLE_IOCTL(MEMUNLOCK)
-COMPATIBLE_IOCTL(MEMGETREGIONCOUNT)
-COMPATIBLE_IOCTL(MEMGETREGIONINFO)
-/* NBD */
-COMPATIBLE_IOCTL(NBD_SET_SOCK)
-COMPATIBLE_IOCTL(NBD_SET_BLKSIZE)
-COMPATIBLE_IOCTL(NBD_SET_SIZE)
-COMPATIBLE_IOCTL(NBD_DO_IT)
-COMPATIBLE_IOCTL(NBD_CLEAR_SOCK)
-COMPATIBLE_IOCTL(NBD_CLEAR_QUE)
-COMPATIBLE_IOCTL(NBD_PRINT_DEBUG)
-COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS)
-COMPATIBLE_IOCTL(NBD_DISCONNECT)
-/* device-mapper */
-COMPATIBLE_IOCTL(DM_VERSION)
-COMPATIBLE_IOCTL(DM_REMOVE_ALL)
-COMPATIBLE_IOCTL(DM_DEV_CREATE)
-COMPATIBLE_IOCTL(DM_DEV_REMOVE)
-COMPATIBLE_IOCTL(DM_DEV_RELOAD)
-COMPATIBLE_IOCTL(DM_DEV_SUSPEND)
-COMPATIBLE_IOCTL(DM_DEV_RENAME)
-COMPATIBLE_IOCTL(DM_DEV_DEPS)
-COMPATIBLE_IOCTL(DM_DEV_STATUS)
-COMPATIBLE_IOCTL(DM_TARGET_STATUS)
-COMPATIBLE_IOCTL(DM_TARGET_WAIT)
+
 /* And these ioctls need translation */
 HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob)
 HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob)
@@ -4473,4 +3874,4 @@
 HANDLE_IOCTL(BLKBSZGET_32, do_blkbszget)
 HANDLE_IOCTL(BLKBSZSET_32, do_blkbszset)
 HANDLE_IOCTL(BLKGETSIZE64_32, do_blkgetsize64)
-};
+IOCTL_TABLE_END
diff -Nru a/arch/ppc64/kernel/irq.c b/arch/ppc64/kernel/irq.c
--- a/arch/ppc64/kernel/irq.c	Thu Mar 20 13:44:14 2003
+++ b/arch/ppc64/kernel/irq.c	Wed Apr 23 22:45:15 2003
@@ -212,7 +212,8 @@
 	return -ENOENT;
 }
 
-int request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *),
+int request_irq(unsigned int irq,
+	irqreturn_t (*handler)(int, void *, struct pt_regs *),
 	unsigned long irqflags, const char * devname, void *dev_id)
 {
 	struct irqaction *action;
@@ -695,7 +696,7 @@
 	struct proc_dir_entry *entry;
 	char name [MAX_NAMELEN];
 
-	if (!root_irq_dir || (irq_desc[irq].handler == NULL))
+	if (!root_irq_dir || (irq_desc[irq].handler == NULL) || irq_dir[irq])
 		return;
 
 	memset(name, 0, MAX_NAMELEN);
@@ -743,6 +744,7 @@
 	}
 }
 
-void no_action(int irq, void *dev, struct pt_regs *regs)
+irqreturn_t no_action(int irq, void *dev, struct pt_regs *regs)
 {
+	return IRQ_NONE;
 }
diff -Nru a/arch/ppc64/kernel/misc.S b/arch/ppc64/kernel/misc.S
--- a/arch/ppc64/kernel/misc.S	Wed Apr 30 08:47:36 2003
+++ b/arch/ppc64/kernel/misc.S	Wed Apr 30 16:00:31 2003
@@ -170,12 +170,14 @@
  */
 	LOADADDR(r10,naca)		/* Get Naca address */
 	ld	r10,0(r10)
-	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get cache line size */
+	LOADADDR(r11,systemcfg)		/* Get systemcfg address */
+	ld	r11,0(r11)
+	lwz	r7,DCACHEL1LINESIZE(r11)/* Get cache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5		/* ensure we get enough */
-	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
+	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of cache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -186,12 +188,12 @@
 
 /* Now invalidate the instruction cache */
 	
-	lhz	r7,ICACHEL1LINESIZE(r10)	/* Get Icache line size */
+	lwz	r7,ICACHEL1LINESIZE(r11)	/* Get Icache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5
-	lhz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
+	lwz	r9,ICACHEL1LOGLINESIZE(r10)	/* Get log-2 of Icache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -217,12 +219,14 @@
  */
 	LOADADDR(r10,naca)		/* Get Naca address */
 	ld	r10,0(r10)
-	lhz	r7,DCACHEL1LINESIZE(r10)	/* Get dcache line size */
+	LOADADDR(r11,systemcfg)		/* Get systemcfg address */
+	ld	r11,0(r11)
+	lwz	r7,DCACHEL1LINESIZE(r11)	/* Get dcache line size */
 	addi	r5,r7,-1
 	andc	r6,r3,r5		/* round low to line bdy */
 	subf	r8,r6,r4		/* compute length */
 	add	r8,r8,r5		/* ensure we get enough */
-	lhz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
+	lwz	r9,DCACHEL1LOGLINESIZE(r10)	/* Get log-2 of dcache line size */
 	srw.	r8,r8,r9		/* compute line count */
 	beqlr				/* nothing to do? */
 	mtctr	r8
@@ -249,9 +253,11 @@
 /* Flush the dcache */
 	LOADADDR(r7,naca)
 	ld	r7,0(r7)
+	LOADADDR(r8,systemcfg)			/* Get systemcfg address */
+	ld	r8,0(r8)
 	clrrdi	r3,r3,12           	    /* Page align */
-	lhz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
-	lhz	r5,DCACHEL1LINESIZE(r7)		/* Get dcache line size */
+	lwz	r4,DCACHEL1LINESPERPAGE(r7)	/* Get # dcache lines per page */
+	lwz	r5,DCACHEL1LINESIZE(r8)		/* Get dcache line size */
 	mr	r6,r3
 	mtctr	r4
 0:	dcbst	0,r6
@@ -261,8 +267,8 @@
 
 /* Now invalidate the icache */	
 
-	lhz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
-	lhz	r5,ICACHEL1LINESIZE(r7)		/* Get icache line size */
+	lwz	r4,ICACHEL1LINESPERPAGE(r7)	/* Get # icache lines per page */
+	lwz	r5,ICACHEL1LINESIZE(r8)		/* Get icache line size */
 	mtctr	r4
 1:	icbi	0,r3
 	add	r3,r3,r5
@@ -574,7 +580,7 @@
 	.llong .sys32_ssetmask
 	.llong .sys_setreuid	        /* 70 */
 	.llong .sys_setregid
-	.llong .sys_sigsuspend
+	.llong .sys32_sigsuspend
 	.llong .compat_sys_sigpending
 	.llong .sys32_sethostname
 	.llong .compat_sys_setrlimit	        /* 75 */
@@ -737,7 +743,7 @@
 	.llong .sys_set_tid_address
 	.llong .ppc32_fadvise64
 	.llong .sys_exit_group
-	.llong .ppc32_lookup_dcookie	/* 245 */
+	.llong .ppc32_lookup_dcookie	/* 235 */
 	.llong .sys_epoll_create
 	.llong .sys_epoll_ctl
 	.llong .sys_epoll_wait
@@ -812,13 +818,13 @@
 	.llong .sys_getppid
 	.llong .sys_getpgrp		/* 65 */
 	.llong .sys_setsid
-	.llong .sys_sigaction
+	.llong .sys_ni_syscall
 	.llong .sys_sgetmask
 	.llong .sys_ssetmask
 	.llong .sys_setreuid		/* 70 */
 	.llong .sys_setregid
-	.llong .sys_sigsuspend
-	.llong .sys_sigpending
+	.llong .sys_ni_syscall
+	.llong .sys_ni_syscall
 	.llong .sys_sethostname
 	.llong .sys_setrlimit		/* 75 */
 	.llong .sys_ni_syscall		/* old getrlimit syscall */
@@ -864,14 +870,14 @@
 	.llong .sys_sysinfo
 	.llong .sys_ipc
 	.llong .sys_fsync
-	.llong .ppc64_sigreturn
+	.llong .sys_ni_syscall
 	.llong .sys_clone		/* 120 */
 	.llong .sys_setdomainname
 	.llong .ppc64_newuname
 	.llong .sys_ni_syscall		/* old modify_ldt syscall */
 	.llong .sys_adjtimex
 	.llong .sys_mprotect		/* 125 */
-	.llong .sys_sigprocmask
+	.llong .sys_ni_syscall
 	.llong .sys_ni_syscall		/* old create_module syscall */
 	.llong .sys_init_module
 	.llong .sys_delete_module
diff -Nru a/arch/ppc64/kernel/module.c b/arch/ppc64/kernel/module.c
--- a/arch/ppc64/kernel/module.c	Mon Feb  3 23:20:10 2003
+++ b/arch/ppc64/kernel/module.c	Mon May 12 21:23:07 2003
@@ -20,6 +20,8 @@
 #include <linux/moduleloader.h>
 #include <linux/err.h>
 #include <linux/vmalloc.h>
+#include <asm/module.h>
+#include <asm/uaccess.h>
 
 /* FIXME: We don't do .init separately.  To do this, we'd need to have
    a separate r2 value in the init and core section, and stub between
@@ -374,15 +376,15 @@
 	return 0;
 }
 
-/* In arch/ppc64/mm/extable.c */
-extern void sort_ex_table(struct exception_table_entry *start,
-			  struct exception_table_entry *finish);
-
 int module_finalize(const Elf_Ehdr *hdr,
-		    const Elf_Shdr *sechdrs,
-		    struct module *me)
+		const Elf_Shdr *sechdrs, struct module *me)
 {
-	sort_ex_table(me->extable.entry,
-		      me->extable.entry + me->extable.num_entries);
+	sort_ex_table((struct exception_table_entry *)me->extable,
+		      (struct exception_table_entry *)me->extable +
+				me->num_exentries);
 	return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
 }
diff -Nru a/arch/ppc64/kernel/open_pic.c b/arch/ppc64/kernel/open_pic.c
--- a/arch/ppc64/kernel/open_pic.c	Sun Feb 16 18:27:44 2003
+++ b/arch/ppc64/kernel/open_pic.c	Wed Apr 23 22:45:15 2003
@@ -111,7 +111,6 @@
  * data has probably been corrupted and we're going to panic or deadlock later
  * anyway --Troy
  */
-extern unsigned long* _get_SP(void);
 #define check_arg_irq(irq) \
     if (irq < open_pic_irq_offset || irq >= (NumSources+open_pic_irq_offset)){ \
       printk(KERN_ERR "open_pic.c:%d: illegal irq %d\n", __LINE__, irq); \
@@ -765,9 +764,11 @@
 	openpic_eoi();
 }
 
-static void openpic_ipi_action(int cpl, void *dev_id, struct pt_regs *regs)
+static irqreturn_t openpic_ipi_action(int cpl, void *dev_id,
+					struct pt_regs *regs)
 {
 	smp_message_recv(cpl-openpic_vec_ipi, regs);
+	return IRQ_HANDLED;
 }
 
 #endif /* CONFIG_SMP */
diff -Nru a/arch/ppc64/kernel/open_pic_defs.h b/arch/ppc64/kernel/open_pic_defs.h
--- a/arch/ppc64/kernel/open_pic_defs.h	Thu Feb 14 04:14:36 2002
+++ b/arch/ppc64/kernel/open_pic_defs.h	Wed Apr 23 22:45:15 2003
@@ -298,7 +298,8 @@
 #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);
+static irqreturn_t openpic_ipi_action(int cpl, void *dev_id,
+					struct pt_regs *regs);
 #endif
 
 /* Timer Interrupts */
diff -Nru a/arch/ppc64/kernel/pSeries_lpar.c b/arch/ppc64/kernel/pSeries_lpar.c
--- a/arch/ppc64/kernel/pSeries_lpar.c	Mon Mar 24 16:01:56 2003
+++ b/arch/ppc64/kernel/pSeries_lpar.c	Thu Mar 27 22:31:06 2003
@@ -110,29 +110,6 @@
 			   lbuf[0], lbuf[1], &dummy, &dummy, &dummy);
 }
 
-long plpar_eoi(unsigned long xirr)
-{
-	return plpar_hcall_norets(H_EOI, xirr);
-}
-
-long plpar_cppr(unsigned long cppr)
-{
-	return plpar_hcall_norets(H_CPPR, cppr);
-}
-
-long plpar_ipi(unsigned long servernum,
-	       unsigned long mfrr)
-{
-	return plpar_hcall_norets(H_IPI, servernum, mfrr);
-}
-
-long plpar_xirr(unsigned long *xirr_ret)
-{
-	unsigned long dummy;
-	return plpar_hcall(H_XIRR, 0, 0, 0, 0,
-			   xirr_ret, &dummy, &dummy);
-}
-
 static void tce_build_pSeriesLP(struct TceTable *tbl, long tcenum, 
 				unsigned long uaddr, int direction )
 {
@@ -179,66 +156,6 @@
 	}
 
 }
-
-/* PowerPC Interrupts for lpar. */
-/* NOTE: this typedef is duplicated (for now) from xics.c! */
-typedef struct {
-	int (*xirr_info_get)(int cpu);
-	void (*xirr_info_set)(int cpu, int val);
-	void (*cppr_info)(int cpu, u8 val);
-	void (*qirr_info)(int cpu, u8 val);
-} xics_ops;
-static int pSeriesLP_xirr_info_get(int n_cpu)
-{
-	unsigned long lpar_rc;
-	unsigned long return_value; 
-
-	lpar_rc = plpar_xirr(&return_value);
-	if (lpar_rc != H_Success) {
-		panic(" bad return code xirr - rc = %lx \n", lpar_rc); 
-	}
-	return ((int)(return_value));
-}
-
-static void pSeriesLP_xirr_info_set(int n_cpu, int value)
-{
-	unsigned long lpar_rc;
-	unsigned long val64 = value & 0xffffffff;
-
-	lpar_rc = plpar_eoi(val64);
-	if (lpar_rc != H_Success) {
-		panic(" bad return code EOI - rc = %ld, value=%lx \n", lpar_rc, val64); 
-	}
-}
-
-static void pSeriesLP_cppr_info(int n_cpu, u8 value)
-{
-	unsigned long lpar_rc;
-
-	lpar_rc = plpar_cppr(value);
-	if (lpar_rc != H_Success) {
-		panic(" bad return code cppr - rc = %lx \n", lpar_rc); 
-	}
-}
-
-static void pSeriesLP_qirr_info(int n_cpu , u8 value)
-{
-	unsigned long lpar_rc;
-
-	lpar_rc = plpar_ipi(n_cpu, value);
-	if (lpar_rc != H_Success) {
-		panic(" bad return code qirr -ipi  - rc = %lx \n", lpar_rc); 
-	}
-}
-
-xics_ops pSeriesLP_ops = {
-	pSeriesLP_xirr_info_get,
-	pSeriesLP_xirr_info_set,
-	pSeriesLP_cppr_info,
-	pSeriesLP_qirr_info
-};
-/* end TAI-LPAR */
-
 
 int vtermno;	/* virtual terminal# for udbg  */
 
diff -Nru a/arch/ppc64/kernel/pacaData.c b/arch/ppc64/kernel/pacaData.c
--- a/arch/ppc64/kernel/pacaData.c	Tue Jul 23 01:36:48 2002
+++ b/arch/ppc64/kernel/pacaData.c	Tue Mar 25 20:30:58 2003
@@ -20,6 +20,7 @@
 #include <asm/paca.h>
 
 struct naca_struct *naca;
+struct systemcfg *systemcfg;
 
 /* The Paca is an array with one entry per processor.  Each contains an 
  * ItLpPaca, which contains the information shared between the 
@@ -65,9 +66,9 @@
 
 struct paca_struct paca[MAX_PACAS] __page_aligned = {
 #ifdef CONFIG_PPC_ISERIES
-	PACAINITDATA( 0, 1, &xItLpQueue, 0, 0xc000000000005000),
+	PACAINITDATA( 0, 1, &xItLpQueue, 0, STAB0_VIRT_ADDR),
 #else
-	PACAINITDATA( 0, 1, 0, 0x5000, 0xc000000000005000),
+	PACAINITDATA( 0, 1, 0, STAB0_PHYS_ADDR, STAB0_VIRT_ADDR),
 #endif
 	PACAINITDATA( 1, 0, 0, 0, 0),
 	PACAINITDATA( 2, 0, 0, 0, 0),
diff -Nru a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
--- a/arch/ppc64/kernel/pci.c	Mon Mar 24 19:22:52 2003
+++ b/arch/ppc64/kernel/pci.c	Wed Apr 23 23:07:46 2003
@@ -21,6 +21,7 @@
 #include <linux/sched.h>
 #include <linux/errno.h>
 #include <linux/bootmem.h>
+#include <linux/module.h>
 #include <linux/mm.h>
 
 #include <asm/processor.h>
diff -Nru a/arch/ppc64/kernel/pci_dma.c b/arch/ppc64/kernel/pci_dma.c
--- a/arch/ppc64/kernel/pci_dma.c	Wed Mar 12 15:19:15 2003
+++ b/arch/ppc64/kernel/pci_dma.c	Wed Apr 23 23:53:25 2003
@@ -134,7 +134,7 @@
 		dev = ppc64_isabridge_dev;
 	if (!dev)
 		return NULL;
-	if (naca->platform == PLATFORM_ISERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_ISERIES_LPAR) {
  		return ISERIES_DEVNODE(dev)->DevTceTable;
 	} else {
 		return PCI_GET_DN(dev)->tce_table;
@@ -723,8 +723,8 @@
 			 */
 			busdn->bussubno = bus->number;
 			create_pci_bus_tce_table((unsigned long)busdn);
-		} else
-			create_tce_tables_for_busesLP(&bus->children);
+		}
+		create_tce_tables_for_busesLP(&bus->children);
 	}
 }
 
@@ -732,7 +732,7 @@
 	struct pci_dev *dev;
 	struct device_node *dn, *mydn;
 
-	if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		create_tce_tables_for_busesLP(&pci_root_buses);
 	}
 	else {
@@ -773,7 +773,7 @@
  	/* - Tce Table Share between buses,                              */
  	/* - Tce Table per logical slot.                                 */
 	/*****************************************************************/
-	if(naca->platform == PLATFORM_ISERIES_LPAR) {
+	if(systemcfg->platform == PLATFORM_ISERIES_LPAR) {
 
 		struct iSeries_Device_Node* DevNode = (struct iSeries_Device_Node*)token;
 		getTceTableParmsiSeries(DevNode,newTceTable);
@@ -797,7 +797,7 @@
 
 		dn = (struct device_node *)token;
 		phb = dn->phb;
-		if (naca->platform == PLATFORM_PSERIES)
+		if (systemcfg->platform == PLATFORM_PSERIES)
 			getTceTableParmsPSeries(phb, dn, newTceTable);
 		else
 			getTceTableParmsPSeriesLP(phb, dn, newTceTable);
@@ -1135,7 +1135,8 @@
  	/* Client asked for way to much space.  This is checked later anyway */
 	/* It is easier to debug here for the drivers than in the tce tables.*/
  	if(order >= NUM_TCE_LEVELS) {
- 		printk("PCI_DMA: pci_unmap_single 0x%lx size to large: 0x%lx \n",dma_handle,size);
+ 		printk("PCI_DMA: pci_unmap_single 0x%lx size too"
+			" large: 0x%lx \n", (long)dma_handle, (long)size);
  		return;
  	}
 	
diff -Nru a/arch/ppc64/kernel/proc_ppc64.c b/arch/ppc64/kernel/proc_ppc64.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/arch/ppc64/kernel/proc_ppc64.c	Tue Mar 25 20:30:59 2003
@@ -0,0 +1,177 @@
+/*
+ * arch/ppc64/kernel/proc_ppc64.c
+ *
+ * Copyright (C) 2001 Mike Corrigan & Dave Engebretsen IBM Corporation
+ * 
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+ */
+
+
+/*
+ * Change Activity:
+ * 2001       : mikec    : Created
+ * 2001/06/05 : engebret : Software event count support.
+ * 2003/02/13 : bergner  : Move PMC code to pmc.c
+ * End Change Activity 
+ */
+
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/proc_fs.h>
+
+#include <asm/proc_fs.h>
+#include <asm/naca.h>
+#include <asm/paca.h>
+#include <asm/systemcfg.h>
+#include <asm/rtas.h>
+#include <asm/uaccess.h>
+
+struct proc_ppc64_t proc_ppc64;
+
+void proc_ppc64_create_paca(int num);
+
+static loff_t  page_map_seek( struct file *file, loff_t off, int whence);
+static ssize_t page_map_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos);
+static int     page_map_mmap( struct file *file, struct vm_area_struct *vma );
+
+static struct file_operations page_map_fops = {
+	llseek:	page_map_seek,
+	read:	page_map_read,
+	mmap:	page_map_mmap
+};
+
+
+static int __init proc_ppc64_init(void)
+{
+
+	printk(KERN_INFO "proc_ppc64: Creating /proc/ppc64/\n");
+
+	proc_ppc64.root = proc_mkdir("ppc64", 0);
+	if (!proc_ppc64.root)
+		return 0;
+
+	proc_ppc64.naca = create_proc_entry("naca", S_IRUSR, proc_ppc64.root);
+	if ( proc_ppc64.naca ) {
+		proc_ppc64.naca->nlink = 1;
+		proc_ppc64.naca->data = naca;
+		proc_ppc64.naca->size = 4096;
+		proc_ppc64.naca->proc_fops = &page_map_fops;
+	}
+	
+	proc_ppc64.systemcfg = create_proc_entry("systemcfg", S_IFREG|S_IRUGO, proc_ppc64.root);
+	if ( proc_ppc64.systemcfg ) {
+		proc_ppc64.systemcfg->nlink = 1;
+		proc_ppc64.systemcfg->data = systemcfg;
+		proc_ppc64.systemcfg->size = 4096;
+		proc_ppc64.systemcfg->proc_fops = &page_map_fops;
+	}
+
+	/* /proc/ppc64/paca/XX -- raw paca contents.  Only readable to root */
+	proc_ppc64.paca = proc_mkdir("paca", proc_ppc64.root);
+	if (proc_ppc64.paca) {
+		unsigned long i;
+
+		for (i = 0; i < NR_CPUS; i++) {
+			if (!cpu_online(i))
+				continue;
+			proc_ppc64_create_paca(i);
+		}
+	}
+
+	/* Placeholder for rtas interfaces. */
+	proc_ppc64.rtas = proc_mkdir("rtas", proc_ppc64.root);
+
+	return 0;
+}
+
+
+/*
+ * NOTE: since paca data is always in flux the values will never be a consistant set.
+ * In theory it could be made consistent if we made the corresponding cpu
+ * copy the page for us (via an IPI).  Probably not worth it.
+ *
+ */
+void proc_ppc64_create_paca(int num)
+{
+	struct proc_dir_entry *ent;
+	struct paca_struct *lpaca = paca + num;
+	char buf[16];
+
+	sprintf(buf, "%02x", num);
+	ent = create_proc_entry(buf, S_IRUSR, proc_ppc64.paca);
+	if ( ent ) {
+		ent->nlink = 1;
+		ent->data = lpaca;
+		ent->size = 4096;
+		ent->proc_fops = &page_map_fops;
+	}
+}
+
+
+static loff_t page_map_seek( struct file *file, loff_t off, int whence)
+{
+	loff_t new;
+	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+
+	switch(whence) {
+	case 0:
+		new = off;
+		break;
+	case 1:
+		new = file->f_pos + off;
+		break;
+	case 2:
+		new = dp->size + off;
+		break;
+	default:
+		return -EINVAL;
+	}
+	if ( new < 0 || new > dp->size )
+		return -EINVAL;
+	return (file->f_pos = new);
+}
+
+static ssize_t page_map_read( struct file *file, char *buf, size_t nbytes, loff_t *ppos)
+{
+	unsigned pos = *ppos;
+	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+
+	if ( pos >= dp->size )
+		return 0;
+	if ( nbytes >= dp->size )
+		nbytes = dp->size;
+	if ( pos + nbytes > dp->size )
+		nbytes = dp->size - pos;
+
+	copy_to_user( buf, (char *)dp->data + pos, nbytes );
+	*ppos = pos + nbytes;
+	return nbytes;
+}
+
+static int page_map_mmap( struct file *file, struct vm_area_struct *vma )
+{
+	struct proc_dir_entry *dp = PDE(file->f_dentry->d_inode);
+
+	vma->vm_flags |= VM_SHM | VM_LOCKED;
+
+	if ((vma->vm_end - vma->vm_start) > dp->size)
+		return -EINVAL;
+
+	remap_page_range( vma, vma->vm_start, __pa(dp->data), dp->size, vma->vm_page_prot );
+	return 0;
+}
+
+fs_initcall(proc_ppc64_init);
+
diff -Nru a/arch/ppc64/kernel/process.c b/arch/ppc64/kernel/process.c
--- a/arch/ppc64/kernel/process.c	Thu Mar 20 08:53:38 2003
+++ b/arch/ppc64/kernel/process.c	Tue May 20 01:35:55 2003
@@ -300,7 +300,6 @@
 	      unsigned long p4, unsigned long p5, unsigned long p6,
 	      struct pt_regs *regs)
 {
-	struct task_struct *p;
 	unsigned long parent_tidptr = 0;
 	unsigned long child_tidptr = 0;
 
@@ -320,36 +319,29 @@
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	p = do_fork(clone_flags & ~CLONE_IDLETASK, p2, regs, 0,
+	return do_fork(clone_flags & ~CLONE_IDLETASK, p2, regs, 0,
 		    (int *)parent_tidptr, (int *)child_tidptr);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
 int sys_fork(unsigned long p1, unsigned long p2, unsigned long p3,
 	     unsigned long p4, unsigned long p5, unsigned long p6,
 	     struct pt_regs *regs)
 {
-	struct task_struct *p;
-
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	p = do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(SIGCHLD, regs->gpr[1], regs, 0, NULL, NULL);
 }
 
 int sys_vfork(unsigned long p1, unsigned long p2, unsigned long p3,
 	      unsigned long p4, unsigned long p5, unsigned long p6,
 	      struct pt_regs *regs)
 {
-	struct task_struct *p;
-
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	p = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0,
+	return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->gpr[1], regs, 0,
 	            NULL, NULL);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
 }
 
 int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
@@ -532,8 +524,6 @@
 		       name_buf, 256));
 	} while (count++ < 32);
 }
-
-extern unsigned long *_get_SP(void);
 
 void dump_stack(void)
 {
diff -Nru a/arch/ppc64/kernel/prom.c b/arch/ppc64/kernel/prom.c
--- a/arch/ppc64/kernel/prom.c	Mon Mar 24 17:04:39 2003
+++ b/arch/ppc64/kernel/prom.c	Thu Apr 24 00:39:23 2003
@@ -118,7 +118,6 @@
 #define FB_MAX	8
 #endif
 
-static int ppc64_is_smp;
 
 struct prom_t prom = {
 	0,			/* entry */
@@ -301,7 +300,9 @@
         unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
         struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 
+	/* NOTE: _naca->debug_switch is already initialized. */
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_initialize_naca: start...\n"));
 #endif
@@ -320,25 +321,35 @@
 			 * d-cache and i-cache sizes... -Peter
 			 */
 			if ( num_cpus == 1 ) {
-				u32 size;
+				u32 size, lsize;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("d-cache-line-size"),
+					  RELOC("d-cache-size"),
 					  &size, sizeof(size));
 
-				_naca->dCacheL1LineSize     = size;
-				_naca->dCacheL1LogLineSize  = __ilog2(size);
-				_naca->dCacheL1LinesPerPage = PAGE_SIZE / size;
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("d-cache-line-size"),
+					  &lsize, sizeof(lsize));
+
+				_systemcfg->dCacheL1Size = size;
+				_systemcfg->dCacheL1LineSize = lsize;
+				_naca->dCacheL1LogLineSize = __ilog2(lsize);
+				_naca->dCacheL1LinesPerPage = PAGE_SIZE/lsize;
 
 				call_prom(RELOC("getprop"), 4, 1, node,
-					  RELOC("i-cache-line-size"),
+					  RELOC("i-cache-size"),
 					  &size, sizeof(size));
 
-				_naca->iCacheL1LineSize     = size;
-				_naca->iCacheL1LogLineSize  = __ilog2(size);
-				_naca->iCacheL1LinesPerPage = PAGE_SIZE / size;
+				call_prom(RELOC("getprop"), 4, 1, node,
+					  RELOC("i-cache-line-size"),
+					  &lsize, sizeof(lsize));
 
-				if (_naca->platform == PLATFORM_PSERIES_LPAR) {
+				_systemcfg->iCacheL1Size = size;
+				_systemcfg->iCacheL1LineSize = lsize;
+				_naca->iCacheL1LogLineSize = __ilog2(lsize);
+				_naca->iCacheL1LinesPerPage = PAGE_SIZE/lsize;
+
+				if (_systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 					u32 pft_size[2];
 					call_prom(RELOC("getprop"), 4, 1, node, 
 						  RELOC("ibm,pft-size"),
@@ -408,20 +419,17 @@
 	}
 
 	/* We gotta have at least 1 cpu... */
-        if (num_cpus < 1)
+        if ( (_systemcfg->processorCount = num_cpus) < 1 )
                 PROM_BUG();
 
-	if (num_cpus > 1)
-		RELOC(ppc64_is_smp) = 1;
-
-	_naca->physicalMemorySize = lmb_phys_mem_size();
+	_systemcfg->physicalMemorySize = lmb_phys_mem_size();
 
-	if (_naca->platform == PLATFORM_PSERIES) {
+	if (_systemcfg->platform == PLATFORM_PSERIES) {
 		unsigned long rnd_mem_size, pteg_count;
 
 		/* round mem_size up to next power of 2 */
-		rnd_mem_size = 1UL << __ilog2(_naca->physicalMemorySize);
-		if (rnd_mem_size < _naca->physicalMemorySize)
+		rnd_mem_size = 1UL << __ilog2(_systemcfg->physicalMemorySize);
+		if (rnd_mem_size < _systemcfg->physicalMemorySize)
 			rnd_mem_size <<= 1;
 
 		/* # pages / 2 */
@@ -442,49 +450,43 @@
 	 */
 	_naca->slb_size = 64;
 
-#ifdef DEBUG_PROM
-        prom_print(RELOC("naca->physicalMemorySize   = 0x"));
-        prom_print_hex(_naca->physicalMemorySize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->pftSize              = 0x"));
-        prom_print_hex(_naca->pftSize);
-        prom_print_nl();
-
-        prom_print(RELOC("naca->dCacheL1LineSize     = 0x"));
-        prom_print_hex(_naca->dCacheL1LineSize);
-        prom_print_nl();
+	/* Add an eye catcher and the systemcfg layout version number */
+	strcpy(_systemcfg->eye_catcher, RELOC("SYSTEMCFG:PPC64"));
+	_systemcfg->version.major = SYSTEMCFG_MAJOR;
+	_systemcfg->version.minor = SYSTEMCFG_MINOR;
+	_systemcfg->processor = _get_PVR();
 
-        prom_print(RELOC("naca->dCacheL1LogLineSize  = 0x"));
-        prom_print_hex(_naca->dCacheL1LogLineSize);
+#ifdef DEBUG_PROM
+        prom_print(RELOC("systemcfg->processorCount       = 0x"));
+        prom_print_hex(_systemcfg->processorCount);
         prom_print_nl();
 
-        prom_print(RELOC("naca->dCacheL1LinesPerPage = 0x"));
-        prom_print_hex(_naca->dCacheL1LinesPerPage);
+        prom_print(RELOC("systemcfg->physicalMemorySize   = 0x"));
+        prom_print_hex(_systemcfg->physicalMemorySize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->iCacheL1LineSize     = 0x"));
-        prom_print_hex(_naca->iCacheL1LineSize);
+        prom_print(RELOC("naca->pftSize                   = 0x"));
+        prom_print_hex(_naca->pftSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->iCacheL1LogLineSize  = 0x"));
-        prom_print_hex(_naca->iCacheL1LogLineSize);
+        prom_print(RELOC("systemcfg->dCacheL1LineSize     = 0x"));
+        prom_print_hex(_systemcfg->dCacheL1LineSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->iCacheL1LinesPerPage = 0x"));
-        prom_print_hex(_naca->iCacheL1LinesPerPage);
+        prom_print(RELOC("systemcfg->iCacheL1LineSize     = 0x"));
+        prom_print_hex(_systemcfg->iCacheL1LineSize);
         prom_print_nl();
 
-        prom_print(RELOC("naca->serialPortAddr       = 0x"));
+        prom_print(RELOC("naca->serialPortAddr            = 0x"));
         prom_print_hex(_naca->serialPortAddr);
         prom_print_nl();
 
-        prom_print(RELOC("naca->interrupt_controller = 0x"));
+        prom_print(RELOC("naca->interrupt_controller      = 0x"));
         prom_print_hex(_naca->interrupt_controller);
         prom_print_nl();
 
-        prom_print(RELOC("naca->platform             = 0x"));
-        prom_print_hex(_naca->platform);
+        prom_print(RELOC("systemcfg->platform             = 0x"));
+        prom_print_hex(_systemcfg->platform);
         prom_print_nl();
 
 	prom_print(RELOC("prom_initialize_naca: end...\n"));
@@ -549,7 +551,7 @@
 	unsigned long offset = reloc_offset();
 	struct prom_t *_prom = PTRRELOC(&prom);
 	struct rtas_t *_rtas = PTRRELOC(&rtas);
-	struct naca_struct *_naca = RELOC(naca);
+	struct systemcfg *_systemcfg = RELOC(systemcfg);
 	ihandle prom_rtas;
         u32 getprop_rval;
 
@@ -565,7 +567,7 @@
 				  RELOC("ibm,hypertas-functions"), 
 				  hypertas_funcs, 
 				  sizeof(hypertas_funcs))) > 0) {
-			_naca->platform = PLATFORM_PSERIES_LPAR;
+			_systemcfg->platform = PLATFORM_PSERIES_LPAR;
 		}
 
 		call_prom(RELOC("getprop"), 
@@ -582,7 +584,7 @@
 			 * of physical memory (or within the RMO region) because RTAS
 			 * runs in 32-bit mode and relocate off.
 			 */
-			if ( _naca->platform == PLATFORM_PSERIES_LPAR ) {
+			if ( _systemcfg->platform == PLATFORM_PSERIES_LPAR ) {
 				struct lmb *_lmb  = PTRRELOC(&lmb);
 				rtas_region = min(_lmb->rmo_size, RTAS_INSTANTIATE_MAX);
 			}
@@ -767,13 +769,21 @@
 		 * By doing this, we avoid the pitfalls of trying to DMA to
 		 * MMIO space and the DMA alias hole.
 		 */
-		minsize = 4UL << 20;
+		/* 
+		 * On POWER4, firmware sets the TCE region by assuming
+		 * each TCE table is 8MB. Using this memory for anything
+		 * else will impact performance, so we always allocate 8MB.
+		 * Anton
+		 *
+		 * XXX FIXME use a cpu feature here
+		 */
+		minsize = 8UL << 20;
 
 		/* Align to the greater of the align or size */
-		align = (minalign < minsize) ? minsize : minalign;
+		align = max(minalign, minsize);
 
 		/* Carve out storage for the TCE table. */
-		base = lmb_alloc(8UL << 20, 8UL << 20);
+		base = lmb_alloc(minsize, align);
 
 		if ( !base ) {
 			prom_print(RELOC("ERROR, cannot find space for TCE table.\n"));
@@ -875,7 +885,7 @@
 prom_hold_cpus(unsigned long mem)
 {
 	unsigned long i;
-	unsigned int reg;
+	unsigned int cpuid;
 	phandle node;
 	unsigned long offset = reloc_offset();
 	char type[64], *path;
@@ -885,9 +895,13 @@
         unsigned long *spinloop     = __v2a(&__secondary_hold_spinloop);
         unsigned long *acknowledge  = __v2a(&__secondary_hold_acknowledge);
         unsigned long secondary_hold = (unsigned long)__v2a(*PTRRELOC((unsigned long *)__secondary_hold));
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 
+	/* Initially, we must have one active CPU. */
+	_systemcfg->processorCount = 1;
+
 #ifdef DEBUG_PROM
 	prom_print(RELOC("prom_hold_cpus: start...\n"));
 	prom_print(RELOC("    1) spinloop       = 0x"));
@@ -933,12 +947,12 @@
 		if (strcmp(type, RELOC("okay")) != 0)
 			continue;
 
-                reg = -1;
+                cpuid = -1;
 		call_prom(RELOC("getprop"), 4, 1, node, RELOC("reg"),
-			  &reg, sizeof(reg));
+			  &cpuid, sizeof(cpuid));
 
 		/* Only need to start secondary procs, not ourself. */
-		if ( reg == _prom->cpu )
+		if ( cpuid == _prom->cpu )
 			continue;
 
 		path = (char *) mem;
@@ -950,7 +964,7 @@
 #ifdef DEBUG_PROM
 		prom_print_nl();
 		prom_print(RELOC("cpu hw idx   = 0x"));
-		prom_print_hex(reg);
+		prom_print_hex(cpuid);
 		prom_print_nl();
 #endif
 		prom_print(RELOC("starting cpu "));
@@ -978,9 +992,8 @@
 		prom_print(RELOC("    3) secondary_hold = 0x"));
 		prom_print_hex(secondary_hold);
 		prom_print_nl();
-		prom_print_nl();
 #endif
-		call_prom(RELOC("start-cpu"), 3, 0, node, secondary_hold, reg);
+		call_prom(RELOC("start-cpu"), 3, 0, node, secondary_hold, cpuid);
 		prom_print(RELOC("..."));
 		for ( i = 0 ; (i < 100000000) && 
 			      (*acknowledge == ((unsigned long)-1)); i++ ) ;
@@ -992,10 +1005,11 @@
 			prom_print_nl();
 		}
 #endif
-		if (*acknowledge == reg) {
+		if (*acknowledge == cpuid) {
 			prom_print(RELOC("ok\n"));
 			/* Set the number of active processors. */
-			_xPaca[reg].active = 1;
+			_systemcfg->processorCount++;
+			_xPaca[cpuid].active = 1;
 		} else {
 			prom_print(RELOC("failed: "));
 			prom_print_hex(*acknowledge);
@@ -1024,8 +1038,8 @@
 				}
 			}
 			_xPaca[i+1].active = 1;
-			RELOC(hmt_thread_data)[i].threadid = i+1;
 		}
+		_systemcfg->processorCount *= 2;
 	} else {
 		prom_print(RELOC("Processor is not HMT capable\n"));
 	}
@@ -1046,20 +1060,21 @@
 prom_init(unsigned long r3, unsigned long r4, unsigned long pp,
 	  unsigned long r6, unsigned long r7)
 {
+	int chrp = 0;
 	unsigned long mem;
-	ihandle prom_root, prom_cpu;
+	ihandle prom_mmu, prom_op, prom_root, prom_cpu;
 	phandle cpu_pkg;
 	unsigned long offset = reloc_offset();
-	long l;
+	long l, sz;
 	char *p, *d;
  	unsigned long phys;
         u32 getprop_rval;
-        struct naca_struct *_naca = RELOC(naca);
+        struct systemcfg *_systemcfg = RELOC(systemcfg);
 	struct paca_struct *_xPaca = PTRRELOC(&paca[0]);
 	struct prom_t *_prom = PTRRELOC(&prom);
 
 	/* Default machine type. */
-	_naca->platform = PLATFORM_PSERIES;
+	_systemcfg->platform = PLATFORM_PSERIES;
 
 #if 0
 	/* Reset klimit to take into account the embedded system map */
@@ -1149,6 +1164,8 @@
 
 	mem = prom_bi_rec_reserve(mem);
 
+	mem = check_display(mem);
+
 	prom_instantiate_rtas();
         
         /* Initialize some system info into the Naca early... */
@@ -1158,11 +1175,9 @@
          * following, regardless of whether we have an SMP
          * kernel or not.
          */
-        if (RELOC(ppc64_is_smp))
+        if (_systemcfg->processorCount > 1)
 	        prom_hold_cpus(mem);
 
-	mem = check_display(mem);
-
 #ifdef DEBUG_PROM
 	prom_print(RELOC("copying OF device tree...\n"));
 #endif
@@ -1172,7 +1187,7 @@
 
 	lmb_reserve(0, __pa(RELOC(klimit)));
 
-	if (_naca->platform == PLATFORM_PSERIES)
+	if (_systemcfg->platform == PLATFORM_PSERIES)
 		prom_initialize_tce_table();
 
 	prom_print(RELOC("Calling quiesce ...\n"));
diff -Nru a/arch/ppc64/kernel/ras.c b/arch/ppc64/kernel/ras.c
--- a/arch/ppc64/kernel/ras.c	Mon Feb 24 10:14:15 2003
+++ b/arch/ppc64/kernel/ras.c	Wed Apr 23 22:45:15 2003
@@ -54,8 +54,10 @@
 #include <asm/rtas.h>
 #include <asm/ppcdebug.h>
 
-static void ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs);
-static void ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t ras_epow_interrupt(int irq, void *dev_id,
+					struct pt_regs * regs);
+static irqreturn_t ras_error_interrupt(int irq, void *dev_id,
+					struct pt_regs * regs);
 void init_ras_IRQ(void);
 
 /* #define DEBUG */
@@ -73,7 +75,7 @@
 						&len))) {
 		for(i=0; i<(len / sizeof(*ireg)); i++) {
 			request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, 
-				    &ras_error_interrupt, 0, 
+				    ras_error_interrupt, 0, 
 				    "RAS_ERROR", NULL);
 			ireg++;
 		}
@@ -84,7 +86,7 @@
 						&len))) {
 		for(i=0; i<(len / sizeof(*ireg)); i++) {
 			request_irq(virt_irq_create_mapping(*(ireg)) + NUM_8259_INTERRUPTS, 
-				    &ras_epow_interrupt, 0, 
+				    ras_epow_interrupt, 0, 
 				    "RAS_EPOW", NULL);
 			ireg++;
 		}
@@ -98,7 +100,7 @@
  * to examine the type of power failure and take appropriate action where
  * the time horizon permits something useful to be done.
  */
-static void
+static irqreturn_t
 ras_epow_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct rtas_error_log log_entry;
@@ -114,7 +116,8 @@
 	udbg_printf("EPOW <0x%lx 0x%lx>\n", 
 		    *((unsigned long *)&log_entry), status); 
 	printk(KERN_WARNING 
-	       "EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status);
+		"EPOW <0x%lx 0x%lx>\n",*((unsigned long *)&log_entry), status);
+	return IRQ_HANDLED;
 }
 
 /*
@@ -125,7 +128,7 @@
  * For nonrecoverable errors, an error is logged and we stop all processing
  * as quickly as possible in order to prevent propagation of the failure.
  */
-static void
+static irqreturn_t
 ras_error_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct rtas_error_log log_entry;
@@ -158,7 +161,6 @@
 		printk(KERN_WARNING 
 		       "Warning: Recoverable hardware error <0x%lx 0x%lx>\n",
 		       *((unsigned long *)&log_entry), status);
-
-		return;
 	}
+	return IRQ_HANDLED;
 }
diff -Nru a/arch/ppc64/kernel/rtas-proc.c b/arch/ppc64/kernel/rtas-proc.c
--- a/arch/ppc64/kernel/rtas-proc.c	Wed Jan 29 00:59:02 2003
+++ b/arch/ppc64/kernel/rtas-proc.c	Mon Apr 21 12:42:07 2003
@@ -201,7 +201,7 @@
 	struct proc_dir_entry *entry;
 
 	rtas_node = find_devices("rtas");
-	if ((rtas_node == NULL) || (naca->platform == PLATFORM_ISERIES_LPAR)) {
+	if ((rtas_node == NULL) || (systemcfg->platform == PLATFORM_ISERIES_LPAR)) {
 		return;
 	}
 	
@@ -506,21 +506,27 @@
 		int error, char * buf) 
 {
 	/* Defined return vales */
-	const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t", "Mainenance" };
+	const char * key_switch[]        = { "Off\t", "Normal\t", "Secure\t", 
+						"Maintenance" };
 	const char * enclosure_switch[]  = { "Closed", "Open" };
 	const char * lid_status[]        = { " ", "Open", "Closed" };
-	const char * power_source[]      = { "AC\t", "Battery", "AC & Battery" };
+	const char * power_source[]      = { "AC\t", "Battery", 
+		  				"AC & Battery" };
 	const char * battery_remaining[] = { "Very Low", "Low", "Mid", "High" };
 	const char * epow_sensor[]       = { 
 		"EPOW Reset", "Cooling warning", "Power warning",
 		"System shutdown", "System halt", "EPOW main enclosure",
 		"EPOW power off" };
-	const char * battery_cyclestate[]  = { "None", "In progress", "Requested" };
-	const char * battery_charging[]    = { "Charging", "Discharching", "No current flow" };
-	const char * ibm_drconnector[]     = { "Empty", "Present" };
+	const char * battery_cyclestate[]  = { "None", "In progress", 
+						"Requested" };
+	const char * battery_charging[]    = { "Charging", "Discharching", 
+						"No current flow" };
+	const char * ibm_drconnector[]     = { "Empty", "Present", "Unusable", 
+						"Exchange" };
 	const char * ibm_intqueue[]        = { "Disabled", "Enabled" };
 
 	int have_strings = 0;
+	int num_states = 0;
 	int temperature = 0;
 	int unknown = 0;
 	int n = 0;
@@ -530,13 +536,20 @@
 	switch (s.token) {
 		case KEY_SWITCH:
 			n += sprintf(buf+n, "Key switch:\t");
-			n += sprintf(buf+n, "%s\t", key_switch[state]);
-			have_strings = 1;
+			num_states = sizeof(key_switch) / sizeof(char *);
+			if (state < num_states) {
+				n += sprintf(buf+n, "%s\t", key_switch[state]);
+				have_strings = 1;
+			}
 			break;
 		case ENCLOSURE_SWITCH:
 			n += sprintf(buf+n, "Enclosure switch:\t");
-			n += sprintf(buf+n, "%s\t", enclosure_switch[state]);
-			have_strings = 1;
+			num_states = sizeof(enclosure_switch) / sizeof(char *);
+			if (state < num_states) {
+				n += sprintf(buf+n, "%s\t", 
+						enclosure_switch[state]);
+				have_strings = 1;
+			}
 			break;
 		case THERMAL_SENSOR:
 			n += sprintf(buf+n, "Temp. (°C/°F):\t");
@@ -544,39 +557,63 @@
 			break;
 		case LID_STATUS:
 			n += sprintf(buf+n, "Lid status:\t");
-			n += sprintf(buf+n, "%s\t", lid_status[state]);
-			have_strings = 1;
+			num_states = sizeof(lid_status) / sizeof(char *);
+			if (state < num_states) {
+				n += sprintf(buf+n, "%s\t", lid_status[state]);
+				have_strings = 1;
+			}
 			break;
 		case POWER_SOURCE:
 			n += sprintf(buf+n, "Power source:\t");
-			n += sprintf(buf+n, "%s\t", power_source[state]);
-			have_strings = 1;
+			num_states = sizeof(power_source) / sizeof(char *);
+			if (state < num_states) {
+				n += sprintf(buf+n, "%s\t", 
+						power_source[state]);
+				have_strings = 1;
+			}
 			break;
 		case BATTERY_VOLTAGE:
 			n += sprintf(buf+n, "Battery voltage:\t");
 			break;
 		case BATTERY_REMAINING:
 			n += sprintf(buf+n, "Battery remaining:\t");
-			n += sprintf(buf+n, "%s\t", battery_remaining[state]);
-			have_strings = 1;
+			num_states = sizeof(battery_remaining) / sizeof(char *);
+			if (state < num_states)
+			{
+				n += sprintf(buf+n, "%s\t", 
+						battery_remaining[state]);
+				have_strings = 1;
+			}
 			break;
 		case BATTERY_PERCENTAGE:
 			n += sprintf(buf+n, "Battery percentage:\t");
 			break;
 		case EPOW_SENSOR:
 			n += sprintf(buf+n, "EPOW Sensor:\t");
-			n += sprintf(buf+n, "%s\t", epow_sensor[state]);
-			have_strings = 1;
+			num_states = sizeof(epow_sensor) / sizeof(char *);
+			if (state < num_states) {
+				n += sprintf(buf+n, "%s\t", epow_sensor[state]);
+				have_strings = 1;
+			}
 			break;
 		case BATTERY_CYCLESTATE:
 			n += sprintf(buf+n, "Battery cyclestate:\t");
-			n += sprintf(buf+n, "%s\t", battery_cyclestate[state]);
-			have_strings = 1;
+			num_states = sizeof(battery_cyclestate) / 
+				     	sizeof(char *);
+			if (state < num_states) {
+				n += sprintf(buf+n, "%s\t", 
+						battery_cyclestate[state]);
+				have_strings = 1;
+			}
 			break;
 		case BATTERY_CHARGING:
 			n += sprintf(buf+n, "Battery Charging:\t");
-			n += sprintf(buf+n, "%s\t", battery_charging[state]);
-			have_strings = 1;
+			num_states = sizeof(battery_charging) / sizeof(char *);
+			if (state < num_states) {
+				n += sprintf(buf+n, "%s\t", 
+						battery_charging[state]);
+				have_strings = 1;
+			}
 			break;
 		case IBM_SURVEILLANCE:
 			n += sprintf(buf+n, "Surveillance:\t");
@@ -589,16 +626,24 @@
 			break;
 		case IBM_DRCONNECTOR:
 			n += sprintf(buf+n, "DR connector:\t");
-			n += sprintf(buf+n, "%s\t", ibm_drconnector[state]);
-			have_strings = 1;
+			num_states = sizeof(ibm_drconnector) / sizeof(char *);
+			if (state < num_states) {
+				n += sprintf(buf+n, "%s\t", 
+						ibm_drconnector[state]);
+				have_strings = 1;
+			}
 			break;
 		case IBM_POWERSUPPLY:
 			n += sprintf(buf+n, "Powersupply:\t");
 			break;
 		case IBM_INTQUEUE:
 			n += sprintf(buf+n, "Interrupt queue:\t");
-			n += sprintf(buf+n, "%s\t", ibm_intqueue[state]);
-			have_strings = 1;
+			num_states = sizeof(ibm_intqueue) / sizeof(char *);
+			if (state < num_states) {
+				n += sprintf(buf+n, "%s\t", 
+						ibm_intqueue[state]);
+				have_strings = 1;
+			}
 			break;
 		default:
 			n += sprintf(buf+n,  "Unkown sensor (type %d), ignoring it\n",
diff -Nru a/arch/ppc64/kernel/rtas.c b/arch/ppc64/kernel/rtas.c
--- a/arch/ppc64/kernel/rtas.c	Thu Feb 13 00:57:29 2003
+++ b/arch/ppc64/kernel/rtas.c	Thu May  1 20:23:50 2003
@@ -18,6 +18,7 @@
 #include <linux/module.h>
 
 #include <asm/prom.h>
+#include <asm/proc_fs.h>
 #include <asm/rtas.h>
 #include <asm/semaphore.h>
 #include <asm/machdep.h>
@@ -27,7 +28,6 @@
 #include <asm/abs_addr.h>
 #include <asm/udbg.h>
 
-struct proc_dir_entry *rtas_proc_dir;	/* /proc/ppc64/rtas dir */
 struct flash_block_list_header rtas_firmware_flash_list = {0, 0};
 
 /*
@@ -216,7 +216,11 @@
 			image_size += f->blocks[i].length;
 		}
 		next = f->next;
-		f->next = (struct flash_block_list *)virt_to_absolute((unsigned long)f->next);
+		/* Don't translate NULL pointer for last entry */
+		if(f->next)
+			f->next = (struct flash_block_list *)virt_to_absolute((unsigned long)f->next);
+		else
+			f->next = 0LL;
 		/* make num_blocks into the version/length field */
 		f->num_blocks = (FLASH_BLOCK_LIST_VERSION << 56) | ((f->num_blocks+1)*16);
 	}
@@ -283,7 +287,7 @@
         rtas_power_off();
 }
 
-EXPORT_SYMBOL(rtas_proc_dir);
+EXPORT_SYMBOL(proc_ppc64);
 EXPORT_SYMBOL(rtas_firmware_flash_list);
 EXPORT_SYMBOL(rtas_token);
 EXPORT_SYMBOL(rtas_call);
diff -Nru a/arch/ppc64/kernel/rtas_flash.c b/arch/ppc64/kernel/rtas_flash.c
--- a/arch/ppc64/kernel/rtas_flash.c	Mon Nov 11 05:21:11 2002
+++ b/arch/ppc64/kernel/rtas_flash.c	Tue Mar 25 20:30:59 2003
@@ -210,7 +210,7 @@
 {
 	struct proc_dir_entry *ent = NULL;
 
-	if (!rtas_proc_dir) {
+	if (!proc_ppc64.rtas) {
 		printk(KERN_WARNING "rtas proc dir does not already exist");
 		return -ENOENT;
 	}
@@ -218,7 +218,7 @@
 	if (rtas_token("ibm,update-flash-64-and-reboot") != RTAS_UNKNOWN_SERVICE)
 		flash_possible = 1;
 
-	if ((ent = create_proc_entry(FIRMWARE_FLASH_NAME, S_IRUSR | S_IWUSR, rtas_proc_dir)) != NULL) {
+	if ((ent = create_proc_entry(FIRMWARE_FLASH_NAME, S_IRUSR | S_IWUSR, proc_ppc64.rtas)) != NULL) {
 		ent->nlink = 1;
 		ent->proc_fops = &rtas_flash_operations;
 		ent->owner = THIS_MODULE;
@@ -228,9 +228,9 @@
 
 void __exit rtas_flash_cleanup(void)
 {
-	if (!rtas_proc_dir)
+	if (!proc_ppc64.rtas)
 		return;
-	remove_proc_entry(FIRMWARE_FLASH_NAME, rtas_proc_dir);
+	remove_proc_entry(FIRMWARE_FLASH_NAME, proc_ppc64.rtas);
 }
 
 module_init(rtas_flash_init);
diff -Nru a/arch/ppc64/kernel/setup.c b/arch/ppc64/kernel/setup.c
--- a/arch/ppc64/kernel/setup.c	Sun Apr 20 09:14:41 2003
+++ b/arch/ppc64/kernel/setup.c	Sun Apr 27 14:32:15 2003
@@ -142,9 +142,6 @@
 void setup_system(unsigned long r3, unsigned long r4, unsigned long r5,
 		  unsigned long r6, unsigned long r7)
 {
-	/* This should be fixed properly in kernel/resource.c */
-	iomem_resource.end = MEM_SPACE_LIMIT;
-
 #ifdef CONFIG_XMON_DEFAULT
 	debugger = xmon;
 	debugger_bpt = xmon_bpt;
@@ -156,10 +153,10 @@
 #ifdef CONFIG_PPC_ISERIES
 	/* pSeries systems are identified in prom.c via OF. */
 	if ( itLpNaca.xLparInstalled == 1 )
-		naca->platform = PLATFORM_ISERIES_LPAR;
+		systemcfg->platform = PLATFORM_ISERIES_LPAR;
 #endif
 	
-	switch (naca->platform) {
+	switch (systemcfg->platform) {
 #ifdef CONFIG_PPC_ISERIES
 	case PLATFORM_ISERIES_LPAR:
 		iSeries_init_early();
@@ -185,7 +182,7 @@
 #endif
 	}
 
-	if (naca->platform & PLATFORM_PSERIES) {
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		early_console_initialized = 1;
 		register_console(&udbg_console);
 	}
@@ -193,32 +190,27 @@
 	printk("Starting Linux PPC64 %s\n", UTS_RELEASE);
 
 	printk("-----------------------------------------------------\n");
-	printk("naca                       = 0x%p\n", naca);
-#if 0
-	printk("naca->processorCount       = 0x%x\n", naca->processorCount);
-#endif
-	printk("naca->physicalMemorySize   = 0x%lx\n", naca->physicalMemorySize);
-	printk("naca->dCacheL1LineSize     = 0x%x\n", naca->dCacheL1LineSize);
-	printk("naca->dCacheL1LogLineSize  = 0x%x\n", naca->dCacheL1LogLineSize);
-	printk("naca->dCacheL1LinesPerPage = 0x%x\n", naca->dCacheL1LinesPerPage);
-	printk("naca->iCacheL1LineSize     = 0x%x\n", naca->iCacheL1LineSize);
-	printk("naca->iCacheL1LogLineSize  = 0x%x\n", naca->iCacheL1LogLineSize);
-	printk("naca->iCacheL1LinesPerPage = 0x%x\n", naca->iCacheL1LinesPerPage);
-	printk("naca->pftSize              = 0x%lx\n", naca->pftSize);
-	printk("naca->debug_switch         = 0x%lx\n", naca->debug_switch);
-	printk("naca->interrupt_controller = 0x%d\n", naca->interrupt_controller);
-	printk("htab_data.htab             = 0x%p\n", htab_data.htab);
-	printk("htab_data.num_ptegs        = 0x%lx\n", htab_data.htab_num_ptegs);
+	printk("naca                          = 0x%p\n", naca);
+	printk("naca->pftSize                 = 0x%lx\n", naca->pftSize);
+	printk("naca->debug_switch            = 0x%lx\n", naca->debug_switch);
+	printk("naca->interrupt_controller    = 0x%d\n", naca->interrupt_controller);
+	printk("systemcf                      = 0x%p\n", systemcfg);
+	printk("systemcfg->processorCount     = 0x%x\n", systemcfg->processorCount);
+	printk("systemcfg->physicalMemorySize = 0x%lx\n", systemcfg->physicalMemorySize);
+	printk("systemcfg->dCacheL1LineSize   = 0x%x\n", systemcfg->dCacheL1LineSize);
+	printk("systemcfg->iCacheL1LineSize   = 0x%x\n", systemcfg->iCacheL1LineSize);
+	printk("htab_data.htab                = 0x%p\n", htab_data.htab);
+	printk("htab_data.num_ptegs           = 0x%lx\n", htab_data.htab_num_ptegs);
 	printk("-----------------------------------------------------\n");
 
-	if (naca->platform & PLATFORM_PSERIES) {
+	if (systemcfg->platform & PLATFORM_PSERIES) {
 		finish_device_tree();
 		chrp_init(r3, r4, r5, r6, r7);
 	}
 
 	mm_init_ppc64();
 
-	switch (naca->platform) {
+	switch (systemcfg->platform) {
 #ifdef CONFIG_PPC_ISERIES
 	case PLATFORM_ISERIES_LPAR:
 		iSeries_init();
@@ -312,7 +304,7 @@
 	 * Assume here that all clock rates are the same in a
 	 * smp system.  -- Cort
 	 */
-	if (naca->platform != PLATFORM_ISERIES_LPAR) {
+	if (systemcfg->platform != PLATFORM_ISERIES_LPAR) {
 		struct device_node *cpu_node;
 		int *fp;
 
@@ -516,8 +508,8 @@
 	 * Systems with OF can look in the properties on the cpu node(s)
 	 * for a possibly more accurate value.
 	 */
-	dcache_bsize = naca->dCacheL1LineSize; 
-	icache_bsize = naca->iCacheL1LineSize; 
+	dcache_bsize = systemcfg->dCacheL1LineSize; 
+	icache_bsize = systemcfg->iCacheL1LineSize; 
 
 	/* reboot on panic */
 	panic_timeout = 180;
diff -Nru a/arch/ppc64/kernel/signal.c b/arch/ppc64/kernel/signal.c
--- a/arch/ppc64/kernel/signal.c	Tue Feb 11 04:25:30 2003
+++ b/arch/ppc64/kernel/signal.c	Tue Mar 25 19:38:55 2003
@@ -43,57 +43,29 @@
 #endif
 
 #define GP_REGS_SIZE	MIN(sizeof(elf_gregset_t), sizeof(struct pt_regs))
+#define FP_REGS_SIZE	sizeof(elf_fpregset_t)
 
-/* 
- * These are the flags in the MSR that the user is allowed to change
- * by modifying the saved value of the MSR on the stack.  SE and BE
- * should not be in this list since gdb may want to change these.  I.e,
- * you should be able to step out of a signal handler to see what
- * instruction executes next after the signal handler completes.
- * Alternately, if you stepped into a signal handler, you should be
- * able to continue 'til the next breakpoint from within the signal
- * handler, even if the handler returns.
- */
-#if 0
-#define MSR_USERCHANGE	(MSR_FE0 | MSR_FE1)
-#else
-/*
- * glibc tries to set FE0/FE1 via a signal handler. Since it only ever
- * sets both bits and this is the default setting we now disable this
- * behaviour. This is done to insure the new prctl which alters FE0/FE1 does
- * not get overriden by glibc. Setting and clearing FE0/FE1 via signal
- * handler has always been bogus since load_up_fpu used to set FE0/FE1
- * unconditionally.
- */
-#define MSR_USERCHANGE	0
-#endif
+#define TRAMP_TRACEBACK	3
+#define TRAMP_SIZE	6
 
 /*
- * When we have signals to deliver, we set up on the
- * user stack, going down from the original stack pointer:
- *	a sigregs struct
- *	one or more sigcontext structs with
- *	a gap of __SIGNAL_FRAMESIZE bytes
- *
- * Each of these things must be a multiple of 16 bytes in size.
- *
+ * When we have signals to deliver, we set up on the user stack,
+ * going down from the original stack pointer:
+ *	1) a rt_sigframe struct which contains the ucontext	
+ *	2) a gap of __SIGNAL_FRAMESIZE bytes which acts as a dummy caller
+ *	   frame for the signal handler.
  */
-struct sigregs {
-	elf_gregset_t	gp_regs;
-	double		fp_regs[ELF_NFPREG];
-	unsigned int	tramp[2];
-	/* 64 bit API allows for 288 bytes below sp before 
-	   decrementing it. */
-	int		abigap[72];
-};
 
-struct rt_sigframe
-{
-	unsigned long	_unused[2];
+struct rt_sigframe {
+	/* sys_rt_sigreturn requires the ucontext be the first field */
+	struct ucontext uc;
+	unsigned long _unused[2];
+	unsigned int tramp[TRAMP_SIZE];
 	struct siginfo *pinfo;
 	void *puc;
 	struct siginfo info;
-	struct ucontext uc;
+	/* 64 bit ABI allows for 288 bytes below sp before decrementing it. */
+	char abigap[288];
 };
 
 
@@ -102,37 +74,6 @@
 /*
  * Atomically swap in the new signal mask, and wait for a signal.
  */
-long sys_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
-	       struct pt_regs *regs)
-{
-	sigset_t saveset;
-
-	mask &= _BLOCKABLE;
-	spin_lock_irq(&current->sighand->siglock);
-	saveset = current->blocked;
-	siginitset(&current->blocked, mask);
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
-
-	regs->result = -EINTR;
-	regs->gpr[3] = EINTR;
-	regs->ccr |= 0x10000000;
-	while (1) {
-		current->state = TASK_INTERRUPTIBLE;
-		schedule();
-		if (do_signal(&saveset, regs))
-			/*
-			 * If a signal handler needs to be called,
-			 * do_signal() has set R3 to the signal number (the
-			 * first argument of the signal handler), so don't
-			 * overwrite that with EINTR !
-			 * In the other cases, do_signal() doesn't touch 
-			 * R3, so it's still set to -EINTR (see above).
-			 */
-			return regs->gpr[3];
-	}
-}
-
 long sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize, int p3, int p4, int p6,
 		  int p7, struct pt_regs *regs)
 {
@@ -170,339 +111,232 @@
 	return do_sigaltstack(uss, uoss, regs->gpr[1]);
 }
 
-long sys_sigaction(int sig, const struct old_sigaction *act,
-	      struct old_sigaction *oact)
+
+/*
+ * Set up the sigcontext for the signal frame.
+ */
+
+static int
+setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
+		 int signr, sigset_t *set, unsigned long handler)
 {
-	struct k_sigaction new_ka, old_ka;
-	int ret;
+	int err = 0;
 
-	if (act) {
-		old_sigset_t mask;
+	if (regs->msr & MSR_FP)
+		giveup_fpu(current);
 
-		if (verify_area(VERIFY_READ, act, sizeof(*act)) ||
-		    __get_user(new_ka.sa.sa_handler, &act->sa_handler) ||
-		    __get_user(new_ka.sa.sa_restorer, &act->sa_restorer))
-			return -EFAULT;
-		__get_user(new_ka.sa.sa_flags, &act->sa_flags);
-		__get_user(mask, &act->sa_mask);
-		siginitset(&new_ka.sa.sa_mask, mask);
-	}
+	current->thread.saved_msr = regs->msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	regs->msr = current->thread.saved_msr | current->thread.fpexc_mode;
+	current->thread.saved_softe = regs->softe;
+
+	err |= __put_user(&sc->gp_regs, &sc->regs);
+	err |= __copy_to_user(&sc->gp_regs, regs, GP_REGS_SIZE);
+	err |= __copy_to_user(&sc->fp_regs, &current->thread.fpr, FP_REGS_SIZE);
+	err |= __put_user(signr, &sc->signal);
+	err |= __put_user(handler, &sc->handler);
+	if (set != NULL)
+		err |=  __put_user(set->sig[0], &sc->oldmask);
 
-	ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL);
-	if (!ret && oact) {
-		if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) ||
-		    __put_user(old_ka.sa.sa_handler, &oact->sa_handler) ||
-		    __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer))
-			return -EFAULT;
-		__put_user(old_ka.sa.sa_flags, &oact->sa_flags);
-		__put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask);
-	}
+	regs->msr &= ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	current->thread.fpscr = 0;
 
-	return ret;
+	return err;
 }
 
 /*
- *  When we have rt signals to deliver, we set up on the
- *  user stack, going down from the original stack pointer:
- *	   a sigregs struct
- *	   one rt_sigframe struct (siginfo + ucontext)
- *	   a gap of __SIGNAL_FRAMESIZE bytes
- *
- *  Each of these things must be a multiple of 16 bytes in size.
- *
+ * Restore the sigcontext from the signal frame.
  */
 
-int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
-		     unsigned long r6, unsigned long r7, unsigned long r8,
-		     struct pt_regs *regs)
+static int
+restore_sigcontext(struct pt_regs *regs, sigset_t *set, struct sigcontext *sc)
 {
-	struct rt_sigframe *rt_sf;
-	struct sigcontext sigctx;
-	struct sigregs *sr;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
-	sigset_t set;
-	stack_t st;
+	unsigned int err = 0;
 
-	rt_sf = (struct rt_sigframe *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, &rt_sf->uc.uc_mcontext, sizeof(sigctx))
-	    || copy_from_user(&set, &rt_sf->uc.uc_sigmask, sizeof(set))
-	    || copy_from_user(&st, &rt_sf->uc.uc_stack, sizeof(st)))
-		goto badframe;
-	sigdelsetmask(&set, ~_BLOCKABLE);
-	spin_lock_irq(&current->sighand->siglock);
-	current->blocked = set;
-	recalc_sigpending();
-	spin_unlock_irq(&current->sighand->siglock);
 	if (regs->msr & MSR_FP)
 		giveup_fpu(current);
 
-	/* restore registers -
-	 * sigctx is initialized to point to the 
-	 * preamble frame (where registers are stored) 
-	 * see handle_signal()
-	 */
-	sr = (struct sigregs *)sigctx.regs;
-	if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs)))
-		goto badframe;
-	saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-		| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-	saved_regs[PT_SOFTE] = regs->softe;
-	memcpy(regs, saved_regs, GP_REGS_SIZE);
-	if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-			   sizeof(sr->fp_regs)))
-		goto badframe;
-	/* This function sets back the stack flags into
-	   the current task structure.  */
-	sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs);
+	err |= __copy_from_user(regs, &sc->gp_regs, GP_REGS_SIZE);
+	err |= __copy_from_user(&current->thread.fpr, &sc->fp_regs, FP_REGS_SIZE);
+	current->thread.fpexc_mode = regs->msr & (MSR_FE0 | MSR_FE1);
+	if (set != NULL)
+		err |=  __get_user(set->sig[0], &sc->oldmask);
+
+	/* Don't allow the signal handler to change these modulo FE{0,1} */
+	regs->msr = current->thread.saved_msr & ~(MSR_FP | MSR_FE0 | MSR_FE1);
+	regs->softe = current->thread.saved_softe;
 
-	return regs->result;
-
-badframe:
-	do_exit(SIGSEGV);
+	return err;
 }
 
-static void setup_rt_frame(struct pt_regs *regs, struct sigregs *frame,
-	       signed long newsp)
+/*
+ * Allocate space for the signal frame
+ */
+static inline void *
+get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size)
 {
-	struct rt_sigframe *rt_sf = (struct rt_sigframe *)newsp;
-	/* Handler is *really* a pointer to the function descriptor for
-	 * the signal routine.  The first entry in the function
-	 * descriptor is the entry address of signal and the second
-	 * entry is the TOC value we need to use.
-	 */
-        struct funct_descr_entry {
-                     unsigned long entry;
-                     unsigned long toc;
-	};
-  
-	struct funct_descr_entry * funct_desc_ptr;
-	unsigned long temp_ptr;
+        unsigned long newsp;
 
-	/* Set up preamble frame */
-	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	    /* li r0, __NR_rt_sigreturn */
-	    || __put_user(0x38000000UL + __NR_rt_sigreturn, &frame->tramp[0])
-	    /* sc */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))
-		goto badframe;
-	flush_icache_range((unsigned long)&frame->tramp[0],
-			   (unsigned long)&frame->tramp[2]);
-	current->thread.fpscr = 0;	/* turn off all fp exceptions */
-
-	/* Retrieve rt_sigframe from stack and
-	   set up registers for signal handler
-	*/
-	newsp -= __SIGNAL_FRAMESIZE;
+        /* Default to using normal stack */
+        newsp = regs->gpr[1];
 
-        if (get_user(temp_ptr, &rt_sf->uc.uc_mcontext.handler)) {
-		goto badframe;
+	if (ka->sa.sa_flags & SA_ONSTACK) {
+		if (! on_sig_stack(regs->gpr[1]))
+			newsp = (current->sas_ss_sp + current->sas_ss_size);
 	}
 
-        funct_desc_ptr = (struct funct_descr_entry *)temp_ptr;
-        
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, &funct_desc_ptr->entry)
-            || get_user(regs->gpr[2], &funct_desc_ptr->toc)
-	    || get_user(regs->gpr[3], &rt_sf->uc.uc_mcontext.signal)
-	    || get_user(regs->gpr[4], (unsigned long *)&rt_sf->pinfo)
-	    || get_user(regs->gpr[5], (unsigned long *)&rt_sf->puc))
-		goto badframe;
+        return (void *)((newsp - frame_size) & -8ul);
+}
 
-	regs->gpr[1] = newsp;
-	regs->gpr[6] = (unsigned long)rt_sf;
-	regs->link = (unsigned long)frame->tramp;
+static int
+setup_trampoline(unsigned int syscall, unsigned int *tramp)
+{
+	int i, err = 0;
 
-	return;
+	/* addi r1, r1, __SIGNAL_FRAMESIZE  # Pop the dummy stackframe */
+	err |= __put_user(0x38210000UL | (__SIGNAL_FRAMESIZE & 0xffff), &tramp[0]);
+	/* li r0, __NR_[rt_]sigreturn| */
+	err |= __put_user(0x38000000UL | (syscall & 0xffff), &tramp[1]);
+	/* sc */
+	err |= __put_user(0x44000002UL, &tramp[2]);
+
+	/* Minimal traceback info */
+	for (i=TRAMP_TRACEBACK; i < TRAMP_SIZE ;i++)
+		err |= __put_user(0, &tramp[i]);
+
+	if (!err)
+		flush_icache_range((unsigned long) &tramp[0],
+			   (unsigned long) &tramp[TRAMP_SIZE]);
 
-badframe:
-#if DEBUG_SIG
-	printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
-	       regs, frame, newsp);
-#endif
-	do_exit(SIGSEGV);
+	return err;
 }
 
 /*
  * Do a signal return; undo the signal stack.
  */
-long sys_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
-		   unsigned long r6, unsigned long r7, unsigned long r8,
-		   struct pt_regs *regs)
-{
-	struct sigcontext *sc, sigctx;
-	struct sigregs *sr;
-	elf_gregset_t saved_regs;  /* an array of ELF_NGREG unsigned longs */
+
+int sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5,
+		     unsigned long r6, unsigned long r7, unsigned long r8,
+		     struct pt_regs *regs)
+{
+	struct ucontext *uc = (struct ucontext *)regs->gpr[1];
 	sigset_t set;
+	stack_t st;
 
-	sc = (struct sigcontext *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);
-	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))
+	if (verify_area(VERIFY_READ, uc, sizeof(*uc)))
 		goto badframe;
 
-	set.sig[0] = sigctx.oldmask;
-#if _NSIG_WORDS > 1
-	set.sig[1] = sigctx._unused[3];
-#endif
+	if (__copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
+		goto badframe;
 	sigdelsetmask(&set, ~_BLOCKABLE);
 	spin_lock_irq(&current->sighand->siglock);
 	current->blocked = set;
 	recalc_sigpending();
 	spin_unlock_irq(&current->sighand->siglock);
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
 
-	/* restore registers */
-	sr = (struct sigregs *)sigctx.regs;
-	if (copy_from_user(saved_regs, &sr->gp_regs, sizeof(sr->gp_regs)))
+	if (restore_sigcontext(regs, NULL, &uc->uc_mcontext))
 		goto badframe;
-	saved_regs[PT_MSR] = (regs->msr & ~MSR_USERCHANGE)
-		| (saved_regs[PT_MSR] & MSR_USERCHANGE);
-	saved_regs[PT_SOFTE] = regs->softe;
-	memcpy(regs, saved_regs, GP_REGS_SIZE);
 
-	if (copy_from_user(current->thread.fpr, &sr->fp_regs,
-			   sizeof(sr->fp_regs)))
+	if (__copy_from_user(&st, &uc->uc_stack, sizeof(st)))
 		goto badframe;
+	/* This function sets back the stack flags into
+	   the current task structure.  */
+	sys_sigaltstack(&st, NULL, 0, 0, 0, 0, regs);
 
 	return regs->result;
 
 badframe:
+#if DEBUG_SIG
+	printk("badframe in sys_rt_sigreturn, regs=%p uc=%p &uc->uc_mcontext=%p\n",
+	       regs, uc, &uc->uc_mcontext);
+#endif
 	do_exit(SIGSEGV);
-}	
+}
 
-/*
- * Set up a signal frame.
- */
-static void setup_frame(struct pt_regs *regs, struct sigregs *frame,
-	    unsigned long newsp)
+static void
+setup_rt_frame(int signr, struct k_sigaction *ka, siginfo_t *info,
+		sigset_t *set, struct pt_regs *regs)
 {
-
 	/* Handler is *really* a pointer to the function descriptor for
 	 * the signal routine.  The first entry in the function
 	 * descriptor is the entry address of signal and the second
 	 * entry is the TOC value we need to use.
 	 */
-	struct funct_descr_entry {
-		unsigned long entry;
-		unsigned long toc;
-	};
-  
-	struct funct_descr_entry * funct_desc_ptr;
-	unsigned long temp_ptr;
+	func_descr_t *funct_desc_ptr;
+	struct rt_sigframe *frame;
+	unsigned long newsp = 0;
+	int err = 0;
 
-	struct sigcontext *sc = (struct sigcontext *)newsp;
-  
-	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
-		goto badframe;
-	if (regs->msr & MSR_FP)
-		giveup_fpu(current);
-	if (__copy_to_user(&frame->gp_regs, regs, GP_REGS_SIZE)
-	    || __copy_to_user(&frame->fp_regs, current->thread.fpr,
-			      ELF_NFPREG * sizeof(double))
-	    /* li r0, __NR_sigreturn */
-	    || __put_user(0x38000000UL + __NR_sigreturn, &frame->tramp[0])
-	    /* sc */
-	    || __put_user(0x44000002UL, &frame->tramp[1]))
-		goto badframe;
-	flush_icache_range((unsigned long)&frame->tramp[0],
-			   (unsigned long)&frame->tramp[2]);
-	current->thread.fpscr = 0;	/* turn off all fp exceptions */
+	frame = get_sigframe(ka, regs, sizeof(*frame));
 
-	newsp -= __SIGNAL_FRAMESIZE;
-	if (get_user(temp_ptr, &sc->handler))
+	if (verify_area(VERIFY_WRITE, frame, sizeof(*frame)))
 		goto badframe;
-  
-	funct_desc_ptr = (struct funct_descr_entry *)temp_ptr;
 
-	if (put_user(regs->gpr[1], (unsigned long *)newsp)
-	    || get_user(regs->nip, &funct_desc_ptr ->entry)
-	    || get_user(regs->gpr[2],&funct_desc_ptr->toc)
-	    || get_user(regs->gpr[3], &sc->signal))
-		goto badframe;
+	err |= __put_user(&frame->info, &frame->pinfo);
+	err |= __put_user(&frame->uc, &frame->puc);
+	err |= copy_siginfo_to_user(&frame->info, info);
+	if (err)
+		goto badframe;
+
+	/* Create the ucontext.  */
+	err |= __put_user(0, &frame->uc.uc_flags);
+	err |= __put_user(0, &frame->uc.uc_link);
+	err |= __put_user(current->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
+	err |= __put_user(sas_ss_flags(regs->gpr[1]),
+			  &frame->uc.uc_stack.ss_flags);
+	err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size);
+	err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, signr, NULL,
+				(unsigned long)ka->sa.sa_handler);
+	err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+	if (err)
+		goto badframe;
+
+	/* Set up to return from userspace. */
+	err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]);
+	if (err)
+		goto badframe;
+
+	funct_desc_ptr = (func_descr_t *) ka->sa.sa_handler;
+
+	/* Allocate a dummy caller frame for the signal handler. */
+	newsp = (unsigned long)frame - __SIGNAL_FRAMESIZE;
+	err |= put_user(0, (unsigned long *)newsp);
+
+	/* Set up "regs" so we "return" to the signal handler. */
+	err |= get_user(regs->nip, &funct_desc_ptr->entry);
+	regs->link = (unsigned long) &frame->tramp[0];
 	regs->gpr[1] = newsp;
-	regs->gpr[4] = (unsigned long)sc;
-	regs->link = (unsigned long)frame->tramp;
+	err |= get_user(regs->gpr[2], &funct_desc_ptr->toc);
+	regs->gpr[3] = signr;
+	if (ka->sa.sa_flags & SA_SIGINFO) {
+		err |= get_user(regs->gpr[4], (unsigned long *)&frame->pinfo);
+		err |= get_user(regs->gpr[5], (unsigned long *)&frame->puc);
+		regs->gpr[6] = (unsigned long) frame;
+	} else {
+		regs->gpr[4] = (unsigned long)&frame->uc.uc_mcontext;
+	}
+	if (err)
+		goto badframe;
 
 	return;
 
 badframe:
 #if DEBUG_SIG
-	printk("badframe in setup_frame, regs=%p frame=%p newsp=%lx\n",
+	printk("badframe in setup_rt_frame, regs=%p frame=%p newsp=%lx\n",
 	       regs, frame, newsp);
 #endif
 	do_exit(SIGSEGV);
 }
 
+
 /*
  * OK, we're invoking a handler
  */
-static void handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset,
-	struct pt_regs * regs, unsigned long *newspp, unsigned long frame)
+static void
+handle_signal(unsigned long sig, struct k_sigaction *ka,
+	      siginfo_t *info, sigset_t *oldset, struct pt_regs *regs)
 {
-	struct sigcontext *sc;
-	struct rt_sigframe *rt_sf;
-	struct k_sigaction *ka = &current->sighand->action[sig-1];
-
-	if (regs->trap == 0x0C00 /* System Call! */
-	    && ((int)regs->result == -ERESTARTNOHAND ||
-		(int)regs->result == -ERESTART_RESTARTBLOCK ||
-		((int)regs->result == -ERESTARTSYS &&
-		 !(ka->sa.sa_flags & SA_RESTART)))) {
-		if ((int)regs->result == -ERESTART_RESTARTBLOCK)
-			current_thread_info()->restart_block.fn
-				= do_no_restart_syscall;
-		regs->result = -EINTR;
-	}
-
 	/* Set up Signal Frame */
-	if (ka->sa.sa_flags & SA_SIGINFO) {
-		/* Put a Real Time Context onto stack */
-		*newspp -= sizeof(*rt_sf);
-		rt_sf = (struct rt_sigframe *)*newspp;
-		if (verify_area(VERIFY_WRITE, rt_sf, sizeof(*rt_sf)))
-			goto badframe;
-
-		if (__put_user((unsigned long)ka->sa.sa_handler,
-					&rt_sf->uc.uc_mcontext.handler)
-		    || __put_user(&rt_sf->info, &rt_sf->pinfo)
-		    || __put_user(&rt_sf->uc, &rt_sf->puc)
-		    /* Put the siginfo */
-		    || copy_siginfo_to_user(&rt_sf->info, info)
-		    /* Create the ucontext */
-		    || __put_user(0, &rt_sf->uc.uc_flags)
-		    || __put_user(0, &rt_sf->uc.uc_link)
-		    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)
-		    || __put_user(sas_ss_flags(regs->gpr[1]), 
-			    &rt_sf->uc.uc_stack.ss_flags)
-		    || __put_user(current->sas_ss_size,
-			    &rt_sf->uc.uc_stack.ss_size)
-		    || __copy_to_user(&rt_sf->uc.uc_sigmask,
-			    oldset, sizeof(*oldset))
-		    /* mcontext.regs points to preamble register frame */
-		    || __put_user((struct pt_regs *)frame, &rt_sf->uc.uc_mcontext.regs)
-		    || __put_user(sig, &rt_sf->uc.uc_mcontext.signal))
-			goto badframe;
-	} else {
-		/* Put a sigcontext on the stack */
-		*newspp -= sizeof(*sc);
-		sc = (struct sigcontext *)*newspp;
-		if (verify_area(VERIFY_WRITE, sc, sizeof(*sc)))
-			goto badframe;
-		
-		if (__put_user((unsigned long)ka->sa.sa_handler, &sc->handler)
-		    || __put_user(oldset->sig[0], &sc->oldmask)
-#if _NSIG_WORDS > 1
-		    || __put_user(oldset->sig[1], &sc->_unused[3])
-#endif
-		    || __put_user((struct pt_regs *)frame, &sc->regs)
-		    || __put_user(sig, &sc->signal))
-			goto badframe;
-	}
+	setup_rt_frame(sig, ka, info, oldset, regs);
 
 	if (ka->sa.sa_flags & SA_ONESHOT)
 		ka->sa.sa_handler = SIG_DFL;
@@ -515,14 +349,40 @@
 		spin_unlock_irq(&current->sighand->siglock);
 	}
 	return;
+}
 
-badframe:
-#if DEBUG_SIG
-	printk("badframe in handle_signal, regs=%p frame=%lx newsp=%lx\n",
-	       regs, frame, *newspp);
-	printk("sc=%p sig=%d ka=%p info=%p oldset=%p\n", sc, sig, ka, info, oldset);
-#endif
-	do_exit(SIGSEGV);
+static inline void
+syscall_restart(struct pt_regs *regs, struct k_sigaction *ka)
+{
+	switch ((int)regs->result) {
+	case -ERESTART_RESTARTBLOCK:
+		current_thread_info()->restart_block.fn = do_no_restart_syscall;
+		/* fallthrough */
+	case -ERESTARTNOHAND:
+		/* ERESTARTNOHAND means that the syscall should only be
+		 * restarted if there was no handler for the signal, and since
+		 * we only get here if there is a handler, we dont restart.
+		 */
+		regs->result = -EINTR;
+		break;
+	case -ERESTARTSYS:
+		/* ERESTARTSYS means to restart the syscall if there is no
+		 * handler or the handler was registered with SA_RESTART
+		 */
+		if (!(ka->sa.sa_flags & SA_RESTART)) {
+			regs->result = -EINTR;
+			break;
+		}
+		/* fallthrough */
+	case -ERESTARTNOINTR:
+		/* ERESTARTNOINTR means that the syscall should be
+		 * called again after the signal handler returns.
+		 */
+		regs->gpr[3] = regs->orig_gpr3;
+		regs->nip -= 4;
+		regs->result = 0;
+		break;
+	}
 }
 
 /*
@@ -535,8 +395,6 @@
 int do_signal(sigset_t *oldset, struct pt_regs *regs)
 {
 	siginfo_t info;
-	struct k_sigaction *ka;
-	unsigned long frame, newsp;
 	int signr;
 
 	/*
@@ -549,20 +407,15 @@
 	if (!oldset)
 		oldset = &current->blocked;
 
-	newsp = frame = 0;
-
 	signr = get_signal_to_deliver(&info, regs, NULL);
 	if (signr > 0) {
-		ka = &current->sighand->action[signr-1];
-		if ((ka->sa.sa_flags & SA_ONSTACK)
-		     && (!on_sig_stack(regs->gpr[1])))
-			newsp = (current->sas_ss_sp + current->sas_ss_size);
-		else
-			newsp = regs->gpr[1];
-		newsp = frame = newsp - sizeof(struct sigregs);
+		struct k_sigaction *ka = &current->sighand->action[signr-1];
 
 		/* Whee!  Actually deliver the signal.  */
-		handle_signal(signr, &info, oldset, regs, &newsp, frame);
+		if (regs->trap == 0x0C00)
+			syscall_restart(regs, ka);
+		handle_signal(signr, ka, &info, oldset, regs);
+		return 1;
 	}
 
 	if (regs->trap == 0x0C00) {	/* System Call! */
@@ -579,13 +432,8 @@
 		}
 	}
 
-	if (newsp == frame)
-		return 0;		/* no signals delivered */
-
-	/* Invoke correct stack setup routine */
-	if (ka->sa.sa_flags & SA_SIGINFO)
-		setup_rt_frame(regs, (struct sigregs *)frame, newsp);
-	else
-		setup_frame(regs, (struct sigregs *)frame, newsp);
-	return 1;
+	return 0;
 }
+
+
+
diff -Nru a/arch/ppc64/kernel/signal32.c b/arch/ppc64/kernel/signal32.c
--- a/arch/ppc64/kernel/signal32.c	Sun Feb 16 19:22:35 2003
+++ b/arch/ppc64/kernel/signal32.c	Tue Mar 25 19:38:55 2003
@@ -114,6 +114,40 @@
  *        setup_frame32
  */
 
+/*
+ * Atomically swap in the new signal mask, and wait for a signal.
+ */
+long sys32_sigsuspend(old_sigset_t mask, int p2, int p3, int p4, int p6, int p7,
+	       struct pt_regs *regs)
+{
+	sigset_t saveset;
+
+	mask &= _BLOCKABLE;
+	spin_lock_irq(&current->sighand->siglock);
+	saveset = current->blocked;
+	siginitset(&current->blocked, mask);
+	recalc_sigpending();
+	spin_unlock_irq(&current->sighand->siglock);
+
+	regs->result = -EINTR;
+	regs->gpr[3] = EINTR;
+	regs->ccr |= 0x10000000;
+	while (1) {
+		current->state = TASK_INTERRUPTIBLE;
+		schedule();
+		if (do_signal32(&saveset, regs))
+			/*
+			 * If a signal handler needs to be called,
+			 * do_signal32() has set R3 to the signal number (the
+			 * first argument of the signal handler), so don't
+			 * overwrite that with EINTR !
+			 * In the other cases, do_signal32() doesn't touch 
+			 * R3, so it's still set to -EINTR (see above).
+			 */
+			return regs->gpr[3];
+	}
+}
+
 long sys32_sigaction(int sig, struct old_sigaction32 *act,
 		struct old_sigaction32 *oact)
 {
@@ -792,13 +826,13 @@
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		schedule();
-		if (do_signal(&saveset, regs))
+		if (do_signal32(&saveset, regs))
 			/*
 			 * If a signal handler needs to be called,
-			 * do_signal() has set R3 to the signal number (the
+			 * do_signal32() has set R3 to the signal number (the
 			 * first argument of the signal handler), so don't
 			 * overwrite that with EINTR !
-			 * In the other cases, do_signal() doesn't touch 
+			 * In the other cases, do_signal32() doesn't touch 
 			 * R3, so it's still set to -EINTR (see above).
 			 */
 			return regs->gpr[3];
diff -Nru a/arch/ppc64/kernel/smp.c b/arch/ppc64/kernel/smp.c
--- a/arch/ppc64/kernel/smp.c	Mon Mar 31 14:29:49 2003
+++ b/arch/ppc64/kernel/smp.c	Tue May 20 01:41:58 2003
@@ -46,8 +46,9 @@
 #include <asm/ppcdebug.h>
 #include "open_pic.h"
 #include <asm/machdep.h>
+#include <asm/xics.h>
 
-int smp_threads_ready = 0;
+int smp_threads_ready;
 unsigned long cache_decay_ticks;
 
 /* initialised so it doesn't end up in bss */
@@ -63,18 +64,6 @@
 void smp_call_function_interrupt(void);
 void smp_message_pass(int target, int msg, unsigned long data, int wait);
 
-void xics_setup_cpu(void);
-void xics_cause_IPI(int cpu);
-
-/*
- * XICS only has a single IPI, so encode the messages per CPU
- */
-struct xics_ipi_struct {
-	        volatile unsigned long value;
-} ____cacheline_aligned;
-
-struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
-
 #define smp_message_pass(t,m,d,w) smp_ops->message_pass((t),(m),(d),(w))
 
 static inline void set_tb(unsigned int upper, unsigned int lower)
@@ -189,7 +178,7 @@
 	smp_ops->kick_cpu     = smp_iSeries_kick_cpu;
 	smp_ops->setup_cpu    = smp_iSeries_setup_cpu;
 #warning fix for iseries
-	naca->processorCount	= smp_iSeries_numProcs();
+	systemcfg->processorCount	= smp_iSeries_numProcs();
 }
 #endif
 
@@ -353,7 +342,7 @@
 		smp_ops->probe		= smp_xics_probe;
 	}
 
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 		smp_ops->give_timebase = pSeries_give_timebase;
 		smp_ops->take_timebase = pSeries_take_timebase;
 	}
@@ -621,10 +610,11 @@
 	/* create a process for the processor */
 	/* only regs.msr is actually used, and 0 is OK for it */
 	memset(&regs, 0, sizeof(struct pt_regs));
-	p = do_fork(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
+	p = copy_process(CLONE_VM|CLONE_IDLETASK, 0, &regs, 0, NULL, NULL);
 	if (IS_ERR(p))
 		panic("failed fork for CPU %u: %li", cpu, PTR_ERR(p));
 
+	wake_up_forked_process(p);
 	init_idle(p, cpu);
 	unhash_process(p);
 
diff -Nru a/arch/ppc64/kernel/sys_ppc32.c b/arch/ppc64/kernel/sys_ppc32.c
--- a/arch/ppc64/kernel/sys_ppc32.c	Sat Apr 19 23:22:56 2003
+++ b/arch/ppc64/kernel/sys_ppc32.c	Wed Apr 23 22:20:43 2003
@@ -1801,7 +1801,7 @@
 		err = do_sys32_shmctl(first, second, (void *)AA(ptr));
 		break;
 	default:
-		err = -EINVAL;
+		err = -ENOSYS;
 		break;
 	}
 	return err;
diff -Nru a/arch/ppc64/kernel/syscalls.c b/arch/ppc64/kernel/syscalls.c
--- a/arch/ppc64/kernel/syscalls.c	Fri Feb 21 23:55:40 2003
+++ b/arch/ppc64/kernel/syscalls.c	Mon Apr  7 14:09:20 2003
@@ -68,7 +68,7 @@
 	version = call >> 16; /* hack for backward compatibility */
 	call &= 0xffff;
 
-	ret = -EINVAL;
+	ret = -ENOSYS;
 	switch (call) {
 	case SEMOP:
 		ret = sys_semop (first, (struct sembuf *)ptr, second);
diff -Nru a/arch/ppc64/kernel/traps.c b/arch/ppc64/kernel/traps.c
--- a/arch/ppc64/kernel/traps.c	Mon Mar 17 21:32:24 2003
+++ b/arch/ppc64/kernel/traps.c	Mon Apr 21 12:42:07 2003
@@ -55,14 +55,12 @@
  * Trap & Exception support
  */
 
-/* Should we panic on bad kernel exceptions or try to recover */
-#undef PANIC_ON_ERROR
-
 static spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
 
 void die(const char *str, struct pt_regs *regs, long err)
 {
 	static int die_counter;
+
 	console_verbose();
 	spin_lock_irq(&die_lock);
 	bust_spinlocks(1);
@@ -71,11 +69,16 @@
 	bust_spinlocks(0);
 	spin_unlock_irq(&die_lock);
 
-#ifdef PANIC_ON_ERROR
-	panic(str);
-#else
+	if (in_interrupt())
+		panic("Fatal exception in interrupt");
+
+	if (panic_on_oops) {
+		printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n");
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(5 * HZ);
+		panic("Fatal exception");
+	}
 	do_exit(SIGSEGV);
-#endif
 }
 
 static void
@@ -139,15 +142,13 @@
 #ifdef CONFIG_DEBUG_KERNEL
 	if (debugger)
 		debugger(regs);
+	else
 #endif
+		panic("System Reset");
 
-#ifdef PANIC_ON_ERROR
-	panic("System Reset");
-#else
 	/* Must die if the interrupt is not recoverable */
 	if (!(regs->msr & MSR_RI))
 		panic("Unrecoverable System Reset");
-#endif
 
 	/* What should we do here? We could issue a shutdown or hard reset. */
 }
@@ -343,6 +344,14 @@
 		info.si_addr = (void *)regs->nip;
 		_exception(SIGILL, &info, regs);
 	}
+}
+
+ void
+KernelFPUnavailableException(struct pt_regs *regs)
+{
+	printk("Illegal floating point used in kernel (task=0x%016lx, pc=0x%016lx, trap=0x%08x)\n",
+		current, regs->nip, regs->trap);
+	panic("Unrecoverable FP Unavailable Exception in Kernel");
 }
 
 void
diff -Nru a/arch/ppc64/kernel/udbg.c b/arch/ppc64/kernel/udbg.c
--- a/arch/ppc64/kernel/udbg.c	Mon Nov  4 17:37:19 2002
+++ b/arch/ppc64/kernel/udbg.c	Tue Mar 25 20:30:59 2003
@@ -176,7 +176,7 @@
 void
 udbg_printSP(const char *s)
 {
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 		unsigned long sp;
 		asm("mr %0,1" : "=r" (sp) :);
 		if (s)
diff -Nru a/arch/ppc64/kernel/xics.c b/arch/ppc64/kernel/xics.c
--- a/arch/ppc64/kernel/xics.c	Sun Feb 16 18:27:44 2003
+++ b/arch/ppc64/kernel/xics.c	Wed Apr 23 23:53:25 2003
@@ -1,5 +1,5 @@
 /* 
- * arch/ppc/kernel/xics.c
+ * arch/ppc64/kernel/xics.c
  *
  * Copyright 2000 IBM Corporation.
  *
@@ -22,10 +22,11 @@
 #include <asm/smp.h>
 #include <asm/naca.h>
 #include <asm/rtas.h>
-#include "i8259.h"
 #include <asm/xics.h>
 #include <asm/ppcdebug.h>
-#include <asm/machdep.h>
+#include <asm/hvcall.h>
+
+#include "i8259.h"
 
 void xics_enable_irq(u_int irq);
 void xics_disable_irq(u_int irq);
@@ -61,33 +62,39 @@
 /* Want a priority other than 0.  Various HW issues require this. */
 #define	DEFAULT_PRIORITY	5
 
+/* 
+ * Mark IPIs as higher priority so we can take them inside interrupts that
+ * arent marked SA_INTERRUPT
+ */
+#define IPI_PRIORITY		4
+
 struct xics_ipl {
 	union {
-		u32	word;
-		u8	bytes[4];
+		u32 word;
+		u8 bytes[4];
 	} xirr_poll;
 	union {
 		u32 word;
-		u8	bytes[4];
+		u8 bytes[4];
 	} xirr;
-	u32	dummy;
+	u32 dummy;
 	union {
-		u32	word;
-		u8	bytes[4];
+		u32 word;
+		u8 bytes[4];
 	} qirr;
 };
 
-struct xics_info {
-	volatile struct xics_ipl *	per_cpu[NR_CPUS];
-};
+static struct xics_ipl *xics_per_cpu[NR_CPUS];
 
-struct xics_info	xics_info;
+static int xics_irq_8259_cascade = 0;
+static int xics_irq_8259_cascade_real = 0;
+static unsigned int default_server = 0xFF;
+static unsigned int default_distrib_server = 0;
 
-unsigned long long intr_base = 0;
-int xics_irq_8259_cascade = 0;
-int xics_irq_8259_cascade_real = 0;
-unsigned int default_server = 0xFF;
-unsigned int default_distrib_server = 0;
+/*
+ * XICS only has a single IPI, so encode the messages per CPU
+ */
+struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
 
 /* RTAS service tokens */
 int ibm_get_xive;
@@ -95,11 +102,6 @@
 int ibm_int_on;
 int ibm_int_off;
 
-struct xics_interrupt_node {
-	unsigned long long addr;
-	unsigned long long size;
-} inodes[NR_CPUS*2];	 
-
 typedef struct {
 	int (*xirr_info_get)(int cpu);
 	void (*xirr_info_set)(int cpu, int val);
@@ -108,24 +110,26 @@
 } xics_ops;
 
 
+/* SMP */
+
 static int pSeries_xirr_info_get(int n_cpu)
 {
-	return (xics_info.per_cpu[n_cpu]->xirr.word);
+	return xics_per_cpu[n_cpu]->xirr.word;
 }
 
 static void pSeries_xirr_info_set(int n_cpu, int value)
 {
-	xics_info.per_cpu[n_cpu]->xirr.word = value;
+	xics_per_cpu[n_cpu]->xirr.word = value;
 }
 
 static void pSeries_cppr_info(int n_cpu, u8 value)
 {
-	xics_info.per_cpu[n_cpu]->xirr.bytes[0] = value;
+	xics_per_cpu[n_cpu]->xirr.bytes[0] = value;
 }
 
-static void pSeries_qirr_info(int n_cpu , u8 value)
+static void pSeries_qirr_info(int n_cpu, u8 value)
 {
-	xics_info.per_cpu[n_cpu]->qirr.bytes[0] = value;
+	xics_per_cpu[n_cpu]->qirr.bytes[0] = value;
 }
 
 static xics_ops pSeries_ops = {
@@ -136,113 +140,174 @@
 };
 
 static xics_ops *ops = &pSeries_ops;
-extern xics_ops pSeriesLP_ops;
 
 
-void
-xics_enable_irq(
-	u_int	virq
-	)
+/* LPAR */
+
+static inline long plpar_eoi(unsigned long xirr)
 {
-	u_int		irq;
-	unsigned long	status;
-	long	        call_status;
+	return plpar_hcall_norets(H_EOI, xirr);
+}
+
+static inline long plpar_cppr(unsigned long cppr)
+{
+	return plpar_hcall_norets(H_CPPR, cppr);
+}
+
+static inline long plpar_ipi(unsigned long servernum, unsigned long mfrr)
+{
+	return plpar_hcall_norets(H_IPI, servernum, mfrr);
+}
+
+static inline long plpar_xirr(unsigned long *xirr_ret)
+{
+	unsigned long dummy;
+	return plpar_hcall(H_XIRR, 0, 0, 0, 0, xirr_ret, &dummy, &dummy);
+}
+
+static int pSeriesLP_xirr_info_get(int n_cpu)
+{
+	unsigned long lpar_rc;
+	unsigned long return_value; 
+
+	lpar_rc = plpar_xirr(&return_value);
+	if (lpar_rc != H_Success)
+		panic(" bad return code xirr - rc = %lx \n", lpar_rc); 
+	return (int)return_value;
+}
+
+static void pSeriesLP_xirr_info_set(int n_cpu, int value)
+{
+	unsigned long lpar_rc;
+	unsigned long val64 = value & 0xffffffff;
+
+	lpar_rc = plpar_eoi(val64);
+	if (lpar_rc != H_Success)
+		panic("bad return code EOI - rc = %ld, value=%lx\n", lpar_rc,
+		      val64); 
+}
+
+static void pSeriesLP_cppr_info(int n_cpu, u8 value)
+{
+	unsigned long lpar_rc;
+
+	lpar_rc = plpar_cppr(value);
+	if (lpar_rc != H_Success)
+		panic("bad return code cppr - rc = %lx\n", lpar_rc); 
+}
+
+static void pSeriesLP_qirr_info(int n_cpu , u8 value)
+{
+	unsigned long lpar_rc;
+
+	lpar_rc = plpar_ipi(n_cpu, value);
+	if (lpar_rc != H_Success)
+		panic("bad return code qirr - rc = %lx\n", lpar_rc); 
+}
+
+xics_ops pSeriesLP_ops = {
+	pSeriesLP_xirr_info_get,
+	pSeriesLP_xirr_info_set,
+	pSeriesLP_cppr_info,
+	pSeriesLP_qirr_info
+};
+
+void xics_enable_irq(u_int virq)
+{
+	u_int irq;
+	long call_status;
+	unsigned int server;
 
 	virq -= XICS_IRQ_OFFSET;
 	irq = virt_irq_to_real(virq);
 	if (irq == XICS_IPI)
 		return;
+
 #ifdef CONFIG_IRQ_ALL_CPUS
-	call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status,
-				irq, smp_threads_ready ? default_distrib_server : default_server, DEFAULT_PRIORITY);
+	if (smp_threads_ready)
+		server = default_distrib_server;
+	else
+		server = default_server;
 #else
-	call_status = rtas_call(ibm_set_xive, 3, 1, (unsigned long*)&status,
-				irq, default_server, DEFAULT_PRIORITY);
+	server = default_server;
 #endif
-	if( call_status != 0 ) {
-		printk("xics_enable_irq: irq=%x: rtas_call failed; retn=%lx, status=%lx\n",
-		       irq, call_status, status);
+
+	call_status = rtas_call(ibm_set_xive, 3, 1, NULL, irq, server,
+				DEFAULT_PRIORITY);
+	if (call_status != 0) {
+		printk("xics_enable_irq: irq=%x: ibm_set_xive returned %lx\n",
+		       irq, call_status);
 		return;
 	}
+
 	/* Now unmask the interrupt (often a no-op) */
-	call_status = rtas_call(ibm_int_on, 1, 1, (unsigned long*)&status, 
-				irq);
-	if( call_status != 0 ) {
-		printk("xics_disable_irq on: irq=%x: rtas_call failed, retn=%lx\n",
+	call_status = rtas_call(ibm_int_on, 1, 1, NULL, irq);
+	if (call_status != 0) {
+		printk("xics_enable_irq: irq=%x: ibm_int_on returned %lx\n",
 		       irq, call_status);
 		return;
 	}
 }
 
-void
-xics_disable_irq(
-	u_int	virq
-	)
-{
-	u_int		irq;
-	unsigned long 	status;
-	long 	        call_status;
+void xics_disable_irq(u_int virq)
+{
+	u_int irq;
+	long call_status;
 
 	virq -= XICS_IRQ_OFFSET;
 	irq = virt_irq_to_real(virq);
-	call_status = rtas_call(ibm_int_off, 1, 1, (unsigned long*)&status, 
-				irq);
-	if( call_status != 0 ) {
-		printk("xics_disable_irq: irq=%x: rtas_call failed, retn=%lx\n",
+	if (irq == XICS_IPI)
+		return;
+
+	call_status = rtas_call(ibm_int_off, 1, 1, NULL, irq);
+	if (call_status != 0) {
+		printk("xics_disable_irq: irq=%x: ibm_int_off returned %lx\n",
 		       irq, call_status);
 		return;
 	}
 }
 
-void
-xics_end_irq(
-	u_int	irq
-	)
+void xics_end_irq(u_int	irq)
 {
 	int cpu = smp_processor_id();
 
-	ops->cppr_info(cpu, 0); /* actually the value overwritten by ack */
-	iosync();
-	ops->xirr_info_set(cpu, ((0xff<<24) | (virt_irq_to_real(irq-XICS_IRQ_OFFSET))));
 	iosync();
+	ops->xirr_info_set(cpu, ((0xff<<24) |
+				 (virt_irq_to_real(irq-XICS_IRQ_OFFSET))));
 }
 
-void
-xics_mask_and_ack_irq(u_int	irq)
+void xics_mask_and_ack_irq(u_int irq)
 {
 	int cpu = smp_processor_id();
 
-	if( irq < XICS_IRQ_OFFSET ) {
+	if (irq < XICS_IRQ_OFFSET) {
 		i8259_pic.ack(irq);
 		iosync();
-		ops->xirr_info_set(cpu, ((0xff<<24) | xics_irq_8259_cascade_real));
-		iosync();
-	}
-	else {
-		ops->cppr_info(cpu, 0xff);
+		ops->xirr_info_set(cpu, ((0xff<<24) |
+					 xics_irq_8259_cascade_real));
 		iosync();
 	}
 }
 
-int
-xics_get_irq(struct pt_regs *regs)
+int xics_get_irq(struct pt_regs *regs)
 {
-	u_int	cpu = smp_processor_id();
-	u_int	vec;
+	u_int cpu = smp_processor_id();
+	u_int vec;
 	int irq;
 
 	vec = ops->xirr_info_get(cpu);
 	/*  (vec >> 24) == old priority */
 	vec &= 0x00ffffff;
+
 	/* for sanity, this had better be < NR_IRQS - 16 */
-	if( vec == xics_irq_8259_cascade_real ) {
+	if (vec == xics_irq_8259_cascade_real) {
 		irq = i8259_irq(cpu);
-		if(irq == -1) {
+		if (irq == -1) {
 			/* Spurious cascaded interrupt.  Still must ack xics */
                         xics_end_irq(XICS_IRQ_OFFSET + xics_irq_8259_cascade);
 			irq = -1;
 		}
-	} else if( vec == XICS_IRQ_SPURIOUS ) {
+	} else if (vec == XICS_IRQ_SPURIOUS) {
 		irq = -1;
 	} else {
 		irq = real_irq_to_virt(vec) + XICS_IRQ_OFFSET;
@@ -250,45 +315,49 @@
 	return irq;
 }
 
-struct xics_ipi_struct {
-	volatile unsigned long value;
-} ____cacheline_aligned;
+#ifdef CONFIG_SMP
 
 extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
 
-#ifdef CONFIG_SMP
-void xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
+irqreturn_t xics_ipi_action(int irq, void *dev_id, struct pt_regs *regs)
 {
 	int cpu = smp_processor_id();
+	int handled = 0;
 
 	ops->qirr_info(cpu, 0xff);
 	while (xics_ipi_message[cpu].value) {
-		if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION, &xics_ipi_message[cpu].value)) {
+		handled = 1;
+		if (test_and_clear_bit(PPC_MSG_CALL_FUNCTION,
+				       &xics_ipi_message[cpu].value)) {
 			mb();
 			smp_message_recv(PPC_MSG_CALL_FUNCTION, regs);
 		}
-		if (test_and_clear_bit(PPC_MSG_RESCHEDULE, &xics_ipi_message[cpu].value)) {
+		if (test_and_clear_bit(PPC_MSG_RESCHEDULE,
+				       &xics_ipi_message[cpu].value)) {
 			mb();
 			smp_message_recv(PPC_MSG_RESCHEDULE, regs);
 		}
 #if 0
-		if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK, &xics_ipi_message[cpu].value)) {
+		if (test_and_clear_bit(PPC_MSG_MIGRATE_TASK,
+				       &xics_ipi_message[cpu].value)) {
 			mb();
 			smp_message_recv(PPC_MSG_MIGRATE_TASK, regs);
 		}
 #endif
 #ifdef CONFIG_XMON
-		if (test_and_clear_bit(PPC_MSG_XMON_BREAK, &xics_ipi_message[cpu].value)) {
+		if (test_and_clear_bit(PPC_MSG_XMON_BREAK,
+				       &xics_ipi_message[cpu].value)) {
 			mb();
 			smp_message_recv(PPC_MSG_XMON_BREAK, regs);
 		}
 #endif
 	}
+	return IRQ_RETVAL(handled);
 }
 
 void xics_cause_IPI(int cpu)
 {
-	ops->qirr_info(cpu,0) ;
+	ops->qirr_info(cpu, IPI_PRIORITY);
 }
 
 void xics_setup_cpu(void)
@@ -298,15 +367,20 @@
 	ops->cppr_info(cpu, 0xff);
 	iosync();
 }
+
 #endif /* CONFIG_SMP */
 
-void
-xics_init_IRQ( void )
+void xics_init_IRQ(void)
 {
 	int i;
 	unsigned long intr_size = 0;
 	struct device_node *np;
 	uint *ireg, ilen, indx=0;
+	unsigned long intr_base = 0;
+	struct xics_interrupt_node {
+		unsigned long long addr;
+		unsigned long long size;
+	} inodes[NR_CPUS*2]; 
 
 	ppc64_boot_msg(0x20, "XICS Init");
 
@@ -386,23 +460,24 @@
 		xics_irq_8259_cascade = virt_irq_create_mapping(xics_irq_8259_cascade_real);
 	}
 
-	if (naca->platform == PLATFORM_PSERIES) {
+	if (systemcfg->platform == PLATFORM_PSERIES) {
 #ifdef CONFIG_SMP
 		for (i = 0; i < NR_CPUS; ++i) {
 			if (!cpu_possible(i))
 				continue;
-			xics_info.per_cpu[i] =
-			  __ioremap((ulong)inodes[i].addr, 
-				  (ulong)inodes[i].size, _PAGE_NO_CACHE);
+			xics_per_cpu[i] = __ioremap((ulong)inodes[i].addr, 
+						    (ulong)inodes[i].size,
+						    _PAGE_NO_CACHE);
 		}
 #else
-		xics_info.per_cpu[0] = __ioremap((ulong)intr_base, intr_size, _PAGE_NO_CACHE);
+		xics_per_cpu[0] = __ioremap((ulong)intr_base, intr_size,
+					    _PAGE_NO_CACHE);
 #endif /* CONFIG_SMP */
 #ifdef CONFIG_PPC_PSERIES
 	/* actually iSeries does not use any of xics...but it has link dependencies
 	 * for now, except this new one...
 	 */
-	} else if (naca->platform == PLATFORM_PSERIES_LPAR) {
+	} else if (systemcfg->platform == PLATFORM_PSERIES_LPAR) {
 		ops = &pSeriesLP_ops;
 #endif
 	}
@@ -417,8 +492,8 @@
 	ops->cppr_info(boot_cpuid, 0xff);
 	iosync();
 	if (xics_irq_8259_cascade != -1) {
-		if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET, no_action,
-				0, "8259 cascade", 0))
+		if (request_irq(xics_irq_8259_cascade + XICS_IRQ_OFFSET,
+				no_action, 0, "8259 cascade", 0))
 			printk(KERN_ERR "xics_init_IRQ: couldn't get 8259 cascade\n");
 		i8259_init();
 	}
diff -Nru a/arch/ppc64/mm/fault.c b/arch/ppc64/mm/fault.c
--- a/arch/ppc64/mm/fault.c	Wed Jan  8 14:25:43 2003
+++ b/arch/ppc64/mm/fault.c	Wed Apr  9 14:06:53 2003
@@ -75,8 +75,8 @@
 	}
 #endif
 
-	/* On an SLB miss we can only check for a valid exception entry */
-	if (regs->trap == 0x380) {
+	/* On a kernel SLB miss we can only check for a valid exception entry */
+	if (!user_mode(regs) && (regs->trap == 0x380)) {
 		bad_page_fault(regs, address, SIGSEGV);
 		return;
 	}
diff -Nru a/arch/ppc64/mm/init.c b/arch/ppc64/mm/init.c
--- a/arch/ppc64/mm/init.c	Sun Feb 16 20:11:50 2003
+++ b/arch/ppc64/mm/init.c	Thu Apr 24 13:05:36 2003
@@ -69,8 +69,6 @@
 int mem_init_done;
 unsigned long ioremap_bot = IMALLOC_BASE;
 
-static int boot_mapsize;
-
 extern pgd_t swapper_pg_dir[];
 extern char __init_begin, __init_end;
 extern char _start[], _end[];
@@ -454,6 +452,7 @@
 	unsigned long i;
 	unsigned long start, bootmap_pages;
 	unsigned long total_pages = lmb_end_of_DRAM() >> PAGE_SHIFT;
+	int boot_mapsize;
 
 	/*
 	 * Find an area to use for the bootmem bitmap.  Calculate the size of
@@ -532,7 +531,7 @@
 	int nid;
 
         for (nid = 0; nid < numnodes; nid++) {
-		if (numa_node_exists[nid]) {
+		if (node_data[nid].node_size != 0) {
 			printk("freeing bootmem node %x\n", nid);
 			totalram_pages +=
 				free_all_bootmem_node(NODE_DATA(nid));
diff -Nru a/arch/ppc64/mm/numa.c b/arch/ppc64/mm/numa.c
--- a/arch/ppc64/mm/numa.c	Sun Nov  3 23:47:58 2002
+++ b/arch/ppc64/mm/numa.c	Thu Apr 24 13:05:36 2003
@@ -24,11 +24,18 @@
 int numa_cpu_lookup_table[NR_CPUS] = { [ 0 ... (NR_CPUS - 1)] = -1};
 int numa_memory_lookup_table[MAX_MEMORY >> MEMORY_INCREMENT_SHIFT] =
 	{ [ 0 ... ((MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1)] = -1};
-int numa_node_exists[MAX_NUMNODES];
+unsigned long numa_cpumask_lookup_table[MAX_NUMNODES];
 
 struct pglist_data node_data[MAX_NUMNODES];
 bootmem_data_t plat_node_bdata[MAX_NUMNODES];
 
+static inline void map_cpu_to_node(int cpu, int node)
+{
+	dbg("cpu %d maps to domain %d\n", cpu, node);
+	numa_cpu_lookup_table[cpu] = node;
+	numa_cpumask_lookup_table[node] |= 1UL << cpu;
+}
+
 static int __init parse_numa_properties(void)
 {
 	struct device_node *cpu;
@@ -88,9 +95,7 @@
 		if (max_domain < numa_domain)
 			max_domain = numa_domain;
 
-		numa_cpu_lookup_table[cpu_nr] = numa_domain;
-
-		dbg("cpu %d maps to domain %d\n", cpu_nr, numa_domain);
+		map_cpu_to_node(cpu_nr, numa_domain);
 	}
 
 	for (memory = find_type_devices("memory"); memory;
@@ -135,7 +140,7 @@
 
 		/* FIXME */
 		if (numa_domain == 0xffff) {
-			dbg("cpu has no numa doman\n");
+			dbg("memory has no numa doman\n");
 			numa_domain = 0;
 		}
 
@@ -145,7 +150,8 @@
 		if (max_domain < numa_domain)
 			max_domain = numa_domain;
 
-		numa_node_exists[numa_domain] = 1;
+		node_data[numa_domain].node_start_pfn = start / PAGE_SIZE;
+		node_data[numa_domain].node_size = size / PAGE_SIZE;
 
 		for (i = start ; i < (start+size); i += MEMORY_INCREMENT)
 			numa_memory_lookup_table[i >> MEMORY_INCREMENT_SHIFT] =
@@ -176,27 +182,17 @@
 		BUG();
 
 	for (nid = 0; nid < numnodes; nid++) {
-		unsigned long start, end;
 		unsigned long start_paddr, end_paddr;
 		int i;
 		unsigned long bootmem_paddr;
 		unsigned long bootmap_pages;
 
-		if (!numa_node_exists[nid])
+		if (node_data[nid].node_size == 0)
 			continue;
 
-		/* Find start and end of this zone */
-		start = 0;
-		while (numa_memory_lookup_table[start] != nid)
-			start++;
-
-		end = (MAX_MEMORY >> MEMORY_INCREMENT_SHIFT) - 1;
-		while (numa_memory_lookup_table[end] != nid)
-			end--;
-		end++;
-
-		start_paddr = start << MEMORY_INCREMENT_SHIFT;
-		end_paddr = end << MEMORY_INCREMENT_SHIFT;
+		start_paddr = node_data[nid].node_start_pfn * PAGE_SIZE;
+		end_paddr = start_paddr + 
+				(node_data[nid].node_size * PAGE_SIZE);
 
 		dbg("node %d\n", nid);
 		dbg("start_paddr = %lx\n", start_paddr);
@@ -278,7 +274,7 @@
 		unsigned long start_pfn;
 		unsigned long end_pfn;
 
-		if (!numa_node_exists[nid])
+		if (node_data[nid].node_size == 0)
 			continue;
 
 		start_pfn = plat_node_bdata[nid].node_boot_start >> PAGE_SHIFT;
diff -Nru a/arch/ppc64/xmon/xmon.c b/arch/ppc64/xmon/xmon.c
--- a/arch/ppc64/xmon/xmon.c	Sun Mar  9 15:17:38 2003
+++ b/arch/ppc64/xmon/xmon.c	Mon Mar 31 11:43:45 2003
@@ -453,7 +453,7 @@
 	int i;
 	struct bpt *bp;
 
-	if (naca->platform != PLATFORM_PSERIES)
+	if (systemcfg->platform != PLATFORM_PSERIES)
 		return;
 	bp = bpts;
 	for (i = 0; i < NBPTS; ++i, ++bp) {
@@ -469,12 +469,10 @@
 		}
 	}
 
-	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
-		if (dabr.enabled)
-			set_dabr(dabr.address);
-		if (iabr.enabled)
-			set_iabr(iabr.address);
-	}
+	if (cpu_has_dabr() && dabr.enabled)
+		set_dabr(dabr.address);
+	if (cpu_has_iabr() && iabr.enabled)
+		set_iabr(iabr.address);
 }
 
 static void
@@ -484,12 +482,13 @@
 	struct bpt *bp;
 	unsigned instr;
 
-	if (naca->platform != PLATFORM_PSERIES)
+	if (systemcfg->platform != PLATFORM_PSERIES)
 		return;
-	if (!__is_processor(PV_POWER4) && !__is_processor(PV_POWER4p)) {
+
+	if (cpu_has_dabr())
 		set_dabr(0);
+	if (cpu_has_iabr())
 		set_iabr(0);
-	}
 
 	bp = bpts;
 	for (i = 0; i < NBPTS; ++i, ++bp) {
@@ -778,8 +777,8 @@
 	cmd = inchar();
 	switch (cmd) {
 	case 'd':	/* bd - hardware data breakpoint */
-		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
-			printf("Not implemented on POWER4\n");
+		if (cpu_has_dabr()) {
+			printf("Not implemented on this cpu\n");
 			break;
 		}
 		mode = 7;
@@ -798,7 +797,7 @@
 			dabr.address = (dabr.address & ~7) | mode;
 		break;
 	case 'i':	/* bi - hardware instr breakpoint */
-		if (__is_processor(PV_POWER4) || __is_processor(PV_POWER4p)) {
+		if (cpu_has_iabr()) {
 			printf("Not implemented on POWER4\n");
 			break;
 		}
diff -Nru a/arch/s390/kernel/compat_exec.c b/arch/s390/kernel/compat_exec.c
--- a/arch/s390/kernel/compat_exec.c	Mon Apr 14 12:11:54 2003
+++ b/arch/s390/kernel/compat_exec.c	Wed May 14 23:43:46 2003
@@ -18,6 +18,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/pagemap.h>
+#include <linux/mm.h>
 #include <linux/highmem.h>
 #include <linux/spinlock.h>
 #include <linux/binfmts.h>
@@ -32,8 +33,6 @@
 #endif
 
 
-extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
-
 #undef STACK_TOP
 #define STACK_TOP TASK31_SIZE
 
@@ -81,7 +80,7 @@
 		struct page *page = bprm->page[i];
 		if (page) {
 			bprm->page[i] = NULL;
-			put_dirty_page(current,page,stack_base);
+			put_dirty_page(current,page,stack_base,PAGE_COPY);
 		}
 		stack_base += PAGE_SIZE;
 	}
diff -Nru a/arch/s390/kernel/module.c b/arch/s390/kernel/module.c
--- a/arch/s390/kernel/module.c	Mon Apr 14 12:11:56 2003
+++ b/arch/s390/kernel/module.c	Mon May 12 21:23:07 2003
@@ -386,3 +386,7 @@
 		kfree(me->arch.syminfo);
 	return 0;
 }
+
+void module_arch_cleanup(struct module *mod)
+{
+}
diff -Nru a/arch/s390/kernel/s390_ksyms.c b/arch/s390/kernel/s390_ksyms.c
--- a/arch/s390/kernel/s390_ksyms.c	Mon Apr 14 12:11:56 2003
+++ b/arch/s390/kernel/s390_ksyms.c	Mon May 12 18:59:21 2003
@@ -13,7 +13,7 @@
 #include <asm/delay.h>
 #include <asm/pgalloc.h>
 #include <asm/setup.h>
-#if CONFIG_IP_MULTICAST
+#ifdef CONFIG_IP_MULTICAST
 #include <net/arp.h>
 #endif
 
diff -Nru a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c
--- a/arch/s390/kernel/traps.c	Mon Apr 14 12:11:57 2003
+++ b/arch/s390/kernel/traps.c	Mon May 12 18:59:21 2003
@@ -304,7 +304,7 @@
 	}
 	else
 	{
-#if CONFIG_REMOTE_DEBUG
+#ifdef CONFIG_REMOTE_DEBUG
 		if(gdb_stub_initialised)
 		{
 			gdb_stub_handle_exception(regs, signal);
diff -Nru a/arch/s390/math-emu/math.c b/arch/s390/math-emu/math.c
--- a/arch/s390/math-emu/math.c	Mon Apr 14 12:11:52 2003
+++ b/arch/s390/math-emu/math.c	Mon May 12 18:59:21 2003
@@ -102,7 +102,7 @@
         struct pt_regs *regs;
         __u16 *location;
         
-#if CONFIG_SYSCTL
+#ifdef CONFIG_SYSCTL
         if(sysctl_ieee_emulation_warnings)
 #endif
         {
diff -Nru a/arch/sparc/Kconfig b/arch/sparc/Kconfig
--- a/arch/sparc/Kconfig	Sun Apr 20 12:56:50 2003
+++ b/arch/sparc/Kconfig	Sun May 18 03:11:54 2003
@@ -1000,6 +1000,13 @@
 	  If you say Y here, various routines which may sleep will become very
 	  noisy if they are called with a spinlock held.	
 
+config DEBUG_BUGVERBOSE
+	bool "Verbose BUG() reporting (adds 70K)"
+	help
+	  Say Y here to make BUG() panics output the file name and line number
+	  of the BUG call as well as the EIP and oops trace.  This aids
+	  debugging but costs about 70-100K of memory.
+
 endmenu
 
 source "security/Kconfig"
diff -Nru a/arch/sparc/defconfig b/arch/sparc/defconfig
--- a/arch/sparc/defconfig	Sun Dec  8 13:54:07 2002
+++ b/arch/sparc/defconfig	Sun May 18 03:10:41 2003
@@ -2,7 +2,6 @@
 # Automatically generated make config: don't edit
 #
 CONFIG_MMU=y
-CONFIG_SWAP=y
 CONFIG_UID16=y
 CONFIG_HIGHMEM=y
 CONFIG_GENERIC_ISA_DMA=y
@@ -15,10 +14,11 @@
 #
 # General setup
 #
-CONFIG_NET=y
+CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
+CONFIG_LOG_BUF_SHIFT=14
 
 #
 # Loadable module support
@@ -26,6 +26,8 @@
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_KMOD=y
 
 #
@@ -45,6 +47,7 @@
 CONFIG_SUN_PM=y
 # CONFIG_SUN4 is not set
 CONFIG_PCI=y
+# CONFIG_PCI_LEGACY_PROC is not set
 # CONFIG_PCI_NAMES is not set
 CONFIG_SUN_OPENPROMFS=m
 CONFIG_KCORE_ELF=y
@@ -59,15 +62,17 @@
 # CONFIG_PARPORT is not set
 
 #
-# Console drivers
+# Graphics support
 #
-# CONFIG_PROM_CONSOLE is not set
-CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FB is not set
 
 #
-# Frame-buffer support
+# Console display driver support
 #
-# CONFIG_FB is not set
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+# CONFIG_PROM_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
 
 #
 # Memory Technology Devices (MTD)
@@ -130,7 +135,32 @@
 #
 # SCSI support
 #
-# CONFIG_SCSI is not set
+CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CDrom)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_SD_EXTRA_DEVS=40
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_SR_EXTRA_DEVS=2
+CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+
+#
+# SCSI low-level drivers
+#
+CONFIG_SCSI_SUNESP=y
+CONFIG_SCSI_QLOGICPTI=m
 
 #
 # Fibre Channel support
@@ -138,6 +168,11 @@
 # CONFIG_FC4 is not set
 
 #
+# Networking support
+#
+CONFIG_NET=y
+
+#
 # Networking options
 #
 CONFIG_PACKET=y
@@ -389,6 +424,7 @@
 # USB support
 #
 # CONFIG_USB is not set
+# CONFIG_USB_GADGET is not set
 
 #
 # Bluetooth support
@@ -407,6 +443,7 @@
 CONFIG_MAGIC_SYSRQ=y
 CONFIG_DEBUG_SPINLOCK=y
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+CONFIG_DEBUG_BUGVERBOSE=y
 
 #
 # Security options
diff -Nru a/arch/sparc/kernel/asm-offsets.c b/arch/sparc/kernel/asm-offsets.c
--- a/arch/sparc/kernel/asm-offsets.c	Thu Oct 17 00:55:04 2002
+++ b/arch/sparc/kernel/asm-offsets.c	Mon May 19 17:34:04 2003
@@ -22,8 +22,6 @@
 int foo(void)
 {
 	DEFINE(AOFF_task_thread, offsetof(struct task_struct, thread));
-	DEFINE(AOFF_task_ptrace, offsetof(struct task_struct, ptrace));
-	DEFINE(AOFF_task_blocked, offsetof(struct task_struct, blocked));
 	BLANK();
 	/* XXX This is the stuff for sclow.S, kill it. */
 	DEFINE(AOFF_task_pid, offsetof(struct task_struct, pid));
diff -Nru a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S
--- a/arch/sparc/kernel/entry.S	Tue Apr 22 21:35:02 2003
+++ b/arch/sparc/kernel/entry.S	Mon May 19 17:34:04 2003
@@ -359,11 +359,11 @@
 	andcc	%o1, %o4, %g0
 	be,a	smp4m_ticker
 	 cmp	%l7, 14
-	cmp	%l7, 13
+	sethi	%hi(0x40000000), %o2
 	add	%o5, %o3, %o5
-	bne,a	1f
-	 sethi	%hi(0x40000000), %o2
-	sethi	%hi(0x20000000), %o2
+	andcc	%o1, %o2, %g0
+	be,a	1f
+	 sethi	%hi(0x20000000), %o2
 1:
 	st	%o2, [%o5 + 0x4]
 	WRITE_PAUSE
@@ -374,7 +374,8 @@
 	WRITE_PAUSE
 	wr	%l4, PSR_ET, %psr
 	WRITE_PAUSE
-	cmp	%l7, 13
+	srl	%o2, (16+14), %o2
+	tst	%o2
 	bne	2f
 	 nop
 	call	C_LABEL(smp_reschedule_irq)
@@ -1245,9 +1246,8 @@
 	call	C_LABEL(do_ptrace)
 	 add	%sp, STACKFRAME_SZ, %o0
 
-	ld	[%curptr + TI_TASK], %l5
-	ld	[%l5 + AOFF_task_ptrace], %l5
-	andcc	%l5, 0x02, %g0
+	ld	[%curptr + TI_FLAGS], %l5
+	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
 	be	1f
 	 nop
 
@@ -1296,9 +1296,8 @@
 	call	C_LABEL(do_sigpause)
 	 add	%sp, STACKFRAME_SZ, %o1
 
-	ld	[%curptr + TI_TASK], %l5
-	ld	[%l5 + AOFF_task_ptrace], %l5
-	andcc	%l5, 0x02, %g0
+	ld	[%curptr + TI_FLAGS], %l5
+	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
 	be	1f
 	 nop
 
@@ -1315,9 +1314,8 @@
 	call	C_LABEL(do_sigsuspend)
 	 add	%sp, STACKFRAME_SZ, %o0
 
-	ld	[%curptr + TI_TASK], %l5
-	ld	[%l5 + AOFF_task_ptrace], %l5
-	andcc	%l5, 0x02, %g0
+	ld	[%curptr + TI_FLAGS], %l5
+	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
 	be	1f
 	 nop
 
@@ -1335,9 +1333,8 @@
 	call	C_LABEL(do_rt_sigsuspend)
 	 add	%sp, STACKFRAME_SZ, %o2
 
-	ld	[%curptr + TI_TASK], %l5
-	ld	[%l5 + AOFF_task_ptrace], %l5
-	andcc	%l5, 0x02, %g0
+	ld	[%curptr + TI_FLAGS], %l5
+	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
 	be	1f
 	 nop
 
@@ -1354,9 +1351,8 @@
 	call	C_LABEL(do_sigreturn)
 	 add	%sp, STACKFRAME_SZ, %o0
 
-	ld	[%curptr + TI_TASK], %l5
-	ld	[%l5 + AOFF_task_ptrace], %l5
-	andcc	%l5, 0x02, %g0
+	ld	[%curptr + TI_FLAGS], %l5
+	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
 	be	1f
 	 nop
 
@@ -1375,9 +1371,8 @@
 	call	C_LABEL(do_rt_sigreturn)
 	 add	%sp, STACKFRAME_SZ, %o0
 
-	ld	[%curptr + TI_TASK], %l5
-	ld	[%l5 + AOFF_task_ptrace], %l5
-	andcc	%l5, 0x02, %g0
+	ld	[%curptr + TI_FLAGS], %l5
+	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
 	be	1f
 	 nop
 
@@ -1511,10 +1506,9 @@
 	mov	%i1, %o1
 	mov	%i2, %o2
 
-	ld	[%curptr + TI_TASK], %l5
-	ld	[%l5 + AOFF_task_ptrace], %l5
+	ld	[%curptr + TI_FLAGS], %l5
 	mov	%i3, %o3
-	andcc	%l5, 0x02, %g0
+	andcc	%l5, _TIF_SYSCALL_TRACE, %g0
 	mov	%i4, %o4
 	bne	linux_syscall_trace
 	 mov	%i0, %l5
@@ -1526,13 +1520,12 @@
 
 	.globl	C_LABEL(ret_sys_call)
 C_LABEL(ret_sys_call):
-	ld	[%curptr + TI_TASK], %l6
-	ld	[%l6 + AOFF_task_ptrace], %l6
+	ld	[%curptr + TI_FLAGS], %l6
 	cmp	%o0, -ENOIOCTLCMD
 	ld	[%sp + STACKFRAME_SZ + PT_PSR], %g3
 	set	PSR_C, %g2
 	bgeu	1f
-	 andcc	%l6, 0x02, %l6	
+	 andcc	%l6, _TIF_SYSCALL_TRACE, %g0
 
 	/* System call success, clear Carry condition code. */
 	andn	%g3, %g2, %g3
diff -Nru a/arch/sparc/kernel/module.c b/arch/sparc/kernel/module.c
--- a/arch/sparc/kernel/module.c	Fri Apr  4 15:59:23 2003
+++ b/arch/sparc/kernel/module.c	Mon May 12 21:23:07 2003
@@ -145,3 +145,7 @@
 {
 	return 0;
 }
+
+void module_arch_cleanup(struct module *mod)
+{
+}
diff -Nru a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c
--- a/arch/sparc/kernel/process.c	Tue Apr 22 21:35:55 2003
+++ b/arch/sparc/kernel/process.c	Mon May 19 17:27:22 2003
@@ -186,18 +186,6 @@
 	machine_halt();
 }
 
-void show_regwindow(struct reg_window *rw)
-{
-	printk("l0: %08lx l1: %08lx l2: %08lx l3: %08lx "
-	       "l4: %08lx l5: %08lx l6: %08lx l7: %08lx\n",
-	       rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
-	       rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
-	printk("i0: %08lx i1: %08lx i2: %08lx i3: %08lx "
-	       "i4: %08lx i5: %08lx fp: %08lx i7: %08lx\n",
-	       rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
-	       rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
-}
-
 static spinlock_t sparc_backtrace_lock = SPIN_LOCK_UNLOCKED;
 
 void __show_backtrace(unsigned long fp)
@@ -248,6 +236,7 @@
 }
 #endif
 
+#if 0
 void show_stackframe(struct sparc_stackf *sf)
 {
 	unsigned long size;
@@ -275,24 +264,27 @@
 		printk("s%d: %08lx\n", i++, *stk++);
 	} while ((size -= sizeof(unsigned long)));
 }
+#endif
 
-void show_regs(struct pt_regs * regs)
+void show_regs(struct pt_regs *r)
 {
-        printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx    %s\n", regs->psr,
-	       regs->pc, regs->npc, regs->y, print_tainted());
-	printk("g0: %08lx g1: %08lx g2: %08lx g3: %08lx ",
-	       regs->u_regs[0], regs->u_regs[1], regs->u_regs[2],
-	       regs->u_regs[3]);
-	printk("g4: %08lx g5: %08lx g6: %08lx g7: %08lx\n",
-	       regs->u_regs[4], regs->u_regs[5], regs->u_regs[6],
-	       regs->u_regs[7]);
-	printk("o0: %08lx o1: %08lx o2: %08lx o3: %08lx ",
-	       regs->u_regs[8], regs->u_regs[9], regs->u_regs[10],
-	       regs->u_regs[11]);
-	printk("o4: %08lx o5: %08lx sp: %08lx o7: %08lx\n",
-	       regs->u_regs[12], regs->u_regs[13], regs->u_regs[14],
-	       regs->u_regs[15]);
-	show_regwindow((struct reg_window *)regs->u_regs[14]);
+	struct reg_window *rw = (struct reg_window *) r->u_regs[14];
+
+        printk("PSR: %08lx PC: %08lx NPC: %08lx Y: %08lx    %s\n",
+	       r->psr, r->pc, r->npc, r->y, print_tainted());
+	printk("%%G: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
+	       r->u_regs[0], r->u_regs[1], r->u_regs[2], r->u_regs[3],
+	       r->u_regs[4], r->u_regs[5], r->u_regs[6], r->u_regs[7]);
+	printk("%%O: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
+	       r->u_regs[8], r->u_regs[9], r->u_regs[10], r->u_regs[11],
+	       r->u_regs[12], r->u_regs[13], r->u_regs[14], r->u_regs[15]);
+
+	printk("%%L: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
+	       rw->locals[0], rw->locals[1], rw->locals[2], rw->locals[3],
+	       rw->locals[4], rw->locals[5], rw->locals[6], rw->locals[7]);
+	printk("%%I: %08lx %08lx  %08lx %08lx  %08lx %08lx  %08lx %08lx\n",
+	       rw->ins[0], rw->ins[1], rw->ins[2], rw->ins[3],
+	       rw->ins[4], rw->ins[5], rw->ins[6], rw->ins[7]);
 }
 
 void show_trace_task(struct task_struct *tsk)
@@ -411,7 +403,6 @@
 {
 	unsigned long parent_tid_ptr = 0;
 	unsigned long child_tid_ptr = 0;
-	struct task_struct *p;
 
 	clone_flags &= ~CLONE_IDLETASK;
 
@@ -419,11 +410,10 @@
 		parent_tid_ptr = regs->u_regs[UREG_G2];
 		child_tid_ptr = regs->u_regs[UREG_G3];
 	}
-	p = do_fork(clone_flags, stack_start,
-		    regs, stack_size,
-		    (int *) parent_tid_ptr,
-		    (int *) child_tid_ptr);
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(clone_flags, stack_start,
+		       regs, stack_size,
+		       (int *) parent_tid_ptr,
+		       (int *) child_tid_ptr);
 }
 
 /* Copy a Sparc thread.  The fork() return value conventions
diff -Nru a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c
--- a/arch/sparc/kernel/ptrace.c	Wed Nov 27 15:14:11 2002
+++ b/arch/sparc/kernel/ptrace.c	Mon May 19 17:34:04 2003
@@ -521,7 +521,7 @@
 		addr = 1;
 
 	case PTRACE_CONT: { /* restart after signal. */
-		if ((unsigned long) data > _NSIG) {
+		if (data > _NSIG) {
 			pt_error_return(regs, EIO);
 			goto out_tsk;
 		}
@@ -545,11 +545,10 @@
 
 		child->exit_code = data;
 #ifdef DEBUG_PTRACE
-		printk("CONT: %s [%d]: set exit_code = %x %x %x\n", child->comm,
-			child->pid, child->exit_code,
+		printk("CONT: %s [%d]: set exit_code = %x %lx %lx\n",
+			child->comm, child->pid, child->exit_code,
 			child->thread.kregs->pc,
 			child->thread.kregs->npc);
-		       
 #endif
 		wake_up_process(child);
 		pt_succ_return(regs, 0);
diff -Nru a/arch/sparc/kernel/sclow.S b/arch/sparc/kernel/sclow.S
--- a/arch/sparc/kernel/sclow.S	Sun Oct 20 23:26:54 2002
+++ b/arch/sparc/kernel/sclow.S	Mon May 19 17:34:04 2003
@@ -67,27 +67,6 @@
 	mov	256, %i0
 	CC_AND_RETT
 
-	.globl	LABEL(sunossblock)
-LABEL(sunossblock):
-	LOAD_CURRENT(l4, l5)
-	ld	[%l4 + TI_TASK], %l4
-	set	-65793, %l5
-	and	%i0, %l5, %l5
-	ld	[%l4 + AOFF_task_blocked], %i0
-	or	%i0, %l5, %l5
-	st	%l5, [%l4 + AOFF_task_blocked]
-	CC_AND_RETT
-
-	.globl	LABEL(sunossmask)
-LABEL(sunossmask):
-	LOAD_CURRENT(l4, l5)
-	ld	[%l4 + TI_TASK], %l4
-	set	-65793, %l5
-	and	%i0, %l5, %l5
-	ld	[%l4 + AOFF_task_blocked], %i0
-	st	%l5, [%l4 + AOFF_task_blocked]
-	CC_AND_RETT
-
 	.globl	LABEL(getpagesize)
 LABEL(getpagesize):
 	set	PAGE_SIZE, %i0
diff -Nru a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c
--- a/arch/sparc/kernel/smp.c	Wed Apr 23 00:07:08 2003
+++ b/arch/sparc/kernel/smp.c	Sun May 18 02:42:33 2003
@@ -133,6 +133,16 @@
 		smp4d_boot_cpus();
 }
 
+void smp_send_reschedule(int cpu)
+{
+	smp_message_pass (cpu, MSG_RESCHEDULE, 0, 0);
+}
+
+void smp_send_stop(void)
+{
+	smp_message_pass (MSG_ALL_BUT_SELF, MSG_STOP_CPU, 0, 0);
+}
+
 void smp_flush_cache_all(void)
 {
 	xc0((smpfunc_t) BTFIXUP_CALL(local_flush_cache_all));
diff -Nru a/arch/sparc/kernel/sparc_ksyms.c b/arch/sparc/kernel/sparc_ksyms.c
--- a/arch/sparc/kernel/sparc_ksyms.c	Tue Apr 22 22:43:02 2003
+++ b/arch/sparc/kernel/sparc_ksyms.c	Sun May 18 03:11:54 2003
@@ -53,6 +53,7 @@
 #endif
 #include <asm/a.out.h>
 #include <asm/io-unit.h>
+#include <asm/bug.h>
 
 extern spinlock_t rtc_lock;
 
@@ -157,7 +158,7 @@
 EXPORT_SYMBOL(rtc_lock);
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
-#if CONFIG_SUN_AUXIO
+#ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(set_auxio);
 EXPORT_SYMBOL(get_auxio);
 #endif
@@ -183,7 +184,7 @@
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_sgl));
 EXPORT_SYMBOL_NOVERS(BTFIXUP_CALL(mmu_release_scsi_one));
 
-#if CONFIG_SBUS
+#ifdef CONFIG_SBUS
 EXPORT_SYMBOL(sbus_root);
 EXPORT_SYMBOL(dma_chain);
 EXPORT_SYMBOL(sbus_set_sbus64);
@@ -198,7 +199,7 @@
 EXPORT_SYMBOL(sbus_iounmap);
 EXPORT_SYMBOL(sbus_ioremap);
 #endif
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
 EXPORT_SYMBOL(ebus_chain);
 EXPORT_SYMBOL(insl);
 EXPORT_SYMBOL(outsl);
@@ -311,6 +312,10 @@
 EXPORT_SYMBOL_DOT(umul);
 EXPORT_SYMBOL_DOT(div);
 EXPORT_SYMBOL_DOT(udiv);
+
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+EXPORT_SYMBOL(do_BUG);
+#endif
 
 /* Sun Power Management Idle Handler */
 EXPORT_SYMBOL(pm_idle);
diff -Nru a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c
--- a/arch/sparc/kernel/traps.c	Fri Apr 11 22:21:41 2003
+++ b/arch/sparc/kernel/traps.c	Sun May 18 03:11:54 2003
@@ -463,6 +463,14 @@
 	send_sig_info(SIGFPE, &info, current);
 }
 
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+void do_BUG(const char *file, int line)
+{
+        // bust_spinlocks(1);   XXX Not in our original BUG()
+        printk("kernel BUG at %s:%d!\n", file, line);
+}
+#endif
+
 /* Since we have our mappings set up, on multiprocessors we can spin them
  * up here so that timer interrupts work during initialization.
  */
diff -Nru a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c
--- a/arch/sparc/mm/init.c	Wed Apr 30 01:05:52 2003
+++ b/arch/sparc/mm/init.c	Sun May 11 22:16:56 2003
@@ -107,8 +107,6 @@
 		add_to_free_ctxlist(ctx_list_pool + ctx);
 }
 
-#define DEBUG_BOOTMEM
-
 extern unsigned long cmdline_memory_size;
 unsigned long last_valid_pfn;
 
@@ -157,14 +155,11 @@
 
 unsigned long __init bootmem_init(unsigned long *pages_avail)
 {
-	unsigned long bootmap_size, start_pfn, max_pfn;
+	unsigned long bootmap_size, start_pfn;
 	unsigned long end_of_phys_memory = 0UL;
 	unsigned long bootmap_pfn, bytes_avail, size;
 	int i;
 
-#ifdef DEBUG_BOOTMEM
-	prom_printf("bootmem_init: Scan sp_banks,  ");
-#endif
 	bytes_avail = 0UL;
 	for (i = 0; sp_banks[i].num_bytes != 0; i++) {
 		end_of_phys_memory = sp_banks[i].base_addr +
@@ -234,10 +229,6 @@
 	}
 #endif	
 	/* Initialize the boot-time allocator. */
-#ifdef DEBUG_BOOTMEM
-	prom_printf("init_bootmem(spfn[%lx],bpfn[%lx],mlpfn[%lx])\n",
-		    start_pfn, bootmap_pfn, max_low_pfn);
-#endif
 	bootmap_size = init_bootmem_node(NODE_DATA(0), bootmap_pfn, phys_base>>PAGE_SHIFT, max_low_pfn);
 
 	/* Now register the available physical memory with the
@@ -264,23 +255,14 @@
 
 		size = (last_pfn - curr_pfn) << PAGE_SHIFT;
 		*pages_avail += last_pfn - curr_pfn;
-#ifdef DEBUG_BOOTMEM
-		prom_printf("free_bootmem: base[%lx] size[%lx]\n",
-			    sp_banks[i].base_addr,
-			    size);
-#endif
-		free_bootmem(sp_banks[i].base_addr,
-			     size);
+
+		free_bootmem(sp_banks[i].base_addr, size);
 	}
 
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (initrd_start) {
-		size = initrd_end - initrd_start;
-#ifdef DEBUG_BOOTMEM
-		prom_printf("reserve_bootmem: base[%lx] size[%lx]\n",
-			     initrd_start, size);
-#endif
 		/* Reserve the initrd image area. */
+		size = initrd_end - initrd_start;
 		reserve_bootmem(initrd_start, size);
 		*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
@@ -290,9 +272,6 @@
 #endif
 	/* Reserve the kernel text/data/bss. */
 	size = (start_pfn << PAGE_SHIFT) - phys_base;
-#ifdef DEBUG_BOOTMEM
-	prom_printf("reserve_bootmem: base[%lx] size[%lx]\n", phys_base, size);
-#endif
 	reserve_bootmem(phys_base, size);
 	*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
@@ -301,10 +280,6 @@
 	 * in free_all_bootmem.
 	 */
 	size = bootmap_size;
-#ifdef DEBUG_BOOTMEM
-	prom_printf("reserve_bootmem: base[%lx] size[%lx]\n",
-		    (bootmap_pfn << PAGE_SHIFT), size);
-#endif
 	reserve_bootmem((bootmap_pfn << PAGE_SHIFT), size);
 	*pages_avail -= PAGE_ALIGN(size) >> PAGE_SHIFT;
 
@@ -448,9 +423,6 @@
 	max_mapnr = last_valid_pfn - (phys_base >> PAGE_SHIFT);
 	high_memory = __va(max_low_pfn << PAGE_SHIFT);
 
-#ifdef DEBUG_BOOTMEM
-	prom_printf("mem_init: Calling free_all_bootmem().\n");
-#endif
 	num_physpages = totalram_pages = free_all_bootmem();
 
 	for (i = 0; sp_banks[i].num_bytes != 0; i++) {
diff -Nru a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c
--- a/arch/sparc/mm/srmmu.c	Wed Apr 30 01:05:53 2003
+++ b/arch/sparc/mm/srmmu.c	Mon May 12 18:59:21 2003
@@ -1310,7 +1310,7 @@
 	flush_tlb_all();
 	poke_srmmu();
 
-#if CONFIG_SUN_IO
+#ifdef CONFIG_SUN_IO
 	srmmu_allocate_ptable_skeleton(sparc_iomap.start, IOBASE_END);
 	srmmu_allocate_ptable_skeleton(DVMA_VADDR, DVMA_END);
 #endif
diff -Nru a/arch/sparc64/defconfig b/arch/sparc64/defconfig
--- a/arch/sparc64/defconfig	Sun May  4 05:48:54 2003
+++ b/arch/sparc64/defconfig	Tue May 13 17:22:34 2003
@@ -477,7 +477,16 @@
 # CONFIG_SCTP_ADLER32 is not set
 # CONFIG_SCTP_DBG_MSG is not set
 # CONFIG_SCTP_DBG_OBJCNT is not set
-# CONFIG_ATM is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+CONFIG_SCTP_HMAC_MD5=y
+CONFIG_ATM=y
+CONFIG_ATM_CLIP=y
+# CONFIG_ATM_CLIP_NO_ICMP is not set
+CONFIG_ATM_LANE=m
+CONFIG_ATM_MPOA=m
+CONFIG_ATM_BR2684=m
+CONFIG_ATM_BR2684_IPFILTER=y
 CONFIG_VLAN_8021Q=m
 CONFIG_LLC=m
 CONFIG_LLC_UI=y
@@ -487,17 +496,24 @@
 # CONFIG_DEV_APPLETALK is not set
 CONFIG_DECNET=m
 CONFIG_DECNET_SIOCGIFCONF=y
-# CONFIG_DECNET_ROUTER is not set
+CONFIG_DECNET_ROUTER=y
+CONFIG_DECNET_ROUTE_FWMARK=y
+
+#
+# DECnet: Netfilter Configuration
+#
+CONFIG_DECNET_NF_GRABULATOR=m
 CONFIG_BRIDGE=m
 CONFIG_BRIDGE_NF_EBTABLES=m
 CONFIG_BRIDGE_EBT_T_FILTER=m
 CONFIG_BRIDGE_EBT_T_NAT=m
 CONFIG_BRIDGE_EBT_BROUTE=m
 CONFIG_BRIDGE_EBT_LOG=m
-CONFIG_BRIDGE_EBT_IPF=m
-CONFIG_BRIDGE_EBT_ARPF=m
-CONFIG_BRIDGE_EBT_VLANF=m
-CONFIG_BRIDGE_EBT_MARKF=m
+CONFIG_BRIDGE_EBT_IP=m
+CONFIG_BRIDGE_EBT_ARP=m
+CONFIG_BRIDGE_EBT_VLAN=m
+CONFIG_BRIDGE_EBT_MARK=m
+CONFIG_BRIDGE_EBT_PKTTYPE=m
 CONFIG_BRIDGE_EBT_SNAT=m
 CONFIG_BRIDGE_EBT_DNAT=m
 CONFIG_BRIDGE_EBT_REDIRECT=m
@@ -517,6 +533,7 @@
 CONFIG_NET_SCH_CBQ=m
 CONFIG_NET_SCH_HTB=m
 CONFIG_NET_SCH_CSZ=m
+CONFIG_NET_SCH_ATM=y
 CONFIG_NET_SCH_PRIO=m
 CONFIG_NET_SCH_RED=m
 CONFIG_NET_SCH_SFQ=m
@@ -632,13 +649,14 @@
 # CONFIG_ROADRUNNER is not set
 CONFIG_PLIP=m
 CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
+CONFIG_PPP_MULTILINK=y
 CONFIG_PPP_FILTER=y
-# CONFIG_PPP_ASYNC is not set
-# CONFIG_PPP_SYNC_TTY is not set
-# CONFIG_PPP_DEFLATE is not set
-# CONFIG_PPP_BSDCOMP is not set
+CONFIG_PPP_ASYNC=m
+CONFIG_PPP_SYNC_TTY=m
+CONFIG_PPP_DEFLATE=m
+CONFIG_PPP_BSDCOMP=m
 CONFIG_PPPOE=m
+CONFIG_PPPOATM=m
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -647,7 +665,19 @@
 #
 # Wireless LAN (non-hamradio)
 #
-# CONFIG_NET_RADIO is not set
+CONFIG_NET_RADIO=y
+
+#
+# Obsolete Wireless cards support (pre-802.11)
+#
+# CONFIG_STRIP is not set
+
+#
+# Wireless 802.11b ISA/PCI cards support
+#
+# CONFIG_AIRO is not set
+# CONFIG_HERMES is not set
+CONFIG_NET_WIRELESS=y
 
 #
 # Token Ring devices (depends on LLC=y)
@@ -663,6 +693,30 @@
 # CONFIG_WAN is not set
 
 #
+# ATM drivers
+#
+CONFIG_ATM_TCP=m
+# CONFIG_ATM_LANAI is not set
+# CONFIG_ATM_ENI is not set
+# CONFIG_ATM_FIRESTREAM is not set
+# CONFIG_ATM_ZATM is not set
+# CONFIG_ATM_NICSTAR is not set
+# CONFIG_ATM_IDT77252 is not set
+# CONFIG_ATM_AMBASSADOR is not set
+# CONFIG_ATM_HORIZON is not set
+# CONFIG_ATM_IA is not set
+CONFIG_ATM_FORE200E_MAYBE=m
+CONFIG_ATM_FORE200E_PCA=y
+CONFIG_ATM_FORE200E_PCA_DEFAULT_FW=y
+CONFIG_ATM_FORE200E_SBA=y
+CONFIG_ATM_FORE200E_SBA_DEFAULT_FW=y
+CONFIG_ATM_FORE200E_TX_RETRY=16
+CONFIG_ATM_FORE200E_DEBUG=0
+CONFIG_ATM_FORE200E=m
+CONFIG_ATM_HE=m
+CONFIG_ATM_HE_USE_SUNI=y
+
+#
 # Amateur Radio support
 #
 CONFIG_HAMRADIO=y
@@ -759,9 +813,11 @@
 CONFIG_EXT2_FS=y
 CONFIG_EXT2_FS_XATTR=y
 CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
 CONFIG_EXT3_FS=m
 CONFIG_EXT3_FS_XATTR=y
 CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
 CONFIG_JBD=m
 # CONFIG_JBD_DEBUG is not set
 CONFIG_FS_MBCACHE=y
@@ -1127,7 +1183,9 @@
 CONFIG_USB_RIO500=m
 # CONFIG_USB_BRLVGER is not set
 CONFIG_USB_LCD=m
+CONFIG_USB_SPEEDTOUCH=m
 CONFIG_USB_TEST=m
+# CONFIG_USB_GADGET is not set
 
 #
 # Bluetooth support
diff -Nru a/arch/sparc64/kernel/ioctl32.c b/arch/sparc64/kernel/ioctl32.c
--- a/arch/sparc64/kernel/ioctl32.c	Thu May  1 01:17:28 2003
+++ b/arch/sparc64/kernel/ioctl32.c	Mon May 19 23:31:53 2003
@@ -659,17 +659,6 @@
 	return err;
 }
 
-static __inline__ void *alloc_user_space(long len)
-{
-	struct pt_regs *regs = current_thread_info()->kregs;
-	unsigned long usp = regs->u_regs[UREG_I6];
-
-	if (!(test_thread_flag(TIF_32BIT)))
-		usp += STACK_BIAS;
-
-	return (void *) (usp - len);
-}
-
 int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifreq *u_ifreq64;
@@ -685,7 +674,7 @@
 		return -EFAULT;
 	data64 = A(data32);
 
-	u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64));
+	u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64));
 
 	/* Don't check these user accesses, just let that get trapped
 	 * in the ioctl handler instead.
@@ -1701,7 +1690,7 @@
 static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg;
-	struct sock_fprog *u_fprog64 = alloc_user_space(sizeof(struct sock_fprog));
+	struct sock_fprog *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog));
 	void __user *fptr64;
 	u32 fptr32;
 	u16 flen;
diff -Nru a/arch/sparc64/kernel/module.c b/arch/sparc64/kernel/module.c
--- a/arch/sparc64/kernel/module.c	Fri Apr  4 15:59:23 2003
+++ b/arch/sparc64/kernel/module.c	Mon May 12 21:23:25 2003
@@ -138,7 +138,9 @@
 /* Free memory returned from module_core_alloc/module_init_alloc */
 void module_free(struct module *mod, void *module_region)
 {
+	write_lock(&vmlist_lock);
 	module_unmap(module_region);
+	write_unlock(&vmlist_lock);
 	/* FIXME: If module_region == mod->init_region, trim exception
            table entries. */
 }
@@ -272,4 +274,8 @@
 		    struct module *me)
 {
 	return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
 }
diff -Nru a/arch/sparc64/kernel/power.c b/arch/sparc64/kernel/power.c
--- a/arch/sparc64/kernel/power.c	Tue Apr 22 22:43:02 2003
+++ b/arch/sparc64/kernel/power.c	Tue May  6 07:33:07 2003
@@ -84,6 +84,16 @@
 	return 0;
 }
 
+static int __init has_button_interrupt(struct linux_ebus_device *edev)
+{
+	if (edev->irqs[0] == PCI_IRQ_NONE)
+		return 0;
+	if (!prom_node_has_property(edev->prom_node, "button"))
+		return 0;
+
+	return 1;
+}
+
 void __init power_init(void)
 {
 	struct linux_ebus *ebus;
@@ -106,7 +116,7 @@
 	power_reg = (unsigned long)ioremap(edev->resource[0].start, 0x4);
 	printk("power: Control reg at %016lx ... ", power_reg);
 	poweroff_method = machine_halt;  /* able to use the standard halt */
-	if (edev->irqs[0] != PCI_IRQ_NONE) {
+	if (has_button_interrupt(edev)) {
 		if (kernel_thread(powerd, 0, CLONE_FS) < 0) {
 			printk("Failed to start power daemon.\n");
 			return;
diff -Nru a/arch/sparc64/kernel/process.c b/arch/sparc64/kernel/process.c
--- a/arch/sparc64/kernel/process.c	Wed Apr  9 15:12:22 2003
+++ b/arch/sparc64/kernel/process.c	Mon May 19 17:27:24 2003
@@ -568,7 +568,6 @@
 			     struct pt_regs *regs,
 			     unsigned long stack_size)
 {
-	struct task_struct *p;
 	unsigned long parent_tid_ptr = 0;
 	unsigned long child_tid_ptr = 0;
 
@@ -583,12 +582,10 @@
 		}
 	}
 
-	p = do_fork(clone_flags, stack_start,
-		    regs, stack_size,
-		    (int *) parent_tid_ptr,
-		    (int *) child_tid_ptr);
-
-	return IS_ERR(p) ? PTR_ERR(p) : p->pid;
+	return do_fork(clone_flags, stack_start,
+		       regs, stack_size,
+		       (int *) parent_tid_ptr,
+		       (int *) child_tid_ptr);
 }
 
 /* Copy a Sparc thread.  The fork() return value conventions
diff -Nru a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c	Wed Apr 30 08:47:42 2003
+++ b/arch/sparc64/kernel/sparc64_ksyms.c	Mon May 12 18:59:21 2003
@@ -196,11 +196,11 @@
 EXPORT_SYMBOL(mostek_lock);
 EXPORT_SYMBOL(mstk48t02_regs);
 EXPORT_SYMBOL(request_fast_irq);
-#if CONFIG_SUN_AUXIO
+#ifdef CONFIG_SUN_AUXIO
 EXPORT_SYMBOL(auxio_set_led);
 EXPORT_SYMBOL(auxio_set_lte);
 #endif
-#if CONFIG_SBUS
+#ifdef CONFIG_SBUS
 EXPORT_SYMBOL(sbus_root);
 EXPORT_SYMBOL(dma_chain);
 EXPORT_SYMBOL(sbus_set_sbus64);
diff -Nru a/arch/sparc64/solaris/socksys.c b/arch/sparc64/solaris/socksys.c
--- a/arch/sparc64/solaris/socksys.c	Mon Dec  2 14:11:29 2002
+++ b/arch/sparc64/solaris/socksys.c	Wed May  7 08:47:29 2003
@@ -191,10 +191,9 @@
 		printk ("Couldn't create socket\n");
 		return ret;
 	}
-	devfs_register (NULL, "socksys", DEVFS_FL_DEFAULT,
-		       30, 0,
-		       S_IFCHR | S_IRUSR | S_IWUSR,
-		       &socksys_fops, NULL);
+
+	devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUSR|S_IWUSR, "socksys");
+
 	file = fcheck(ret);
 	/* N.B. Is this valid? Suppose the f_ops are in a module ... */
 	socksys_file_ops = *file->f_op;
diff -Nru a/arch/um/drivers/mmapper_kern.c b/arch/um/drivers/mmapper_kern.c
--- a/arch/um/drivers/mmapper_kern.c	Sat Mar 22 07:37:12 2003
+++ b/arch/um/drivers/mmapper_kern.c	Wed May  7 08:47:29 2003
@@ -124,9 +124,7 @@
 
 	p_buf = __pa(v_buf);
 
-	devfs_register (NULL, "mmapper", DEVFS_FL_DEFAULT, 
-			30, 0, S_IFCHR | S_IRUGO | S_IWUGO, 
-			&mmapper_fops, NULL); 
+	devfs_mk_cdev(MKDEV(30, 0), S_IFCHR|S_IRUGO|S_IWUGO, "mmapper");
 	devfs_mk_symlink("mmapper0", "mmapper");
 	return(0);
 }
diff -Nru a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
--- a/arch/um/kernel/irq.c	Tue Feb 25 01:38:50 2003
+++ b/arch/um/kernel/irq.c	Mon May 12 18:47:05 2003
@@ -48,7 +48,7 @@
  * each architecture has to answer this themselves, it doesn't deserve
  * a generic callback i think.
  */
-#if CONFIG_X86
+#ifdef CONFIG_X86
 	printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq);
 #ifdef CONFIG_X86_LOCAL_APIC
 	/*
@@ -121,7 +121,7 @@
 	}
 	p += sprintf(p, "\n");
 #ifdef notdef
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	p += sprintf(p, "LOC: ");
 	for (j = 0; j < num_online_cpus(); j++)
 		p += sprintf(p, "%10u ",
@@ -198,7 +198,7 @@
 	spin_unlock_irqrestore(&desc->lock, flags);
 }
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 inline void synchronize_irq(unsigned int irq)
 {
 	/* is there anything to synchronize with? */
@@ -621,7 +621,7 @@
 
 	err = parse_hex_value(buffer, count, &new_value);
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	/*
 	 * Do not allow disabling IRQs completely - it's a too easy
 	 * way to make the system unusable accidentally :-) At least
diff -Nru a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
--- a/arch/um/kernel/mem.c	Sat Apr 19 23:22:41 2003
+++ b/arch/um/kernel/mem.c	Mon May 12 18:47:06 2003
@@ -124,7 +124,7 @@
 	kmem_top = new;
 }
 
-#if CONFIG_HIGHMEM
+#ifdef CONFIG_HIGHMEM
 /* Changed during early boot */
 pte_t *kmap_pte;
 pgprot_t kmap_prot;
@@ -329,7 +329,7 @@
 	vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK;
 	fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir);
 
-#if CONFIG_HIGHMEM
+#ifdef CONFIG_HIGHMEM
 	init_highmem();
 	setup_highmem(highmem);
 #endif
diff -Nru a/arch/um/kernel/sys_call_table.c b/arch/um/kernel/sys_call_table.c
--- a/arch/um/kernel/sys_call_table.c	Wed Feb  5 20:16:02 2003
+++ b/arch/um/kernel/sys_call_table.c	Mon May 12 19:05:22 2003
@@ -236,7 +236,7 @@
 extern syscall_handler_t sys_remap_file_pages;
 extern syscall_handler_t sys_set_tid_address;
 
-#if CONFIG_NFSD
+#ifdef CONFIG_NFSD
 #define NFSSERVCTL sys_nfsservctl
 #else
 #define NFSSERVCTL sys_ni_syscall
diff -Nru a/arch/v850/kernel/module.c b/arch/v850/kernel/module.c
--- a/arch/v850/kernel/module.c	Mon Jan 13 09:46:25 2003
+++ b/arch/v850/kernel/module.c	Mon May 12 21:23:07 2003
@@ -230,3 +230,8 @@
 
 	return 0;
 }
+
+void
+module_arch_cleanup(struct module *mod)
+{
+}
diff -Nru a/arch/x86_64/ia32/ia32_binfmt.c b/arch/x86_64/ia32/ia32_binfmt.c
--- a/arch/x86_64/ia32/ia32_binfmt.c	Fri Mar 28 09:55:32 2003
+++ b/arch/x86_64/ia32/ia32_binfmt.c	Wed May 14 23:43:46 2003
@@ -13,6 +13,7 @@
 #include <linux/sched.h>
 #include <linux/string.h>
 #include <linux/binfmts.h>
+#include <linux/mm.h>
 #include <asm/segment.h> 
 #include <asm/ptrace.h>
 #include <asm/processor.h>
@@ -272,9 +273,6 @@
 	set_thread_flag(TIF_IA32); 
 }
 
-extern void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address);
- 
-
 int setup_arg_pages(struct linux_binprm *bprm)
 {
 	unsigned long stack_base;
@@ -319,7 +317,7 @@
 		struct page *page = bprm->page[i];
 		if (page) {
 			bprm->page[i] = NULL;
-			put_dirty_page(current,page,stack_base);
+			put_dirty_page(current,page,stack_base,PAGE_COPY_EXEC);
 		}
 		stack_base += PAGE_SIZE;
 	}
diff -Nru a/arch/x86_64/ia32/ia32_ioctl.c b/arch/x86_64/ia32/ia32_ioctl.c
--- a/arch/x86_64/ia32/ia32_ioctl.c	Wed Apr 30 18:31:08 2003
+++ b/arch/x86_64/ia32/ia32_ioctl.c	Mon May 19 23:31:53 2003
@@ -671,12 +671,6 @@
 	return err;
 }
 
-static __inline__ void *alloc_user_space(long len)
-{
-	struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs); 
-	return (void *)regs->rsp - len; 
-}
-
 int siocdevprivate_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct ifreq *u_ifreq64;
@@ -692,7 +686,7 @@
 		return -EFAULT;
 	data64 = (void *) A(data32);
 
-	u_ifreq64 = alloc_user_space(sizeof(*u_ifreq64));
+	u_ifreq64 = compat_alloc_user_space(sizeof(*u_ifreq64));
 
 	/* Don't check these user accesses, just let that get trapped
 	 * in the ioctl handler instead.
@@ -1573,7 +1567,7 @@
 static int ppp_sock_fprog_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
 {
 	struct sock_fprog32 *u_fprog32 = (struct sock_fprog32 *) arg;
-	struct sock_fprog *u_fprog64 = alloc_user_space(sizeof(struct sock_fprog));
+	struct sock_fprog *u_fprog64 = compat_alloc_user_space(sizeof(struct sock_fprog));
 	void *fptr64;
 	u32 fptr32;
 	u16 flen;
diff -Nru a/arch/x86_64/kernel/irq.c b/arch/x86_64/kernel/irq.c
--- a/arch/x86_64/kernel/irq.c	Wed Apr 30 18:31:11 2003
+++ b/arch/x86_64/kernel/irq.c	Mon May 12 18:59:22 2003
@@ -90,7 +90,7 @@
  * each architecture has to answer this themselves, it doesn't deserve
  * a generic callback i think.
  */
-#if CONFIG_X86
+#ifdef CONFIG_X86
 	printk("unexpected IRQ trap at vector %02x\n", irq);
 #ifdef CONFIG_X86_LOCAL_APIC
 	/*
@@ -171,7 +171,7 @@
 		if (cpu_online(j))
 		seq_printf(p, "%10u ", cpu_pda[j].__nmi_count);
 	seq_putc(p, '\n');
-#if CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_X86_LOCAL_APIC
 	seq_printf(p, "LOC: ");
 	for (j = 0; j < NR_CPUS; j++)
 		if (cpu_online(j))
@@ -827,7 +827,7 @@
 	return 0;
 }
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 
 static struct proc_dir_entry * smp_affinity_entry [NR_IRQS];
 
@@ -906,7 +906,7 @@
 	/* create /proc/irq/1234 */
 	irq_dir[irq] = proc_mkdir(name, root_irq_dir);
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	{
 		struct proc_dir_entry *entry;
 
diff -Nru a/arch/x86_64/kernel/module.c b/arch/x86_64/kernel/module.c
--- a/arch/x86_64/kernel/module.c	Fri Jan 31 13:16:08 2003
+++ b/arch/x86_64/kernel/module.c	Mon May 12 21:23:25 2003
@@ -48,7 +48,6 @@
 	for (prevp = &mod_vmlist ; (map = *prevp) ; prevp = &map->next) {
 		if ((unsigned long)map->addr == addr) {
 			*prevp = map->next;
-			write_unlock(&vmlist_lock); 
 			goto found;
 		}
 	}
@@ -57,6 +56,7 @@
 	return;
  found:
 	unmap_vm_area(map);
+	write_unlock(&vmlist_lock); 
 	if (map->pages) {
 		for (i = 0; i < map->nr_pages; i++)
 			if (map->pages[i])
@@ -230,4 +230,8 @@
 		    struct module *me)
 {
 	return 0;
+}
+
+void module_arch_cleanup(struct module *mod)
+{
 }
diff -Nru a/arch/x86_64/kernel/reboot.c b/arch/x86_64/kernel/reboot.c
--- a/arch/x86_64/kernel/reboot.c	Sat Mar 22 10:30:29 2003
+++ b/arch/x86_64/kernel/reboot.c	Mon May 12 18:59:22 2003
@@ -68,7 +68,7 @@
 
 void machine_restart(char * __unused)
 {
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	int cpuid;
 	
 	cpuid = GET_APIC_ID(apic_read(APIC_ID));
diff -Nru a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
--- a/arch/x86_64/kernel/traps.c	Fri Mar 28 09:55:32 2003
+++ b/arch/x86_64/kernel/traps.c	Mon May 12 18:59:22 2003
@@ -529,7 +529,7 @@
 	unsigned char reason = inb(0x61);
 
 	if (!(reason & 0xc0)) {
-#if CONFIG_X86_LOCAL_APIC
+#ifdef CONFIG_X86_LOCAL_APIC
 		/*
 		 * Ok, so this is none of the documented NMI sources,
 		 * so it must be the NMI watchdog.
diff -Nru a/arch/x86_64/mm/ioremap.c b/arch/x86_64/mm/ioremap.c
--- a/arch/x86_64/mm/ioremap.c	Sat Mar 22 11:29:07 2003
+++ b/arch/x86_64/mm/ioremap.c	Mon May 12 21:23:25 2003
@@ -222,7 +222,6 @@
 		return;
 	} 
 
-	unmap_vm_area(p);
 	if (p->flags && p->phys_addr < virt_to_phys(high_memory)) { 
 		change_page_attr(virt_to_page(__va(p->phys_addr)),
 				 p->size >> PAGE_SHIFT,
diff -Nru a/crypto/Kconfig b/crypto/Kconfig
--- a/crypto/Kconfig	Sat Mar 29 03:16:58 2003
+++ b/crypto/Kconfig	Sat May 17 15:30:03 2003
@@ -6,14 +6,16 @@
 
 config CRYPTO
 	bool "Cryptographic API"
-	default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m
+	default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \
+		     INET6_ESP=y || INET6_ESP=m
 	help
 	  This option provides the core Cryptographic API.
 
 config CRYPTO_HMAC
 	bool "HMAC support"
 	depends on CRYPTO
-	default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m
+	default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \
+		     INET6_ESP=y || INET6_ESP=m
 	help
 	  HMAC: Keyed-Hashing for Message Authentication (RFC2104).
 	  This is required for IPSec.
@@ -33,14 +35,16 @@
 config CRYPTO_MD5
 	tristate "MD5 digest algorithm"
 	depends on CRYPTO
-	default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m
+	default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m || INET6_AH=y || INET6_AH=m || \
+	             INET6_ESP=y || INET6_ESP=m
 	help
 	  MD5 message digest algorithm (RFC1321).
 
 config CRYPTO_SHA1
 	tristate "SHA1 digest algorithm"
 	depends on CRYPTO
-	default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m
+	default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m  || INET6_AH=y || INET6_AH=m || \
+	             INET6_ESP=y || INET6_ESP=m
 	help
 	  SHA-1 secure hash standard (FIPS 180-1/DFIPS 180-2).
 
@@ -68,7 +72,7 @@
 config CRYPTO_DES
 	tristate "DES and Triple DES EDE cipher algorithms"
 	depends on CRYPTO
-	default y if INET_AH=y || INET_AH=m || INET_ESP=y || INET_ESP=m
+	default y if INET_ESP=y || INET_ESP=m || INET6_ESP=y || INET6_ESP=m
 	help
 	  DES cipher algorithm (FIPS 46-2), and Triple DES EDE (FIPS 46-3).
 
@@ -134,7 +138,7 @@
 config CRYPTO_DEFLATE
 	tristate "Deflate compression algorithm"
 	depends on CRYPTO
-	default y if INET_IPCOMP=y || INET_IPCOMP=m
+	default y if INET_IPCOMP=y || INET_IPCOMP=m || INET6_IPCOMP=y || INET6_IPCOMP=m
 	help
 	  This is the Deflate algorithm (RFC1951), specified for use in
 	  IPSec with the IPCOMP protocol (RFC3173, RFC2394).
diff -Nru a/crypto/autoload.c b/crypto/autoload.c
--- a/crypto/autoload.c	Sat Nov  2 02:07:08 2002
+++ b/crypto/autoload.c	Sat May 17 12:39:13 2003
@@ -23,7 +23,7 @@
  */
 void crypto_alg_autoload(const char *name)
 {
-	request_module(name);
+	request_module("%s", name);
 }
 
 struct crypto_alg *crypto_alg_mod_lookup(const char *name)
diff -Nru a/crypto/deflate.c b/crypto/deflate.c
--- a/crypto/deflate.c	Tue Apr  1 14:21:14 2003
+++ b/crypto/deflate.c	Thu May 15 17:08:41 2003
@@ -81,7 +81,7 @@
 		ret = -ENOMEM;
 		goto out;
 	}
-	memset(stream->workspace, 0, sizeof(stream->workspace));
+	memset(stream->workspace, 0, zlib_deflate_workspacesize());
 	ret = zlib_deflateInit2(stream, DEFLATE_DEF_LEVEL, Z_DEFLATED,
 	                        -DEFLATE_DEF_WINBITS, DEFLATE_DEF_MEMLEVEL,
 	                        Z_DEFAULT_STRATEGY);
@@ -108,7 +108,7 @@
 		ret = -ENOMEM;
 		goto out;
 	}
-	memset(stream->workspace, 0, sizeof(stream->workspace));
+	memset(stream->workspace, 0, zlib_inflate_workspacesize());
 	ret = zlib_inflateInit2(stream, -DEFLATE_DEF_WINBITS);
 	if (ret != Z_OK) {
 		ret = -EINVAL;
diff -Nru a/crypto/md4.c b/crypto/md4.c
--- a/crypto/md4.c	Wed Oct 30 14:59:07 2002
+++ b/crypto/md4.c	Thu May 15 17:08:41 2003
@@ -215,7 +215,7 @@
 	md4_transform(mctx->hash, mctx->block);
 	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
 	memcpy(out, mctx->hash, sizeof(mctx->hash));
-	memset(mctx, 0, sizeof(mctx));
+	memset(mctx, 0, sizeof(*mctx));
 }
 
 static struct crypto_alg alg = {
diff -Nru a/crypto/md5.c b/crypto/md5.c
--- a/crypto/md5.c	Wed Oct 30 14:59:07 2002
+++ b/crypto/md5.c	Thu May 15 17:08:41 2003
@@ -210,7 +210,7 @@
 	md5_transform(mctx->hash, mctx->block);
 	cpu_to_le32_array(mctx->hash, sizeof(mctx->hash) / sizeof(u32));
 	memcpy(out, mctx->hash, sizeof(mctx->hash));
-	memset(mctx, 0, sizeof(mctx));
+	memset(mctx, 0, sizeof(*mctx));
 }
 
 static struct crypto_alg alg = {
diff -Nru a/crypto/tcrypt.c b/crypto/tcrypt.c
--- a/crypto/tcrypt.c	Sat Mar 29 03:16:58 2003
+++ b/crypto/tcrypt.c	Thu May 15 17:08:41 2003
@@ -113,7 +113,7 @@
 	printk("\ntesting md5 across pages\n");
 
 	/* setup the dummy buffer first */
-	memset(xbuf, 0, sizeof (xbuf));
+	memset(xbuf, 0, XBUFSIZE);
 	memcpy(&xbuf[IDX1], "abcdefghijklm", 13);
 	memcpy(&xbuf[IDX2], "nopqrstuvwxyz", 13);
 
@@ -188,7 +188,7 @@
 
 	printk("\ntesting hmac_md5 across pages\n");
 
-	memset(xbuf, 0, sizeof (xbuf));
+	memset(xbuf, 0, XBUFSIZE);
 
 	memcpy(&xbuf[IDX1], "what do ya want ", 16);
 	memcpy(&xbuf[IDX2], "for nothing?", 12);
@@ -267,7 +267,7 @@
 	printk("\ntesting hmac_sha1 across pages\n");
 
 	/* setup the dummy buffer first */
-	memset(xbuf, 0, sizeof (xbuf));
+	memset(xbuf, 0, XBUFSIZE);
 
 	memcpy(&xbuf[IDX1], "what do ya want ", 16);
 	memcpy(&xbuf[IDX2], "for nothing?", 12);
@@ -450,7 +450,7 @@
 	printk("\ntesting sha1 across pages\n");
 
 	/* setup the dummy buffer first */
-	memset(xbuf, 0, sizeof (xbuf));
+	memset(xbuf, 0, XBUFSIZE);
 	memcpy(&xbuf[IDX1], "abcdbcdecdefdefgefghfghighij", 28);
 	memcpy(&xbuf[IDX2], "hijkijkljklmklmnlmnomnopnopq", 28);
 
@@ -525,7 +525,7 @@
 	printk("\ntesting sha256 across pages\n");
 
 	/* setup the dummy buffer first */
-	memset(xbuf, 0, sizeof (xbuf));
+	memset(xbuf, 0, XBUFSIZE);
 	memcpy(&xbuf[IDX1], "abcdbcdecdefdefgefghfghighij", 28);
 	memcpy(&xbuf[IDX2], "hijkijkljklmklmnlmnomnopnopq", 28);
 
@@ -1027,7 +1027,7 @@
 	}
 
 	/* setup the dummy buffer first */
-	memset(xbuf, 0, sizeof (xbuf));
+	memset(xbuf, 0, XBUFSIZE);
 
 	xbuf[IDX1] = des_tv[i].plaintext[0];
 	xbuf[IDX2] = des_tv[i].plaintext[1];
diff -Nru a/drivers/Makefile b/drivers/Makefile
--- a/drivers/Makefile	Mon Mar 10 22:34:21 2003
+++ b/drivers/Makefile	Sun May 11 11:12:52 2003
@@ -37,6 +37,7 @@
 obj-$(CONFIG_PARIDE) 		+= block/paride/
 obj-$(CONFIG_TC)		+= tc/
 obj-$(CONFIG_USB)		+= usb/
+obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
 obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_GAMEPORT)		+= input/gameport/
 obj-$(CONFIG_SERIO)		+= input/serio/
diff -Nru a/drivers/acorn/char/i2c.c b/drivers/acorn/char/i2c.c
--- a/drivers/acorn/char/i2c.c	Sat Mar 22 23:26:39 2003
+++ b/drivers/acorn/char/i2c.c	Thu May 15 07:13:08 2003
@@ -19,6 +19,7 @@
 #include <linux/rtc.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
+#include <linux/fs.h>
 
 #include <asm/hardware.h>
 #include <asm/io.h>
@@ -306,7 +307,7 @@
 	.id			= I2C_HW_B_IOC,
 	.algo_data		= &ioc_data,
 	.client_register	= ioc_client_reg,
-	.client_unregister	= ioc_client_unreg
+	.client_unregister	= ioc_client_unreg,
 	.dev			= {
 		.name		= "IOC/IOMD",
 	},
diff -Nru a/drivers/acorn/char/pcf8583.c b/drivers/acorn/char/pcf8583.c
--- a/drivers/acorn/char/pcf8583.c	Sun Jan 26 15:52:37 2003
+++ b/drivers/acorn/char/pcf8583.c	Thu May 15 07:13:08 2003
@@ -34,7 +34,7 @@
 	.force			= ignore,
 };
 
-#define DAT(x) ((unsigned int)(x->data))
+#define DAT(x) ((unsigned int)(x->dev.driver_data))
 
 static int
 pcf8583_attach(struct i2c_adapter *adap, int addr, unsigned short flags,
@@ -51,13 +51,13 @@
 	if (!c)
 		return -ENOMEM;
 
-	strcpy(c->name, "PCF8583");
+	strcpy(c->dev.name, "PCF8583");
 	c->id		= pcf8583_driver.id;
 	c->flags	= 0;
 	c->addr		= addr;
 	c->adapter	= adap;
 	c->driver	= &pcf8583_driver;
-	c->data		= NULL;
+	c->dev.driver_data = NULL;
 
 	if (i2c_transfer(c->adapter, msgs, 2) == 2)
 		DAT(c) = buf[0];
diff -Nru a/drivers/acorn/net/Kconfig b/drivers/acorn/net/Kconfig
--- a/drivers/acorn/net/Kconfig	Tue Oct 29 17:16:55 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,25 +0,0 @@
-#
-# Acorn Network device configuration
-#  These are for Acorn's Expansion card network interfaces
-#
-config ARM_ETHER1
-	tristate "Acorn Ether1 support"
-	depends on NET_ETHERNET && ARM && ARCH_ACORN
-	help
-	  If you have an Acorn system with one of these (AKA25) network cards,
-	  you should say Y to this option if you wish to use it with Linux.
-
-config ARM_ETHER3
-	tristate "Acorn/ANT Ether3 support"
-	depends on NET_ETHERNET && ARM && ARCH_ACORN
-	help
-	  If you have an Acorn system with one of these network cards, you
-	  should say Y to this option if you wish to use it with Linux.
-
-config ARM_ETHERH
-	tristate "I-cubed EtherH/ANT EtherM support"
-	depends on NET_ETHERNET && ARM && ARCH_ACORN
-	help
-	  If you have an Acorn system with one of these network cards, you
-	  should say Y to this option if you wish to use it with Linux.
-
diff -Nru a/drivers/acorn/net/Makefile b/drivers/acorn/net/Makefile
--- a/drivers/acorn/net/Makefile	Sat Dec 14 04:38:56 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,8 +0,0 @@
-# File: drivers/acorn/net/Makefile
-#
-# Makefile for the Acorn ethercard network device drivers
-#
-
-obj-$(CONFIG_ARM_ETHERH)	+= etherh.o
-obj-$(CONFIG_ARM_ETHER3)	+= ether3.o
-obj-$(CONFIG_ARM_ETHER1)	+= ether1.o
diff -Nru a/drivers/acorn/net/ether1.c b/drivers/acorn/net/ether1.c
--- a/drivers/acorn/net/ether1.c	Thu Mar  6 05:00:32 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,1103 +0,0 @@
-/*
- *  linux/drivers/acorn/net/ether1.c
- *
- *  Copyright (C) 1996-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.
- *
- *  Acorn ether1 driver (82586 chip) for Acorn machines
- *
- * We basically keep two queues in the cards memory - one for transmit
- * and one for receive.  Each has a head and a tail.  The head is where
- * we/the chip adds packets to be transmitted/received, and the tail
- * is where the transmitter has got to/where the receiver will stop.
- * Both of these queues are circular, and since the chip is running
- * all the time, we have to be careful when we modify the pointers etc
- * so that the buffer memory contents is valid all the time.
- *
- * Change log:
- * 1.00	RMK			Released
- * 1.01	RMK	19/03/1996	Transfers the last odd byte onto/off of the card now.
- * 1.02	RMK	25/05/1997	Added code to restart RU if it goes not ready
- * 1.03	RMK	14/09/1997	Cleaned up the handling of a reset during the TX interrupt.
- *				Should prevent lockup.
- * 1.04 RMK	17/09/1997	Added more info when initialsation of chip goes wrong.
- *				TDR now only reports failure when chip reports non-zero
- *				TDR time-distance.
- * 1.05	RMK	31/12/1997	Removed calls to dev_tint for 2.1
- * 1.06	RMK	10/02/2000	Updated for 2.3.43
- * 1.07	RMK	13/05/2000	Updated for 2.3.99-pre8
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-#include <asm/ecard.h>
-
-#define __ETHER1_C
-#include "ether1.h"
-
-static unsigned int net_debug = NET_DEBUG;
-
-#define BUFFER_SIZE	0x10000
-#define TX_AREA_START	0x00100
-#define TX_AREA_END	0x05000
-#define RX_AREA_START	0x05000
-#define RX_AREA_END	0x0fc00
-
-static int ether1_open(struct net_device *dev);
-static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
-static void ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int ether1_close(struct net_device *dev);
-static struct net_device_stats *ether1_getstats(struct net_device *dev);
-static void ether1_setmulticastlist(struct net_device *dev);
-static void ether1_timeout(struct net_device *dev);
-
-/* ------------------------------------------------------------------------- */
-
-static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
-
-#define BUS_16 16
-#define BUS_8  8
-
-/* ------------------------------------------------------------------------- */
-
-#define DISABLEIRQS 1
-#define NORMALIRQS  0
-
-#define ether1_inw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
-#define ether1_outw(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
-
-static inline unsigned short
-ether1_inw_p (struct net_device *dev, int addr, int svflgs)
-{
-	unsigned long flags;
-	unsigned short ret;
-
-	if (svflgs)
-		local_irq_save (flags);
-
-	outb (addr >> 12, REG_PAGE);
-	ret = inw (ETHER1_RAM + ((addr & 4095) >> 1));
-	if (svflgs)
-		local_irq_restore (flags);
-	return ret;
-}
-
-static inline void
-ether1_outw_p (struct net_device *dev, unsigned short val, int addr, int svflgs)
-{
-	unsigned long flags;
-
-	if (svflgs)
-		local_irq_save (flags);
-
-	outb (addr >> 12, REG_PAGE);
-	outw (val, ETHER1_RAM + ((addr & 4095) >> 1));
-	if (svflgs)
-		local_irq_restore (flags);
-}
-
-/*
- * Some inline assembler to allow fast transfers on to/off of the card.
- * Since this driver depends on some features presented by the ARM
- * specific architecture, and that you can't configure this driver
- * without specifiing ARM mode, this is not a problem.
- *
- * This routine is essentially an optimised memcpy from the card's
- * onboard RAM to kernel memory.
- */
-static void
-ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
-{
-	unsigned int page, thislen, offset, addr;
-
-	offset = start & 4095;
-	page = start >> 12;
-	addr = ioaddr(ETHER1_RAM + (offset >> 1));
-
-	if (offset + length > 4096)
-		thislen = 4096 - offset;
-	else
-		thislen = length;
-
-	do {
-		int used;
-
-		outb(page, REG_PAGE);
-		length -= thislen;
-
-		__asm__ __volatile__(
-	"subs	%3, %3, #2
-	bmi	2f
-1:	ldr	%0, [%1], #2
-	mov	%0, %0, lsl #16
-	orr	%0, %0, %0, lsr #16
-	str	%0, [%2], #4
-	subs	%3, %3, #2
-	bmi	2f
-	ldr	%0, [%1], #2
-	mov	%0, %0, lsl #16
-	orr	%0, %0, %0, lsr #16
-	str	%0, [%2], #4
-	subs	%3, %3, #2
-	bmi	2f
-	ldr	%0, [%1], #2
-	mov	%0, %0, lsl #16
-	orr	%0, %0, %0, lsr #16
-	str	%0, [%2], #4
-	subs	%3, %3, #2
-	bmi	2f
-	ldr	%0, [%1], #2
-	mov	%0, %0, lsl #16
-	orr	%0, %0, %0, lsr #16
-	str	%0, [%2], #4
-	subs	%3, %3, #2
-	bpl	1b
-2:	adds	%3, %3, #1
-	ldreqb	%0, [%1]
-	streqb	%0, [%2]"
-		: "=&r" (used), "=&r" (data)
-		: "r"  (addr), "r" (thislen), "1" (data));
-
-		addr = ioaddr(ETHER1_RAM);
-
-		thislen = length;
-		if (thislen > 4096)
-			thislen = 4096;
-		page++;
-	} while (thislen);
-}
-
-static void
-ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
-{
-	unsigned int page, thislen, offset, addr;
-
-	offset = start & 4095;
-	page = start >> 12;
-	addr = ioaddr(ETHER1_RAM + (offset >> 1));
-
-	if (offset + length > 4096)
-		thislen = 4096 - offset;
-	else
-		thislen = length;
-
-	do {
-		int used;
-
-		outb(page, REG_PAGE);
-		length -= thislen;
-
-		__asm__ __volatile__(
-	"subs	%3, %3, #2
-	bmi	2f
-1:	ldr	%0, [%2], #4
-	strb	%0, [%1], #1
-	mov	%0, %0, lsr #8
-	strb	%0, [%1], #1
-	subs	%3, %3, #2
-	bmi	2f
-	ldr	%0, [%2], #4
-	strb	%0, [%1], #1
-	mov	%0, %0, lsr #8
-	strb	%0, [%1], #1
-	subs	%3, %3, #2
-	bmi	2f
-	ldr	%0, [%2], #4
-	strb	%0, [%1], #1
-	mov	%0, %0, lsr #8
-	strb	%0, [%1], #1
-	subs	%3, %3, #2
-	bmi	2f
-	ldr	%0, [%2], #4
-	strb	%0, [%1], #1
-	mov	%0, %0, lsr #8
-	strb	%0, [%1], #1
-	subs	%3, %3, #2
-	bpl	1b
-2:	adds	%3, %3, #1
-	ldreqb	%0, [%2]
-	streqb	%0, [%1]"
-		: "=&r" (used), "=&r" (data)
-		: "r"  (addr), "r" (thislen), "1" (data));
-
-		addr = ioaddr(ETHER1_RAM);
-
-		thislen = length;
-		if (thislen > 4096)
-			thislen = 4096;
-		page++;
-	} while (thislen);
-}
-
-static int __init
-ether1_ramtest(struct net_device *dev, unsigned char byte)
-{
-	unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
-	int i, ret = BUFFER_SIZE;
-	int max_errors = 15;
-	int bad = -1;
-	int bad_start = 0;
-
-	if (!buffer)
-		return 1;
-
-	memset (buffer, byte, BUFFER_SIZE);
-	ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE);
-	memset (buffer, byte ^ 0xff, BUFFER_SIZE);
-	ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
-
-	for (i = 0; i < BUFFER_SIZE; i++) {
-		if (buffer[i] != byte) {
-			if (max_errors >= 0 && bad != buffer[i]) {
-				if (bad != -1)
-					printk ("\n");
-				printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
-					dev->name, buffer[i], byte, i);
-				ret = -ENODEV;
-				max_errors --;
-				bad = buffer[i];
-				bad_start = i;
-			}
-		} else {
-			if (bad != -1) {
-			    	if (bad_start == i - 1)
-					printk ("\n");
-				else
-					printk (" - 0x%04X\n", i - 1);
-				bad = -1;
-			}
-		}
-	}
-
-	if (bad != -1)
-		printk (" - 0x%04X\n", BUFFER_SIZE);
-	kfree (buffer);
-
-	return ret;
-}
-
-static int
-ether1_reset (struct net_device *dev)
-{
-	outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
-	return BUS_16;
-}
-
-static int __init
-ether1_init_2(struct net_device *dev)
-{
-	int i;
-	dev->mem_start = 0;
-
-	i = ether1_ramtest (dev, 0x5a);
-
-	if (i > 0)
-		i = ether1_ramtest (dev, 0x1e);
-
-	if (i <= 0)
-	    	return -ENODEV;
-
-	dev->mem_end = i;
-	return 0;
-}
-
-/*
- * These are the structures that are loaded into the ether RAM card to
- * initialise the 82586
- */
-
-/* at 0x0100 */
-#define NOP_ADDR	(TX_AREA_START)
-#define NOP_SIZE	(0x06)
-static nop_t  init_nop  = {
-	0,
-	CMD_NOP,
-	NOP_ADDR
-};
-
-/* at 0x003a */
-#define TDR_ADDR	(0x003a)
-#define TDR_SIZE	(0x08)
-static tdr_t  init_tdr	= {
-	0,
-	CMD_TDR | CMD_INTR,
-	NOP_ADDR,
-	0
-};
-
-/* at 0x002e */
-#define MC_ADDR		(0x002e)
-#define MC_SIZE		(0x0c)
-static mc_t   init_mc   = {
-	0,
-	CMD_SETMULTICAST,
-	TDR_ADDR,
-	0,
-	{ { 0, } }
-};
-
-/* at 0x0022 */
-#define SA_ADDR		(0x0022)
-#define SA_SIZE		(0x0c)
-static sa_t   init_sa   = {
-	0,
-	CMD_SETADDRESS,
-	MC_ADDR,
-	{ 0, }
-};
-
-/* at 0x0010 */
-#define CFG_ADDR	(0x0010)
-#define CFG_SIZE	(0x12)
-static cfg_t  init_cfg  = {
-	0,
-	CMD_CONFIG,
-	SA_ADDR,
-	8,
-	8,
-	CFG8_SRDY,
-	CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6),
-	0,
-	0x60,
-	0,
-	CFG13_RETRY(15) | CFG13_SLOTH(2),
-	0,
-};
-
-/* at 0x0000 */
-#define SCB_ADDR	(0x0000)
-#define SCB_SIZE	(0x10)
-static scb_t  init_scb  = {
-	0,
-	SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX,
-	CFG_ADDR,
-	RX_AREA_START,
-	0,
-	0,
-	0,
-	0
-};
-
-/* at 0xffee */
-#define ISCP_ADDR	(0xffee)
-#define ISCP_SIZE	(0x08)
-static iscp_t init_iscp = {
-	1,
-	SCB_ADDR,
-	0x0000,
-	0x0000
-};
-
-/* at 0xfff6 */
-#define SCP_ADDR	(0xfff6)
-#define SCP_SIZE	(0x0a)
-static scp_t  init_scp  = {
-	SCP_SY_16BBUS,
-	{ 0, 0 },
-	ISCP_ADDR,
-	0
-};
-
-#define RFD_SIZE	(0x16)
-static rfd_t  init_rfd	= {
-	0,
-	0,
-	0,
-	0,
-	{ 0, },
-	{ 0, },
-	0
-};
-
-#define RBD_SIZE	(0x0a)
-static rbd_t  init_rbd	= {
-	0,
-	0,
-	0,
-	0,
-	ETH_FRAME_LEN + 8
-};
-
-#define TX_SIZE		(0x08)
-#define TBD_SIZE	(0x08)
-
-static int
-ether1_init_for_open (struct net_device *dev)
-{
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-	int i, status, addr, next, next2;
-	int failures = 0;
-
-	outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
-
-	for (i = 0; i < 6; i++)
-		init_sa.sa_addr[i] = dev->dev_addr[i];
-
-	/* load data structures into ether1 RAM */
-	ether1_writebuffer (dev, &init_scp,  SCP_ADDR,  SCP_SIZE);
-	ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE);
-	ether1_writebuffer (dev, &init_scb,  SCB_ADDR,  SCB_SIZE);
-	ether1_writebuffer (dev, &init_cfg,  CFG_ADDR,  CFG_SIZE);
-	ether1_writebuffer (dev, &init_sa,   SA_ADDR,   SA_SIZE);
-	ether1_writebuffer (dev, &init_mc,   MC_ADDR,   MC_SIZE);
-	ether1_writebuffer (dev, &init_tdr,  TDR_ADDR,  TDR_SIZE);
-	ether1_writebuffer (dev, &init_nop,  NOP_ADDR,  NOP_SIZE);
-
-	if (ether1_inw (dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
-		printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n",
-			dev->name);
-		return 1;
-	}
-
-	/*
-	 * setup circularly linked list of { rfd, rbd, buffer }, with
-	 * all rfds circularly linked, rbds circularly linked.
-	 * First rfd is linked to scp, first rbd is linked to first
-	 * rfd.  Last rbd has a suspend command.
-	 */
-	addr = RX_AREA_START;
-	do {
-		next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
-		next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
-
-		if (next2 >= RX_AREA_END) {
-			next = RX_AREA_START;
-			init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
-			priv->rx_tail = addr;
-		} else
-			init_rfd.rfd_command = 0;
-		if (addr == RX_AREA_START)
-			init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
-		else
-			init_rfd.rfd_rbdoffset = 0;
-		init_rfd.rfd_link = next;
-		init_rbd.rbd_link = next + RFD_SIZE;
-		init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE;
-
-		ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
-		ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
-		addr = next;
-	} while (next2 < RX_AREA_END);
-
-	priv->tx_link = NOP_ADDR;
-	priv->tx_head = NOP_ADDR + NOP_SIZE;
-	priv->tx_tail = TDR_ADDR;
-	priv->rx_head = RX_AREA_START;
-
-	/* release reset & give 586 a prod */
-	priv->resetting = 1;
-	priv->initialising = 1;
-	outb (CTRL_RST, REG_CONTROL);
-	outb (0, REG_CONTROL);
-	outb (CTRL_CA, REG_CONTROL);
-
-	/* 586 should now unset iscp.busy */
-	i = jiffies + HZ/2;
-	while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
-		if (time_after(jiffies, i)) {
-			printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
-			return 1;
-		}
-	}
-
-	/* check status of commands that we issued */
-	i += HZ/10;
-	while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
-			& STAT_COMPLETE) == 0) {
-		if (time_after(jiffies, i))
-			break;
-	}
-
-	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
-		printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
-		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
-		failures += 1;
-	}
-
-	i += HZ/10;
-	while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
-			& STAT_COMPLETE) == 0) {
-		if (time_after(jiffies, i))
-			break;
-	}
-
-	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
-		printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
-		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
-		failures += 1;
-	}
-
-	i += HZ/10;
-	while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
-			& STAT_COMPLETE) == 0) {
-		if (time_after(jiffies, i))
-			break;
-	}
-
-	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
-		printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
-		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
-		failures += 1;
-	}
-
-	i += HZ;
-	while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
-			& STAT_COMPLETE) == 0) {
-		if (time_after(jiffies, i))
-			break;
-	}
-
-	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
-		printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
-		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
-			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
-	} else {
-		status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
-		if (status & TDR_XCVRPROB)
-			printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
-		else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {
-#ifdef FANCY
-			printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
-				status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
-				(status & TDR_TIME) % 10);
-#else
-			printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
-				status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
-#endif
-		}
-	}
-
-	if (failures)
-		ether1_reset (dev);
-	return failures ? 1 : 0;
-}
-
-/* ------------------------------------------------------------------------- */
-
-static int
-ether1_txalloc (struct net_device *dev, int size)
-{
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-	int start, tail;
-
-	size = (size + 1) & ~1;
-	tail = priv->tx_tail;
-
-	if (priv->tx_head + size > TX_AREA_END) {
-		if (tail > priv->tx_head)
-			return -1;
-		start = TX_AREA_START;
-		if (start + size > tail)
-			return -1;
-		priv->tx_head = start + size;
-	} else {
-		if (priv->tx_head < tail && (priv->tx_head + size) > tail)
-			return -1;
-		start = priv->tx_head;
-		priv->tx_head += size;
-	}
-
-	return start;
-}
-
-static int
-ether1_open (struct net_device *dev)
-{
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-
-	if (!is_valid_ether_addr(dev->dev_addr)) {
-		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
-			dev->name);
-		return -EINVAL;
-	}
-
-	if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
-		return -EAGAIN;
-
-	memset (&priv->stats, 0, sizeof (struct net_device_stats));
-
-	if (ether1_init_for_open (dev)) {
-		free_irq (dev->irq, dev);
-		return -EAGAIN;
-	}
-
-	netif_start_queue(dev);
-
-	return 0;
-}
-
-static void
-ether1_timeout(struct net_device *dev)
-{
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-
-	printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
-		dev->name);
-	printk(KERN_WARNING "%s: resetting device\n", dev->name);
-
-	ether1_reset (dev);
-
-	if (ether1_init_for_open (dev))
-		printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
-
-	priv->stats.tx_errors++;
-	netif_wake_queue(dev);
-}
-
-static int
-ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
-{
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-	int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
-	int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
-	unsigned long flags;
-	tx_t tx;
-	tbd_t tbd;
-	nop_t nop;
-
-	if (priv->restart) {
-		printk(KERN_WARNING "%s: resetting device\n", dev->name);
-
-		ether1_reset(dev);
-
-		if (ether1_init_for_open(dev))
-			printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
-		else
-			priv->restart = 0;
-	}
-
-	/*
-	 * insert packet followed by a nop
-	 */
-	txaddr = ether1_txalloc (dev, TX_SIZE);
-	tbdaddr = ether1_txalloc (dev, TBD_SIZE);
-	dataddr = ether1_txalloc (dev, len);
-	nopaddr = ether1_txalloc (dev, NOP_SIZE);
-
-	tx.tx_status = 0;
-	tx.tx_command = CMD_TX | CMD_INTR;
-	tx.tx_link = nopaddr;
-	tx.tx_tbdoffset = tbdaddr;
-	tbd.tbd_opts = TBD_EOL | len;
-	tbd.tbd_link = I82586_NULL;
-	tbd.tbd_bufl = dataddr;
-	tbd.tbd_bufh = 0;
-	nop.nop_status = 0;
-	nop.nop_command = CMD_NOP;
-	nop.nop_link = nopaddr;
-
-	local_irq_save(flags);
-	ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
-	ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
-	ether1_writebuffer (dev, skb->data, dataddr, len);
-	ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
-	tmp = priv->tx_link;
-	priv->tx_link = nopaddr;
-
-	/* now reset the previous nop pointer */
-	ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
-
-	local_irq_restore(flags);
-
-	/* handle transmit */
-	dev->trans_start = jiffies;
-
-	/* check to see if we have room for a full sized ether frame */
-	tmp = priv->tx_head;
-	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
-	priv->tx_head = tmp;
-	dev_kfree_skb (skb);
-
-	if (tst == -1)
-		netif_stop_queue(dev);
-
-	return 0;
-}
-
-static void
-ether1_xmit_done (struct net_device *dev)
-{
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-	nop_t nop;
-	int caddr, tst;
-
-	caddr = priv->tx_tail;
-
-again:
-	ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
-
-	switch (nop.nop_command & CMD_MASK) {
-	case CMD_TDR:
-		/* special case */
-		if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
-				!= (unsigned short)I82586_NULL) {
-			ether1_outw(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
-				    scb_command, NORMALIRQS);
-			outb (CTRL_CA, REG_CONTROL);
-		}
-		priv->tx_tail = NOP_ADDR;
-		return;
-
-	case CMD_NOP:
-		if (nop.nop_link == caddr) {
-			if (priv->initialising == 0)
-				printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
-			else
-			        priv->initialising = 0;
-			return;
-		}
-		if (caddr == nop.nop_link)
-			return;
-		caddr = nop.nop_link;
-		goto again;
-
-	case CMD_TX:
-		if (nop.nop_status & STAT_COMPLETE)
-			break;
-		printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
-		priv->restart = 1;
-		return;
-
-	default:
-		printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
-			nop.nop_command & CMD_MASK, caddr);
-		priv->restart = 1;
-		return;
-	}
-
-	while (nop.nop_status & STAT_COMPLETE) {
-		if (nop.nop_status & STAT_OK) {
-			priv->stats.tx_packets ++;
-			priv->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
-		} else {
-			priv->stats.tx_errors ++;
-
-			if (nop.nop_status & STAT_COLLAFTERTX)
-				priv->stats.collisions ++;
-			if (nop.nop_status & STAT_NOCARRIER)
-				priv->stats.tx_carrier_errors ++;
-			if (nop.nop_status & STAT_TXLOSTCTS)
-				printk (KERN_WARNING "%s: cts lost\n", dev->name);
-			if (nop.nop_status & STAT_TXSLOWDMA)
-				priv->stats.tx_fifo_errors ++;
-			if (nop.nop_status & STAT_COLLEXCESSIVE)
-				priv->stats.collisions += 16;
-		}
-
-		if (nop.nop_link == caddr) {
-			printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);
-			break;
-		}
-
-		caddr = nop.nop_link;
-		ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
-		if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
-			printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);
-			break;
-		}
-
-		if (caddr == nop.nop_link)
-			break;
-
-		caddr = nop.nop_link;
-		ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
-		if ((nop.nop_command & CMD_MASK) != CMD_TX) {
-			printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);
-			break;
-		}
-	}
-	priv->tx_tail = caddr;
-
-	caddr = priv->tx_head;
-	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
-	priv->tx_head = caddr;
-	if (tst != -1)
-		netif_wake_queue(dev);
-}
-
-static void
-ether1_recv_done (struct net_device *dev)
-{
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-	int status;
-	int nexttail, rbdaddr;
-	rbd_t rbd;
-
-	do {
-		status = ether1_inw (dev, priv->rx_head, rfd_t, rfd_status, NORMALIRQS);
-		if ((status & RFD_COMPLETE) == 0)
-			break;
-
-		rbdaddr = ether1_inw (dev, priv->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
-		ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
-
-		if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
-			int length = rbd.rbd_status & RBD_ACNT;
-			struct sk_buff *skb;
-
-			length = (length + 1) & ~1;
-			skb = dev_alloc_skb (length + 2);
-
-			if (skb) {
-				skb->dev = dev;
-				skb_reserve (skb, 2);
-
-				ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
-
-				skb->protocol = eth_type_trans (skb, dev);
-				netif_rx (skb);
-				priv->stats.rx_packets ++;
-			} else
-				priv->stats.rx_dropped ++;
-		} else {
-			printk(KERN_WARNING "%s: %s\n", dev->name,
-				(rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
-			priv->stats.rx_dropped ++;
-		}
-
-		nexttail = ether1_inw (dev, priv->rx_tail, rfd_t, rfd_link, NORMALIRQS);
-		/* nexttail should be rx_head */
-		if (nexttail != priv->rx_head)
-			printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
-				dev->name, nexttail, priv->rx_head);
-		ether1_outw (dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
-		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_command, NORMALIRQS);
-		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_status, NORMALIRQS);
-		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
-	
-		priv->rx_tail = nexttail;
-		priv->rx_head = ether1_inw (dev, priv->rx_head, rfd_t, rfd_link, NORMALIRQS);
-	} while (1);
-}
-
-static void
-ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-	int status;
-
-	status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
-
-	if (status) {
-		ether1_outw(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
-			    SCB_ADDR, scb_t, scb_command, NORMALIRQS);
-		outb (CTRL_CA | CTRL_ACK, REG_CONTROL);
-		if (status & SCB_STCX) {
-			ether1_xmit_done (dev);
-		}
-		if (status & SCB_STCNA) {
-			if (priv->resetting == 0)
-				printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
-			else
-				priv->resetting += 1;
-			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
-					!= (unsigned short)I82586_NULL) {
-				ether1_outw (dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
-				outb (CTRL_CA, REG_CONTROL);
-			}
-			if (priv->resetting == 2)
-				priv->resetting = 0;
-		}
-		if (status & SCB_STFR) {
-			ether1_recv_done (dev);
-		}
-		if (status & SCB_STRNR) {
-			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
-				printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
-				ether1_outw (dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
-				outb (CTRL_CA, REG_CONTROL);
-				priv->stats.rx_dropped ++;	/* we suspended due to lack of buffer space */
-			} else
-				printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
-					ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
-			printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset,
-						NORMALIRQS));
-		}
-	} else
-	        outb (CTRL_ACK, REG_CONTROL);
-}
-
-static int
-ether1_close (struct net_device *dev)
-{
-	ether1_reset (dev);
-
-	free_irq(dev->irq, dev);
-
-	return 0;
-}
-
-static struct net_device_stats *
-ether1_getstats (struct net_device *dev)
-{
-	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
-	return &priv->stats;
-}
-
-/*
- * Set or clear the multicast filter for this adaptor.
- * 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.
- */
-static void
-ether1_setmulticastlist (struct net_device *dev)
-{
-}
-
-/* ------------------------------------------------------------------------- */
-
-static void __init ether1_banner(void)
-{
-	static unsigned int version_printed = 0;
-
-	if (net_debug && version_printed++ == 0)
-		printk(KERN_INFO "%s", version);
-}
-
-static int __devinit
-ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct net_device *dev;
-	struct ether1_priv *priv;
-	int i, ret = 0;
-
-	ether1_banner();
-
-	dev = init_etherdev(NULL, sizeof(struct ether1_priv));
-	if (!dev) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	SET_MODULE_OWNER(dev);
-
-	dev->base_addr	= ecard_address(ec, ECARD_IOC, ECARD_FAST);
-	dev->irq	= ec->irq;
-
-	/*
-	 * these will not fail - the nature of the bus ensures this
-	 */
-	request_region(dev->base_addr, 16, dev->name);
-	request_region(dev->base_addr + 0x800, 4096, dev->name);
-
-	priv = (struct ether1_priv *)dev->priv;
-	if ((priv->bus_type = ether1_reset(dev)) == 0) {
-		ret = -ENODEV;
-		goto release;
-	}
-
-	printk(KERN_INFO "%s: ether1 in slot %d, ",
-		dev->name, ec->slot_no);
-    
-	for (i = 0; i < 6; i++) {
-		dev->dev_addr[i] = inb(IDPROM_ADDRESS + i);
-		printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-	}
-
-	if (ether1_init_2(dev)) {
-		ret = -ENODEV;
-		goto release;
-	}
-
-	dev->open		= ether1_open;
-	dev->stop		= ether1_close;
-	dev->hard_start_xmit    = ether1_sendpacket;
-	dev->get_stats		= ether1_getstats;
-	dev->set_multicast_list = ether1_setmulticastlist;
-	dev->tx_timeout		= ether1_timeout;
-	dev->watchdog_timeo	= 5 * HZ / 100;
-
-	ecard_set_drvdata(ec, dev);
-	return 0;
-
-release:
-	release_region(dev->base_addr, 16);
-	release_region(dev->base_addr + 0x800, 4096);
-	unregister_netdev(dev);
-	kfree(dev);
-out:
-	return ret;
-}
-
-static void __devexit ether1_remove(struct expansion_card *ec)
-{
-	struct net_device *dev = ecard_get_drvdata(ec);
-
-	ecard_set_drvdata(ec, NULL);	
-
-	unregister_netdev(dev);
-
-	release_region(dev->base_addr, 16);
-	release_region(dev->base_addr + 0x800, 4096);
-	kfree(dev);
-}
-
-static const struct ecard_id ether1_ids[] = {
-	{ MANU_ACORN, PROD_ACORN_ETHER1 },
-	{ 0xffff, 0xffff }
-};
-
-static struct ecard_driver ether1_driver = {
-	.probe		= ether1_probe,
-	.remove		= __devexit_p(ether1_remove),
-	.id_table	= ether1_ids,
-	.drv = {
-		.name	= "ether1",
-	},
-};
-
-static int __init ether1_init(void)
-{
-	return ecard_register_driver(&ether1_driver);
-}
-
-static void __exit ether1_exit(void)
-{
-	ecard_remove_driver(&ether1_driver);
-}
-
-module_init(ether1_init);
-module_exit(ether1_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/acorn/net/ether1.h b/drivers/acorn/net/ether1.h
--- a/drivers/acorn/net/ether1.h	Tue Feb  5 09:40:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,278 +0,0 @@
-/*
- *  linux/drivers/acorn/net/ether1.h
- *
- *  Copyright (C) 1996 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.
- *
- *  Network driver for Acorn Ether1 cards.
- */
-
-#ifndef _LINUX_ether1_H
-#define _LINUX_ether1_H
-
-#ifdef __ETHER1_C
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 0
-#endif
-
-/* Page register */
-#define REG_PAGE	(dev->base_addr + 0x00)
-
-/* Control register */
-#define REG_CONTROL	(dev->base_addr + 0x01)
-#define CTRL_RST	0x01
-#define CTRL_LOOPBACK	0x02
-#define CTRL_CA		0x04
-#define CTRL_ACK	0x08
-
-#define ETHER1_RAM	(dev->base_addr + 0x800)
-
-/* HW address */
-#define IDPROM_ADDRESS	(dev->base_addr + 0x09)
-
-struct ether1_priv {
-	struct net_device_stats stats;
-	unsigned int tx_link;
-	unsigned int tx_head;
-	volatile unsigned int tx_tail;
-	volatile unsigned int rx_head;
-	volatile unsigned int rx_tail;
-	unsigned char bus_type;
-	unsigned char resetting;
-	unsigned char initialising : 1;
-	unsigned char restart      : 1;
-};
-
-#define I82586_NULL (-1)
-
-typedef struct { /* tdr */
-	unsigned short tdr_status;
-	unsigned short tdr_command;
-	unsigned short tdr_link;
-	unsigned short tdr_result;
-#define TDR_TIME	(0x7ff)
-#define TDR_SHORT	(1 << 12)
-#define TDR_OPEN	(1 << 13)
-#define TDR_XCVRPROB	(1 << 14)
-#define TDR_LNKOK	(1 << 15)
-} tdr_t;
-
-typedef struct { /* transmit */
-	unsigned short tx_status;
-	unsigned short tx_command;
-	unsigned short tx_link;
-	unsigned short tx_tbdoffset;
-} tx_t;
-
-typedef struct { /* tbd */
-	unsigned short tbd_opts;
-#define TBD_CNT		(0x3fff)
-#define TBD_EOL		(1 << 15)
-	unsigned short tbd_link;
-	unsigned short tbd_bufl;
-	unsigned short tbd_bufh;
-} tbd_t;
-
-typedef struct { /* rfd */
-	unsigned short rfd_status;
-#define RFD_NOEOF	(1 << 6)
-#define RFD_FRAMESHORT	(1 << 7)
-#define RFD_DMAOVRN	(1 << 8)
-#define RFD_NORESOURCES	(1 << 9)
-#define RFD_ALIGNERROR	(1 << 10)
-#define RFD_CRCERROR	(1 << 11)
-#define RFD_OK		(1 << 13)
-#define RFD_FDCONSUMED	(1 << 14)
-#define RFD_COMPLETE	(1 << 15)
-	unsigned short rfd_command;
-#define RFD_CMDSUSPEND	(1 << 14)
-#define RFD_CMDEL	(1 << 15)
-	unsigned short rfd_link;
-	unsigned short rfd_rbdoffset;
-	unsigned char  rfd_dest[6];
-	unsigned char  rfd_src[6];
-	unsigned short rfd_len;
-} rfd_t;
-
-typedef struct { /* rbd */
-	unsigned short rbd_status;
-#define RBD_ACNT	(0x3fff)
-#define RBD_ACNTVALID	(1 << 14)
-#define RBD_EOF		(1 << 15)
-	unsigned short rbd_link;
-	unsigned short rbd_bufl;
-	unsigned short rbd_bufh;
-	unsigned short rbd_len;
-} rbd_t;
-
-typedef struct { /* nop */
-	unsigned short nop_status;
-	unsigned short nop_command;
-	unsigned short nop_link;
-} nop_t;
-
-typedef struct { /* set multicast */
-	unsigned short mc_status;
-	unsigned short mc_command;
-	unsigned short mc_link;
-	unsigned short mc_cnt;
-	unsigned char  mc_addrs[1][6];
-} mc_t;
-
-typedef struct { /* set address */
-	unsigned short sa_status;
-	unsigned short sa_command;
-	unsigned short sa_link;
-	unsigned char  sa_addr[6];
-} sa_t;
-
-typedef struct { /* config command */
-	unsigned short cfg_status;
-	unsigned short cfg_command;
-	unsigned short cfg_link;
-	unsigned char  cfg_bytecnt;	/* size foll data: 4 - 12		 */
-	unsigned char  cfg_fifolim;	/* FIFO threshold			 */
-	unsigned char  cfg_byte8;
-#define CFG8_SRDY	(1 << 6)
-#define CFG8_SAVEBADF	(1 << 7)
-	unsigned char  cfg_byte9;
-#define CFG9_ADDRLEN(x)	(x)
-#define CFG9_ADDRLENBUF	(1 << 3)
-#define CFG9_PREAMB2	(0 << 4)
-#define CFG9_PREAMB4	(1 << 4)
-#define CFG9_PREAMB8	(2 << 4)
-#define CFG9_PREAMB16	(3 << 4)
-#define CFG9_ILOOPBACK	(1 << 6)
-#define CFG9_ELOOPBACK	(1 << 7)
-	unsigned char  cfg_byte10;
-#define CFG10_LINPRI(x)	(x)
-#define CFG10_ACR(x)	(x << 4)
-#define CFG10_BOFMET	(1 << 7)
-	unsigned char  cfg_ifs;
-	unsigned char  cfg_slotl;
-	unsigned char  cfg_byte13;
-#define CFG13_SLOTH(x)	(x)
-#define CFG13_RETRY(x)	(x << 4)
-	unsigned char  cfg_byte14;
-#define CFG14_PROMISC	(1 << 0)
-#define CFG14_DISBRD	(1 << 1)
-#define CFG14_MANCH	(1 << 2)
-#define CFG14_TNCRS	(1 << 3)
-#define CFG14_NOCRC	(1 << 4)
-#define CFG14_CRC16	(1 << 5)
-#define CFG14_BTSTF	(1 << 6)
-#define CFG14_FLGPAD	(1 << 7)
-	unsigned char  cfg_byte15;
-#define CFG15_CSTF(x)	(x)
-#define CFG15_ICSS	(1 << 3)
-#define CFG15_CDTF(x)	(x << 4)
-#define CFG15_ICDS	(1 << 7)
-	unsigned short cfg_minfrmlen;
-} cfg_t;
-
-typedef struct { /* scb */
-	unsigned short scb_status;	/* status of 82586			*/
-#define SCB_STRXMASK		(7 << 4)	/* Receive unit status		*/
-#define SCB_STRXIDLE		(0 << 4)	/* Idle				*/
-#define SCB_STRXSUSP		(1 << 4)	/* Suspended			*/
-#define SCB_STRXNRES		(2 << 4)	/* No resources			*/
-#define SCB_STRXRDY		(4 << 4)	/* Ready			*/
-#define SCB_STCUMASK		(7 << 8)	/* Command unit status		*/
-#define SCB_STCUIDLE		(0 << 8)	/* Idle				*/
-#define SCB_STCUSUSP		(1 << 8)	/* Suspended			*/
-#define SCB_STCUACTV		(2 << 8)	/* Active			*/
-#define SCB_STRNR		(1 << 12)	/* Receive unit not ready	*/
-#define SCB_STCNA		(1 << 13)	/* Command unit not ready	*/
-#define SCB_STFR		(1 << 14)	/* Frame received		*/
-#define SCB_STCX		(1 << 15)	/* Command completed		*/
-	unsigned short scb_command;	/* Next command				*/
-#define SCB_CMDRXSTART		(1 << 4)	/* Start (at rfa_offset)	*/
-#define SCB_CMDRXRESUME		(2 << 4)	/* Resume reception		*/
-#define SCB_CMDRXSUSPEND	(3 << 4)	/* Suspend reception		*/
-#define SCB_CMDRXABORT		(4 << 4)	/* Abort reception		*/
-#define SCB_CMDCUCSTART		(1 << 8)	/* Start (at cbl_offset)	*/
-#define SCB_CMDCUCRESUME	(2 << 8)	/* Resume execution		*/
-#define SCB_CMDCUCSUSPEND	(3 << 8)	/* Suspend execution		*/
-#define SCB_CMDCUCABORT		(4 << 8)	/* Abort execution		*/
-#define SCB_CMDACKRNR		(1 << 12)	/* Ack RU not ready		*/
-#define SCB_CMDACKCNA		(1 << 13)	/* Ack CU not ready		*/
-#define SCB_CMDACKFR		(1 << 14)	/* Ack Frame received		*/
-#define SCB_CMDACKCX		(1 << 15)	/* Ack Command complete		*/
-	unsigned short scb_cbl_offset;	/* Offset of first command unit		*/
-	unsigned short scb_rfa_offset;	/* Offset of first receive frame area	*/
-	unsigned short scb_crc_errors;	/* Properly aligned frame with CRC error*/
-	unsigned short scb_aln_errors;	/* Misaligned frames			*/
-	unsigned short scb_rsc_errors;	/* Frames lost due to no space		*/
-	unsigned short scb_ovn_errors;	/* Frames lost due to slow bus		*/
-} scb_t;
-
-typedef struct { /* iscp */
-	unsigned short iscp_busy;	/* set by CPU before CA			*/
-	unsigned short iscp_offset;	/* offset of SCB			*/
-	unsigned short iscp_basel;	/* base of SCB				*/
-	unsigned short iscp_baseh;
-} iscp_t;
-
-    /* this address must be 0xfff6 */
-typedef struct { /* scp */
-	unsigned short scp_sysbus;	/* bus size */
-#define SCP_SY_16BBUS	0x00
-#define SCP_SY_8BBUS	0x01
-	unsigned short scp_junk[2];	/* junk */
-	unsigned short scp_iscpl;	/* lower 16 bits of iscp */
-	unsigned short scp_iscph;	/* upper 16 bits of iscp */
-} scp_t;
-
-/* commands */
-#define CMD_NOP			0
-#define CMD_SETADDRESS		1
-#define CMD_CONFIG		2
-#define CMD_SETMULTICAST	3
-#define CMD_TX			4
-#define CMD_TDR			5
-#define CMD_DUMP		6
-#define CMD_DIAGNOSE		7
-
-#define CMD_MASK		7
-
-#define CMD_INTR		(1 << 13)
-#define CMD_SUSP		(1 << 14)
-#define CMD_EOL			(1 << 15)
-
-#define STAT_COLLISIONS		(15)
-#define STAT_COLLEXCESSIVE	(1 << 5)
-#define STAT_COLLAFTERTX	(1 << 6)
-#define STAT_TXDEFERRED		(1 << 7)
-#define STAT_TXSLOWDMA		(1 << 8)
-#define STAT_TXLOSTCTS		(1 << 9)
-#define STAT_NOCARRIER		(1 << 10)
-#define STAT_FAIL		(1 << 11)
-#define STAT_ABORTED		(1 << 12)
-#define STAT_OK			(1 << 13)
-#define STAT_BUSY		(1 << 14)
-#define STAT_COMPLETE		(1 << 15)
-#endif
-#endif
-
-/*
- * Ether1 card definitions:
- *
- * FAST accesses:
- *	+0	Page register
- * 			16 pages
- *	+4	Control
- *			'1' = reset
- *			'2' = loopback
- *			'4' = CA
- *			'8' = int ack
- *
- * RAM at address + 0x2000
- * Pod. Prod id = 3
- * Words after ID block [base + 8 words]
- *	+0 pcb issue (0x0c and 0xf3 invalid)
- *	+1 - +6 eth hw address
- */
diff -Nru a/drivers/acorn/net/ether3.c b/drivers/acorn/net/ether3.c
--- a/drivers/acorn/net/ether3.c	Thu Mar  6 05:00:32 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,944 +0,0 @@
-/*
- *  linux/drivers/acorn/net/ether3.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.
- *
- * SEEQ nq8005 ethernet driver for Acorn/ANT Ether3 card
- *  for Acorn machines
- *
- * By Russell King, with some suggestions from borris@ant.co.uk
- *
- * Changelog:
- * 1.04	RMK	29/02/1996	Won't pass packets that are from our ethernet
- *				address up to the higher levels - they're
- *				silently ignored.  I/F can now be put into
- *				multicast mode.  Receiver routine optimised.
- * 1.05	RMK	30/02/1996	Now claims interrupt at open when part of
- *				the kernel rather than when a module.
- * 1.06	RMK	02/03/1996	Various code cleanups
- * 1.07	RMK	13/10/1996	Optimised interrupt routine and transmit
- *				routines.
- * 1.08	RMK	14/10/1996	Fixed problem with too many packets,
- *				prevented the kernel message about dropped
- *				packets appearing too many times a second.
- *				Now does not disable all IRQs, only the IRQ
- *				used by this card.
- * 1.09	RMK	10/11/1996	Only enables TX irq when buffer space is low,
- *				but we still service the TX queue if we get a
- *				RX interrupt.
- * 1.10	RMK	15/07/1997	Fixed autoprobing of NQ8004.
- * 1.11	RMK	16/11/1997	Fixed autoprobing of NQ8005A.
- * 1.12	RMK	31/12/1997	Removed reference to dev_tint for Linux 2.1.
- *      RMK	27/06/1998	Changed asm/delay.h to linux/delay.h.
- * 1.13	RMK	29/06/1998	Fixed problem with transmission of packets.
- *				Chip seems to have a bug in, whereby if the
- *				packet starts two bytes from the end of the
- *				buffer, it corrupts the receiver chain, and
- *				never updates the transmit status correctly.
- * 1.14	RMK	07/01/1998	Added initial code for ETHERB addressing.
- * 1.15	RMK	30/04/1999	More fixes to the transmit routine for buggy
- *				hardware.
- * 1.16	RMK	10/02/2000	Updated for 2.3.43
- * 1.17	RMK	13/05/2000	Updated for 2.3.99-pre8
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/device.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/ecard.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
-
-#include "ether3.h"
-
-static unsigned int net_debug = NET_DEBUG;
-
-static void	ether3_setmulticastlist(struct net_device *dev);
-static int	ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
-static void	ether3_tx(struct net_device *dev, struct dev_priv *priv);
-static int	ether3_open (struct net_device *dev);
-static int	ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
-static void	ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-static int	ether3_close (struct net_device *dev);
-static struct net_device_stats *ether3_getstats (struct net_device *dev);
-static void	ether3_setmulticastlist (struct net_device *dev);
-static void	ether3_timeout(struct net_device *dev);
-
-#define BUS_16		2
-#define BUS_8		1
-#define BUS_UNKNOWN	0
-
-/* --------------------------------------------------------------------------- */
-
-typedef enum {
-	buffer_write,
-	buffer_read
-} buffer_rw_t;
-
-/*
- * ether3 read/write.  Slow things down a bit...
- * The SEEQ8005 doesn't like us writing to its registers
- * too quickly.
- */
-static inline void ether3_outb(int v, const int r)
-{
-	outb(v, r);
-	udelay(1);
-}
-
-static inline void ether3_outw(int v, const int r)
-{
-	outw(v, r);
-	udelay(1);
-}
-#define ether3_inb(r)		({ unsigned int __v = inb((r)); udelay(1); __v; })
-#define ether3_inw(r)		({ unsigned int __v = inw((r)); udelay(1); __v; })
-
-static int
-ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	int timeout = 1000;
-
-	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
-	ether3_outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
-
-	while ((ether3_inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) {
-		if (!timeout--) {
-			printk("%s: setbuffer broken\n", dev->name);
-			priv->broken = 1;
-			return 1;
-		}
-		udelay(1);
-	}
-
-	if (read == buffer_read) {
-		ether3_outw(start, REG_DMAADDR);
-		ether3_outw(priv->regs.command | CMD_FIFOREAD, REG_COMMAND);
-	} else {
-		ether3_outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
-		ether3_outw(start, REG_DMAADDR);
-	}
-	return 0;
-}
-
-/*
- * write data to the buffer memory
- */
-#define ether3_writebuffer(dev,data,length)			\
-	outsw(REG_BUFWIN, (data), (length) >> 1)
-
-#define ether3_writeword(dev,data)				\
-	outw((data), REG_BUFWIN)
-
-#define ether3_writelong(dev,data)	{			\
-	unsigned long reg_bufwin = REG_BUFWIN;			\
-	outw((data), reg_bufwin);				\
-	outw((data) >> 16, reg_bufwin);				\
-}
-
-/*
- * read data from the buffer memory
- */
-#define ether3_readbuffer(dev,data,length)			\
-	insw(REG_BUFWIN, (data), (length) >> 1)
-
-#define ether3_readword(dev)					\
-	inw(REG_BUFWIN)
-
-#define ether3_readlong(dev)	 				\
-	inw(REG_BUFWIN) | (inw(REG_BUFWIN) << 16)
-
-/*
- * Switch LED off...
- */
-static void
-ether3_ledoff(unsigned long data)
-{
-	struct net_device *dev = (struct net_device *)data;
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	ether3_outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2);
-}
-
-/*
- * switch LED on...
- */
-static inline void
-ether3_ledon(struct net_device *dev, struct dev_priv *priv)
-{
-	del_timer(&priv->timer);
-	priv->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */
-	priv->timer.data = (unsigned long)dev;
-	priv->timer.function = ether3_ledoff;
-	add_timer(&priv->timer);
-	if (priv->regs.config2 & CFG2_CTRLO)
-		ether3_outw(priv->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2);
-}
-
-/*
- * Read the ethernet address string from the on board rom.
- * This is an ascii string!!!
- */
-static int __init
-ether3_addr(char *addr, struct expansion_card *ec)
-{
-	struct in_chunk_dir cd;
-	char *s;
-	
-	if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
-		int i;
-		for (i = 0; i<6; i++) {
-			addr[i] = simple_strtoul(s + 1, &s, 0x10);
-			if (*s != (i==5?')' : ':' ))
-				break;
-		}
-		if (i == 6)
-			return 0;
-	}
-	/* I wonder if we should even let the user continue in this case
-	 *   - no, it would be better to disable the device
-	 */
-	printk(KERN_ERR "ether3: Couldn't read a valid MAC address from card.\n");
-	return -ENODEV;
-}
-
-/* --------------------------------------------------------------------------- */
-
-static int __init
-ether3_ramtest(struct net_device *dev, unsigned char byte)
-{
-	unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL);
-	int i,ret = 0;
-	int max_errors = 4;
-	int bad = -1;
-
-	if (!buffer)
-		return 1;
-
-	memset(buffer, byte, RX_END);
-	ether3_setbuffer(dev, buffer_write, 0);
-	ether3_writebuffer(dev, buffer, TX_END);
-	ether3_setbuffer(dev, buffer_write, RX_START);
-	ether3_writebuffer(dev, buffer + RX_START, RX_LEN);
-	memset(buffer, byte ^ 0xff, RX_END);
-	ether3_setbuffer(dev, buffer_read, 0);
-	ether3_readbuffer(dev, buffer, TX_END);
-	ether3_setbuffer(dev, buffer_read, RX_START);
-	ether3_readbuffer(dev, buffer + RX_START, RX_LEN);
-
-	for (i = 0; i < RX_END; i++) {
-		if (buffer[i] != byte) {
-			if (max_errors > 0 && bad != buffer[i]) {
-				printk("%s: RAM failed with (%02X instead of %02X) at 0x%04X",
-				       dev->name, buffer[i], byte, i);
-				ret = 2;
-				max_errors--;
-				bad = i;
-			}
-		} else {
-			if (bad != -1) {
-				if (bad != i - 1)
-					printk(" - 0x%04X\n", i - 1);
-				printk("\n");
-				bad = -1;
-			}
-		}
-	}
-	if (bad != -1)
-		printk(" - 0xffff\n");
-	kfree(buffer);
-
-	return ret;
-}
-
-/* ------------------------------------------------------------------------------- */
-
-static int __init
-ether3_init_2(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	int i;
-
-	priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
-	priv->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC;
-	priv->regs.command = 0;
-
-	/*
-	 * Set up our hardware address
-	 */
-	ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
-	for (i = 0; i < 6; i++)
-		ether3_outb(dev->dev_addr[i], REG_BUFWIN);
-
-	if (dev->flags & IFF_PROMISC)
-		priv->regs.config1 |= CFG1_RECVPROMISC;
-	else if (dev->flags & IFF_MULTICAST)
-		priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
-	else
-		priv->regs.config1 |= CFG1_RECVSPECBROAD;
-
-	/*
-	 * There is a problem with the NQ8005 in that it occasionally loses the
-	 * last two bytes.  To get round this problem, we receive the CRC as
-	 * well.  That way, if we do lose the last two, then it doesn't matter.
-	 */
-	ether3_outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
-	ether3_outw((TX_END>>8) - 1, REG_BUFWIN);
-	ether3_outw(priv->rx_head, REG_RECVPTR);
-	ether3_outw(0, REG_TRANSMITPTR);
-	ether3_outw(priv->rx_head >> 8, REG_RECVEND);
-	ether3_outw(priv->regs.config2, REG_CONFIG2);
-	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
-	ether3_outw(priv->regs.command, REG_COMMAND);
-
-	i = ether3_ramtest(dev, 0x5A);
-	if(i)
-		return i;
-	i = ether3_ramtest(dev, 0x1E);
-	if(i)
-		return i;
-
-	ether3_setbuffer(dev, buffer_write, 0);
-	ether3_writelong(dev, 0);
-	return 0;
-}
-
-static void
-ether3_init_for_open(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	int i;
-
-	memset(&priv->stats, 0, sizeof(struct net_device_stats));
-
-	/* Reset the chip */
-	ether3_outw(CFG2_RESET, REG_CONFIG2);
-	udelay(4);
-
-	priv->regs.command = 0;
-	ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
-	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
-
-	ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
-	for (i = 0; i < 6; i++)
-		ether3_outb(dev->dev_addr[i], REG_BUFWIN);
-
-	priv->tx_head	= 0;
-	priv->tx_tail	= 0;
-	priv->regs.config2 |= CFG2_CTRLO;
-	priv->rx_head	= RX_START;
-
-	ether3_outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
-	ether3_outw((TX_END>>8) - 1, REG_BUFWIN);
-	ether3_outw(priv->rx_head, REG_RECVPTR);
-	ether3_outw(priv->rx_head >> 8, REG_RECVEND);
-	ether3_outw(0, REG_TRANSMITPTR);
-	ether3_outw(priv->regs.config2, REG_CONFIG2);
-	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
-
-	ether3_setbuffer(dev, buffer_write, 0);
-	ether3_writelong(dev, 0);
-
-	priv->regs.command = CMD_ENINTRX | CMD_ENINTTX;
-	ether3_outw(priv->regs.command | CMD_RXON, REG_COMMAND);
-}
-
-static inline int
-ether3_probe_bus_8(struct net_device *dev, int val)
-{
-	int write_low, write_high, read_low, read_high;
-
-	write_low = val & 255;
-	write_high = val >> 8;
-
-	printk(KERN_DEBUG "ether3_probe: write8 [%02X:%02X]", write_high, write_low);
-
-	ether3_outb(write_low, REG_RECVPTR);
-	ether3_outb(write_high, REG_RECVPTR + 1);
-
-	read_low = ether3_inb(REG_RECVPTR);
-	read_high = ether3_inb(REG_RECVPTR + 1);
-
-	printk(", read8 [%02X:%02X]\n", read_high, read_low);
-
-	return read_low == write_low && read_high == write_high;
-}
-
-static inline int
-ether3_probe_bus_16(struct net_device *dev, int val)
-{
-	int read_val;
-
-	ether3_outw(val, REG_RECVPTR);
-	read_val = ether3_inw(REG_RECVPTR);
-
-	printk(KERN_DEBUG "ether3_probe: write16 [%04X], read16 [%04X]\n", val, read_val);
-
-	return read_val == val;
-}
-
-/*
- * Open/initialize the board.  This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
- */
-static int
-ether3_open(struct net_device *dev)
-{
-	if (!is_valid_ether_addr(dev->dev_addr)) {
-		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
-			dev->name);
-		return -EINVAL;
-	}
-
-	if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev))
-		return -EAGAIN;
-
-	ether3_init_for_open(dev);
-
-	netif_start_queue(dev);
-
-	return 0;
-}
-
-/*
- * The inverse routine to ether3_open().
- */
-static int
-ether3_close(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-
-	netif_stop_queue(dev);
-
-	disable_irq(dev->irq);
-
-	ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
-	priv->regs.command = 0;
-	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
-	ether3_outb(0x80, REG_CONFIG2 + 1);
-	ether3_outw(0, REG_COMMAND);
-
-	free_irq(dev->irq, dev);
-
-	return 0;
-}
-
-/*
- * Get the current statistics.	This may be called with the card open or
- * closed.
- */
-static struct net_device_stats *ether3_getstats(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	return &priv->stats;
-}
-
-/*
- * Set or clear promiscuous/multicast mode filter for this adaptor.
- *
- * We don't attempt any packet filtering.  The card may have a SEEQ 8004
- * in which does not have the other ethernet address registers present...
- */
-static void ether3_setmulticastlist(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-
-	priv->regs.config1 &= ~CFG1_RECVPROMISC;
-
-	if (dev->flags & IFF_PROMISC) {
-		/* promiscuous mode */
-		priv->regs.config1 |= CFG1_RECVPROMISC;
-	} else if (dev->flags & IFF_ALLMULTI) {
-		priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
-	} else
-		priv->regs.config1 |= CFG1_RECVSPECBROAD;
-
-	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
-}
-
-static void
-ether3_timeout(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	unsigned long flags;
-
-	del_timer(&priv->timer);
-
-	local_irq_save(flags);
-	printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name);
-	printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name,
-		ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
-	printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
-		ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
-	printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
-		priv->tx_head, priv->tx_tail);
-	ether3_setbuffer(dev, buffer_read, priv->tx_tail);
-	printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
-	local_irq_restore(flags);
-
-	priv->regs.config2 |= CFG2_CTRLO;
-	priv->stats.tx_errors += 1;
-	ether3_outw(priv->regs.config2, REG_CONFIG2);
-	priv->tx_head = priv->tx_tail = 0;
-
-	netif_wake_queue(dev);
-}
-
-/*
- * Transmit a packet
- */
-static int
-ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	unsigned long flags;
-	unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
-	unsigned int ptr, next_ptr;
-
-	length = (length + 1) & ~1;
-
-	if (priv->broken) {
-		dev_kfree_skb(skb);
-		priv->stats.tx_dropped ++;
-		netif_start_queue(dev);
-		return 0;
-	}
-
-	next_ptr = (priv->tx_head + 1) & 15;
-
-	local_irq_save(flags);
-
-	if (priv->tx_tail == next_ptr) {
-		local_irq_restore(flags);
-		return 1;	/* unable to queue */
-	}
-
-	dev->trans_start = jiffies;
-	ptr		 = 0x600 * priv->tx_head;
-	priv->tx_head	 = next_ptr;
-	next_ptr	*= 0x600;
-
-#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
-
-	ether3_setbuffer(dev, buffer_write, next_ptr);
-	ether3_writelong(dev, 0);
-	ether3_setbuffer(dev, buffer_write, ptr);
-	ether3_writelong(dev, 0);
-	ether3_writebuffer(dev, skb->data, length);
-	ether3_writeword(dev, htons(next_ptr));
-	ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16);
-	ether3_setbuffer(dev, buffer_write, ptr);
-	ether3_writeword(dev, htons((ptr + length + 4)));
-	ether3_writeword(dev, TXHDR_FLAGS >> 16);
-	ether3_ledon(dev, priv);
-
-	if (!(ether3_inw(REG_STATUS) & STAT_TXON)) {
-		ether3_outw(ptr, REG_TRANSMITPTR);
-		ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
-	}
-
-	next_ptr = (priv->tx_head + 1) & 15;
-	local_irq_restore(flags);
-
-	dev_kfree_skb(skb);
-
-	if (priv->tx_tail == next_ptr)
-		netif_stop_queue(dev);
-
-	return 0;
-}
-
-static void
-ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	struct dev_priv *priv;
-	unsigned int status;
-
-#if NET_DEBUG > 1
-	if(net_debug & DEBUG_INT)
-		printk("eth3irq: %d ", irq);
-#endif
-
-	priv = (struct dev_priv *)dev->priv;
-
-	status = ether3_inw(REG_STATUS);
-
-	if (status & STAT_INTRX) {
-		ether3_outw(CMD_ACKINTRX | priv->regs.command, REG_COMMAND);
-		ether3_rx(dev, priv, 12);
-	}
-
-	if (status & STAT_INTTX) {
-		ether3_outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND);
-		ether3_tx(dev, priv);
-	}
-
-#if NET_DEBUG > 1
-	if(net_debug & DEBUG_INT)
-		printk("done\n");
-#endif
-}
-
-/*
- * If we have a good packet(s), get it/them out of the buffers.
- */
-static int
-ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt)
-{
-	unsigned int next_ptr = priv->rx_head, received = 0;
-	ether3_ledon(dev, priv);
-
-	do {
-		unsigned int this_ptr, status;
-		unsigned char addrs[16];
-
-		/*
-		 * read the first 16 bytes from the buffer.
-		 * This contains the status bytes etc and ethernet addresses,
-		 * and we also check the source ethernet address to see if
-		 * it originated from us.
-		 */
-		{
-			unsigned int temp_ptr;
-			ether3_setbuffer(dev, buffer_read, next_ptr);
-			temp_ptr = ether3_readword(dev);
-			status = ether3_readword(dev);
-			if ((status & (RXSTAT_DONE | RXHDR_CHAINCONTINUE | RXHDR_RECEIVE)) !=
-				(RXSTAT_DONE | RXHDR_CHAINCONTINUE) || !temp_ptr)
-				break;
-
-			this_ptr = next_ptr + 4;
-			next_ptr = ntohs(temp_ptr);
-		}
-		ether3_setbuffer(dev, buffer_read, this_ptr);
-		ether3_readbuffer(dev, addrs+2, 12);
-
-if (next_ptr < RX_START || next_ptr >= RX_END) {
- int i;
- printk("%s: bad next pointer @%04X: ", dev->name, priv->rx_head);
- printk("%02X %02X %02X %02X ", next_ptr >> 8, next_ptr & 255, status & 255, status >> 8);
- for (i = 2; i < 14; i++)
-   printk("%02X ", addrs[i]);
- printk("\n");
- next_ptr = priv->rx_head;
- break;
-}
-		/*
- 		 * ignore our own packets...
-	 	 */
-		if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) &&
-		    !(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) {
-			maxcnt ++; /* compensate for loopedback packet */
-			ether3_outw(next_ptr >> 8, REG_RECVEND);
-		} else
-		if (!(status & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET))) {
-			unsigned int length = next_ptr - this_ptr;
-			struct sk_buff *skb;
-
-			if (next_ptr <= this_ptr)
-				length += RX_END - RX_START;
-
-			skb = dev_alloc_skb(length + 2);
-			if (skb) {
-				unsigned char *buf;
-
-				skb->dev = dev;
-				skb_reserve(skb, 2);
-				buf = skb_put(skb, length);
-				ether3_readbuffer(dev, buf + 12, length - 12);
-				ether3_outw(next_ptr >> 8, REG_RECVEND);
-				*(unsigned short *)(buf + 0)	= *(unsigned short *)(addrs + 2);
-				*(unsigned long *)(buf + 2)	= *(unsigned long *)(addrs + 4);
-				*(unsigned long *)(buf + 6)	= *(unsigned long *)(addrs + 8);
-				*(unsigned short *)(buf + 10)	= *(unsigned short *)(addrs + 12);
-				skb->protocol = eth_type_trans(skb, dev);
-				netif_rx(skb);
-				received ++;
-			} else
-				goto dropping;
-		} else {
-			struct net_device_stats *stats = &priv->stats;
-			ether3_outw(next_ptr >> 8, REG_RECVEND);
-			if (status & RXSTAT_OVERSIZE)	  stats->rx_over_errors ++;
-			if (status & RXSTAT_CRCERROR)	  stats->rx_crc_errors ++;
-			if (status & RXSTAT_DRIBBLEERROR) stats->rx_fifo_errors ++;
-			if (status & RXSTAT_SHORTPACKET)  stats->rx_length_errors ++;
-			stats->rx_errors++;
-		}
-	}
-	while (-- maxcnt);
-
-done:
-	priv->stats.rx_packets += received;
-	priv->rx_head = next_ptr;
-	/*
-	 * If rx went off line, then that means that the buffer may be full.  We
-	 * have dropped at least one packet.
-	 */
-	if (!(ether3_inw(REG_STATUS) & STAT_RXON)) {
-		priv->stats.rx_dropped ++;
-    		ether3_outw(next_ptr, REG_RECVPTR);
-		ether3_outw(priv->regs.command | CMD_RXON, REG_COMMAND);
-	}
-
-	return maxcnt;
-
-dropping:{
-	static unsigned long last_warned;
-
-	ether3_outw(next_ptr >> 8, REG_RECVEND);
-	/*
-	 * Don't print this message too many times...
-	 */
-	if (time_after(jiffies, last_warned + 10 * HZ)) {
-		last_warned = jiffies;
-		printk("%s: memory squeeze, dropping packet.\n", dev->name);
-	}
-	priv->stats.rx_dropped ++;
-	goto done;
-	}
-}
-
-/*
- * Update stats for the transmitted packet(s)
- */
-static void
-ether3_tx(struct net_device *dev, struct dev_priv *priv)
-{
-	unsigned int tx_tail = priv->tx_tail;
-	int max_work = 14;
-
-	do {
-	    	unsigned long status;
-
-    		/*
-	    	 * Read the packet header
-    		 */
-	    	ether3_setbuffer(dev, buffer_read, tx_tail * 0x600);
-    		status = ether3_readlong(dev);
-
-		/*
-		 * Check to see if this packet has been transmitted
-		 */
-		if ((status & (TXSTAT_DONE | TXHDR_TRANSMIT)) !=
-		    (TXSTAT_DONE | TXHDR_TRANSMIT))
-			break;
-
-		/*
-		 * Update errors
-		 */
-		if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS)))
-			priv->stats.tx_packets++;
-		else {
-			priv->stats.tx_errors ++;
-			if (status & TXSTAT_16COLLISIONS) priv->stats.collisions += 16;
-			if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
-		}
-
-		tx_tail = (tx_tail + 1) & 15;
-	} while (--max_work);
-
-	if (priv->tx_tail != tx_tail) {
-		priv->tx_tail = tx_tail;
-		netif_wake_queue(dev);
-	}
-}
-
-static void __init ether3_banner(void)
-{
-	static unsigned version_printed = 0;
-
-	if (net_debug && version_printed++ == 0)
-		printk(KERN_INFO "%s", version);
-}
-
-static const char * __init
-ether3_get_dev(struct net_device *dev, struct expansion_card *ec)
-{
-	const char *name = "ether3";
-
-	dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
-	dev->irq = ec->irq;
-
-	if (ec->cid.manufacturer == MANU_ANT &&
-	    ec->cid.product == PROD_ANT_ETHERB) {
-		dev->base_addr += 0x200;
-		name = "etherb";
-	}
-
-	ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
-	ec->irqmask = 0xf0;
-
-	ether3_addr(dev->dev_addr, ec);
-
-	return name;
-}
-
-static int __devinit
-ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct net_device *dev;
-	struct dev_priv *priv;
-	const char *name;
-	int i, bus_type, ret;
-
-	ether3_banner();
-
-	dev = init_etherdev(NULL, sizeof(struct dev_priv));
-	if (!dev) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	SET_MODULE_OWNER(dev);
-
-	name = ether3_get_dev(dev, ec);
-	if (!name) {
-		ret = -ENODEV;
-		goto free;
-	}
-
-	/*
-	 * this will not fail - the nature of the bus ensures this
-	 */
-	if (!request_region(dev->base_addr, 128, dev->name)) {
-		ret = -EBUSY;
-		goto free;
-	}
-
-	priv = (struct dev_priv *) dev->priv;
-	init_timer(&priv->timer);
-
-	/* Reset card...
-	 */
-	ether3_outb(0x80, REG_CONFIG2 + 1);
-	bus_type = BUS_UNKNOWN;
-	udelay(4);
-
-	/* Test using Receive Pointer (16-bit register) to find out
-	 * how the ether3 is connected to the bus...
-	 */
-	if (ether3_probe_bus_8(dev, 0x100) &&
-	    ether3_probe_bus_8(dev, 0x201))
-		bus_type = BUS_8;
-
-	if (bus_type == BUS_UNKNOWN &&
-	    ether3_probe_bus_16(dev, 0x101) &&
-	    ether3_probe_bus_16(dev, 0x201))
-		bus_type = BUS_16;
-
-	switch (bus_type) {
-	case BUS_UNKNOWN:
-		printk(KERN_ERR "%s: unable to identify bus width\n", dev->name);
-		ret = -ENODEV;
-		goto failed;
-
-	case BUS_8:
-		printk(KERN_ERR "%s: %s found, but is an unsupported "
-			"8-bit card\n", dev->name, name);
-		ret = -ENODEV;
-		goto failed;
-
-	default:
-		break;
-	}
-
-	printk("%s: %s in slot %d, ", dev->name, name, ec->slot_no);
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
-	if (ether3_init_2(dev)) {
-		ret = -ENODEV;
-		goto failed;
-	}
-
-	dev->open		= ether3_open;
-	dev->stop		= ether3_close;
-	dev->hard_start_xmit	= ether3_sendpacket;
-	dev->get_stats		= ether3_getstats;
-	dev->set_multicast_list	= ether3_setmulticastlist;
-	dev->tx_timeout		= ether3_timeout;
-	dev->watchdog_timeo	= 5 * HZ / 100;
-
-	ecard_set_drvdata(ec, dev);
-	return 0;
-
-failed:
-	release_region(dev->base_addr, 128);
-free:
-	unregister_netdev(dev);
-	kfree(dev);
-out:
-	return ret;
-}
-
-static void __devexit ether3_remove(struct expansion_card *ec)
-{
-	struct net_device *dev = ecard_get_drvdata(ec);
-
-	ecard_set_drvdata(ec, NULL);
-
-	unregister_netdev(dev);
-	release_region(dev->base_addr, 128);
-	kfree(dev);
-}
-
-static const struct ecard_id ether3_ids[] = {
-	{ MANU_ANT2, PROD_ANT_ETHER3 },
-	{ MANU_ANT,  PROD_ANT_ETHER3 },
-	{ MANU_ANT,  PROD_ANT_ETHERB },
-	{ 0xffff, 0xffff }
-};
-
-static struct ecard_driver ether3_driver = {
-	.probe		= ether3_probe,
-	.remove		= __devexit_p(ether3_remove),
-	.id_table	= ether3_ids,
-	.drv = {
-		.name	= "ether3",
-	},
-};
-
-static int __init ether3_init(void)
-{
-	return ecard_register_driver(&ether3_driver);
-}
-
-static void __exit ether3_exit(void)
-{
-	ecard_remove_driver(&ether3_driver);
-}
-
-module_init(ether3_init);
-module_exit(ether3_exit);
-
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/acorn/net/ether3.h b/drivers/acorn/net/ether3.h
--- a/drivers/acorn/net/ether3.h	Tue Feb  5 09:40:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,168 +0,0 @@
-/*
- *  linux/drivers/acorn/net/ether3.h
- *
- *  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.
- *
- *  network driver for Acorn/ANT Ether3 cards
- */
-
-#ifndef _LINUX_ether3_H
-#define _LINUX_ether3_H
-
-/* use 0 for production, 1 for verification, >2 for debug. debug flags: */
-#define DEBUG_TX	 2
-#define DEBUG_RX	 4
-#define DEBUG_INT	 8
-#define DEBUG_IC	16
-#ifndef NET_DEBUG
-#define NET_DEBUG 	0
-#endif
-
-/* Command register definitions & bits */
-#define REG_COMMAND		(dev->base_addr + 0x00)
-#define CMD_ENINTDMA		0x0001
-#define CMD_ENINTRX		0x0002
-#define CMD_ENINTTX		0x0004
-#define CMD_ENINTBUFWIN		0x0008
-#define CMD_ACKINTDMA		0x0010
-#define CMD_ACKINTRX		0x0020
-#define CMD_ACKINTTX		0x0040
-#define CMD_ACKINTBUFWIN	0x0080
-#define CMD_DMAON		0x0100
-#define CMD_RXON		0x0200
-#define CMD_TXON		0x0400
-#define CMD_DMAOFF		0x0800
-#define CMD_RXOFF		0x1000
-#define CMD_TXOFF		0x2000
-#define CMD_FIFOREAD		0x4000
-#define CMD_FIFOWRITE		0x8000
-
-/* status register */
-#define REG_STATUS		(dev->base_addr + 0x00)
-#define STAT_ENINTSTAT		0x0001
-#define STAT_ENINTRX		0x0002
-#define STAT_ENINTTX		0x0004
-#define STAT_ENINTBUFWIN	0x0008
-#define STAT_INTDMA		0x0010
-#define STAT_INTRX		0x0020
-#define STAT_INTTX		0x0040
-#define STAT_INTBUFWIN		0x0080
-#define STAT_DMAON		0x0100
-#define STAT_RXON		0x0200
-#define STAT_TXON		0x0400
-#define STAT_FIFOFULL		0x2000
-#define STAT_FIFOEMPTY		0x4000
-#define STAT_FIFODIR		0x8000
-
-/* configuration register 1 */
-#define REG_CONFIG1		(dev->base_addr + 0x10)
-#define CFG1_BUFSELSTAT0	0x0000
-#define CFG1_BUFSELSTAT1	0x0001
-#define CFG1_BUFSELSTAT2	0x0002
-#define CFG1_BUFSELSTAT3	0x0003
-#define CFG1_BUFSELSTAT4	0x0004
-#define CFG1_BUFSELSTAT5	0x0005
-#define CFG1_ADDRPROM		0x0006
-#define CFG1_TRANSEND		0x0007
-#define CFG1_LOCBUFMEM		0x0008
-#define CFG1_INTVECTOR		0x0009
-#define CFG1_RECVSPECONLY	0x0000
-#define CFG1_RECVSPECBROAD	0x4000
-#define CFG1_RECVSPECBRMULTI	0x8000
-#define CFG1_RECVPROMISC	0xC000
-
-/* The following aren't in 8004 */
-#define CFG1_DMABURSTCONT	0x0000
-#define CFG1_DMABURST800NS	0x0010
-#define CFG1_DMABURST1600NS	0x0020
-#define CFG1_DMABURST3200NS	0x0030
-#define CFG1_DMABURST1		0x0000
-#define CFG1_DMABURST4		0x0040
-#define CFG1_DMABURST8		0x0080
-#define CFG1_DMABURST16		0x00C0
-#define CFG1_RECVCOMPSTAT0	0x0100
-#define CFG1_RECVCOMPSTAT1	0x0200
-#define CFG1_RECVCOMPSTAT2	0x0400
-#define CFG1_RECVCOMPSTAT3	0x0800
-#define CFG1_RECVCOMPSTAT4	0x1000
-#define CFG1_RECVCOMPSTAT5	0x2000
-
-/* configuration register 2 */
-#define REG_CONFIG2		(dev->base_addr + 0x20)
-#define CFG2_BYTESWAP		0x0001
-#define CFG2_ERRENCRC		0x0008
-#define CFG2_ERRENDRIBBLE	0x0010
-#define CFG2_ERRSHORTFRAME	0x0020
-#define CFG2_SLOTSELECT		0x0040
-#define CFG2_PREAMSELECT	0x0080
-#define CFG2_ADDRLENGTH		0x0100
-#define CFG2_RECVCRC		0x0200
-#define CFG2_XMITNOCRC		0x0400
-#define CFG2_LOOPBACK		0x0800
-#define CFG2_CTRLO		0x1000
-#define CFG2_RESET		0x8000
-
-#define REG_RECVEND		(dev->base_addr + 0x30)
-
-#define REG_BUFWIN		(dev->base_addr + 0x40)
-
-#define REG_RECVPTR		(dev->base_addr + 0x50)
-
-#define REG_TRANSMITPTR		(dev->base_addr + 0x60)
-
-#define REG_DMAADDR		(dev->base_addr + 0x70)
-
-/*
- * Cards transmit/receive headers
- */
-#define TX_NEXT			(0xffff)
-#define TXHDR_ENBABBLEINT	(1 << 16)
-#define TXHDR_ENCOLLISIONINT	(1 << 17)
-#define TXHDR_EN16COLLISION	(1 << 18)
-#define TXHDR_ENSUCCESS		(1 << 19)
-#define TXHDR_DATAFOLLOWS	(1 << 21)
-#define TXHDR_CHAINCONTINUE	(1 << 22)
-#define TXHDR_TRANSMIT		(1 << 23)
-#define TXSTAT_BABBLED		(1 << 24)
-#define TXSTAT_COLLISION	(1 << 25)
-#define TXSTAT_16COLLISIONS	(1 << 26)
-#define TXSTAT_DONE		(1 << 31)
-
-#define RX_NEXT			(0xffff)
-#define RXHDR_CHAINCONTINUE	(1 << 6)
-#define RXHDR_RECEIVE		(1 << 7)
-#define RXSTAT_OVERSIZE		(1 << 8)
-#define RXSTAT_CRCERROR		(1 << 9)
-#define RXSTAT_DRIBBLEERROR	(1 << 10)
-#define RXSTAT_SHORTPACKET	(1 << 11)
-#define RXSTAT_DONE		(1 << 15)
-
-
-#define TX_START	0x0000
-#define TX_END		0x6000
-#define RX_START	0x6000
-#define RX_LEN		0xA000
-#define RX_END		0x10000
-/* must be a power of 2 and greater than MAX_TX_BUFFERED */
-#define MAX_TXED	16
-#define MAX_TX_BUFFERED	10
-
-struct dev_priv {
-    struct {
-	unsigned int command;
-	unsigned int config1;
-	unsigned int config2;
-    } regs;
-    unsigned char tx_head;		/* buffer nr to insert next packet	 */
-    unsigned char tx_tail;		/* buffer nr of transmitting packet	 */
-    unsigned int rx_head;		/* address to fetch next packet from	 */
-    struct net_device_stats stats;
-    struct timer_list timer;
-    int broken;				/* 0 = ok, 1 = something went wrong	 */
-};
-
-#endif
diff -Nru a/drivers/acorn/net/etherh.c b/drivers/acorn/net/etherh.c
--- a/drivers/acorn/net/etherh.c	Thu Mar  6 05:00:33 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,763 +0,0 @@
-/*
- *  linux/drivers/acorn/net/etherh.c
- *
- *  Copyright (C) 2000-2002 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.
- *
- * NS8390 I-cubed EtherH and ANT EtherM specific driver
- * Thanks to I-Cubed for information on their cards.
- * EtherM conversion (C) 1999 Chris Kemp and Tim Watterton
- * EtherM integration (C) 2000 Aleph One Ltd (Tak-Shing Chan)
- * EtherM integration re-engineered by Russell King.
- *
- * Changelog:
- *  08-12-1996	RMK	1.00	Created
- *		RMK	1.03	Added support for EtherLan500 cards
- *  23-11-1997	RMK	1.04	Added media autodetection
- *  16-04-1998	RMK	1.05	Improved media autodetection
- *  10-02-2000	RMK	1.06	Updated for 2.3.43
- *  13-05-2000	RMK	1.07	Updated for 2.3.99-pre8
- *  12-10-1999  CK/TEW		EtherM driver first release
- *  21-12-2000	TTC		EtherH/EtherM integration
- *  25-12-2000	RMK	1.08	Clean integration of EtherM into this driver.
- *  03-01-2002	RMK	1.09	Always enable IRQs if we're in the nic slot.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/ecard.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-
-#include "../../net/8390.h"
-
-#define NET_DEBUG  0
-#define DEBUG_INIT 2
-
-static unsigned int net_debug = NET_DEBUG;
-
-struct etherh_priv {
-	struct ei_device eidev;
-	unsigned int	id;
-	unsigned int	ctrl_port;
-	unsigned int	ctrl;
-};
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("EtherH/EtherM driver");
-MODULE_LICENSE("GPL");
-
-static char version[] __initdata =
-	"EtherH/EtherM Driver (c) 2002 Russell King v1.09\n";
-
-#define ETHERH500_DATAPORT	0x200	/* MEMC */
-#define ETHERH500_NS8390	0x000	/* MEMC */
-#define ETHERH500_CTRLPORT	0x200	/* IOC  */
-
-#define ETHERH600_DATAPORT	16	/* MEMC */
-#define ETHERH600_NS8390	0x200	/* MEMC */
-#define ETHERH600_CTRLPORT	0x080	/* MEMC */
-
-#define ETHERH_CP_IE		1
-#define ETHERH_CP_IF		2
-#define ETHERH_CP_HEARTBEAT	2
-
-#define ETHERH_TX_START_PAGE	1
-#define ETHERH_STOP_PAGE	127
-
-/*
- * These came from CK/TEW
- */
-#define ETHERM_DATAPORT		0x080	/* MEMC */
-#define ETHERM_NS8390		0x200	/* MEMC */
-#define ETHERM_CTRLPORT		0x08f	/* MEMC */
-
-#define ETHERM_TX_START_PAGE	64
-#define ETHERM_STOP_PAGE	127
-
-/* ------------------------------------------------------------------------ */
-
-static inline void etherh_set_ctrl(struct etherh_priv *eh, unsigned int mask)
-{
-	eh->ctrl |= mask;
-	outb(eh->ctrl, eh->ctrl_port);
-}
-
-static inline void etherh_clr_ctrl(struct etherh_priv *eh, unsigned int mask)
-{
-	eh->ctrl &= ~mask;
-	outb(eh->ctrl, eh->ctrl_port);
-}
-
-static inline unsigned int etherh_get_stat(struct etherh_priv *eh)
-{
-	return inb(eh->ctrl_port);
-}
-
-
-
-
-static void etherh_irq_enable(ecard_t *ec, int irqnr)
-{
-	struct etherh_priv *eh = ec->irq_data;
-
-	etherh_set_ctrl(eh, ETHERH_CP_IE);
-}
-
-static void etherh_irq_disable(ecard_t *ec, int irqnr)
-{
-	struct etherh_priv *eh = ec->irq_data;
-
-	etherh_clr_ctrl(eh, ETHERH_CP_IE);
-}
-
-static expansioncard_ops_t etherh_ops = {
-	.irqenable	= etherh_irq_enable,
-	.irqdisable	= etherh_irq_disable,
-};
-
-
-
-
-static void
-etherh_setif(struct net_device *dev)
-{
-	struct etherh_priv *eh = (struct etherh_priv *)dev->priv;
-	struct ei_device *ei_local = &eh->eidev;
-	unsigned long addr, flags;
-
-	local_irq_save(flags);
-
-	/* set the interface type */
-	switch (eh->id) {
-	case PROD_I3_ETHERLAN600:
-	case PROD_I3_ETHERLAN600A:
-		addr = dev->base_addr + EN0_RCNTHI;
-
-		switch (dev->if_port) {
-		case IF_PORT_10BASE2:
-			outb((inb(addr) & 0xf8) | 1, addr);
-			break;
-		case IF_PORT_10BASET:
-			outb((inb(addr) & 0xf8), addr);
-			break;
-		}
-		break;
-
-	case PROD_I3_ETHERLAN500:
-		switch (dev->if_port) {
-		case IF_PORT_10BASE2:
-			etherh_clr_ctrl(eh, ETHERH_CP_IF);
-			break;
-
-		case IF_PORT_10BASET:
-			etherh_set_ctrl(eh, ETHERH_CP_IF);
-			break;
-		}
-		break;
-
-	default:
-		break;
-	}
-
-	local_irq_restore(flags);
-}
-
-static int
-etherh_getifstat(struct net_device *dev)
-{
-	struct etherh_priv *eh = (struct etherh_priv *)dev->priv;
-	struct ei_device *ei_local = &eh->eidev;
-	int stat = 0;
-
-	switch (eh->id) {
-	case PROD_I3_ETHERLAN600:
-	case PROD_I3_ETHERLAN600A:
-		switch (dev->if_port) {
-		case IF_PORT_10BASE2:
-			stat = 1;
-			break;
-		case IF_PORT_10BASET:
-			stat = inb(dev->base_addr+EN0_RCNTHI) & 4;
-			break;
-		}
-		break;
-
-	case PROD_I3_ETHERLAN500:
-		switch (dev->if_port) {
-		case IF_PORT_10BASE2:
-			stat = 1;
-			break;
-		case IF_PORT_10BASET:
-			stat = etherh_get_stat(eh) & ETHERH_CP_HEARTBEAT;
-			break;
-		}
-		break;
-
-	default:
-		stat = 0;
-		break;
-	}
-
-	return stat != 0;
-}
-
-/*
- * Configure the interface.  Note that we ignore the other
- * parts of ifmap, since its mostly meaningless for this driver.
- */
-static int etherh_set_config(struct net_device *dev, struct ifmap *map)
-{
-	switch (map->port) {
-	case IF_PORT_10BASE2:
-	case IF_PORT_10BASET:
-		/*
-		 * If the user explicitly sets the interface
-		 * media type, turn off automedia detection.
-		 */
-		dev->flags &= ~IFF_AUTOMEDIA;
-		dev->if_port = map->port;
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	etherh_setif(dev);
-
-	return 0;
-}
-
-/*
- * Reset the 8390 (hard reset).  Note that we can't actually do this.
- */
-static void
-etherh_reset(struct net_device *dev)
-{
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
-
-	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr);
-
-	/*
-	 * See if we need to change the interface type.
-	 * Note that we use 'interface_num' as a flag
-	 * to indicate that we need to change the media.
-	 */
-	if (dev->flags & IFF_AUTOMEDIA && ei_local->interface_num) {
-		ei_local->interface_num = 0;
-
-		if (dev->if_port == IF_PORT_10BASET)
-			dev->if_port = IF_PORT_10BASE2;
-		else
-			dev->if_port = IF_PORT_10BASET;
-
-		etherh_setif(dev);
-	}
-}
-
-/*
- * Write a block of data out to the 8390
- */
-static void
-etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page)
-{
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
-	unsigned int addr, dma_addr;
-	unsigned long dma_start;
-
-	if (ei_local->dmaing) {
-		printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: "
-			" DMAstat %d irqlock %d\n", dev->name,
-			ei_local->dmaing, ei_local->irqlock);
-		return;
-	}
-
-	/*
-	 * Make sure we have a round number of bytes if we're in word mode.
-	 */
-	if (count & 1 && ei_local->word16)
-		count++;
-
-	ei_local->dmaing = 1;
-
-	addr = dev->base_addr;
-	dma_addr = dev->mem_start;
-
-	count = (count + 1) & ~1;
-	outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
-
-	outb (0x42, addr + EN0_RCNTLO);
-	outb (0x00, addr + EN0_RCNTHI);
-	outb (0x42, addr + EN0_RSARLO);
-	outb (0x00, addr + EN0_RSARHI);
-	outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
-
-	udelay (1);
-
-	outb (ENISR_RDC, addr + EN0_ISR);
-	outb (count, addr + EN0_RCNTLO);
-	outb (count >> 8, addr + EN0_RCNTHI);
-	outb (0, addr + EN0_RSARLO);
-	outb (start_page, addr + EN0_RSARHI);
-	outb (E8390_RWRITE | E8390_START, addr + E8390_CMD);
-
-	if (ei_local->word16)
-		outsw (dma_addr, buf, count >> 1);
-	else
-		outsb (dma_addr, buf, count);
-
-	dma_start = jiffies;
-
-	while ((inb (addr + EN0_ISR) & ENISR_RDC) == 0)
-		if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
-			printk(KERN_ERR "%s: timeout waiting for TX RDC\n",
-				dev->name);
-			etherh_reset (dev);
-			NS8390_init (dev, 1);
-			break;
-		}
-
-	outb (ENISR_RDC, addr + EN0_ISR);
-	ei_local->dmaing = 0;
-}
-
-/*
- * Read a block of data from the 8390
- */
-static void
-etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
-{
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
-	unsigned int addr, dma_addr;
-	unsigned char *buf;
-
-	if (ei_local->dmaing) {
-		printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: "
-			" DMAstat %d irqlock %d\n", dev->name,
-			ei_local->dmaing, ei_local->irqlock);
-		return;
-	}
-
-	ei_local->dmaing = 1;
-
-	addr = dev->base_addr;
-	dma_addr = dev->mem_start;
-
-	buf = skb->data;
-	outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
-	outb (count, addr + EN0_RCNTLO);
-	outb (count >> 8, addr + EN0_RCNTHI);
-	outb (ring_offset, addr + EN0_RSARLO);
-	outb (ring_offset >> 8, addr + EN0_RSARHI);
-	outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
-
-	if (ei_local->word16) {
-		insw (dma_addr, buf, count >> 1);
-		if (count & 1)
-			buf[count - 1] = inb (dma_addr);
-	} else
-		insb (dma_addr, buf, count);
-
-	outb (ENISR_RDC, addr + EN0_ISR);
-	ei_local->dmaing = 0;
-}
-
-/*
- * Read a header from the 8390
- */
-static void
-etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
-{
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
-	unsigned int addr, dma_addr;
-
-	if (ei_local->dmaing) {
-		printk(KERN_ERR "%s: DMAing conflict in etherh_get_header: "
-			" DMAstat %d irqlock %d\n", dev->name,
-			ei_local->dmaing, ei_local->irqlock);
-		return;
-	}
-
-	ei_local->dmaing = 1;
-
-	addr = dev->base_addr;
-	dma_addr = dev->mem_start;
-
-	outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
-	outb (sizeof (*hdr), addr + EN0_RCNTLO);
-	outb (0, addr + EN0_RCNTHI);
-	outb (0, addr + EN0_RSARLO);
-	outb (ring_page, addr + EN0_RSARHI);
-	outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
-
-	if (ei_local->word16)
-		insw (dma_addr, hdr, sizeof (*hdr) >> 1);
-	else
-		insb (dma_addr, hdr, sizeof (*hdr));
-
-	outb (ENISR_RDC, addr + EN0_ISR);
-	ei_local->dmaing = 0;
-}
-
-/*
- * Open/initialize the board.  This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
- *
- * This routine should set everything up anew at each open, even
- * registers that "should" only need to be set once at boot, so that
- * there is non-reboot way to recover if something goes wrong.
- */
-static int
-etherh_open(struct net_device *dev)
-{
-	struct ei_device *ei_local = (struct ei_device *) dev->priv;
-
-	if (!is_valid_ether_addr(dev->dev_addr)) {
-		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
-			dev->name);
-		return -EINVAL;
-	}
-
-	if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))
-		return -EAGAIN;
-
-	/*
-	 * Make sure that we aren't going to change the
-	 * media type on the next reset - we are about to
-	 * do automedia manually now.
-	 */
-	ei_local->interface_num = 0;
-
-	/*
-	 * If we are doing automedia detection, do it now.
-	 * This is more reliable than the 8390's detection.
-	 */
-	if (dev->flags & IFF_AUTOMEDIA) {
-		dev->if_port = IF_PORT_10BASET;
-		etherh_setif(dev);
-		mdelay(1);
-		if (!etherh_getifstat(dev)) {
-			dev->if_port = IF_PORT_10BASE2;
-			etherh_setif(dev);
-		}
-	} else
-		etherh_setif(dev);
-
-	etherh_reset(dev);
-	ei_open(dev);
-
-	return 0;
-}
-
-/*
- * The inverse routine to etherh_open().
- */
-static int
-etherh_close(struct net_device *dev)
-{
-	ei_close (dev);
-	free_irq (dev->irq, dev);
-	return 0;
-}
-
-/*
- * Initialisation
- */
-
-static void __init etherh_banner(void)
-{
-	static int version_printed;
-
-	if (net_debug && version_printed++ == 0)
-		printk(KERN_INFO "%s", version);
-}
-
-/*
- * Read the ethernet address string from the on board rom.
- * This is an ascii string...
- */
-static int __init etherh_addr(char *addr, struct expansion_card *ec)
-{
-	struct in_chunk_dir cd;
-	char *s;
-	
-	if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
-		int i;
-		for (i = 0; i < 6; i++) {
-			addr[i] = simple_strtoul(s + 1, &s, 0x10);
-			if (*s != (i == 5? ')' : ':'))
-				break;
-		}
-		if (i == 6)
-			return 0;
-	}
-	return -ENODEV;
-}
-
-/*
- * Create an ethernet address from the system serial number.
- */
-static int __init etherm_addr(char *addr)
-{
-	unsigned int serial;
-
-	if (system_serial_low == 0 && system_serial_high == 0)
-		return -ENODEV;
-
-	serial = system_serial_low | system_serial_high;
-
-	addr[0] = 0;
-	addr[1] = 0;
-	addr[2] = 0xa4;
-	addr[3] = 0x10 + (serial >> 24);
-	addr[4] = serial >> 16;
-	addr[5] = serial >> 8;
-	return 0;
-}
-
-static u32 etherh_regoffsets[16];
-static u32 etherm_regoffsets[16];
-
-static int __init
-etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct ei_device *ei_local;
-	struct net_device *dev;
-	struct etherh_priv *eh;
-	const char *dev_type;
-	int i, size, ret;
-
-	etherh_banner();
-
-	dev = init_etherdev(NULL, sizeof(struct etherh_priv));
-	if (!dev) {
-		ret = -ENOMEM;
-		goto out;
-	}
-
-	/*
-	 * init_etherdev allocs and zeros dev->priv
-	 */
-	eh = dev->priv;
-
-	spin_lock_init(&eh->eidev.page_lock);
-
-	SET_MODULE_OWNER(dev);
-
-	dev->open		= etherh_open;
-	dev->stop		= etherh_close;
-	dev->set_config		= etherh_set_config;
-	dev->irq		= ec->irq;
-	dev->base_addr		= ecard_address(ec, ECARD_MEMC, 0);
-
-	/*
-	 * IRQ and control port handling
-	 */
-	if (ec->irq != 11) {
-		ec->ops		= &etherh_ops;
-		ec->irq_data	= eh;
-	}
-	eh->ctrl		= 0;
-	eh->id			= ec->cid.product;
-
-	switch (ec->cid.product) {
-	case PROD_ANT_ETHERM:
-		etherm_addr(dev->dev_addr);
-		dev->base_addr += ETHERM_NS8390;
-		dev->mem_start  = dev->base_addr + ETHERM_DATAPORT;
-		eh->ctrl_port   = dev->base_addr + ETHERM_CTRLPORT;
-		break;
-
-	case PROD_I3_ETHERLAN500:
-		etherh_addr(dev->dev_addr, ec);
-		dev->base_addr += ETHERH500_NS8390;
-		dev->mem_start  = dev->base_addr + ETHERH500_DATAPORT;
-		eh->ctrl_port   = ecard_address (ec, ECARD_IOC, ECARD_FAST)
-				  + ETHERH500_CTRLPORT;
-		break;
-
-	case PROD_I3_ETHERLAN600:
-	case PROD_I3_ETHERLAN600A:
-		etherh_addr(dev->dev_addr, ec);
-		dev->base_addr += ETHERH600_NS8390;
-		dev->mem_start  = dev->base_addr + ETHERH600_DATAPORT;
-		eh->ctrl_port   = dev->base_addr + ETHERH600_CTRLPORT;
-		break;
-
-	default:
-		printk(KERN_ERR "%s: unknown card type %x\n",
-		       dev->name, ec->cid.product);
-		ret = -ENODEV;
-		goto free;
-	}
-
-	size = 16;
-	if (ec->cid.product == PROD_ANT_ETHERM)
-		size <<= 3;
-
-	if (!request_region(dev->base_addr, size, dev->name)) {
-		ret = -EBUSY;
-		goto free;
-	}
-
-	if (ethdev_init(dev)) {
-		ret = -ENODEV;
-		goto release;
-	}
-
-	/*
-	 * If we're in the NIC slot, make sure the IRQ is enabled
-	 */
-	if (dev->irq == 11)
-		etherh_set_ctrl(eh, ETHERH_CP_IE);
-
-	/*
-	 * Unfortunately, ethdev_init eventually calls
-	 * ether_setup, which re-writes dev->flags.
-	 */
-	switch (ec->cid.product) {
-	case PROD_ANT_ETHERM:
-		dev_type = "ANT EtherM";
-		dev->if_port = IF_PORT_UNKNOWN;
-		break;
-
-	case PROD_I3_ETHERLAN500:
-		dev_type = "i3 EtherH 500";
-		dev->if_port = IF_PORT_UNKNOWN;
-		break;
-
-	case PROD_I3_ETHERLAN600:
-		dev_type = "i3 EtherH 600";
-		dev->flags  |= IFF_PORTSEL | IFF_AUTOMEDIA;
-		dev->if_port = IF_PORT_10BASET;
-		break;
-
-	case PROD_I3_ETHERLAN600A:
-		dev_type = "i3 EtherH 600A";
-		dev->flags  |= IFF_PORTSEL | IFF_AUTOMEDIA;
-		dev->if_port = IF_PORT_10BASET;
-		break;
-
-	default:
-		dev_type = "unknown";
-		break;
-	}
-
-	printk(KERN_INFO "%s: %s in slot %d, ",
-		dev->name, dev_type, ec->slot_no);
-
-	for (i = 0; i < 6; i++)
-		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
-
-	ei_local = (struct ei_device *) dev->priv;
-	if (ec->cid.product == PROD_ANT_ETHERM) {
-		ei_local->tx_start_page = ETHERM_TX_START_PAGE;
-		ei_local->stop_page     = ETHERM_STOP_PAGE;
-		ei_local->reg_offset    = etherm_regoffsets;
-	} else {
-		ei_local->tx_start_page = ETHERH_TX_START_PAGE;
-		ei_local->stop_page     = ETHERH_STOP_PAGE;
-		ei_local->reg_offset    = etherh_regoffsets;
-	}
-
-	ei_local->name          = dev->name;
-	ei_local->word16        = 1;
-	ei_local->rx_start_page = ei_local->tx_start_page + TX_PAGES;
-	ei_local->reset_8390    = etherh_reset;
-	ei_local->block_input   = etherh_block_input;
-	ei_local->block_output  = etherh_block_output;
-	ei_local->get_8390_hdr  = etherh_get_header;
-	ei_local->interface_num = 0;
-
-	etherh_reset(dev);
-	NS8390_init(dev, 0);
-
-	ecard_set_drvdata(ec, dev);
-
-	return 0;
-
-release:
-	release_region(dev->base_addr, 16);
-free:
-	unregister_netdev(dev);
-	kfree(dev->priv);
-	kfree(dev);
-out:
-	return ret;
-}
-
-static void __devexit etherh_remove(struct expansion_card *ec)
-{
-	struct net_device *dev = ecard_get_drvdata(ec);
-	int size = 16;
-
-	ecard_set_drvdata(ec, NULL);
-
-	unregister_netdev(dev);
-	if (ec->cid.product == PROD_ANT_ETHERM)
-		size <<= 3;
-	release_region(dev->base_addr, size);
-	kfree(dev);
-
-	ec->ops = NULL;
-	kfree(ec->irq_data);
-}
-
-static const struct ecard_id etherh_ids[] = {
-	{ MANU_ANT, PROD_ANT_ETHERM      },
-	{ MANU_I3,  PROD_I3_ETHERLAN500  },
-	{ MANU_I3,  PROD_I3_ETHERLAN600  },
-	{ MANU_I3,  PROD_I3_ETHERLAN600A },
-	{ 0xffff,   0xffff }
-};
-
-static struct ecard_driver etherh_driver = {
-	.probe		= etherh_probe,
-	.remove		= __devexit_p(etherh_remove),
-	.id_table	= etherh_ids,
-	.drv = {
-		.name	= "etherh",
-	},
-};
-
-static int __init etherh_init(void)
-{
-	int i;
-
-	for (i = 0; i < 16; i++) {
-		etherh_regoffsets[i] = i;
-		etherm_regoffsets[i] = i << 3;
-	}
-
-	return ecard_register_driver(&etherh_driver);
-}
-
-static void __exit etherh_exit(void)
-{
-	ecard_remove_driver(&etherh_driver);
-}
-
-module_init(etherh_init);
-module_exit(etherh_exit);
diff -Nru a/drivers/acorn/scsi/Kconfig b/drivers/acorn/scsi/Kconfig
--- a/drivers/acorn/scsi/Kconfig	Tue Oct 29 17:16:55 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,89 +0,0 @@
-#
-# SCSI driver configuration for Acorn
-#
-config SCSI_ACORNSCSI_3
-	tristate "Acorn SCSI card (aka30) support"
-	depends on ARCH_ACORN && SCSI
-	help
-	  This enables support for the Acorn SCSI card (aka30). If you have an
-	  Acorn system with one of these, say Y. If unsure, say N.
-
-config SCSI_ACORNSCSI_TAGGED_QUEUE
-	bool "Support SCSI 2 Tagged queueing"
-	depends on SCSI_ACORNSCSI_3
-	help
-	  Say Y here to enable tagged queuing support on the Acorn SCSI card.
-
-	  This is a feature of SCSI-2 which improves performance: the host
-	  adapter can send several SCSI commands to a device's queue even if
-	  previous commands haven't finished yet. Some SCSI devices don't
-	  implement this properly, so the safe answer is N.
-
-config SCSI_ACORNSCSI_SYNC
-	bool "Support SCSI 2 Synchronous Transfers"
-	depends on SCSI_ACORNSCSI_3
-	help
-	  Say Y here to enable synchronous transfer negotiation with all
-	  targets on the Acorn SCSI card.
-
-	  In general, this improves performance; however some SCSI devices
-	  don't implement it properly, so the safe answer is N.
-
-config SCSI_ARXESCSI
-	tristate "ARXE SCSI support"
-	depends on ARCH_ACORN && SCSI
-	help
-	  Around 1991, Arxe Systems Limited released a high density floppy
-	  disc interface for the Acorn Archimedes range, to allow the use of
-	  HD discs from the then new A5000 on earlier models. This interface
-	  was either sold on its own or with an integral SCSI controller.
-	  Technical details on this NCR53c94-based device are available at
-	  <http://www.cryton.demon.co.uk/acornbits/scsi_arxe.html>
-	  Say Y here to compile in support for the SCSI controller.
-
-config SCSI_CUMANA_2
-	tristate "CumanaSCSI II support"
-	depends on ARCH_ACORN && SCSI
-	help
-	  This enables support for the Cumana SCSI II card. If you have an
-	  Acorn system with one of these, say Y. If unsure, say N.
-
-config SCSI_EESOXSCSI
-	tristate "EESOX support"
-	depends on ARCH_ACORN && SCSI
-	help
-	  This enables support for the EESOX SCSI card. If you have an Acorn
-	  system with one of these, say Y, otherwise say N.
-
-config SCSI_POWERTECSCSI
-	tristate "PowerTec support"
-	depends on ARCH_ACORN && SCSI
-	help
-	  This enables support for the Powertec SCSI card on Acorn systems. If
-	  you have one of these, say Y. If unsure, say N.
-
-comment "The following drivers are not fully supported"
-	depends on ARCH_ACORN && EXPERIMENTAL
-
-config SCSI_CUMANA_1
-	tristate "CumanaSCSI I support (EXPERIMENTAL)"
-	depends on ARCH_ACORN && EXPERIMENTAL && SCSI
-	help
-	  This enables support for the Cumana SCSI I card. If you have an
-	  Acorn system with one of these, say Y. If unsure, say N.
-
-config SCSI_ECOSCSI
-	tristate "EcoScsi support (EXPERIMENTAL)"
-	depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI
-	help
-	  This enables support for the EcoSCSI card -- a small card that sits
-	  in the Econet socket. If you have an Acorn system with one of these,
-	  say Y. If unsure, say N.
-
-config SCSI_OAK1
-	tristate "Oak SCSI support (EXPERIMENTAL)"
-	depends on ARCH_ACORN && EXPERIMENTAL && SCSI
-	help
-	  This enables support for the Oak SCSI card. If you have an Acorn
-	  system with one of these, say Y. If unsure, say N.
-
diff -Nru a/drivers/acorn/scsi/Makefile b/drivers/acorn/scsi/Makefile
--- a/drivers/acorn/scsi/Makefile	Mon Feb  3 14:19:36 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,14 +0,0 @@
-#
-# Makefile for drivers/acorn/scsi
-#
-
-acornscsi_mod-objs	:= acornscsi.o acornscsi-io.o
-
-obj-$(CONFIG_SCSI_ACORNSCSI_3)	+= acornscsi_mod.o queue.o msgqueue.o
-obj-$(CONFIG_SCSI_ARXESCSI)	+= arxescsi.o fas216.o queue.o msgqueue.o
-obj-$(CONFIG_SCSI_CUMANA_1)	+= cumana_1.o
-obj-$(CONFIG_SCSI_CUMANA_2)	+= cumana_2.o fas216.o queue.o msgqueue.o
-obj-$(CONFIG_SCSI_ECOSCSI)	+= ecoscsi.o
-obj-$(CONFIG_SCSI_OAK1)		+= oak.o
-obj-$(CONFIG_SCSI_POWERTECSCSI)	+= powertec.o fas216.o queue.o msgqueue.o
-obj-$(CONFIG_SCSI_EESOXSCSI)	+= eesox.o fas216.o queue.o msgqueue.o
diff -Nru a/drivers/acorn/scsi/acornscsi-io.S b/drivers/acorn/scsi/acornscsi-io.S
--- a/drivers/acorn/scsi/acornscsi-io.S	Tue Feb  5 09:40:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,145 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/acornscsi-io.S: Acorn SCSI card IO
- *
- * 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/linkage.h>
-
-#include <asm/assembler.h>
-#include <asm/hardware.h>
-
-#if (IO_BASE == (PCIO_BASE & 0xff000000))
-#define ADDR(off,reg)						\
-		tst	off, $0x80000000			;\
-		mov	reg, $IO_BASE				;\
-		orreq	reg, reg, $(PCIO_BASE & 0x00ff0000)
-#else
-#define ADDR(off,reg)						\
-		tst	off, $0x80000000			;\
-		movne	reg, $IO_BASE				;\
-		moveq	reg, $(PCIO_BASE & 0xff000000)		;\
-		orreq	reg, reg, $(PCIO_BASE & 0x00ff0000)
-#endif
-
-@ Purpose: transfer a block of data from the acorn scsi card to memory
-@ Proto  : void acornscsi_in(unsigned int addr_start, char *buffer, int length)
-@ Returns: nothing
-
-		.align
-ENTRY(__acornscsi_in)
-		stmfd	sp!, {r4 - r7, lr}
-		bic	r0, r0, #3
-		mov	lr, #0xff
-		orr	lr, lr, #0xff00
-acornscsi_in16lp:
-		subs	r2, r2, #16
-		bmi	acornscsi_in8
-		ldmia	r0!, {r3, r4, r5, r6}
-		and	r3, r3, lr
-		orr	r3, r3, r4, lsl #16
-		and 	r4, r5, lr
-		orr	r4, r4, r6, lsl #16
-		ldmia	r0!, {r5, r6, r7, ip}
-		and	r5, r5, lr
-		orr	r5, r5, r6, lsl #16
-		and	r6, r7, lr
-		orr	r6, r6, ip, lsl #16
-		stmia	r1!, {r3 - r6}
-		bne	acornscsi_in16lp
-		LOADREGS(fd, sp!, {r4 - r7, pc})
-
-acornscsi_in8:	adds	r2, r2, #8
-		bmi	acornscsi_in4
-		ldmia	r0!, {r3, r4, r5, r6}
-		and	r3, r3, lr
-		orr	r3, r3, r4, lsl #16
-		and	r4, r5, lr
-		orr	r4, r4, r6, lsl #16
-		stmia	r1!, {r3 - r4}
-		LOADREGS(eqfd, sp!, {r4 - r7, pc})
-		sub	r2, r2, #8
-
-acornscsi_in4:	adds	r2, r2, #4
-		bmi	acornscsi_in2
-		ldmia	r0!, {r3, r4}
-		and	r3, r3, lr
-		orr	r3, r3, r4, lsl #16
-		str	r3, [r1], #4
-		LOADREGS(eqfd, sp!, {r4 - r7, pc})
-		sub	r2, r2, #4
-
-acornscsi_in2:	adds	r2, r2, #2
-		ldr	r3, [r0], #4
-		and	r3, r3, lr
-		strb	r3, [r1], #1
-		mov	r3, r3, lsr #8
-		strplb	r3, [r1], #1
-		LOADREGS(fd, sp!, {r4 - r7, pc})
-
-@ Purpose: transfer a block of data from memory to the acorn scsi card
-@ Proto  : void acornscsi_in(unsigned int addr_start, char *buffer, int length)
-@ Returns: nothing
-
-ENTRY(__acornscsi_out)
-		stmfd	sp!, {r4 - r6, lr}
-		bic	r0, r0, #3
-acornscsi_out16lp:
-		subs	r2, r2, #16
-		bmi	acornscsi_out8
-		ldmia	r1!, {r4, r6, ip, lr}
-		mov	r3, r4, lsl #16
-		orr	r3, r3, r3, lsr #16
-		mov	r4, r4, lsr #16
-		orr	r4, r4, r4, lsl #16
-		mov	r5, r6, lsl #16
-		orr	r5, r5, r5, lsr #16
-		mov	r6, r6, lsr #16
-		orr	r6, r6, r6, lsl #16
-		stmia	r0!, {r3, r4, r5, r6}
-		mov	r3, ip, lsl #16
-		orr	r3, r3, r3, lsr #16
-		mov	r4, ip, lsr #16
-		orr	r4, r4, r4, lsl #16
-		mov	ip, lr, lsl #16
-		orr	ip, ip, ip, lsr #16
-		mov	lr, lr, lsr #16
-		orr	lr, lr, lr, lsl #16
-		stmia	r0!, {r3, r4, ip, lr}
-		bne	acornscsi_out16lp
-		LOADREGS(fd, sp!, {r4 - r6, pc})
-
-acornscsi_out8:	adds	r2, r2, #8
-		bmi	acornscsi_out4
-		ldmia	r1!, {r4, r6}
-		mov	r3, r4, lsl #16
-		orr	r3, r3, r3, lsr #16
-		mov	r4, r4, lsr #16
-		orr	r4, r4, r4, lsl #16
-		mov	r5, r6, lsl #16
-		orr	r5, r5, r5, lsr #16
-		mov	r6, r6, lsr #16
-		orr	r6, r6, r6, lsl #16
-		stmia	r0!, {r3, r4, r5, r6}
-		LOADREGS(eqfd, sp!, {r4 - r6, pc})
-
-		sub	r2, r2, #8
-acornscsi_out4:	adds	r2, r2, #4
-		bmi	acornscsi_out2
-		ldr	r4, [r1], #4
-		mov	r3, r4, lsl #16
-		orr	r3, r3, r3, lsr #16
-		mov	r4, r4, lsr #16
-		orr	r4, r4, r4, lsl #16
-		stmia	r0!, {r3, r4}
-		LOADREGS(eqfd, sp!, {r4 - r6, pc})
-
-		sub	r2, r2, #4
-acornscsi_out2:	adds	r2, r2, #2
-		ldr	r3, [r1], #2
-		strb	r3, [r0], #1
-		mov	r3, r3, lsr #8
-		strplb	r3, [r0], #1
-		LOADREGS(fd, sp!, {r4 - r6, pc})
-
diff -Nru a/drivers/acorn/scsi/acornscsi.c b/drivers/acorn/scsi/acornscsi.c
--- a/drivers/acorn/scsi/acornscsi.c	Wed Mar 19 07:19:28 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3133 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/acornscsi.c
- *
- *  Acorn SCSI 3 driver
- *  By R.M.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.
- *
- * Abandoned using the Select and Transfer command since there were
- * some nasty races between our software and the target devices that
- * were not easy to solve, and the device errata had a lot of entries
- * for this command, some of them quite nasty...
- *
- * Changelog:
- *  26-Sep-1997	RMK	Re-jigged to use the queue module.
- *			Re-coded state machine to be based on driver
- *			state not scsi state.  Should be easier to debug.
- *			Added acornscsi_release to clean up properly.
- *			Updated proc/scsi reporting.
- *  05-Oct-1997	RMK	Implemented writing to SCSI devices.
- *  06-Oct-1997	RMK	Corrected small (non-serious) bug with the connect/
- *			reconnect race condition causing a warning message.
- *  12-Oct-1997	RMK	Added catch for re-entering interrupt routine.
- *  15-Oct-1997	RMK	Improved handling of commands.
- *  27-Jun-1998	RMK	Changed asm/delay.h to linux/delay.h.
- *  13-Dec-1998	RMK	Better abort code and command handling.  Extra state
- *			transitions added to allow dodgy devices to work.
- */
-#define DEBUG_NO_WRITE	1
-#define DEBUG_QUEUES	2
-#define DEBUG_DMA	4
-#define DEBUG_ABORT	8
-#define DEBUG_DISCON	16
-#define DEBUG_CONNECT	32
-#define DEBUG_PHASES	64
-#define DEBUG_WRITE	128
-#define DEBUG_LINK	256
-#define DEBUG_MESSAGES	512
-#define DEBUG_RESET	1024
-#define DEBUG_ALL	(DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\
-			 DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\
-			 DEBUG_DMA|DEBUG_QUEUES)
-
-/* DRIVER CONFIGURATION
- *
- * SCSI-II Tagged queue support.
- *
- * I don't have any SCSI devices that support it, so it is totally untested
- * (except to make sure that it doesn't interfere with any non-tagging
- * devices).  It is not fully implemented either - what happens when a
- * tagging device reconnects???
- *
- * You can tell if you have a device that supports tagged queueing my
- * cating (eg) /proc/scsi/acornscsi/0 and see if the SCSI revision is reported
- * as '2 TAG'.
- *
- * Also note that CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE is normally set in the config
- * scripts, but disabled here.  Once debugged, remove the #undef, otherwise to debug,
- * comment out the undef.
- */
-#undef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
-/*
- * SCSI-II Linked command support.
- *
- * The higher level code doesn't support linked commands yet, and so the option
- * is undef'd here.
- */
-#undef CONFIG_SCSI_ACORNSCSI_LINK
-/*
- * SCSI-II Synchronous transfer support.
- *
- * Tried and tested...
- *
- * SDTR_SIZE	  - maximum number of un-acknowledged bytes (0 = off, 12 = max)
- * SDTR_PERIOD	  - period of REQ signal (min=125, max=1020)
- * DEFAULT_PERIOD - default REQ period.
- */
-#define SDTR_SIZE	12
-#define SDTR_PERIOD	125
-#define DEFAULT_PERIOD	500
-
-/*
- * Debugging information
- *
- * DEBUG	  - bit mask from list above
- * DEBUG_TARGET   - is defined to the target number if you want to debug
- *		    a specific target. [only recon/write/dma].
- */
-#define DEBUG (DEBUG_RESET|DEBUG_WRITE|DEBUG_NO_WRITE)
-/* only allow writing to SCSI device 0 */
-#define NO_WRITE 0xFE
-/*#define DEBUG_TARGET 2*/
-/*
- * Select timeout time (in 10ms units)
- *
- * This is the timeout used between the start of selection and the WD33C93
- * chip deciding that the device isn't responding.
- */
-#define TIMEOUT_TIME 10
-/*
- * Define this if you want to have verbose explaination of SCSI
- * status/messages.
- */
-#undef CONFIG_ACORNSCSI_CONSTANTS
-/*
- * Define this if you want to use the on board DMAC [don't remove this option]
- * If not set, then use PIO mode (not currently supported).
- */
-#define USE_DMAC
-
-/*
- * ====================================================================================
- */
-
-#ifdef DEBUG_TARGET
-#define DBG(cmd,xxx...) \
-  if (cmd->device->id == DEBUG_TARGET) { \
-    xxx; \
-  }
-#else
-#define DBG(cmd,xxx...) xxx
-#endif
-
-#ifndef STRINGIFY
-#define STRINGIFY(x) #x
-#endif
-#define STRx(x) STRINGIFY(x)
-#define NO_WRITE_STR STRx(NO_WRITE)
-
-#include <linux/config.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/proc_fs.h>
-#include <linux/ioport.h>
-#include <linux/blk.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-
-#include <asm/bitops.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/ecard.h>
-
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-#include "acornscsi.h"
-#include "msgqueue.h"
-#include "scsi.h"
-
-#include <scsi/scsicam.h>
-
-#define VER_MAJOR 2
-#define VER_MINOR 0
-#define VER_PATCH 6
-
-#ifndef ABORT_TAG
-#define ABORT_TAG 0xd
-#else
-#error "Yippee!  ABORT TAG is now defined!  Remove this error!"
-#endif
-
-#ifdef CONFIG_SCSI_ACORNSCSI_LINK
-#error SCSI2 LINKed commands not supported (yet)!
-#endif
-
-#ifdef USE_DMAC
-/*
- * DMAC setup parameters
- */ 
-#define INIT_DEVCON0	(DEVCON0_RQL|DEVCON0_EXW|DEVCON0_CMP)
-#define INIT_DEVCON1	(DEVCON1_BHLD)
-#define DMAC_READ	(MODECON_READ)
-#define DMAC_WRITE	(MODECON_WRITE)
-#define INIT_SBICDMA	(CTRL_DMABURST)
-
-#define scsi_xferred	have_data_in
-
-/*
- * Size of on-board DMA buffer
- */
-#define DMAC_BUFFER_SIZE	65536
-#endif
-
-#define STATUS_BUFFER_TO_PRINT	24
-
-unsigned int sdtr_period = SDTR_PERIOD;
-unsigned int sdtr_size   = SDTR_SIZE;
-
-static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
-static int acornscsi_reconnect_finish(AS_Host *host);
-static void acornscsi_dma_cleanup(AS_Host *host);
-static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
-
-/* ====================================================================================
- * Miscellaneous
- */
-
-static inline void
-sbic_arm_write(unsigned int io_port, int reg, int value)
-{
-    __raw_writeb(reg, io_port);
-    __raw_writeb(value, io_port + 4);
-}
-
-#define sbic_arm_writenext(io,val) \
-	__raw_writeb((val), (io) + 4)
-
-static inline
-int sbic_arm_read(unsigned int io_port, int reg)
-{
-    if(reg == ASR)
-	   return __raw_readl(io_port) & 255;
-    __raw_writeb(reg, io_port);
-    return __raw_readl(io_port + 4) & 255;
-}
-
-#define sbic_arm_readnext(io) \
-	__raw_readb((io) + 4)
-
-#ifdef USE_DMAC
-#define dmac_read(io_port,reg) \
-	inb((io_port) + (reg))
-
-#define dmac_write(io_port,reg,value) \
-	({ outb((value), (io_port) + (reg)); })
-
-#define dmac_clearintr(io_port) \
-	({ outb(0, (io_port)); })
-
-static inline
-unsigned int dmac_address(unsigned int io_port)
-{
-    return dmac_read(io_port, TXADRHI) << 16 |
-	   dmac_read(io_port, TXADRMD) << 8 |
-	   dmac_read(io_port, TXADRLO);
-}
-
-static
-void acornscsi_dumpdma(AS_Host *host, char *where)
-{
-	unsigned int mode, addr, len;
-
-	mode = dmac_read(host->dma.io_port, MODECON);
-	addr = dmac_address(host->dma.io_port);
-	len  = dmac_read(host->dma.io_port, TXCNTHI) << 8 |
-	       dmac_read(host->dma.io_port, TXCNTLO);
-
-	printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",
-		host->host->host_no, where,
-		mode, addr, (len + 1) & 0xffff,
-		dmac_read(host->dma.io_port, MASKREG));
-
-	printk("DMA @%06x, ", host->dma.start_addr);
-	printk("BH @%p +%04x, ", host->scsi.SCp.ptr,
-		host->scsi.SCp.this_residual);
-	printk("DT @+%04x ST @+%04x", host->dma.transferred,
-		host->scsi.SCp.scsi_xferred);
-	printk("\n");
-}
-#endif
-
-static
-unsigned long acornscsi_sbic_xfcount(AS_Host *host)
-{
-    unsigned long length;
-
-    length = sbic_arm_read(host->scsi.io_port, TRANSCNTH) << 16;
-    length |= sbic_arm_readnext(host->scsi.io_port) << 8;
-    length |= sbic_arm_readnext(host->scsi.io_port);
-
-    return length;
-}
-
-static int
-acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg)
-{
-	int asr;
-
-	do {
-		asr = sbic_arm_read(host->scsi.io_port, ASR);
-
-		if ((asr & stat_mask) == stat)
-			return 0;
-
-		udelay(1);
-	} while (--timeout);
-
-	printk("scsi%d: timeout while %s\n", host->host->host_no, msg);
-
-	return -1;
-}
-
-static
-int acornscsi_sbic_issuecmd(AS_Host *host, int command)
-{
-    if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command"))
-	return -1;
-
-    sbic_arm_write(host->scsi.io_port, CMND, command);
-
-    return 0;
-}
-
-static void
-acornscsi_csdelay(unsigned int cs)
-{
-    unsigned long target_jiffies, flags;
-
-    target_jiffies = jiffies + 1 + cs * HZ / 100;
-
-    local_save_flags(flags);
-    local_irq_enable();
-
-    while (time_before(jiffies, target_jiffies)) barrier();
-
-    local_irq_restore(flags);
-}
-
-static
-void acornscsi_resetcard(AS_Host *host)
-{
-    unsigned int i, timeout;
-
-    /* assert reset line */
-    host->card.page_reg = 0x80;
-    outb(host->card.page_reg, host->card.io_page);
-
-    /* wait 3 cs.  SCSI standard says 25ms. */
-    acornscsi_csdelay(3);
-
-    host->card.page_reg = 0;
-    outb(host->card.page_reg, host->card.io_page);
-
-    /*
-     * Should get a reset from the card
-     */
-    timeout = 1000;
-    do {
-	if (inb(host->card.io_intr) & 8)
-	    break;
-	udelay(1);
-    } while (--timeout);
-
-    if (timeout == 0)
-	printk("scsi%d: timeout while resetting card\n",
-		host->host->host_no);
-
-    sbic_arm_read(host->scsi.io_port, ASR);
-    sbic_arm_read(host->scsi.io_port, SSR);
-
-    /* setup sbic - WD33C93A */
-    sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
-    sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
-
-    /*
-     * Command should cause a reset interrupt
-     */
-    timeout = 1000;
-    do {
-	if (inb(host->card.io_intr) & 8)
-	    break;
-	udelay(1);
-    } while (--timeout);
-
-    if (timeout == 0)
-	printk("scsi%d: timeout while resetting card\n",
-		host->host->host_no);
-
-    sbic_arm_read(host->scsi.io_port, ASR);
-    if (sbic_arm_read(host->scsi.io_port, SSR) != 0x01)
-	printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n",
-		host->host->host_no);
-
-    sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
-    sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
-    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
-    sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
-
-    host->card.page_reg = 0x40;
-    outb(host->card.page_reg, host->card.io_page);
-
-    /* setup dmac - uPC71071 */
-    dmac_write(host->dma.io_port, INIT, 0);
-#ifdef USE_DMAC
-    dmac_write(host->dma.io_port, INIT, INIT_8BIT);
-    dmac_write(host->dma.io_port, CHANNEL, CHANNEL_0);
-    dmac_write(host->dma.io_port, DEVCON0, INIT_DEVCON0);
-    dmac_write(host->dma.io_port, DEVCON1, INIT_DEVCON1);
-#endif
-
-    host->SCpnt = NULL;
-    host->scsi.phase = PHASE_IDLE;
-    host->scsi.disconnectable = 0;
-
-    memset(host->busyluns, 0, sizeof(host->busyluns));
-
-    for (i = 0; i < 8; i++) {
-	host->device[i].sync_state = SYNC_NEGOCIATE;
-	host->device[i].disconnect_ok = 1;
-    }
-
-    /* wait 25 cs.  SCSI standard says 250ms. */
-    acornscsi_csdelay(25);
-}
-
-/*=============================================================================================
- * Utility routines (eg. debug)
- */
-#ifdef CONFIG_ACORNSCSI_CONSTANTS
-static char *acornscsi_interrupttype[] = {
-  "rst",  "suc",  "p/a",  "3",
-  "term", "5",	  "6",	  "7",
-  "serv", "9",	  "a",	  "b",
-  "c",	  "d",	  "e",	  "f"
-};
-
-static signed char acornscsi_map[] = {
-  0,  1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- -1,  2, -1, -1,  -1, -1,  3, -1,   4,	5,  6,	7,   8,  9, 10, 11,
- 12, 13, 14, -1,  -1, -1, -1, -1,   4,	5,  6,	7,   8,  9, 10, 11,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- 15, 16, 17, 18,  19, -1, -1, 20,   4,	5,  6,	7,   8,  9, 10, 11,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- 21, 22, -1, -1,  -1, 23, -1, -1,   4,	5,  6,	7,   8,  9, 10, 11,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
- -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1
-};      
-
-static char *acornscsi_interruptcode[] = {
-    /* 0 */
-    "reset - normal mode",	/* 00 */
-    "reset - advanced mode",	/* 01 */
-
-    /* 2 */
-    "sel",			/* 11 */
-    "sel+xfer", 		/* 16 */
-    "data-out", 		/* 18 */
-    "data-in",			/* 19 */
-    "cmd",			/* 1A */
-    "stat",			/* 1B */
-    "??-out",			/* 1C */
-    "??-in",			/* 1D */
-    "msg-out",			/* 1E */
-    "msg-in",			/* 1F */
-
-    /* 12 */
-    "/ACK asserted",		/* 20 */
-    "save-data-ptr",		/* 21 */
-    "{re}sel",			/* 22 */
-
-    /* 15 */
-    "inv cmd",			/* 40 */
-    "unexpected disconnect",	/* 41 */
-    "sel timeout",		/* 42 */
-    "P err",			/* 43 */
-    "P err+ATN",		/* 44 */
-    "bad status byte",		/* 47 */
-
-    /* 21 */
-    "resel, no id",		/* 80 */
-    "resel",			/* 81 */
-    "discon",			/* 85 */
-};
-
-static
-void print_scsi_status(unsigned int ssr)
-{
-    if (acornscsi_map[ssr] != -1)
-	printk("%s:%s",
-		acornscsi_interrupttype[(ssr >> 4)],
-		acornscsi_interruptcode[acornscsi_map[ssr]]);
-    else
-	printk("%X:%X", ssr >> 4, ssr & 0x0f);    
-}    
-#endif
-
-static
-void print_sbic_status(int asr, int ssr, int cmdphase)
-{
-#ifdef CONFIG_ACORNSCSI_CONSTANTS
-    printk("sbic: %c%c%c%c%c%c ",
-	    asr & ASR_INT ? 'I' : 'i',
-	    asr & ASR_LCI ? 'L' : 'l',
-	    asr & ASR_BSY ? 'B' : 'b',
-	    asr & ASR_CIP ? 'C' : 'c',
-	    asr & ASR_PE  ? 'P' : 'p',
-	    asr & ASR_DBR ? 'D' : 'd');
-    printk("scsi: ");
-    print_scsi_status(ssr);
-    printk(" ph %02X\n", cmdphase);
-#else
-    printk("sbic: %02X scsi: %X:%X ph: %02X\n",
-	    asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);
-#endif
-}
-
-static void
-acornscsi_dumplogline(AS_Host *host, int target, int line)
-{
-	unsigned long prev;
-	signed int ptr;
-
-	ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT;
-	if (ptr < 0)
-		ptr += STATUS_BUFFER_SIZE;
-
-	printk("%c: %3s:", target == 8 ? 'H' : '0' + target,
-		line == 0 ? "ph" : line == 1 ? "ssr" : "int");
-
-	prev = host->status[target][ptr].when;
-
-	for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
-		unsigned long time_diff;
-
-		if (!host->status[target][ptr].when)
-			continue;
-
-		switch (line) {
-		case 0:
-			printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ',
-					 host->status[target][ptr].ph);
-			break;
-
-		case 1:
-			printk(" %02X", host->status[target][ptr].ssr);
-			break;
-
-		case 2:
-			time_diff = host->status[target][ptr].when - prev;
-			prev = host->status[target][ptr].when;
-			if (time_diff == 0)
-				printk("==^");
-			else if (time_diff >= 100)
-				printk("   ");
-			else
-				printk(" %02ld", time_diff);
-			break;
-		}
-	}
-
-	printk("\n");
-}
-
-static
-void acornscsi_dumplog(AS_Host *host, int target)
-{
-    do {
-	acornscsi_dumplogline(host, target, 0);
-	acornscsi_dumplogline(host, target, 1);
-	acornscsi_dumplogline(host, target, 2);
-
-	if (target == 8)
-	    break;
-
-	target = 8;
-    } while (1);
-}
-
-static
-char acornscsi_target(AS_Host *host)
-{
-	if (host->SCpnt)
-		return '0' + host->SCpnt->device->id;
-	return 'H';
-}
-
-/*
- * Prototype: cmdtype_t acornscsi_cmdtype(int command)
- * Purpose  : differentiate READ from WRITE from other commands
- * Params   : command - command to interpret
- * Returns  : CMD_READ	- command reads data,
- *	      CMD_WRITE - command writes data,
- *	      CMD_MISC	- everything else
- */
-static inline
-cmdtype_t acornscsi_cmdtype(int command)
-{
-    switch (command) {
-    case WRITE_6:  case WRITE_10:  case WRITE_12:
-	return CMD_WRITE;
-    case READ_6:   case READ_10:   case READ_12:
-	return CMD_READ;
-    default:
-	return CMD_MISC;
-    }
-}
-
-/*
- * Prototype: int acornscsi_datadirection(int command)
- * Purpose  : differentiate between commands that have a DATA IN phase
- *	      and a DATA OUT phase
- * Params   : command - command to interpret
- * Returns  : DATADIR_OUT - data out phase expected
- *	      DATADIR_IN  - data in phase expected
- */
-static
-datadir_t acornscsi_datadirection(int command)
-{
-    switch (command) {
-    case CHANGE_DEFINITION:	case COMPARE:		case COPY:
-    case COPY_VERIFY:		case LOG_SELECT:	case MODE_SELECT:
-    case MODE_SELECT_10:	case SEND_DIAGNOSTIC:	case WRITE_BUFFER:
-    case FORMAT_UNIT:		case REASSIGN_BLOCKS:	case RESERVE:
-    case SEARCH_EQUAL:		case SEARCH_HIGH:	case SEARCH_LOW:
-    case WRITE_6:		case WRITE_10:		case WRITE_VERIFY:
-    case UPDATE_BLOCK:		case WRITE_LONG:	case WRITE_SAME:
-    case SEARCH_HIGH_12:	case SEARCH_EQUAL_12:	case SEARCH_LOW_12:
-    case WRITE_12:		case WRITE_VERIFY_12:	case SET_WINDOW:
-    case MEDIUM_SCAN:		case SEND_VOLUME_TAG:	case 0xea:
-	return DATADIR_OUT;
-    default:
-	return DATADIR_IN;
-    }
-}
-
-/*
- * Purpose  : provide values for synchronous transfers with 33C93.
- * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
- *	Modified by Russell King for 8MHz WD33C93A
- */
-static struct sync_xfer_tbl {
-    unsigned int period_ns;
-    unsigned char reg_value;
-} sync_xfer_table[] = {
-    {	1, 0x20 },    { 249, 0x20 },	{ 374, 0x30 },
-    { 499, 0x40 },    { 624, 0x50 },	{ 749, 0x60 },
-    { 874, 0x70 },    { 999, 0x00 },	{   0,	  0 }
-};
-
-/*
- * Prototype: int acornscsi_getperiod(unsigned char syncxfer)
- * Purpose  : period for the synchronous transfer setting
- * Params   : syncxfer SYNCXFER register value
- * Returns  : period in ns.
- */
-static
-int acornscsi_getperiod(unsigned char syncxfer)
-{
-    int i;
-
-    syncxfer &= 0xf0;
-    if (syncxfer == 0x10)
-	syncxfer = 0;
-
-    for (i = 1; sync_xfer_table[i].period_ns; i++)
-	if (syncxfer == sync_xfer_table[i].reg_value)
-	    return sync_xfer_table[i].period_ns;
-    return 0;
-}
-
-/*
- * Prototype: int round_period(unsigned int period)
- * Purpose  : return index into above table for a required REQ period
- * Params   : period - time (ns) for REQ
- * Returns  : table index
- * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
- */
-static inline
-int round_period(unsigned int period)
-{
-    int i;
-
-    for (i = 1; sync_xfer_table[i].period_ns; i++) {
-	if ((period <= sync_xfer_table[i].period_ns) &&
-	    (period > sync_xfer_table[i - 1].period_ns))
-	    return i;
-    }
-    return 7;
-}
-
-/*
- * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
- * Purpose  : calculate value for 33c93s SYNC register
- * Params   : period - time (ns) for REQ
- *	      offset - offset in bytes between REQ/ACK
- * Returns  : value for SYNC register
- * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
- */
-static
-unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
-{
-    return sync_xfer_table[round_period(period)].reg_value |
-		((offset < SDTR_SIZE) ? offset : SDTR_SIZE);
-}
-
-/* ====================================================================================
- * Command functions
- */
-/*
- * Function: acornscsi_kick(AS_Host *host)
- * Purpose : kick next command to interface
- * Params  : host - host to send command to
- * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING
- * Notes   : interrupts are always disabled!
- */
-static
-intr_ret_t acornscsi_kick(AS_Host *host)
-{
-    int from_queue = 0;
-    Scsi_Cmnd *SCpnt;
-
-    /* first check to see if a command is waiting to be executed */
-    SCpnt = host->origSCpnt;
-    host->origSCpnt = NULL;
-
-    /* retrieve next command */
-    if (!SCpnt) {
-	SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns);
-	if (!SCpnt)
-	    return INTR_IDLE;
-
-	from_queue = 1;
-    }
-
-    if (host->scsi.disconnectable && host->SCpnt) {
-	queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
-	host->scsi.disconnectable = 0;
-#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-	DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n",
-		host->host->host_no, acornscsi_target(host)));
-#endif
-	host->SCpnt = NULL;
-    }
-
-    /*
-     * If we have an interrupt pending, then we may have been reselected.
-     * In this case, we don't want to write to the registers
-     */
-    if (!(sbic_arm_read(host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
-	sbic_arm_write(host->scsi.io_port, DESTID, SCpnt->device->id);
-	sbic_arm_write(host->scsi.io_port, CMND, CMND_SELWITHATN);
-    }
-
-    /*
-     * claim host busy - all of these must happen atomically wrt
-     * our interrupt routine.  Failure means command loss.
-     */
-    host->scsi.phase = PHASE_CONNECTING;
-    host->SCpnt = SCpnt;
-    host->scsi.SCp = SCpnt->SCp;
-    host->dma.xfer_setup = 0;
-    host->dma.xfer_required = 0;
-    host->dma.xfer_done = 0;
-
-#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT))
-    DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n",
-	    host->host->host_no, '0' + SCpnt->device->id,
-	    SCpnt->cmnd[0]));
-#endif
-
-    if (from_queue) {
-#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
-	/*
-	 * tagged queueing - allocate a new tag to this command
-	 */
-	if (SCpnt->device->tagged_queue) {
-	    SCpnt->device->current_tag += 1;
-	    if (SCpnt->device->current_tag == 0)
-		SCpnt->device->current_tag = 1;
-	    SCpnt->tag = SCpnt->device->current_tag;
-	} else
-#endif
-	    set_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns);
-
-	host->stats.removes += 1;
-
-	switch (acornscsi_cmdtype(SCpnt->cmnd[0])) {
-	case CMD_WRITE:
-	    host->stats.writes += 1;
-	    break;
-	case CMD_READ:
-	    host->stats.reads += 1;
-	    break;
-	case CMD_MISC:
-	    host->stats.miscs += 1;
-	    break;
-	}
-    }
-
-    return INTR_PROCESSING;
-}    
-
-/*
- * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
- * Purpose : complete processing for command
- * Params  : host   - interface that completed
- *	     result - driver byte of result
- */
-static
-void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
-{
-    Scsi_Cmnd *SCpnt = *SCpntp;
-
-    /* clean up */
-    sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
-
-    host->stats.fins += 1;
-
-    if (SCpnt) {
-	*SCpntp = NULL;
-
-	acornscsi_dma_cleanup(host);
-
-	SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status;
-
-	/*
-	 * In theory, this should not happen.  In practice, it seems to.
-	 * Only trigger an error if the device attempts to report all happy
-	 * but with untransferred buffers...  If we don't do something, then
-	 * data loss will occur.  Should we check SCpnt->underflow here?
-	 * It doesn't appear to be set to something meaningful by the higher
-	 * levels all the time.
-	 */
-	if (result == DID_OK) {
-		int xfer_warn = 0;
-
-		if (SCpnt->underflow == 0) {
-			if (host->scsi.SCp.ptr &&
-			    acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC)
-				xfer_warn = 1;
-		} else {
-			if (host->scsi.SCp.scsi_xferred < SCpnt->underflow ||
-			    host->scsi.SCp.scsi_xferred != host->dma.transferred)
-				xfer_warn = 1;
-		}
-
-		/* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6)
-		 *  Targets which break data transfers into multiple
-		 *  connections shall end each successful connection
-		 *  (except possibly the last) with a SAVE DATA
-		 *  POINTER - DISCONNECT message sequence.
-		 *
-		 * This makes it difficult to ensure that a transfer has
-		 * completed.  If we reach the end of a transfer during
-		 * the command, then we can only have finished the transfer.
-		 * therefore, if we seem to have some data remaining, this
-		 * is not a problem.
-		 */
-		if (host->dma.xfer_done)
-			xfer_warn = 0;
-
-		if (xfer_warn) {
-		    switch (status_byte(SCpnt->result)) {
-		    case CHECK_CONDITION:
-		    case COMMAND_TERMINATED:
-		    case BUSY:
-		    case QUEUE_FULL:
-		    case RESERVATION_CONFLICT:
-			break;
-
-		    default:
-			printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
-				host->host->host_no, SCpnt->result);
-			print_command(SCpnt->cmnd);
-			acornscsi_dumpdma(host, "done");
-		 	acornscsi_dumplog(host, SCpnt->device->id);
-			SCpnt->result &= 0xffff;
-			SCpnt->result |= DID_ERROR << 16;
-		    }
-		}
-	}
-
-	if (!SCpnt->scsi_done)
-	    panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no);
-
-	clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns);
-
-	SCpnt->scsi_done(SCpnt);
-    } else
-	printk("scsi%d: null command in acornscsi_done", host->host->host_no);
-
-    host->scsi.phase = PHASE_IDLE;
-}
-
-/* ====================================================================================
- * DMA routines
- */
-/*
- * Purpose  : update SCSI Data Pointer
- * Notes    : this will only be one SG entry or less
- */
-static
-void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length)
-{
-    SCp->ptr += length;
-    SCp->this_residual -= length;
-
-    if (SCp->this_residual == 0 && next_SCp(SCp) == 0)
-	host->dma.xfer_done = 1;
-}
-
-/*
- * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr,
- *				unsigned int start_addr, unsigned int length)
- * Purpose  : read data from DMA RAM
- * Params   : host - host to transfer from
- *	      ptr  - DRAM address
- *	      start_addr - host mem address
- *	      length - number of bytes to transfer
- * Notes    : this will only be one SG entry or less
- */
-static
-void acornscsi_data_read(AS_Host *host, char *ptr,
-				 unsigned int start_addr, unsigned int length)
-{
-    extern void __acornscsi_in(int port, char *buf, int len);
-    unsigned int page, offset, len = length;
-
-    page = (start_addr >> 12);
-    offset = start_addr & ((1 << 12) - 1);
-
-    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
-
-    while (len > 0) {
-	unsigned int this_len;
-
-	if (len + offset > (1 << 12))
-	    this_len = (1 << 12) - offset;
-	else
-	    this_len = len;
-
-	__acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len);
-
-	offset += this_len;
-	ptr += this_len;
-	len -= this_len;
-
-	if (offset == (1 << 12)) {
-	    offset = 0;
-	    page ++;
-	    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
-	}
-    }
-    outb(host->card.page_reg, host->card.io_page);
-}
-
-/*
- * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr,
- *				unsigned int start_addr, unsigned int length)
- * Purpose  : write data to DMA RAM
- * Params   : host - host to transfer from
- *	      ptr  - DRAM address
- *	      start_addr - host mem address
- *	      length - number of bytes to transfer
- * Notes    : this will only be one SG entry or less
- */
-static
-void acornscsi_data_write(AS_Host *host, char *ptr,
-				 unsigned int start_addr, unsigned int length)
-{
-    extern void __acornscsi_out(int port, char *buf, int len);
-    unsigned int page, offset, len = length;
-
-    page = (start_addr >> 12);
-    offset = start_addr & ((1 << 12) - 1);
-
-    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
-
-    while (len > 0) {
-	unsigned int this_len;
-
-	if (len + offset > (1 << 12))
-	    this_len = (1 << 12) - offset;
-	else
-	    this_len = len;
-
-	__acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len);
-
-	offset += this_len;
-	ptr += this_len;
-	len -= this_len;
-
-	if (offset == (1 << 12)) {
-	    offset = 0;
-	    page ++;
-	    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
-	}
-    }
-    outb(host->card.page_reg, host->card.io_page);
-}
-
-/* =========================================================================================
- * On-board DMA routines
- */
-#ifdef USE_DMAC
-/*
- * Prototype: void acornscsi_dmastop(AS_Host *host)
- * Purpose  : stop all DMA
- * Params   : host - host on which to stop DMA
- * Notes    : This is called when leaving DATA IN/OUT phase,
- *	      or when interface is RESET
- */
-static inline
-void acornscsi_dma_stop(AS_Host *host)
-{
-    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
-    dmac_clearintr(host->dma.io_intr_clear);
-
-#if (DEBUG & DEBUG_DMA)
-    DBG(host->SCpnt, acornscsi_dumpdma(host, "stop"));
-#endif
-}
-
-/*
- * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
- * Purpose : setup DMA controller for data transfer
- * Params  : host - host to setup
- *	     direction - data transfer direction
- * Notes   : This is called when entering DATA I/O phase, not
- *	     while we're in a DATA I/O phase
- */
-static
-void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
-{
-    unsigned int address, length, mode;
-
-    host->dma.direction = direction;
-
-    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
-
-    if (direction == DMA_OUT) {
-#if (DEBUG & DEBUG_NO_WRITE)
-	if (NO_WRITE & (1 << host->SCpnt->device->id)) {
-	    printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",
-		    host->host->host_no, acornscsi_target(host));
-	    return;
-	}
-#endif
-	mode = DMAC_WRITE;
-    } else
-	mode = DMAC_READ;
-
-    /*
-     * Allocate some buffer space, limited to half the buffer size
-     */
-    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
-    if (length) {
-	host->dma.start_addr = address = host->dma.free_addr;
-	host->dma.free_addr = (host->dma.free_addr + length) &
-				(DMAC_BUFFER_SIZE - 1);
-
-	/*
-	 * Transfer data to DMA memory
-	 */
-	if (direction == DMA_OUT)
-	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
-				length);
-
-	length -= 1;
-	dmac_write(host->dma.io_port, TXCNTLO, length);
-	dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
-	dmac_write(host->dma.io_port, TXADRLO, address);
-	dmac_write(host->dma.io_port, TXADRMD, address >> 8);
-	dmac_write(host->dma.io_port, TXADRHI, 0);
-	dmac_write(host->dma.io_port, MODECON, mode);
-	dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
-
-#if (DEBUG & DEBUG_DMA)
-	DBG(host->SCpnt, acornscsi_dumpdma(host, "strt"));
-#endif
-	host->dma.xfer_setup = 1;
-    }
-}
-
-/*
- * Function: void acornscsi_dma_cleanup(AS_Host *host)
- * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct
- * Params  : host - host to finish
- * Notes   : This is called when a command is:
- *		terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT
- *	   : This must not return until all transfers are completed.
- */
-static
-void acornscsi_dma_cleanup(AS_Host *host)
-{
-    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
-    dmac_clearintr(host->dma.io_intr_clear);
-
-    /*
-     * Check for a pending transfer
-     */
-    if (host->dma.xfer_required) {
-	host->dma.xfer_required = 0;
-	if (host->dma.direction == DMA_IN)
-	    acornscsi_data_read(host, host->dma.xfer_ptr,
-				 host->dma.xfer_start, host->dma.xfer_length);
-    }
-
-    /*
-     * Has a transfer been setup?
-     */
-    if (host->dma.xfer_setup) {
-	unsigned int transferred;
-
-	host->dma.xfer_setup = 0;
-
-#if (DEBUG & DEBUG_DMA)
-	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupi"));
-#endif
-
-	/*
-	 * Calculate number of bytes transferred from DMA.
-	 */
-	transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
-	host->dma.transferred += transferred;
-
-	if (host->dma.direction == DMA_IN)
-	    acornscsi_data_read(host, host->scsi.SCp.ptr,
-				 host->dma.start_addr, transferred);
-
-	/*
-	 * Update SCSI pointers
-	 */
-	acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
-#if (DEBUG & DEBUG_DMA)
-	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo"));
-#endif
-    }
-}
-
-/*
- * Function: void acornscsi_dmacintr(AS_Host *host)
- * Purpose : handle interrupts from DMAC device
- * Params  : host - host to process
- * Notes   : If reading, we schedule the read to main memory &
- *	     allow the transfer to continue.
- *	   : If writing, we fill the onboard DMA memory from main
- *	     memory.
- *	   : Called whenever DMAC finished it's current transfer.
- */
-static
-void acornscsi_dma_intr(AS_Host *host)
-{
-    unsigned int address, length, transferred;
-
-#if (DEBUG & DEBUG_DMA)
-    DBG(host->SCpnt, acornscsi_dumpdma(host, "inti"));
-#endif
-
-    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
-    dmac_clearintr(host->dma.io_intr_clear);
-
-    /*
-     * Calculate amount transferred via DMA
-     */
-    transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
-    host->dma.transferred += transferred;
-
-    /*
-     * Schedule DMA transfer off board
-     */
-    if (host->dma.direction == DMA_IN) {
-	host->dma.xfer_start = host->dma.start_addr;
-	host->dma.xfer_length = transferred;
-	host->dma.xfer_ptr = host->scsi.SCp.ptr;
-	host->dma.xfer_required = 1;
-    }
-
-    acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
-
-    /*
-     * Allocate some buffer space, limited to half the on-board RAM size
-     */
-    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
-    if (length) {
-	host->dma.start_addr = address = host->dma.free_addr;
-	host->dma.free_addr = (host->dma.free_addr + length) &
-				(DMAC_BUFFER_SIZE - 1);
-
-	/*
-	 * Transfer data to DMA memory
-	 */
-	if (host->dma.direction == DMA_OUT)
-	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
-				length);
-
-	length -= 1;
-	dmac_write(host->dma.io_port, TXCNTLO, length);
-	dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
-	dmac_write(host->dma.io_port, TXADRLO, address);
-	dmac_write(host->dma.io_port, TXADRMD, address >> 8);
-	dmac_write(host->dma.io_port, TXADRHI, 0);
-	dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
-
-#if (DEBUG & DEBUG_DMA)
-	DBG(host->SCpnt, acornscsi_dumpdma(host, "into"));
-#endif
-    } else {
-	host->dma.xfer_setup = 0;
-#if 0
-	/*
-	 * If the interface still wants more, then this is an error.
-	 * We give it another byte, but we also attempt to raise an
-	 * attention condition.  We continue giving one byte until
-	 * the device recognises the attention.
-	 */
-	if (dmac_read(host->dma.io_port, STATUS) & STATUS_RQ0) {
-	    acornscsi_abortcmd(host, host->SCpnt->tag);
-
-	    dmac_write(host->dma.io_port, TXCNTLO, 0);
-	    dmac_write(host->dma.io_port, TXCNTHI, 0);
-	    dmac_write(host->dma.io_port, TXADRLO, 0);
-	    dmac_write(host->dma.io_port, TXADRMD, 0);
-	    dmac_write(host->dma.io_port, TXADRHI, 0);
-	    dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
-	}
-#endif
-    }
-}
-
-/*
- * Function: void acornscsi_dma_xfer(AS_Host *host)
- * Purpose : transfer data between AcornSCSI and memory
- * Params  : host - host to process
- */
-static
-void acornscsi_dma_xfer(AS_Host *host)
-{
-    host->dma.xfer_required = 0;
-
-    if (host->dma.direction == DMA_IN)
-	acornscsi_data_read(host, host->dma.xfer_ptr,
-				host->dma.xfer_start, host->dma.xfer_length);
-}
-
-/*
- * Function: void acornscsi_dma_adjust(AS_Host *host)
- * Purpose : adjust DMA pointers & count for bytes transferred to
- *	     SBIC but not SCSI bus.
- * Params  : host - host to adjust DMA count for
- */
-static
-void acornscsi_dma_adjust(AS_Host *host)
-{
-    if (host->dma.xfer_setup) {
-	signed long transferred;
-#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
-	DBG(host->SCpnt, acornscsi_dumpdma(host, "adji"));
-#endif
-	/*
-	 * Calculate correct DMA address - DMA is ahead of SCSI bus while
-	 * writing.
-	 *  host->scsi.SCp.scsi_xferred is the number of bytes
-	 *  actually transferred to/from the SCSI bus.
-	 *  host->dma.transferred is the number of bytes transferred
-	 *  over DMA since host->dma.start_addr was last set.
-	 *
-	 * real_dma_addr = host->dma.start_addr + host->scsi.SCp.scsi_xferred
-	 *		   - host->dma.transferred
-	 */
-	transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred;
-	if (transferred < 0)
-	    printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",
-		    host->host->host_no, acornscsi_target(host), transferred);
-	else if (transferred == 0)
-	    host->dma.xfer_setup = 0;
-	else {
-	    transferred += host->dma.start_addr;
-	    dmac_write(host->dma.io_port, TXADRLO, transferred);
-	    dmac_write(host->dma.io_port, TXADRMD, transferred >> 8);
-	    dmac_write(host->dma.io_port, TXADRHI, transferred >> 16);
-#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
-	    DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo"));
-#endif
-	}
-    }
-}
-#endif
-
-/* =========================================================================================
- * Data I/O
- */
-static int
-acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout)
-{
-	unsigned int asr, timeout = max_timeout;
-	int my_ptr = *ptr;
-
-	while (my_ptr < len) {
-		asr = sbic_arm_read(host->scsi.io_port, ASR);
-
-		if (asr & ASR_DBR) {
-			timeout = max_timeout;
-
-			sbic_arm_write(host->scsi.io_port, DATA, bytes[my_ptr++]);
-		} else if (asr & ASR_INT)
-			break;
-		else if (--timeout == 0)
-			break;
-		udelay(1);
-	}
-
-	*ptr = my_ptr;
-
-	return (timeout == 0) ? -1 : 0;
-}
-
-/*
- * Function: void acornscsi_sendcommand(AS_Host *host)
- * Purpose : send a command to a target
- * Params  : host - host which is connected to target
- */
-static void
-acornscsi_sendcommand(AS_Host *host)
-{
-    Scsi_Cmnd *SCpnt = host->SCpnt;
-
-    sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
-    sbic_arm_writenext(host->scsi.io_port, 0);
-    sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command);
-
-    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
-
-    if (acornscsi_write_pio(host, SCpnt->cmnd,
-	(int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000))
-	printk("scsi%d: timeout while sending command\n", host->host->host_no);
-
-    host->scsi.phase = PHASE_COMMAND;
-}
-
-static
-void acornscsi_sendmessage(AS_Host *host)
-{
-    unsigned int message_length = msgqueue_msglength(&host->scsi.msgs);
-    unsigned int msgnr;
-    struct message *msg;
-
-#if (DEBUG & DEBUG_MESSAGES)
-    printk("scsi%d.%c: sending message ",
-	    host->host->host_no, acornscsi_target(host));
-#endif
-
-    switch (message_length) {
-    case 0:
-	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
-
-	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1");
-
-	sbic_arm_write(host->scsi.io_port, DATA, NOP);
-
-	host->scsi.last_message = NOP;
-#if (DEBUG & DEBUG_MESSAGES)
-	printk("NOP");
-#endif
-	break;
-
-    case 1:
-	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
-	msg = msgqueue_getmsg(&host->scsi.msgs, 0);
-
-	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2");
-
-	sbic_arm_write(host->scsi.io_port, DATA, msg->msg[0]);
-
-	host->scsi.last_message = msg->msg[0];
-#if (DEBUG & DEBUG_MESSAGES)
-	print_msg(msg->msg);
-#endif
-	break;
-
-    default:
-	/*
-	 * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14)
-	 * 'When a target sends this (MESSAGE_REJECT) message, it
-	 *  shall change to MESSAGE IN phase and send this message
-	 *  prior to requesting additional message bytes from the
-	 *  initiator.  This provides an interlock so that the
-	 *  initiator can determine which message byte is rejected.
-	 */
-	sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
-	sbic_arm_writenext(host->scsi.io_port, 0);
-	sbic_arm_writenext(host->scsi.io_port, message_length);
-	acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
-
-	msgnr = 0;
-	while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) {
-	    unsigned int i;
-#if (DEBUG & DEBUG_MESSAGES)
-	    print_msg(msg);
-#endif
-	    i = 0;
-	    if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000))
-		printk("scsi%d: timeout while sending message\n", host->host->host_no);
-
-	    host->scsi.last_message = msg->msg[0];
-	    if (msg->msg[0] == EXTENDED_MESSAGE)
-		host->scsi.last_message |= msg->msg[2] << 8;
-
-	    if (i != msg->length)
-		break;
-	}
-	break;
-    }
-#if (DEBUG & DEBUG_MESSAGES)
-    printk("\n");
-#endif
-}
-
-/*
- * Function: void acornscsi_readstatusbyte(AS_Host *host)
- * Purpose : Read status byte from connected target
- * Params  : host - host connected to target
- */
-static
-void acornscsi_readstatusbyte(AS_Host *host)
-{
-    acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT);
-    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte");
-    host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, DATA);
-}
-
-/*
- * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host)
- * Purpose : Read one message byte from connected target
- * Params  : host - host connected to target
- */
-static
-unsigned char acornscsi_readmessagebyte(AS_Host *host)
-{
-    unsigned char message;
-
-    acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
-
-    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte");
-
-    message = sbic_arm_read(host->scsi.io_port, DATA);
-
-    /* wait for MSGIN-XFER-PAUSED */
-    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte");
-
-    sbic_arm_read(host->scsi.io_port, SSR);
-
-    return message;
-}
-
-/*
- * Function: void acornscsi_message(AS_Host *host)
- * Purpose : Read complete message from connected target & action message
- * Params  : host - host connected to target
- */
-static
-void acornscsi_message(AS_Host *host)
-{
-    unsigned char message[16];
-    unsigned int msgidx = 0, msglen = 1;
-
-    do {
-	message[msgidx] = acornscsi_readmessagebyte(host);
-
-	switch (msgidx) {
-	case 0:
-	    if (message[0] == EXTENDED_MESSAGE ||
-		(message[0] >= 0x20 && message[0] <= 0x2f))
-		msglen = 2;
-	    break;
-
-	case 1:
-	    if (message[0] == EXTENDED_MESSAGE)
-		msglen += message[msgidx];
-	    break;
-	}
-	msgidx += 1;
-	if (msgidx < msglen) {
-	    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
-
-	    /* wait for next msg-in */
-	    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack");
-	    sbic_arm_read(host->scsi.io_port, SSR);
-	}
-    } while (msgidx < msglen);
-
-#if (DEBUG & DEBUG_MESSAGES)
-    printk("scsi%d.%c: message in: ",
-	    host->host->host_no, acornscsi_target(host));
-    print_msg(message);
-    printk("\n");
-#endif
-
-    if (host->scsi.phase == PHASE_RECONNECTED) {
-	/*
-	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)
-	 * 'Whenever a target reconnects to an initiator to continue
-	 *  a tagged I/O process, the SIMPLE QUEUE TAG message shall
-	 *  be sent immediately following the IDENTIFY message...'
-	 */
-	if (message[0] == SIMPLE_QUEUE_TAG)
-	    host->scsi.reconnected.tag = message[1];
-	if (acornscsi_reconnect_finish(host))
-	    host->scsi.phase = PHASE_MSGIN;
-    }
-
-    switch (message[0]) {
-    case ABORT:
-    case ABORT_TAG:
-    case COMMAND_COMPLETE:
-	if (host->scsi.phase != PHASE_STATUSIN) {
-	    printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n",
-		    host->host->host_no, acornscsi_target(host));
-	    acornscsi_dumplog(host, host->SCpnt->device->id);
-	}
-	host->scsi.phase = PHASE_DONE;
-	host->scsi.SCp.Message = message[0];
-	break;
-
-    case SAVE_POINTERS:
-	/*
-	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20)
-	 * 'The SAVE DATA POINTER message is sent from a target to
-	 *  direct the initiator to copy the active data pointer to
-	 *  the saved data pointer for the current I/O process.
-	 */
-	acornscsi_dma_cleanup(host);
-	host->SCpnt->SCp = host->scsi.SCp;
-	host->SCpnt->SCp.sent_command = 0;
-	host->scsi.phase = PHASE_MSGIN;
-	break;
-
-    case RESTORE_POINTERS:
-	/*
-	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19)
-	 * 'The RESTORE POINTERS message is sent from a target to
-	 *  direct the initiator to copy the most recently saved
-	 *  command, data, and status pointers for the I/O process
-	 *  to the corresponding active pointers.  The command and
-	 *  status pointers shall be restored to the beginning of
-	 *  the present command and status areas.'
-	 */
-	acornscsi_dma_cleanup(host);
-	host->scsi.SCp = host->SCpnt->SCp;
-	host->scsi.phase = PHASE_MSGIN;
-	break;
-
-    case DISCONNECT:
-	/*
-	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2)
-	 * 'On those occasions when an error or exception condition occurs
-	 *  and the target elects to repeat the information transfer, the
-	 *  target may repeat the transfer either issuing a RESTORE POINTERS
-	 *  message or by disconnecting without issuing a SAVE POINTERS
-	 *  message.  When reconnection is completed, the most recent
-	 *  saved pointer values are restored.'
-	 */
-	acornscsi_dma_cleanup(host);
-	host->scsi.phase = PHASE_DISCONNECT;
-	break;
-
-    case MESSAGE_REJECT:
-#if 0 /* this isn't needed any more */
-	/*
-	 * If we were negociating sync transfer, we don't yet know if
-	 * this REJECT is for the sync transfer or for the tagged queue/wide
-	 * transfer.  Re-initiate sync transfer negociation now, and if
-	 * we got a REJECT in response to SDTR, then it'll be set to DONE.
-	 */
-	if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST)
-	    host->device[host->SCpnt->device->id].sync_state = SYNC_NEGOCIATE;
-#endif
-
-	/*
-	 * If we have any messages waiting to go out, then assert ATN now
-	 */
-	if (msgqueue_msglength(&host->scsi.msgs))
-	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
-
-	switch (host->scsi.last_message) {
-#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
-	case HEAD_OF_QUEUE_TAG:
-	case ORDERED_QUEUE_TAG:
-	case SIMPLE_QUEUE_TAG:
-	    /*
-	     * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)
-	     *  If a target does not implement tagged queuing and a queue tag
-	     *  message is received, it shall respond with a MESSAGE REJECT
-	     *  message and accept the I/O process as if it were untagged.
-	     */
-	    printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",
-		    host->host->host_no, acornscsi_target(host));
-	    host->SCpnt->device->tagged_queue = 0;
-	    set_bit(host->SCpnt->device->id * 8 + host->SCpnt->device->lun, host->busyluns);
-	    break;
-#endif
-	case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8):
-	    /*
-	     * Target can't handle synchronous transfers
-	     */
-	    printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",
-		    host->host->host_no, acornscsi_target(host));
-	    host->device[host->SCpnt->device->id].sync_xfer = SYNCHTRANSFER_2DBA;
-	    host->device[host->SCpnt->device->id].sync_state = SYNC_ASYNCHRONOUS;
-	    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
-	    break;
-
-	default:
-	    break;
-	}
-	break;
-
-    case QUEUE_FULL:
-	/* TODO: target queue is full */
-	break;
-
-    case SIMPLE_QUEUE_TAG:
-	/* tag queue reconnect... message[1] = queue tag.  Print something to indicate something happened! */
-	printk("scsi%d.%c: reconnect queue tag %02X\n",
-		host->host->host_no, acornscsi_target(host),
-		message[1]);
-	break;
-
-    case EXTENDED_MESSAGE:
-	switch (message[2]) {
-#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
-	case EXTENDED_SDTR:
-	    if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST) {
-		/*
-		 * We requested synchronous transfers.  This isn't quite right...
-		 * We can only say if this succeeded if we proceed on to execute the
-		 * command from this message.  If we get a MESSAGE PARITY ERROR,
-		 * and the target retries fail, then we fallback to asynchronous mode
-		 */
-		host->device[host->SCpnt->device->id].sync_state = SYNC_COMPLETED;
-		printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",
-			host->host->host_no, acornscsi_target(host),
-			message[4], message[3] * 4);
-		host->device[host->SCpnt->device->id].sync_xfer =
-			calc_sync_xfer(message[3] * 4, message[4]);
-	    } else {
-		unsigned char period, length;
-		/*
-		 * Target requested synchronous transfers.  The agreement is only
-		 * to be in operation AFTER the target leaves message out phase.
-		 */
-		acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
-		period = max_t(unsigned int, message[3], sdtr_period / 4);
-		length = min_t(unsigned int, message[4], sdtr_size);
-		msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,
-				 EXTENDED_SDTR, period, length);
-		host->device[host->SCpnt->device->id].sync_xfer =
-			calc_sync_xfer(period * 4, length);
-	    }
-	    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
-	    break;
-#else
-	    /* We do not accept synchronous transfers.  Respond with a
-	     * MESSAGE_REJECT.
-	     */
-#endif
-
-	case EXTENDED_WDTR:
-	    /* The WD33C93A is only 8-bit.  We respond with a MESSAGE_REJECT
-	     * to a wide data transfer request.
-	     */
-	default:
-	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
-	    msgqueue_flush(&host->scsi.msgs);
-	    msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
-	    break;
-	}
-	break;
-
-#ifdef CONFIG_SCSI_ACORNSCSI_LINK
-    case LINKED_CMD_COMPLETE:
-    case LINKED_FLG_CMD_COMPLETE:
-	/*
-	 * We don't support linked commands yet
-	 */
-	if (0) {
-#if (DEBUG & DEBUG_LINK)
-	    printk("scsi%d.%c: lun %d tag %d linked command complete\n",
-		    host->host->host_no, acornscsi_target(host), host->SCpnt->tag);
-#endif
-	    /*
-	     * A linked command should only terminate with one of these messages
-	     * if there are more linked commands available.
-	     */
-	    if (!host->SCpnt->next_link) {
-		printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n",
-			instance->host_no, acornscsi_target(host), host->SCpnt->tag);
-		acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
-		msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
-	    } else {
-		Scsi_Cmnd *SCpnt = host->SCpnt;
-
-		acornscsi_dma_cleanup(host);
-
-		host->SCpnt = host->SCpnt->next_link;
-		host->SCpnt->tag = SCpnt->tag;
-		SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status;
-		SCpnt->done(SCpnt);
-
-		/* initialise host->SCpnt->SCp */
-	    }
-	    break;
-	}
-#endif
-
-    default: /* reject message */
-	printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",
-		host->host->host_no, acornscsi_target(host),
-		message[0]);
-	acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
-	msgqueue_flush(&host->scsi.msgs);
-	msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
-	host->scsi.phase = PHASE_MSGIN;
-	break;
-    }
-    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
-}
-
-/*
- * Function: int acornscsi_buildmessages(AS_Host *host)
- * Purpose : build the connection messages for a host
- * Params  : host - host to add messages to
- */
-static
-void acornscsi_buildmessages(AS_Host *host)
-{
-#if 0
-    /* does the device need resetting? */
-    if (cmd_reset) {
-	msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET);
-	return;
-    }
-#endif
-
-    msgqueue_addmsg(&host->scsi.msgs, 1,
-		     IDENTIFY(host->device[host->SCpnt->device->id].disconnect_ok,
-			     host->SCpnt->device->lun));
-
-#if 0
-    /* does the device need the current command aborted */
-    if (cmd_aborted) {
-	acornscsi_abortcmd(host->SCpnt->tag);
-	return;
-    }
-#endif
-
-#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
-    if (host->SCpnt->tag) {
-	unsigned int tag_type;
-
-	if (host->SCpnt->cmnd[0] == REQUEST_SENSE ||
-	    host->SCpnt->cmnd[0] == TEST_UNIT_READY ||
-	    host->SCpnt->cmnd[0] == INQUIRY)
-	    tag_type = HEAD_OF_QUEUE_TAG;
-	else
-	    tag_type = SIMPLE_QUEUE_TAG;
-	msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag);
-    }
-#endif
-
-#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
-    if (host->device[host->SCpnt->device->id].sync_state == SYNC_NEGOCIATE) {
-	host->device[host->SCpnt->device->id].sync_state = SYNC_SENT_REQUEST;
-	msgqueue_addmsg(&host->scsi.msgs, 5,
-			 EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
-			 sdtr_period / 4, sdtr_size);
-    }
-#endif
-}
-
-/*
- * Function: int acornscsi_starttransfer(AS_Host *host)
- * Purpose : transfer data to/from connected target
- * Params  : host - host to which target is connected
- * Returns : 0 if failure
- */
-static
-int acornscsi_starttransfer(AS_Host *host)
-{
-    int residual;
-
-    if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) {
-	printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",
-		host->host->host_no, acornscsi_target(host));
-	return 0;
-    }
-
-    residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred;
-
-    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
-    sbic_arm_writenext(host->scsi.io_port, residual >> 16);
-    sbic_arm_writenext(host->scsi.io_port, residual >> 8);
-    sbic_arm_writenext(host->scsi.io_port, residual);
-    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
-    return 1;
-}
-
-/* =========================================================================================
- * Connection & Disconnection
- */
-/*
- * Function : acornscsi_reconnect(AS_Host *host)
- * Purpose  : reconnect a previously disconnected command
- * Params   : host - host specific data
- * Remarks  : SCSI spec says:
- *		'The set of active pointers is restored from the set
- *		 of saved pointers upon reconnection of the I/O process'
- */
-static
-int acornscsi_reconnect(AS_Host *host)
-{
-    unsigned int target, lun, ok = 0;
-
-    target = sbic_arm_read(host->scsi.io_port, SOURCEID);
-
-    if (!(target & 8))
-	printk(KERN_ERR "scsi%d: invalid source id after reselection "
-		"- device fault?\n",
-		host->host->host_no);
-
-    target &= 7;
-
-    if (host->SCpnt && !host->scsi.disconnectable) {
-	printk(KERN_ERR "scsi%d.%d: reconnected while command in "
-		"progress to target %d?\n",
-		host->host->host_no, target, host->SCpnt->device->id);
-	host->SCpnt = NULL;
-    }
-
-    lun = sbic_arm_read(host->scsi.io_port, DATA) & 7;
-
-    host->scsi.reconnected.target = target;
-    host->scsi.reconnected.lun = lun;
-    host->scsi.reconnected.tag = 0;
-
-    if (host->scsi.disconnectable && host->SCpnt &&
-	host->SCpnt->device->id == target && host->SCpnt->device->lun == lun)
-	ok = 1;
-
-    if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun))
-	ok = 1;
-
-    ADD_STATUS(target, 0x81, host->scsi.phase, 0);
-
-    if (ok) {
-	host->scsi.phase = PHASE_RECONNECTED;
-    } else {
-	/* this doesn't seem to work */
-	printk(KERN_ERR "scsi%d.%c: reselected with no command "
-		"to reconnect with\n",
-		host->host->host_no, '0' + target);
-	acornscsi_dumplog(host, target);
-	acornscsi_abortcmd(host, 0);
-	if (host->SCpnt) {
-	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
-	    host->SCpnt = NULL;
-	}
-    }
-    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
-    return !ok;
-}
-
-/*
- * Function: int acornscsi_reconect_finish(AS_Host *host)
- * Purpose : finish reconnecting a command
- * Params  : host - host to complete
- * Returns : 0 if failed
- */
-static
-int acornscsi_reconnect_finish(AS_Host *host)
-{
-    if (host->scsi.disconnectable && host->SCpnt) {
-	host->scsi.disconnectable = 0;
-	if (host->SCpnt->device->id  == host->scsi.reconnected.target &&
-	    host->SCpnt->device->lun == host->scsi.reconnected.lun &&
-	    host->SCpnt->tag         == host->scsi.reconnected.tag) {
-#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-	    DBG(host->SCpnt, printk("scsi%d.%c: reconnected",
-		    host->host->host_no, acornscsi_target(host)));
-#endif
-	} else {
-	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
-#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-	    DBG(host->SCpnt, printk("scsi%d.%c: had to move command "
-		    "to disconnected queue\n",
-		    host->host->host_no, acornscsi_target(host)));
-#endif
-	    host->SCpnt = NULL;
-	}
-    }
-    if (!host->SCpnt) {
-	host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected,
-				host->scsi.reconnected.target,
-				host->scsi.reconnected.lun,
-				host->scsi.reconnected.tag);
-#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-	DBG(host->SCpnt, printk("scsi%d.%c: had to get command",
-		host->host->host_no, acornscsi_target(host)));
-#endif
-    }
-
-    if (!host->SCpnt)
-	acornscsi_abortcmd(host, host->scsi.reconnected.tag);
-    else {
-	/*
-	 * Restore data pointer from SAVED pointers.
-	 */
-	host->scsi.SCp = host->SCpnt->SCp;
-#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-	printk(", data pointers: [%p, %X]",
-		host->scsi.SCp.ptr, host->scsi.SCp.this_residual);
-#endif
-    }
-#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
-    printk("\n");
-#endif
-
-    host->dma.transferred = host->scsi.SCp.scsi_xferred;
-
-    return host->SCpnt != NULL;
-}
-
-/*
- * Function: void acornscsi_disconnect_unexpected(AS_Host *host)
- * Purpose : handle an unexpected disconnect
- * Params  : host - host on which disconnect occurred
- */
-static
-void acornscsi_disconnect_unexpected(AS_Host *host)
-{
-    printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n",
-	    host->host->host_no, acornscsi_target(host));
-#if (DEBUG & DEBUG_ABORT)
-    acornscsi_dumplog(host, 8);
-#endif
-
-    acornscsi_done(host, &host->SCpnt, DID_ERROR);
-}
-
-/*
- * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag)
- * Purpose : abort a currently executing command
- * Params  : host - host with connected command to abort
- *	     tag  - tag to abort
- */
-static
-void acornscsi_abortcmd(AS_Host *host, unsigned char tag)
-{
-    host->scsi.phase = PHASE_ABORTED;
-    sbic_arm_write(host->scsi.io_port, CMND, CMND_ASSERTATN);
-
-    msgqueue_flush(&host->scsi.msgs);
-#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
-    if (tag)
-	msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag);
-    else
-#endif
-	msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
-}
-
-/* ==========================================================================================
- * Interrupt routines.
- */
-/*
- * Function: int acornscsi_sbicintr(AS_Host *host)
- * Purpose : handle interrupts from SCSI device
- * Params  : host - host to process
- * Returns : INTR_PROCESS if expecting another SBIC interrupt
- *	     INTR_IDLE if no interrupt
- *	     INTR_NEXT_COMMAND if we have finished processing the command
- */
-static
-intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
-{
-    unsigned int asr, ssr;
-
-    asr = sbic_arm_read(host->scsi.io_port, ASR);
-    if (!(asr & ASR_INT))
-	return INTR_IDLE;
-
-    ssr = sbic_arm_read(host->scsi.io_port, SSR);
-
-#if (DEBUG & DEBUG_PHASES)
-    print_sbic_status(asr, ssr, host->scsi.phase);
-#endif
-
-    ADD_STATUS(8, ssr, host->scsi.phase, in_irq);
-
-    if (host->SCpnt && !host->scsi.disconnectable)
-	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);
-
-    switch (ssr) {
-    case 0x00:				/* reset state - not advanced			*/
-	printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",
-		host->host->host_no);
-	/* setup sbic - WD33C93A */
-	sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
-	sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
-	return INTR_IDLE;
-
-    case 0x01:				/* reset state - advanced			*/
-	sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
-	sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
-	sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
-	sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
-	msgqueue_flush(&host->scsi.msgs);
-	return INTR_IDLE;
-
-    case 0x41:				/* unexpected disconnect aborted command	*/
-	acornscsi_disconnect_unexpected(host);
-	return INTR_NEXT_COMMAND;
-    }
-
-    switch (host->scsi.phase) {
-    case PHASE_CONNECTING:		/* STATE: command removed from issue queue	*/
-	switch (ssr) {
-	case 0x11:			/* -> PHASE_CONNECTED				*/
-	    /* BUS FREE -> SELECTION */
-	    host->scsi.phase = PHASE_CONNECTED;
-	    msgqueue_flush(&host->scsi.msgs);
-	    host->dma.transferred = host->scsi.SCp.scsi_xferred;
-	    /* 33C93 gives next interrupt indicating bus phase */
-	    asr = sbic_arm_read(host->scsi.io_port, ASR);
-	    if (!(asr & ASR_INT))
-		break;
-	    ssr = sbic_arm_read(host->scsi.io_port, SSR);
-	    ADD_STATUS(8, ssr, host->scsi.phase, 1);
-	    ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, 1);
-	    goto connected;
-	    
-	case 0x42:			/* select timed out				*/
-					/* -> PHASE_IDLE				*/
-	    acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT);
-	    return INTR_NEXT_COMMAND;
-
-	case 0x81:			/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/
-	    /* BUS FREE -> RESELECTION */
-	    host->origSCpnt = host->SCpnt;
-	    host->SCpnt = NULL;
-	    msgqueue_flush(&host->scsi.msgs);
-	    acornscsi_reconnect(host);
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	    acornscsi_abortcmd(host, host->SCpnt->tag);
-	}
-	return INTR_PROCESSING;
-
-    connected:
-    case PHASE_CONNECTED:		/* STATE: device selected ok			*/
-	switch (ssr) {
-#ifdef NONSTANDARD
-	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
-	    /* SELECTION -> COMMAND */
-	    acornscsi_sendcommand(host);
-	    break;
-
-	case 0x8b:			/* -> PHASE_STATUS				*/
-	    /* SELECTION -> STATUS */
-	    acornscsi_readstatusbyte(host);
-	    host->scsi.phase = PHASE_STATUSIN;
-	    break;
-#endif
-
-	case 0x8e:			/* -> PHASE_MSGOUT				*/
-	    /* SELECTION ->MESSAGE OUT */
-	    host->scsi.phase = PHASE_MSGOUT;
-	    acornscsi_buildmessages(host);
-	    acornscsi_sendmessage(host);
-	    break;
-
-	/* these should not happen */
-	case 0x85:			/* target disconnected				*/
-	    acornscsi_done(host, &host->SCpnt, DID_ERROR);
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	    acornscsi_abortcmd(host, host->SCpnt->tag);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_MSGOUT:			/* STATE: connected & sent IDENTIFY message	*/
-	/*
-	 * SCSI standard says that MESSAGE OUT phases can be followed by a
-	 * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase
-	 */
-	switch (ssr) {
-	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
-	case 0x1a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
-	    /* MESSAGE OUT -> COMMAND */
-	    acornscsi_sendcommand(host);
-	    break;
-
-	case 0x8b:			/* -> PHASE_STATUS				*/
-	case 0x1b:			/* -> PHASE_STATUS				*/
-	    /* MESSAGE OUT -> STATUS */
-	    acornscsi_readstatusbyte(host);
-	    host->scsi.phase = PHASE_STATUSIN;
-	    break;
-
-	case 0x8e:			/* -> PHASE_MSGOUT				*/
-	    /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */
-	    acornscsi_sendmessage(host);
-	    break;
-
-	case 0x4f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
-	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
-	    /* MESSAGE OUT -> MESSAGE IN */
-	    acornscsi_message(host);
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_COMMAND: 		/* STATE: connected & command sent		*/
-	switch (ssr) {
-	case 0x18:			/* -> PHASE_DATAOUT				*/
-	    /* COMMAND -> DATA OUT */
-	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
-		acornscsi_abortcmd(host, host->SCpnt->tag);
-	    acornscsi_dma_setup(host, DMA_OUT);
-	    if (!acornscsi_starttransfer(host))
-		acornscsi_abortcmd(host, host->SCpnt->tag);
-	    host->scsi.phase = PHASE_DATAOUT;
-	    return INTR_IDLE;
-
-	case 0x19:			/* -> PHASE_DATAIN				*/
-	    /* COMMAND -> DATA IN */
-	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
-		acornscsi_abortcmd(host, host->SCpnt->tag);
-	    acornscsi_dma_setup(host, DMA_IN);
-	    if (!acornscsi_starttransfer(host))
-		acornscsi_abortcmd(host, host->SCpnt->tag);
-	    host->scsi.phase = PHASE_DATAIN;
-	    return INTR_IDLE;
-
-	case 0x1b:			/* -> PHASE_STATUS				*/
-	    /* COMMAND -> STATUS */
-	    acornscsi_readstatusbyte(host);
-	    host->scsi.phase = PHASE_STATUSIN;
-	    break;
-
-	case 0x1e:			/* -> PHASE_MSGOUT				*/
-	    /* COMMAND -> MESSAGE OUT */
-	    acornscsi_sendmessage(host);
-	    break;
-
-	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
-	    /* COMMAND -> MESSAGE IN */
-	    acornscsi_message(host);
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_DISCONNECT:		/* STATE: connected, received DISCONNECT msg	*/
-	if (ssr == 0x85) {		/* -> PHASE_IDLE				*/
-	    host->scsi.disconnectable = 1;
-	    host->scsi.reconnected.tag = 0;
-	    host->scsi.phase = PHASE_IDLE;
-	    host->stats.disconnects += 1;
-	} else {
-	    printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_NEXT_COMMAND;
-
-    case PHASE_IDLE:			/* STATE: disconnected				*/
-	if (ssr == 0x81)		/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/
-	    acornscsi_reconnect(host);
-	else {
-	    printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_RECONNECTED:		/* STATE: device reconnected to initiator	*/
-	/*
-	 * Command reconnected - if MESGIN, get message - it may be
-	 * the tag.  If not, get command out of disconnected queue
-	 */
-	/*
-	 * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY,
-	 * reconnect I_T_L command
-	 */
-	if (ssr != 0x8f && !acornscsi_reconnect_finish(host))
-	    return INTR_IDLE;
-	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);
-	switch (ssr) {
-	case 0x88:			/* data out phase				*/
-					/* -> PHASE_DATAOUT				*/
-	    /* MESSAGE IN -> DATA OUT */
-	    acornscsi_dma_setup(host, DMA_OUT);
-	    if (!acornscsi_starttransfer(host))
-		acornscsi_abortcmd(host, host->SCpnt->tag);
-	    host->scsi.phase = PHASE_DATAOUT;
-	    return INTR_IDLE;
-
-	case 0x89:			/* data in phase				*/
-					/* -> PHASE_DATAIN				*/
-	    /* MESSAGE IN -> DATA IN */
-	    acornscsi_dma_setup(host, DMA_IN);
-	    if (!acornscsi_starttransfer(host))
-		acornscsi_abortcmd(host, host->SCpnt->tag);
-	    host->scsi.phase = PHASE_DATAIN;
-	    return INTR_IDLE;
-
-	case 0x8a:			/* command out					*/
-	    /* MESSAGE IN -> COMMAND */
-	    acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
-	    break;
-
-	case 0x8b:			/* status in					*/
-					/* -> PHASE_STATUSIN				*/
-	    /* MESSAGE IN -> STATUS */
-	    acornscsi_readstatusbyte(host);
-	    host->scsi.phase = PHASE_STATUSIN;
-	    break;
-
-	case 0x8e:			/* message out					*/
-					/* -> PHASE_MSGOUT				*/
-	    /* MESSAGE IN -> MESSAGE OUT */
-	    acornscsi_sendmessage(host);
-	    break;
-
-	case 0x8f:			/* message in					*/
-	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_DATAIN:			/* STATE: transferred data in			*/
-	/*
-	 * This is simple - if we disconnect then the DMA address & count is
-	 * correct.
-	 */
-	switch (ssr) {
-	case 0x19:			/* -> PHASE_DATAIN				*/
-	case 0x89:			/* -> PHASE_DATAIN				*/
-	    acornscsi_abortcmd(host, host->SCpnt->tag);
-	    return INTR_IDLE;
-
-	case 0x1b:			/* -> PHASE_STATUSIN				*/
-	case 0x4b:			/* -> PHASE_STATUSIN				*/
-	case 0x8b:			/* -> PHASE_STATUSIN				*/
-	    /* DATA IN -> STATUS */
-	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-					  acornscsi_sbic_xfcount(host);
-	    acornscsi_dma_stop(host);
-	    acornscsi_readstatusbyte(host);
-	    host->scsi.phase = PHASE_STATUSIN;
-	    break;
-
-	case 0x1e:			/* -> PHASE_MSGOUT				*/
-	case 0x4e:			/* -> PHASE_MSGOUT				*/
-	case 0x8e:			/* -> PHASE_MSGOUT				*/
-	    /* DATA IN -> MESSAGE OUT */
-	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-					  acornscsi_sbic_xfcount(host);
-	    acornscsi_dma_stop(host);
-	    acornscsi_sendmessage(host);
-	    break;
-
-	case 0x1f:			/* message in					*/
-	case 0x4f:			/* message in					*/
-	case 0x8f:			/* message in					*/
-	    /* DATA IN -> MESSAGE IN */
-	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-					  acornscsi_sbic_xfcount(host);
-	    acornscsi_dma_stop(host);
-	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_DATAOUT: 		/* STATE: transferred data out			*/
-	/*
-	 * This is more complicated - if we disconnect, the DMA could be 12
-	 * bytes ahead of us.  We need to correct this.
-	 */
-	switch (ssr) {
-	case 0x18:			/* -> PHASE_DATAOUT				*/
-	case 0x88:			/* -> PHASE_DATAOUT				*/
-	    acornscsi_abortcmd(host, host->SCpnt->tag);
-	    return INTR_IDLE;
-
-	case 0x1b:			/* -> PHASE_STATUSIN				*/
-	case 0x4b:			/* -> PHASE_STATUSIN				*/
-	case 0x8b:			/* -> PHASE_STATUSIN				*/
-	    /* DATA OUT -> STATUS */
-	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-					  acornscsi_sbic_xfcount(host);
-	    acornscsi_dma_stop(host);
-	    acornscsi_dma_adjust(host);
-	    acornscsi_readstatusbyte(host);
-	    host->scsi.phase = PHASE_STATUSIN;
-	    break;
-
-	case 0x1e:			/* -> PHASE_MSGOUT				*/
-	case 0x4e:			/* -> PHASE_MSGOUT				*/
-	case 0x8e:			/* -> PHASE_MSGOUT				*/
-	    /* DATA OUT -> MESSAGE OUT */
-	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-					  acornscsi_sbic_xfcount(host);
-	    acornscsi_dma_stop(host);
-	    acornscsi_dma_adjust(host);
-	    acornscsi_sendmessage(host);
-	    break;
-
-	case 0x1f:			/* message in					*/
-	case 0x4f:			/* message in					*/
-	case 0x8f:			/* message in					*/
-	    /* DATA OUT -> MESSAGE IN */
-	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
-					  acornscsi_sbic_xfcount(host);
-	    acornscsi_dma_stop(host);
-	    acornscsi_dma_adjust(host);
-	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_STATUSIN:		/* STATE: status in complete			*/
-	switch (ssr) {
-	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
-	case 0x8f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
-	    /* STATUS -> MESSAGE IN */
-	    acornscsi_message(host);
-	    break;
-
-	case 0x1e:			/* -> PHASE_MSGOUT				*/
-	case 0x8e:			/* -> PHASE_MSGOUT				*/
-	    /* STATUS -> MESSAGE OUT */
-	    acornscsi_sendmessage(host);
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_MSGIN:			/* STATE: message in				*/
-	switch (ssr) {
-	case 0x1e:			/* -> PHASE_MSGOUT				*/
-	case 0x4e:			/* -> PHASE_MSGOUT				*/
-	case 0x8e:			/* -> PHASE_MSGOUT				*/
-	    /* MESSAGE IN -> MESSAGE OUT */
-	    acornscsi_sendmessage(host);
-	    break;
-
-	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
-	case 0x2f:
-	case 0x4f:
-	case 0x8f:
-	    acornscsi_message(host);
-	    break;
-
-	case 0x85:
-	    printk("scsi%d.%c: strange message in disconnection\n",
-		host->host->host_no, acornscsi_target(host));
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	    acornscsi_done(host, &host->SCpnt, DID_ERROR);
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_DONE:			/* STATE: received status & message		*/
-	switch (ssr) {
-	case 0x85:			/* -> PHASE_IDLE				*/
-	    acornscsi_done(host, &host->SCpnt, DID_OK);
-	    return INTR_NEXT_COMMAND;
-
-	case 0x1e:
-	case 0x8e:
-	    acornscsi_sendmessage(host);
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    case PHASE_ABORTED:
-	switch (ssr) {
-	case 0x85:
-	    if (host->SCpnt)
-		acornscsi_done(host, &host->SCpnt, DID_ABORT);
-	    else {
-		clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun,
-			  host->busyluns);
-		host->scsi.phase = PHASE_IDLE;
-	    }
-	    return INTR_NEXT_COMMAND;
-
-	case 0x1e:
-	case 0x2e:
-	case 0x4e:
-	case 0x8e:
-	    acornscsi_sendmessage(host);
-	    break;
-
-	default:
-	    printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n",
-		    host->host->host_no, acornscsi_target(host), ssr);
-	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-	}
-	return INTR_PROCESSING;
-
-    default:
-	printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n",
-		host->host->host_no, acornscsi_target(host), ssr);
-	acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
-    }
-    return INTR_PROCESSING;
-}
-
-/*
- * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
- * Purpose  : handle interrupts from Acorn SCSI card
- * Params   : irq    - interrupt number
- *	      dev_id - device specific data (AS_Host structure)
- *	      regs   - processor registers when interrupt occurred
- */
-static
-void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-    AS_Host *host = (AS_Host *)dev_id;
-    intr_ret_t ret;
-    int iostatus;
-    int in_irq = 0;
-
-    if (host->scsi.interrupt)
-	printk("scsi%d: interrupt re-entered\n", host->host->host_no);
-    host->scsi.interrupt = 1;
-
-    do {
-	ret = INTR_IDLE;
-
-	iostatus = inb(host->card.io_intr);
-
-	if (iostatus & 2) {
-	    acornscsi_dma_intr(host);
-	    iostatus = inb(host->card.io_intr);
-	}
-
-	if (iostatus & 8)
-	    ret = acornscsi_sbicintr(host, in_irq);
-
-	/*
-	 * If we have a transfer pending, start it.
-	 * Only start it if the interface has already started transferring
-	 * it's data
-	 */
-	if (host->dma.xfer_required)
-	    acornscsi_dma_xfer(host);
-
-	if (ret == INTR_NEXT_COMMAND)
-	    ret = acornscsi_kick(host);
-
-	in_irq = 1;
-    } while (ret != INTR_IDLE);
-
-    host->scsi.interrupt = 0;
-}
-
-/*=============================================================================================
- * Interfaces between interrupt handler and rest of scsi code
- */
-
-/*
- * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
- * Purpose  : queues a SCSI command
- * Params   : cmd  - SCSI command
- *	      done - function called on completion, with pointer to command descriptor
- * Returns  : 0, or < 0 on error.
- */
-int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
-{
-    AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
-
-    if (!done) {
-	/* there should be some way of rejecting errors like this without panicing... */
-	panic("scsi%d: queuecommand called with NULL done function [cmd=%p]",
-		host->host->host_no, SCpnt);
-	return -EINVAL;
-    }
-
-#if (DEBUG & DEBUG_NO_WRITE)
-    if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->device->id))) {
-	printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",
-	    host->host->host_no, '0' + SCpnt->device->id);
-	SCpnt->result = DID_NO_CONNECT << 16;
-	done(SCpnt);
-	return 0;
-    }
-#endif
-
-    SCpnt->scsi_done = done;
-    SCpnt->host_scribble = NULL;
-    SCpnt->result = 0;
-    SCpnt->tag = 0;
-    SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]);
-    SCpnt->SCp.sent_command = 0;
-    SCpnt->SCp.scsi_xferred = 0;
-
-    init_SCp(SCpnt);
-
-    host->stats.queues += 1;
-
-    {
-	unsigned long flags;
-
-	if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) {
-	    SCpnt->result = DID_ERROR << 16;
-	    done(SCpnt);
-	    return 0;
-	}
-	local_irq_save(flags);
-	if (host->scsi.phase == PHASE_IDLE)
-	    acornscsi_kick(host);
-	local_irq_restore(flags);
-    }
-    return 0;
-}
-
-/*
- * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
- * Purpose  : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
- * Params   : SCpntp1 - pointer to command to return
- *	      SCpntp2 - pointer to command to check
- *	      result  - result to pass back to mid-level done function
- * Returns  : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
- */
-static inline
-void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
-{
-    Scsi_Cmnd *SCpnt = *SCpntp1;
-
-    if (SCpnt) {
-	*SCpntp1 = NULL;
-
-	SCpnt->result = result;
-	SCpnt->scsi_done(SCpnt);
-    }
-
-    if (SCpnt == *SCpntp2)
-	*SCpntp2 = NULL;
-}
-
-enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
-
-/*
- * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
- * Purpose  : abort a command on this host
- * Params   : SCpnt - command to abort
- * Returns  : our abort status
- */
-static enum res_abort
-acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
-{
-	enum res_abort res = res_not_running;
-
-	if (queue_remove_cmd(&host->queues.issue, SCpnt)) {
-		/*
-		 * The command was on the issue queue, and has not been
-		 * issued yet.  We can remove the command from the queue,
-		 * and acknowledge the abort.  Neither the devices nor the
-		 * interface know about the command.
-		 */
-//#if (DEBUG & DEBUG_ABORT)
-		printk("on issue queue ");
-//#endif
-		res = res_success;
-	} else if (queue_remove_cmd(&host->queues.disconnected, SCpnt)) {
-		/*
-		 * The command was on the disconnected queue.  Simply
-		 * acknowledge the abort condition, and when the target
-		 * reconnects, we will give it an ABORT message.  The
-		 * target should then disconnect, and we will clear
-		 * the busylun bit.
-		 */
-//#if (DEBUG & DEBUG_ABORT)
-		printk("on disconnected queue ");
-//#endif
-		res = res_success;
-	} else if (host->SCpnt == SCpnt) {
-		unsigned long flags;
-
-//#if (DEBUG & DEBUG_ABORT)
-		printk("executing ");
-//#endif
-
-		local_irq_save(flags);
-		switch (host->scsi.phase) {
-		/*
-		 * If the interface is idle, and the command is 'disconnectable',
-		 * then it is the same as on the disconnected queue.  We simply
-		 * remove all traces of the command.  When the target reconnects,
-		 * we will give it an ABORT message since the command could not
-		 * be found.  When the target finally disconnects, we will clear
-		 * the busylun bit.
-		 */
-		case PHASE_IDLE:
-			if (host->scsi.disconnectable) {
-				host->scsi.disconnectable = 0;
-				host->SCpnt = NULL;
-				res = res_success;
-			}
-			break;
-
-		/*
-		 * If the command has connected and done nothing further,
-		 * simply force a disconnect.  We also need to clear the
-		 * busylun bit.
-		 */
-		case PHASE_CONNECTED:
-			sbic_arm_write(host->scsi.io_port, CMND, CMND_DISCONNECT);
-			host->SCpnt = NULL;
-			res = res_success_clear;
-			break;
-
-		default:
-			acornscsi_abortcmd(host, host->SCpnt->tag);
-			res = res_snooze;
-		}
-		local_irq_restore(flags);
-	} else if (host->origSCpnt == SCpnt) {
-		/*
-		 * The command will be executed next, but a command
-		 * is currently using the interface.  This is similar to
-		 * being on the issue queue, except the busylun bit has
-		 * been set.
-		 */
-		host->origSCpnt = NULL;
-//#if (DEBUG & DEBUG_ABORT)
-		printk("waiting for execution ");
-//#endif
-		res = res_success_clear;
-	} else
-		printk("unknown ");
-
-	return res;
-}
-
-/*
- * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
- * Purpose  : abort a command on this host
- * Params   : SCpnt - command to abort
- * Returns  : one of SCSI_ABORT_ macros
- */
-int acornscsi_abort(Scsi_Cmnd *SCpnt)
-{
-	AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata;
-	int result;
-
-	host->stats.aborts += 1;
-
-#if (DEBUG & DEBUG_ABORT)
-	{
-		int asr, ssr;
-		asr = sbic_arm_read(host->scsi.io_port, ASR);
-		ssr = sbic_arm_read(host->scsi.io_port, SSR);
-
-		printk(KERN_WARNING "acornscsi_abort: ");
-		print_sbic_status(asr, ssr, host->scsi.phase);
-		acornscsi_dumplog(host, SCpnt->device->id);
-	}
-#endif
-
-	printk("scsi%d: ", host->host->host_no);
-
-	switch (acornscsi_do_abort(host, SCpnt)) {
-	/*
-	 * We managed to find the command and cleared it out.
-	 * We do not expect the command to be executing on the
-	 * target, but we have set the busylun bit.
-	 */
-	case res_success_clear:
-//#if (DEBUG & DEBUG_ABORT)
-		printk("clear ");
-//#endif
-		clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns);
-
-	/*
-	 * We found the command, and cleared it out.  Either
-	 * the command is still known to be executing on the
-	 * target, or the busylun bit is not set.
-	 */
-	case res_success:
-//#if (DEBUG & DEBUG_ABORT)
-		printk("success\n");
-//#endif
-		SCpnt->result = DID_ABORT << 16;
-		SCpnt->scsi_done(SCpnt);
-		result = SCSI_ABORT_SUCCESS;
-		break;
-
-	/*
-	 * We did find the command, but unfortunately we couldn't
-	 * unhook it from ourselves.  Wait some more, and if it
-	 * still doesn't complete, reset the interface.
-	 */
-	case res_snooze:
-//#if (DEBUG & DEBUG_ABORT)
-		printk("snooze\n");
-//#endif
-		result = SCSI_ABORT_SNOOZE;
-		break;
-
-	/*
-	 * The command could not be found (either because it completed,
-	 * or it got dropped.
-	 */
-	default:
-	case res_not_running:
-		acornscsi_dumplog(host, SCpnt->device->id);
-#if (DEBUG & DEBUG_ABORT)
-		result = SCSI_ABORT_SNOOZE;
-#else
-		result = SCSI_ABORT_NOT_RUNNING;
-#endif
-//#if (DEBUG & DEBUG_ABORT)
-		printk("not running\n");
-//#endif
-		break;
-	}
-
-	return result;
-}
-
-/*
- * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
- * Purpose  : reset a command on this host/reset this host
- * Params   : SCpnt  - command causing reset
- *	      result - what type of reset to perform
- * Returns  : one of SCSI_RESET_ macros
- */
-int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
-{
-    AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
-    Scsi_Cmnd *SCptr;
-    
-    host->stats.resets += 1;
-
-#if (DEBUG & DEBUG_RESET)
-    {
-	int asr, ssr;
-
-	asr = sbic_arm_read(host->scsi.io_port, ASR);
-	ssr = sbic_arm_read(host->scsi.io_port, SSR);
-
-	printk(KERN_WARNING "acornscsi_reset: ");
-	print_sbic_status(asr, ssr, host->scsi.phase);
-	acornscsi_dumplog(host, SCpnt->device->id);
-    }
-#endif
-
-    acornscsi_dma_stop(host);
-
-    SCptr = host->SCpnt;
-
-    /*
-     * do hard reset.  This resets all devices on this host, and so we
-     * must set the reset status on all commands.
-     */
-    acornscsi_resetcard(host);
-
-    /*
-     * report reset on commands current connected/disconnected
-     */
-    acornscsi_reportstatus(&host->SCpnt, &SCptr, DID_RESET);
-
-    while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL)
-	acornscsi_reportstatus(&SCptr, &SCpnt, DID_RESET);
-
-    if (SCpnt) {
-	SCpnt->result = DID_RESET << 16;
-	SCpnt->scsi_done(SCpnt);
-    }
-
-    return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS;
-}
-
-/*==============================================================================================
- * initialisation & miscellaneous support
- */
-
-/*
- * Function: char *acornscsi_info(struct Scsi_Host *host)
- * Purpose : return a string describing this interface
- * Params  : host - host to give information on
- * Returns : a constant string
- */
-const
-char *acornscsi_info(struct Scsi_Host *host)
-{
-    static char string[100], *p;
-
-    p = string;
-    
-    p += sprintf(string, "%s at port %08lX irq %d v%d.%d.%d"
-#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
-    " SYNC"
-#endif
-#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
-    " TAG"
-#endif
-#ifdef CONFIG_SCSI_ACORNSCSI_LINK
-    " LINK"
-#endif
-#if (DEBUG & DEBUG_NO_WRITE)
-    " NOWRITE ("NO_WRITE_STR")"
-#endif
-		, host->hostt->name, host->io_port, host->irq,
-		VER_MAJOR, VER_MINOR, VER_PATCH);
-    return string;
-}
-
-int acornscsi_proc_info(char *buffer, char **start, off_t offset,
-			int length, int host_no, int inout)
-{
-    int pos, begin = 0, devidx;
-    struct Scsi_Host *instance;
-    Scsi_Device *scd;
-    AS_Host *host;
-    char *p = buffer;
-
-    instance = scsi_host_hn_get(host_no);
-
-    if (inout == 1 || !instance)
-	return -EINVAL;
-
-    host  = (AS_Host *)instance->hostdata;
-    
-    p += sprintf(p, "AcornSCSI driver v%d.%d.%d"
-#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
-    " SYNC"
-#endif
-#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
-    " TAG"
-#endif
-#ifdef CONFIG_SCSI_ACORNSCSI_LINK
-    " LINK"
-#endif
-#if (DEBUG & DEBUG_NO_WRITE)
-    " NOWRITE ("NO_WRITE_STR")"
-#endif
-		"\n\n", VER_MAJOR, VER_MINOR, VER_PATCH);
-
-    p += sprintf(p,	"SBIC: WD33C93A  Address: %08X  IRQ : %d\n",
-			host->scsi.io_port, host->scsi.irq);
-#ifdef USE_DMAC
-    p += sprintf(p,	"DMAC: uPC71071  Address: %08X  IRQ : %d\n\n",
-			host->dma.io_port, host->scsi.irq);
-#endif
-
-    p += sprintf(p,	"Statistics:\n"
-			"Queued commands: %-10u    Issued commands: %-10u\n"
-			"Done commands  : %-10u    Reads          : %-10u\n"
-			"Writes         : %-10u    Others         : %-10u\n"
-			"Disconnects    : %-10u    Aborts         : %-10u\n"
-			"Resets         : %-10u\n\nLast phases:",
-			host->stats.queues,		host->stats.removes,
-			host->stats.fins,		host->stats.reads,
-			host->stats.writes,		host->stats.miscs,
-			host->stats.disconnects,	host->stats.aborts,
-			host->stats.resets);
-
-    for (devidx = 0; devidx < 9; devidx ++) {
-	unsigned int statptr, prev;
-
-	p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
-	statptr = host->status_ptr[devidx] - 10;
-
-	if ((signed int)statptr < 0)
-	    statptr += STATUS_BUFFER_SIZE;
-
-	prev = host->status[devidx][statptr].when;
-
-	for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
-	    if (host->status[devidx][statptr].when) {
-		p += sprintf(p, "%c%02X:%02X+%2ld",
-			host->status[devidx][statptr].irq ? '-' : ' ',
-			host->status[devidx][statptr].ph,
-			host->status[devidx][statptr].ssr,
-			(host->status[devidx][statptr].when - prev) < 100 ?
-				(host->status[devidx][statptr].when - prev) : 99);
-		prev = host->status[devidx][statptr].when;
-	    }
-	}
-    }
-
-    p += sprintf(p, "\nAttached devices:\n");
-
-    list_for_each_entry(scd, &instance->my_devices, siblings) {
-	int len;
-
-	proc_print_scsidevice(scd, p, &len, 0);
-	p += len;
-
-	p += sprintf(p, "Extensions: ");
-
-	if (scd->tagged_supported)
-	    p += sprintf(p, "TAG %sabled [%d] ",
-			  scd->tagged_queue ? "en" : "dis", scd->current_tag);
-	p += sprintf(p, "\nTransfers: ");
-	if (host->device[scd->id].sync_xfer & 15)
-	    p += sprintf(p, "sync, offset %d, %d ns\n",
-			  host->device[scd->id].sync_xfer & 15,
-			  acornscsi_getperiod(host->device[scd->id].sync_xfer));
-	else
-	    p += sprintf(p, "async\n");
-
-	pos = p - buffer;
-	if (pos + begin < offset) {
-	    begin += pos;
-	    p = buffer;
-	}
-	pos = p - buffer;
-	if (pos + begin > offset + length)
-	    break;
-    }
-
-    pos = p - buffer;
-
-    *start = buffer + (offset - begin);
-    pos -= offset - begin;
-
-    if (pos > length)
-	pos = length;
-
-    return pos;
-}
-
-static Scsi_Host_Template acornscsi_template = {
-	.module			= THIS_MODULE,
-	.proc_info		= acornscsi_proc_info,
-	.name			= "AcornSCSI",
-	.info			= acornscsi_info,
-	.queuecommand		= acornscsi_queuecmd,
-#warning fixme
-	.abort			= acornscsi_abort,
-	.reset			= acornscsi_reset,
-	.can_queue		= 16,
-	.this_id		= 7,
-	.sg_tablesize		= SG_ALL,
-	.cmd_per_lun		= 2,
-	.unchecked_isa_dma	= 0,
-	.use_clustering		= DISABLE_CLUSTERING,
-	.proc_name		= "acornscsi",
-};
-
-static int __devinit
-acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct Scsi_Host *host;
-	AS_Host *ashost;
-	int ret = -ENOMEM;
-
-	host = scsi_register(&acornscsi_template, sizeof(AS_Host));
-	if (!host)
-		goto out;
-
-	ashost = (AS_Host *)host->hostdata;
-
-	host->io_port = ecard_address(ec, ECARD_MEMC, 0);
-	host->irq = ec->irq;
-
-	ashost->host		= host;
-	ashost->scsi.io_port	= ioaddr(host->io_port + 0x800);
-	ashost->scsi.irq	= host->irq;
-	ashost->card.io_intr	= POD_SPACE(host->io_port) + 0x800;
-	ashost->card.io_page	= POD_SPACE(host->io_port) + 0xc00;
-	ashost->card.io_ram	= ioaddr(host->io_port);
-	ashost->dma.io_port	= host->io_port + 0xc00;
-	ashost->dma.io_intr_clear = POD_SPACE(host->io_port) + 0x800;
-
-	ec->irqaddr	= (char *)ioaddr(ashost->card.io_intr);
-	ec->irqmask	= 0x0a;
-
-	ret = -EBUSY;
-	if (!request_region(host->io_port + 0x800, 2, "acornscsi(sbic)"))
-		goto err_1;
-	if (!request_region(ashost->card.io_intr, 1, "acornscsi(intr)"))
-		goto err_2;
-	if (!request_region(ashost->card.io_page, 1, "acornscsi(page)"))
-		goto err_3;
-#ifdef USE_DMAC
-	if (!request_region(ashost->dma.io_port, 256, "acornscsi(dmac)"))
-		goto err_4;
-#endif
-	if (!request_region(host->io_port, 2048, "acornscsi(ram)"))
-		goto err_5;
-
-	ret = request_irq(host->irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", ashost);
-	if (ret) {
-		printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n",
-			host->host_no, ashost->scsi.irq, ret);
-		goto err_6;
-	}
-
-	memset(&ashost->stats, 0, sizeof (ashost->stats));
-	queue_initialise(&ashost->queues.issue);
-	queue_initialise(&ashost->queues.disconnected);
-	msgqueue_initialise(&ashost->scsi.msgs);
-
-	acornscsi_resetcard(ashost);
-
-	ret = scsi_add_host(host, &ec->dev);
-	if (ret == 0)
-		goto out;
-
-	free_irq(host->irq, ashost);
- err_6:
-	release_region(host->io_port, 2048);
- err_5:
-#ifdef USE_DMAC
-	release_region(ashost->dma.io_port, 256);
-#endif
- err_4:
-	release_region(ashost->card.io_page, 1);
- err_3:
-	release_region(ashost->card.io_intr, 1);    
- err_2:
-	release_region(host->io_port + 0x800, 2);
- err_1:
-	scsi_unregister(host);
- out:
-	return ret;
-}
-
-static void __devexit acornscsi_remove(struct expansion_card *ec)
-{
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-	AS_Host *ashost = (AS_Host *)host->hostdata;
-
-	ecard_set_drvdata(ec, NULL);
-	scsi_remove_host(host);
-
-	/*
-	 * Put card into RESET state
-	 */
-	outb(0x80, ashost->card.io_page);
-
-	free_irq(host->irq, ashost);
-
-	release_region(host->io_port + 0x800, 2);
-	release_region(ashost->card.io_intr, 1);
-	release_region(ashost->card.io_page, 1);
-	release_region(ashost->dma.io_port, 256);
-	release_region(host->io_port, 2048);
-
-	msgqueue_free(&ashost->scsi.msgs);
-	queue_free(&ashost->queues.disconnected);
-	queue_free(&ashost->queues.issue);
-}
-
-static const struct ecard_id acornscsi_cids[] = {
-	{ MANU_ACORN, PROD_ACORN_SCSI },
-	{ 0xffff, 0xffff },
-};
-
-static struct ecard_driver acornscsi_driver = {
-	.probe		= acornscsi_probe,
-	.remove		= __devexit_p(acornscsi_remove),
-	.id_table	= acornscsi_cids,
-	.drv = {
-		.devclass	= &shost_devclass,
-		.name		= "acornscsi",
-	},
-};
-
-static int __init acornscsi_init(void)
-{
-	return ecard_register_driver(&acornscsi_driver);
-}
-
-static void __exit acornscsi_exit(void)
-{
-	ecard_remove_driver(&acornscsi_driver);
-}
-
-module_init(acornscsi_init);
-module_exit(acornscsi_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("AcornSCSI driver");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/acorn/scsi/acornscsi.h b/drivers/acorn/scsi/acornscsi.h
--- a/drivers/acorn/scsi/acornscsi.h	Sun Oct 13 08:02:27 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,359 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/acornscsi.h
- *
- *  Copyright (C) 1997 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.
- *
- *  Acorn SCSI driver
- */
-#ifndef ACORNSCSI_H
-#define ACORNSCSI_H
-
-/* SBIC registers */
-#define OWNID			0
-#define OWNID_FS1		(1<<7)
-#define OWNID_FS2		(1<<6)
-#define OWNID_EHP		(1<<4)
-#define OWNID_EAF		(1<<3)
-
-#define CTRL			1
-#define CTRL_DMAMODE		(1<<7)
-#define CTRL_DMADBAMODE		(1<<6)
-#define CTRL_DMABURST		(1<<5)
-#define CTRL_DMAPOLLED		0
-#define CTRL_HHP		(1<<4)
-#define CTRL_EDI		(1<<3)
-#define CTRL_IDI		(1<<2)
-#define CTRL_HA			(1<<1)
-#define CTRL_HSP		(1<<0)
-
-#define TIMEOUT			2
-#define TOTSECTS		3
-#define TOTHEADS		4
-#define TOTCYLH			5
-#define TOTCYLL			6
-#define LOGADDRH		7
-#define LOGADDRM2		8
-#define LOGADDRM1		9
-#define LOGADDRL		10
-#define SECTORNUM		11
-#define HEADNUM			12
-#define CYLH			13
-#define CYLL			14
-#define TARGETLUN		15
-#define TARGETLUN_TLV		(1<<7)
-#define TARGETLUN_DOK		(1<<6)
-
-#define CMNDPHASE		16
-#define SYNCHTRANSFER		17
-#define SYNCHTRANSFER_OF0	0x00
-#define SYNCHTRANSFER_OF1	0x01
-#define SYNCHTRANSFER_OF2	0x02
-#define SYNCHTRANSFER_OF3	0x03
-#define SYNCHTRANSFER_OF4	0x04
-#define SYNCHTRANSFER_OF5	0x05
-#define SYNCHTRANSFER_OF6	0x06
-#define SYNCHTRANSFER_OF7	0x07
-#define SYNCHTRANSFER_OF8	0x08
-#define SYNCHTRANSFER_OF9	0x09
-#define SYNCHTRANSFER_OF10	0x0A
-#define SYNCHTRANSFER_OF11	0x0B
-#define SYNCHTRANSFER_OF12	0x0C
-#define SYNCHTRANSFER_8DBA	0x00
-#define SYNCHTRANSFER_2DBA	0x20
-#define SYNCHTRANSFER_3DBA	0x30
-#define SYNCHTRANSFER_4DBA	0x40
-#define SYNCHTRANSFER_5DBA	0x50
-#define SYNCHTRANSFER_6DBA	0x60
-#define SYNCHTRANSFER_7DBA	0x70
-
-#define TRANSCNTH		18
-#define TRANSCNTM		19
-#define TRANSCNTL		20
-#define DESTID			21
-#define DESTID_SCC		(1<<7)
-#define DESTID_DPD		(1<<6)
-
-#define SOURCEID		22
-#define SOURCEID_ER		(1<<7)
-#define SOURCEID_ES		(1<<6)
-#define SOURCEID_DSP		(1<<5)
-#define SOURCEID_SIV		(1<<4)
-
-#define SSR			23
-#define CMND			24
-#define CMND_RESET		0x00
-#define CMND_ABORT		0x01
-#define CMND_ASSERTATN		0x02
-#define CMND_NEGATEACK		0x03
-#define CMND_DISCONNECT		0x04
-#define CMND_RESELECT		0x05
-#define CMND_SELWITHATN		0x06
-#define CMND_SELECT		0x07
-#define CMND_SELECTATNTRANSFER	0x08
-#define CMND_SELECTTRANSFER	0x09
-#define CMND_RESELECTRXDATA	0x0A
-#define CMND_RESELECTTXDATA	0x0B
-#define CMND_WAITFORSELRECV	0x0C
-#define CMND_SENDSTATCMD	0x0D
-#define CMND_SENDDISCONNECT	0x0E
-#define CMND_SETIDI		0x0F
-#define CMND_RECEIVECMD		0x10
-#define CMND_RECEIVEDTA		0x11
-#define CMND_RECEIVEMSG		0x12
-#define CMND_RECEIVEUSP		0x13
-#define CMND_SENDCMD		0x14
-#define CMND_SENDDATA		0x15
-#define CMND_SENDMSG		0x16
-#define CMND_SENDUSP		0x17
-#define CMND_TRANSLATEADDR	0x18
-#define CMND_XFERINFO		0x20
-#define CMND_SBT		(1<<7)
-
-#define DATA			25
-#define ASR			26
-#define ASR_INT			(1<<7)
-#define ASR_LCI			(1<<6)
-#define ASR_BSY			(1<<5)
-#define ASR_CIP			(1<<4)
-#define ASR_PE			(1<<1)
-#define ASR_DBR			(1<<0)
-
-/* DMAC registers */
-#define INIT			0x00
-#define INIT_8BIT		(1)
-
-#define CHANNEL			0x80
-#define CHANNEL_0		0x00
-#define CHANNEL_1		0x01
-#define CHANNEL_2		0x02
-#define CHANNEL_3		0x03
-
-#define TXCNTLO			0x01
-#define TXCNTHI			0x81
-#define TXADRLO			0x02
-#define TXADRMD			0x82
-#define TXADRHI			0x03
-
-#define DEVCON0			0x04
-#define DEVCON0_AKL		(1<<7)
-#define DEVCON0_RQL		(1<<6)
-#define DEVCON0_EXW		(1<<5)
-#define DEVCON0_ROT		(1<<4)
-#define DEVCON0_CMP		(1<<3)
-#define DEVCON0_DDMA		(1<<2)
-#define DEVCON0_AHLD		(1<<1)
-#define DEVCON0_MTM		(1<<0)
-
-#define DEVCON1			0x84
-#define DEVCON1_WEV		(1<<1)
-#define DEVCON1_BHLD		(1<<0)
-
-#define MODECON			0x05
-#define MODECON_WOED		0x01
-#define MODECON_VERIFY		0x00
-#define MODECON_READ		0x04
-#define MODECON_WRITE		0x08
-#define MODECON_AUTOINIT	0x10
-#define MODECON_ADDRDIR		0x20
-#define MODECON_DEMAND		0x00
-#define MODECON_SINGLE		0x40
-#define MODECON_BLOCK		0x80
-#define MODECON_CASCADE		0xC0
-
-#define STATUS			0x85
-#define STATUS_TC0		(1<<0)
-#define STATUS_RQ0		(1<<4)
-
-#define TEMPLO			0x06
-#define TEMPHI			0x86
-#define REQREG			0x07
-#define MASKREG			0x87
-#define MASKREG_M0		0x01
-#define MASKREG_M1		0x02
-#define MASKREG_M2		0x04
-#define MASKREG_M3		0x08
-
-/* miscellaneous internal variables */
-
-#define POD_SPACE(x)	((x) + 0xd0000)
-#define MASK_ON		(MASKREG_M3|MASKREG_M2|MASKREG_M1|MASKREG_M0)
-#define MASK_OFF	(MASKREG_M3|MASKREG_M2|MASKREG_M1)
-
-/*
- * SCSI driver phases
- */
-typedef enum {
-    PHASE_IDLE,					/* we're not planning on doing anything	 */
-    PHASE_CONNECTING,				/* connecting to a target		 */
-    PHASE_CONNECTED,				/* connected to a target		 */
-    PHASE_MSGOUT,				/* message out to device		 */
-    PHASE_RECONNECTED,				/* reconnected				 */
-    PHASE_COMMANDPAUSED,			/* command partly sent			 */
-    PHASE_COMMAND,				/* command all sent			 */
-    PHASE_DATAOUT,				/* data out to device			 */
-    PHASE_DATAIN,				/* data in from device			 */
-    PHASE_STATUSIN,				/* status in from device		 */
-    PHASE_MSGIN,				/* message in from device		 */
-    PHASE_DONE,					/* finished				 */
-    PHASE_ABORTED,				/* aborted				 */
-    PHASE_DISCONNECT,				/* disconnecting			 */
-} phase_t;
-
-/*
- * After interrupt, what to do now
- */
-typedef enum {
-    INTR_IDLE,					/* not expecting another IRQ		 */
-    INTR_NEXT_COMMAND,				/* start next command			 */
-    INTR_PROCESSING,				/* interrupt routine still processing	 */
-} intr_ret_t;
-
-/*
- * DMA direction
- */
-typedef enum {
-    DMA_OUT,					/* DMA from memory to chip		*/
-    DMA_IN					/* DMA from chip to memory		*/
-} dmadir_t;
-
-/*
- * Synchronous transfer state
- */
-typedef enum {					/* Synchronous transfer state		*/
-    SYNC_ASYNCHRONOUS,				/* don't negociate synchronous transfers*/
-    SYNC_NEGOCIATE,				/* start negociation			*/
-    SYNC_SENT_REQUEST,				/* sent SDTR message			*/
-    SYNC_COMPLETED,				/* received SDTR reply			*/
-} syncxfer_t;
-
-/*
- * Command type
- */
-typedef enum {					/* command type				*/
-    CMD_READ,					/* READ_6, READ_10, READ_12		*/
-    CMD_WRITE,					/* WRITE_6, WRITE_10, WRITE_12		*/
-    CMD_MISC,					/* Others				*/
-} cmdtype_t;
-
-/*
- * Data phase direction
- */
-typedef enum {					/* Data direction			*/
-    DATADIR_IN,					/* Data in phase expected		*/
-    DATADIR_OUT					/* Data out phase expected		*/
-} datadir_t;
-
-#include "queue.h"
-#include "msgqueue.h"
-
-#define STATUS_BUFFER_SIZE	32
-/*
- * This is used to dump the previous states of the SBIC
- */
-struct status_entry {
-	unsigned long	when;
-	unsigned char	ssr;
-	unsigned char	ph;
-	unsigned char	irq;
-	unsigned char	unused;
-};
-
-#define ADD_STATUS(_q,_ssr,_ph,_irq) \
-({									\
-	host->status[(_q)][host->status_ptr[(_q)]].when = jiffies;	\
-	host->status[(_q)][host->status_ptr[(_q)]].ssr  = (_ssr);	\
-	host->status[(_q)][host->status_ptr[(_q)]].ph   = (_ph);	\
-	host->status[(_q)][host->status_ptr[(_q)]].irq  = (_irq);	\
-	host->status_ptr[(_q)] = (host->status_ptr[(_q)] + 1) & (STATUS_BUFFER_SIZE - 1); \
-})
-
-/*
- * AcornSCSI host specific data
- */
-typedef struct acornscsi_hostdata {
-    /* miscellaneous */
-    struct Scsi_Host	*host;			/* host					*/
-    Scsi_Cmnd		*SCpnt;			/* currently processing command		*/
-    Scsi_Cmnd		*origSCpnt;		/* original connecting command		*/
-
-    /* driver information */
-    struct {
-	unsigned int	io_port;		/* base address of WD33C93		*/
-	unsigned int	irq;			/* interrupt				*/
-	phase_t		phase;			/* current phase			*/
-
-	struct {
-	    unsigned char	target;		/* reconnected target			*/
-	    unsigned char	lun;		/* reconnected lun			*/
-	    unsigned char	tag;		/* reconnected tag			*/
-	} reconnected;
-
-	Scsi_Pointer	SCp;			/* current commands data pointer	*/
-
-	MsgQueue_t	msgs;
-
-	unsigned short	last_message;		/* last message to be sent		*/
-	unsigned char	disconnectable:1;	/* this command can be disconnected	*/
-	unsigned char	interrupt:1;		/* interrupt active			*/
-    } scsi;
-
-    /* statistics information */
-    struct {
-	unsigned int	queues;
-	unsigned int	removes;
-	unsigned int	fins;
-	unsigned int	reads;
-	unsigned int	writes;
-	unsigned int	miscs;
-	unsigned int	disconnects;
-	unsigned int	aborts;
-	unsigned int	resets;
-    } stats;
-
-    /* queue handling */
-    struct {
-	Queue_t		issue;			/* issue queue				*/
-	Queue_t		disconnected;		/* disconnected command queue		*/
-    } queues;
-
-    /* per-device info */
-    struct {
-	unsigned char	sync_xfer;		/* synchronous transfer (SBIC value)	*/
-	syncxfer_t	sync_state;		/* sync xfer negociation state		*/
-	unsigned char	disconnect_ok:1;	/* device can disconnect		*/
-    } device[8];
-    unsigned long	busyluns[64 / sizeof(unsigned long)];/* array of bits indicating LUNs busy	*/
-
-    /* DMA info */
-    struct {
-	unsigned int	io_port;		/* base address of DMA controller	*/
-	unsigned int	io_intr_clear;		/* address of DMA interrupt clear	*/
-	unsigned int	free_addr;		/* next free address			*/
-	unsigned int	start_addr;		/* start address of current transfer	*/
-	dmadir_t	direction;		/* dma direction			*/
-	unsigned int	transferred;		/* number of bytes transferred		*/
-	unsigned int	xfer_start;		/* scheduled DMA transfer start		*/
-	unsigned int	xfer_length;		/* scheduled DMA transfer length	*/
-	char		*xfer_ptr;		/* pointer to area			*/
-	unsigned char	xfer_required:1;	/* set if we need to transfer something	*/
-	unsigned char	xfer_setup:1;		/* set if DMA is setup			*/
-	unsigned char	xfer_done:1;		/* set if DMA reached end of BH list	*/
-    } dma;
-
-    /* card info */
-    struct {
-	unsigned int	io_intr;		/* base address of interrupt id reg	*/
-	unsigned int	io_page;		/* base address of page reg		*/
-	unsigned int	io_ram;			/* base address of RAM access		*/
-	unsigned char	page_reg;		/* current setting of page reg		*/
-    } card;
-
-    unsigned char status_ptr[9];
-    struct status_entry status[9][STATUS_BUFFER_SIZE];
-} AS_Host;
-
-#endif /* ACORNSCSI_H */
diff -Nru a/drivers/acorn/scsi/arxescsi.c b/drivers/acorn/scsi/arxescsi.c
--- a/drivers/acorn/scsi/arxescsi.c	Sun Jan 26 11:34:35 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,421 +0,0 @@
-/*
- * linux/arch/arm/drivers/scsi/arxescsi.c
- *
- * Copyright (C) 1997-2000 Russell King, Stefan Hanske
- *
- * This driver is based on experimentation.  Hence, it may have made
- * assumptions about the particular card that I have available, and
- * may not be reliable!
- *
- * Changelog:
- *  30-08-1997	RMK	0.0.0	Created, READONLY version as cumana_2.c
- *  22-01-1998	RMK	0.0.1	Updated to 2.1.80
- *  15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
- *  11-06-1998 	SH	0.0.2   Changed to support ARXE 16-bit SCSI card
- *				enabled writing
- *  01-01-2000	SH	0.1.0   Added *real* pseudo dma writing
- *				(arxescsi_pseudo_dma_write)
- *  02-04-2000	RMK	0.1.1	Updated for new error handling code.
- *  22-10-2000  SH		Updated for new registering scheme.
- */
-#include <linux/module.h>
-#include <linux/blk.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/unistd.h>
-#include <linux/stat.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/ecard.h>
-
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-#include "fas216.h"
-
-struct arxescsi_info {
-	FAS216_Info		info;
-	struct expansion_card	*ec;
-};
-
-#define DMADATA_OFFSET	(0x200)
-
-#define DMASTAT_OFFSET	(0x600)
-#define DMASTAT_DRQ	(1 << 0)
-
-#define CSTATUS_IRQ	(1 << 0)
-
-#define VERSION "1.10 (23/01/2003 2.5.57)"
-
-/*
- * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type)
- * Purpose : initialises DMA/PIO
- * Params  : host      - host
- *	     SCpnt     - command
- *	     direction - DMA on to/off of card
- *	     min_type  - minimum DMA support that we must have for this transfer
- * Returns : 0 if we should not set CMD_WITHDMA for transfer info command
- */
-static fasdmatype_t
-arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
-		       fasdmadir_t direction, fasdmatype_t min_type)
-{
-	/*
-	 * We don't do real DMA
-	 */
-	return fasdma_pseudo;
-}
-
-static void arxescsi_pseudo_dma_write(unsigned char *addr, unsigned char *base)
-{
-       __asm__ __volatile__(
-       "               stmdb   sp!, {r0-r12}\n"
-       "               mov     r3, %0\n"
-       "               mov     r1, %1\n"
-       "               add     r2, r1, #512\n"
-       "               mov     r4, #256\n"
-       ".loop_1:       ldmia   r3!, {r6, r8, r10, r12}\n"
-       "               mov     r5, r6, lsl #16\n"
-       "               mov     r7, r8, lsl #16\n"
-       ".loop_2:       ldrb    r0, [r1, #1536]\n"
-       "               tst     r0, #1\n"
-       "               beq     .loop_2\n"
-       "               stmia   r2, {r5-r8}\n\t"
-       "               mov     r9, r10, lsl #16\n"
-       "               mov     r11, r12, lsl #16\n"
-       ".loop_3:       ldrb    r0, [r1, #1536]\n"
-       "               tst     r0, #1\n"
-       "               beq     .loop_3\n"
-       "               stmia   r2, {r9-r12}\n"
-       "               subs    r4, r4, #16\n"
-       "               bne     .loop_1\n"
-       "               ldmia   sp!, {r0-r12}\n"
-       :
-       : "r" (addr), "r" (base));
-}
-
-/*
- * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer)
- * Purpose : handles pseudo DMA
- * Params  : host      - host
- *	     SCpnt     - command
- *	     direction - DMA on to/off of card
- *	     transfer  - minimum number of bytes we expect to transfer
- */
-static void
-arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
-		    fasdmadir_t direction, int transfer)
-{
-	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
-	unsigned int length, error = 0;
-	unsigned char *base = info->info.scsi.io_base;
-	unsigned char *addr;
-
-	length = SCp->this_residual;
-	addr = SCp->ptr;
-
-	if (direction == DMA_OUT) {
-		unsigned int word;
-		while (length > 256) {
-			if (readb(base + 0x80) & STAT_INT) {
-				error = 1;
-				break;
-			}
-			arxescsi_pseudo_dma_write(addr, base);
-			addr += 256;
-			length -= 256;
-		}
-
-		if (!error)
-			while (length > 0) {
-				if (readb(base + 0x80) & STAT_INT)
-					break;
-	 
-				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
-					continue;
-
-				word = *addr | *(addr + 1) << 8;
-
-				writew(word, base + DMADATA_OFFSET);
-				if (length > 1) {
-					addr += 2;
-					length -= 2;
-				} else {
-					addr += 1;
-					length -= 1;
-				}
-			}
-	}
-	else {
-		if (transfer && (transfer & 255)) {
-			while (length >= 256) {
-				if (readb(base + 0x80) & STAT_INT) {
-					error = 1;
-					break;
-				}
-	    
-				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
-					continue;
-
-				readsw(base + DMADATA_OFFSET, addr, 256 >> 1);
-				addr += 256;
-				length -= 256;
-			}
-		}
-
-		if (!(error))
-			while (length > 0) {
-				unsigned long word;
-
-				if (readb(base + 0x80) & STAT_INT)
-					break;
-
-				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
-					continue;
-
-				word = readw(base + DMADATA_OFFSET);
-				*addr++ = word;
-				if (--length > 0) {
-					*addr++ = word >> 8;
-					length --;
-				}
-			}
-	}
-}
-
-/*
- * Function: int arxescsi_dma_stop(host, SCpnt)
- * Purpose : stops DMA/PIO
- * Params  : host  - host
- *	     SCpnt - command
- */
-static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
-{
-	/*
-	 * no DMA to stop
-	 */
-}
-
-/*
- * Function: const char *arxescsi_info(struct Scsi_Host * host)
- * Purpose : returns a descriptive string about this interface,
- * Params  : host - driver host structure to return info for.
- * Returns : pointer to a static buffer containing null terminated string.
- */
-static const char *arxescsi_info(struct Scsi_Host *host)
-{
-	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
-	static char string[150];
-
-	sprintf(string, "%s (%s) in slot %d v%s",
-		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
-		VERSION);
-
-	return string;
-}
-
-/*
- * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset,
- *					 int length, int host_no, int inout)
- * Purpose : Return information about the driver to a user process accessing
- *	     the /proc filesystem.
- * Params  : buffer - a buffer to write information to
- *	     start  - a pointer into this buffer set by this routine to the start
- *		      of the required information.
- *	     offset - offset into information that we have read upto.
- *	     length - length of buffer
- *	     host_no - host number to return information for
- *	     inout  - 0 for reading, 1 for writing.
- * Returns : length of data written to buffer.
- */
-static int
-arxescsi_proc_info(char *buffer, char **start, off_t offset, int length,
-		   int host_no, int inout)
-{
-	int pos, begin;
-	struct Scsi_Host *host;
-	struct arxescsi_info *info;
-	Scsi_Device *scd;
-
-	host = scsi_host_hn_get(host_no);
-	if (!host)
-		return 0;
-
-	info = (struct arxescsi_info *)host->hostdata;
-	if (inout == 1)
-		return -EINVAL;
-
-	begin = 0;
-	pos = sprintf(buffer, "ARXE 16-bit SCSI driver v%s\n", VERSION);
-	pos += fas216_print_host(&info->info, buffer + pos);
-	pos += fas216_print_stats(&info->info, buffer + pos);
-
-	pos += sprintf (buffer+pos, "\nAttached devices:\n");
-
-	list_for_each_entry(scd, &host->my_devices, siblings) {
-		pos += fas216_print_device(&info->info, scd, buffer + pos);
-
-		if (pos + begin < offset) {
-			begin += pos;
-			pos = 0;
-		}
-		if (pos + begin > offset + length)
-			break;
-	}
-
-	*start = buffer + (offset - begin);
-	pos -= offset - begin;
-	if (pos > length)
-		pos = length;
-
-	return pos;
-}
-
-static Scsi_Host_Template arxescsi_template = {
-	.proc_info			= arxescsi_proc_info,
-	.name				= "ARXE SCSI card",
-	.info				= arxescsi_info,
-	.command			= fas216_command,
-	.queuecommand			= fas216_queue_command,
-	.eh_host_reset_handler		= fas216_eh_host_reset,
-	.eh_bus_reset_handler		= fas216_eh_bus_reset,
-	.eh_device_reset_handler	= fas216_eh_device_reset,
-	.eh_abort_handler		= fas216_eh_abort,
-	.can_queue			= 0,
-	.this_id			= 7,
-	.sg_tablesize			= SG_ALL,
-	.cmd_per_lun			= 1,
-	.use_clustering			= DISABLE_CLUSTERING,
-	.proc_name			= "arxescsi",
-};
-
-static int __devinit
-arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct Scsi_Host *host;
-	struct arxescsi_info *info;
-	unsigned long resbase, reslen;
-	unsigned char *base;
-	int ret;
-
-	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
-	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
-
-	if (!request_mem_region(resbase, reslen, "arxescsi")) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	base = ioremap(resbase, reslen);
-	if (!base) {
-		ret = -ENOMEM;
-		goto out_region;
-	}
-
-	host = scsi_register(&arxescsi_template, sizeof(struct arxescsi_info));
-	if (!host) {
-		ret = -ENOMEM;
-		goto out_unmap;
-	}
-
-	host->base = (unsigned long)base;
-	host->irq = NO_IRQ;
-	host->dma_channel = NO_DMA;
-
-	info = (struct arxescsi_info *)host->hostdata;
-	info->ec = ec;
-
-	info->info.scsi.io_base		= base + 0x2000;
-	info->info.scsi.irq		= host->irq;
-	info->info.scsi.io_shift	= 5;
-	info->info.ifcfg.clockrate	= 24; /* MHz */
-	info->info.ifcfg.select_timeout = 255;
-	info->info.ifcfg.asyncperiod	= 200; /* ns */
-	info->info.ifcfg.sync_max_depth	= 0;
-	info->info.ifcfg.cntl3		= CNTL3_FASTSCSI | CNTL3_FASTCLK;
-	info->info.ifcfg.disconnect_ok	= 0;
-	info->info.ifcfg.wide_max_size	= 0;
-	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
-	info->info.dma.setup		= arxescsi_dma_setup;
-	info->info.dma.pseudo		= arxescsi_dma_pseudo;
-	info->info.dma.stop		= arxescsi_dma_stop;
-		
-	ec->irqaddr = base;
-	ec->irqmask = CSTATUS_IRQ;
-
-	ret = fas216_init(host);
-	if (ret)
-		goto out_unregister;
-
-	ret = fas216_add(host, &ec->dev);
-	if (ret == 0)
-		goto out;
-
-	fas216_release(host);
- out_unregister:
-	scsi_unregister(host);
- out_unmap:
-	iounmap(base);
- out_region:
-	release_mem_region(resbase, reslen);
- out:
-	return ret;
-}
-
-static void __devexit arxescsi_remove(struct expansion_card *ec)
-{
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-	unsigned long resbase, reslen;
-
-	ecard_set_drvdata(ec, NULL);
-	fas216_remove(host);
-
-	iounmap((void *)host->base);
-
-	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
-	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
-
-	release_mem_region(resbase, reslen);
-
-	fas216_release(host);
-	scsi_unregister(host);
-}
-
-static const struct ecard_id arxescsi_cids[] = {
-	{ MANU_ARXE, PROD_ARXE_SCSI },
-	{ 0xffff, 0xffff },
-};
-
-static struct ecard_driver arxescsi_driver = {
-	.probe		= arxescsi_probe,
-	.remove		= __devexit_p(arxescsi_remove),
-	.id_table	= arxescsi_cids,
-	.drv = {
-		.devclass	= &shost_devclass,
-		.name		= "arxescsi",
-	},
-};
-
-static int __init init_arxe_scsi_driver(void)
-{
-	return ecard_register_driver(&arxescsi_driver);
-}
-
-static void __exit exit_arxe_scsi_driver(void)
-{
-	ecard_remove_driver(&arxescsi_driver);
-}
-
-module_init(init_arxe_scsi_driver);
-module_exit(exit_arxe_scsi_driver);
-
-MODULE_AUTHOR("Stefan Hanske");
-MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines");
-MODULE_LICENSE("GPL");
-
diff -Nru a/drivers/acorn/scsi/cumana_1.c b/drivers/acorn/scsi/cumana_1.c
--- a/drivers/acorn/scsi/cumana_1.c	Sun Jan 26 11:34:35 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,356 +0,0 @@
-/*
- * Generic Generic NCR5380 driver
- *
- * Copyright 1995-2002, Russell King
- */
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/blk.h>
-#include <linux/init.h>
-
-#include <asm/ecard.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-
-#include <scsi/scsicam.h>
-
-#define AUTOSENSE
-#define PSEUDO_DMA
-
-#define CUMANASCSI_PUBLIC_RELEASE 1
-
-#define NCR5380_implementation_fields	int port, ctrl
-#define NCR5380_local_declare()		struct Scsi_Host *_instance
-#define NCR5380_setup(instance)		_instance = instance
-#define NCR5380_read(reg)		cumanascsi_read(_instance, reg)
-#define NCR5380_write(reg, value)	cumanascsi_write(_instance, reg, value)
-#define NCR5380_intr			cumanascsi_intr
-#define NCR5380_queue_command		cumanascsi_queue_command
-#define NCR5380_proc_info		cumanascsi_proc_info
-
-int NCR5380_proc_info(char *buffer, char **start, off_t offset,
-		      int length, int hostno, int inout);
-
-#define BOARD_NORMAL	0
-#define BOARD_NCR53C400	1
-
-#include "../../scsi/NCR5380.h"
-
-void cumanascsi_setup(char *str, int *ints)
-{
-}
-
-const char *cumanascsi_info(struct Scsi_Host *spnt)
-{
-	return "";
-}
-
-#ifdef NOT_EFFICIENT
-#define CTRL(p,v)     outb(*ctrl = (v), (p) - 577)
-#define STAT(p)       inb((p)+1)
-#define IN(p)         inb((p))
-#define OUT(v,p)      outb((v), (p))
-#else
-#define CTRL(p,v)	(p[-2308] = (*ctrl = (v)))
-#define STAT(p)		(p[4])
-#define IN(p)		(*(p))
-#define IN2(p)		((unsigned short)(*(volatile unsigned long *)(p)))
-#define OUT(v,p)	(*(p) = (v))
-#define OUT2(v,p)	(*((volatile unsigned long *)(p)) = (v))
-#endif
-#define L(v)		(((v)<<16)|((v) & 0x0000ffff))
-#define H(v)		(((v)>>16)|((v) & 0xffff0000))
-
-static inline int
-NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, int len)
-{
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
-  unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = iobase & ~(0x3C0000>>2);
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
-
-  if(!len) return 0;
-
-  CTRL(iobase, 0x02);
-  laddr = (unsigned long *)addr;
-  while(len >= 32)
-  {
-    int status;
-    unsigned long v;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(!(status & 0x40))
-      continue;
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
-    len -= 32;
-    if(len == 0)
-      break;
-  }
-
-  addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x12);
-  while(len > 0)
-  {
-    int status;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      OUT(*addr++, dma_io);
-      if(--len == 0)
-        break;
-    }
-
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      OUT(*addr++, dma_io);
-      if(--len == 0)
-        break;
-    }
-  }
-end:
-  CTRL(iobase, oldctrl|0x40);
-  return len;
-}
-
-static inline int
-NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, int len)
-{
-  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-  int oldctrl = *ctrl;
-  unsigned long *laddr;
-#ifdef NOT_EFFICIENT
-  int iobase = instance->io_port;
-  int dma_io = iobase & ~(0x3C0000>>2);
-#else
-  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
-  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
-#endif
-
-  if(!len) return 0;
-
-  CTRL(iobase, 0x00);
-  laddr = (unsigned long *)addr;
-  while(len >= 32)
-  {
-    int status;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(!(status & 0x40))
-      continue;
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
-    len -= 32;
-    if(len == 0)
-      break;
-  }
-
-  addr = (unsigned char *)laddr;
-  CTRL(iobase, 0x10);
-  while(len > 0)
-  {
-    int status;
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      *addr++ = IN(dma_io);
-      if(--len == 0)
-        break;
-    }
-
-    status = STAT(iobase);
-    if(status & 0x80)
-      goto end;
-    if(status & 0x40)
-    {
-      *addr++ = IN(dma_io);
-      if(--len == 0)
-        break;
-    }
-  }
-end:
-  CTRL(iobase, oldctrl|0x40);
-  return len;
-}
-
-#undef STAT
-#undef CTRL
-#undef IN
-#undef OUT
-
-#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
-
-static char cumanascsi_read(struct Scsi_Host *instance, int reg)
-{
-	unsigned int iobase = instance->io_port;
-	int i;
-	int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-
-	CTRL(iobase, 0);
-	i = inb(iobase + 64 + reg);
-	CTRL(iobase, 0x40);
-
-	return i;
-}
-
-static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value)
-{
-	int iobase = instance->io_port;
-	int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-
-	CTRL(iobase, 0);
-	outb(value, iobase + 64 + reg);
-	CTRL(iobase, 0x40);
-}
-
-#undef CTRL
-
-#include "../../scsi/NCR5380.c"
-
-static Scsi_Host_Template cumanascsi_template = {
-	.module			= THIS_MODULE,
-	.name			= "Cumana 16-bit SCSI",
-	.info			= cumanascsi_info,
-	.queuecommand		= cumanascsi_queue_command,
-	.eh_abort_handler	= NCR5380_abort,
-	.eh_device_reset_handler= NCR5380_device_reset,
-	.eh_bus_reset_handler	= NCR5380_bus_reset,
-	.eh_host_reset_handler	= NCR5380_host_reset,
-	.can_queue		= 16,
-	.this_id		= 7,
-	.sg_tablesize		= SG_ALL,
-	.cmd_per_lun		= 2,
-	.unchecked_isa_dma	= 0,
-	.use_clustering		= DISABLE_CLUSTERING,
-	.proc_name		= "CumanaSCSI-1",
-};
-
-static int __devinit
-cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct Scsi_Host *host;
-	int ret = -ENOMEM;
-
-	host = scsi_register(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
-	if (!host)
-		goto out;
-
-        host->io_port = ecard_address(ec, ECARD_IOC, ECARD_SLOW) + 0x800;
-	host->irq = ec->irq;
-
-	NCR5380_init(host, 0);
-
-	host->n_io_port = 255;
-	if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
-		ret = -EBUSY;
-		goto out_free;
-	}
-
-        ((struct NCR5380_hostdata *)host->hostdata)->ctrl = 0;
-        outb(0x00, host->io_port - 577);
-
-	ret = request_irq(host->irq, cumanascsi_intr, SA_INTERRUPT,
-			  "CumanaSCSI-1", host);
-	if (ret) {
-		printk("scsi%d: IRQ%d not free: %d\n",
-		    host->host_no, host->irq, ret);
-		goto out_release;
-	}
-
-	printk("scsi%d: at port 0x%08lx irq %d",
-		host->host_no, host->io_port, host->irq);
-	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
-		host->can_queue, host->cmd_per_lun, CUMANASCSI_PUBLIC_RELEASE);
-	printk("\nscsi%d:", host->host_no);
-	NCR5380_print_options(host);
-	printk("\n");
-
-	ret = scsi_add_host(host, &ec->dev);
-	if (ret == 0)
-		goto out;
-
-	free_irq(host->irq, host);
- out_release:
-	release_region(host->io_port, host->n_io_port);
- out_free:
-	scsi_unregister(host);
- out:
-	return ret;
-}
-
-static void __devexit cumanascsi1_remove(struct expansion_card *ec)
-{
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-
-	ecard_set_drvdata(ec, NULL);
-
-	scsi_remove_host(host);
-	free_irq(host->irq, host);
-	release_region(host->io_port, host->n_io_port);
-	scsi_unregister(host);
-}
-
-static const struct ecard_id cumanascsi1_cids[] = {
-	{ MANU_CUMANA, PROD_CUMANA_SCSI_1 },
-	{ 0xffff, 0xffff }
-};
-
-static struct ecard_driver cumanascsi1_driver = {
-	.probe		= cumanascsi1_probe,
-	.remove		= __devexit_p(cumanascsi1_remove),
-	.id_table	= cumanascsi1_cids,
-	.drv = {
-		.devclass	= &shost_devclass,
-		.name		= "cumanascsi1",
-	},
-};
-
-static int __init cumanascsi_init(void)
-{
-	return ecard_register_driver(&cumanascsi1_driver);
-}
-
-static void __exit cumanascsi_exit(void)
-{
-	ecard_remove_driver(&cumanascsi1_driver);
-}
-
-module_init(cumanascsi_init);
-module_exit(cumanascsi_exit);
-
-MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/acorn/scsi/cumana_2.c b/drivers/acorn/scsi/cumana_2.c
--- a/drivers/acorn/scsi/cumana_2.c	Sun Jan 26 11:34:36 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,597 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/cumana_2.c
- *
- *  Copyright (C) 1997-2002 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.
- *
- *  Changelog:
- *   30-08-1997	RMK	0.0.0	Created, READONLY version.
- *   22-01-1998	RMK	0.0.1	Updated to 2.1.80.
- *   15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
- *   02-05-1998	RMK	0.0.2	Updated & added DMA support.
- *   27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
- *   18-08-1998	RMK	0.0.3	Fixed synchronous transfer depth.
- *   02-04-2000	RMK	0.0.4	Updated for new error handling code.
- */
-#include <linux/module.h>
-#include <linux/blk.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-#include "fas216.h"
-#include "scsi.h"
-
-#include <scsi/scsicam.h>
-
-#define CUMANASCSI2_STATUS		(0x0000)
-#define STATUS_INT			(1 << 0)
-#define STATUS_DRQ			(1 << 1)
-#define STATUS_LATCHED			(1 << 3)
-
-#define CUMANASCSI2_ALATCH		(0x0014)
-#define ALATCH_ENA_INT			(3)
-#define ALATCH_DIS_INT			(2)
-#define ALATCH_ENA_TERM			(5)
-#define ALATCH_DIS_TERM			(4)
-#define ALATCH_ENA_BIT32		(11)
-#define ALATCH_DIS_BIT32		(10)
-#define ALATCH_ENA_DMA			(13)
-#define ALATCH_DIS_DMA			(12)
-#define ALATCH_DMA_OUT			(15)
-#define ALATCH_DMA_IN			(14)
-
-#define CUMANASCSI2_PSEUDODMA		(0x0200)
-
-#define CUMANASCSI2_FAS216_OFFSET	(0x0300)
-#define CUMANASCSI2_FAS216_SHIFT	2
-
-/*
- * Version
- */
-#define VERSION "1.00 (13/11/2002 2.5.47)"
-
-/*
- * Use term=0,1,0,0,0 to turn terminators on/off
- */
-static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
-
-#define NR_SG	256
-
-struct cumanascsi2_info {
-	FAS216_Info		info;
-	struct expansion_card	*ec;
-
-	void			*status;	/* card status register	*/
-	void			*alatch;	/* Control register	*/
-	unsigned int		terms;		/* Terminator state	*/
-	void			*dmaarea;	/* Pseudo DMA area	*/
-	struct scatterlist	sg[NR_SG];	/* Scatter DMA list	*/
-};
-
-#define CSTATUS_IRQ	(1 << 0)
-#define CSTATUS_DRQ	(1 << 1)
-
-/* Prototype: void cumanascsi_2_irqenable(ec, irqnr)
- * Purpose  : Enable interrupts on Cumana SCSI 2 card
- * Params   : ec    - expansion card structure
- *          : irqnr - interrupt number
- */
-static void
-cumanascsi_2_irqenable(struct expansion_card *ec, int irqnr)
-{
-	writeb(ALATCH_ENA_INT, ec->irq_data);
-}
-
-/* Prototype: void cumanascsi_2_irqdisable(ec, irqnr)
- * Purpose  : Disable interrupts on Cumana SCSI 2 card
- * Params   : ec    - expansion card structure
- *          : irqnr - interrupt number
- */
-static void
-cumanascsi_2_irqdisable(struct expansion_card *ec, int irqnr)
-{
-	writeb(ALATCH_DIS_INT, ec->irq_data);
-}
-
-static const expansioncard_ops_t cumanascsi_2_ops = {
-	.irqenable	= cumanascsi_2_irqenable,
-	.irqdisable	= cumanascsi_2_irqdisable,
-};
-
-/* Prototype: void cumanascsi_2_terminator_ctl(host, on_off)
- * Purpose  : Turn the Cumana SCSI 2 terminators on or off
- * Params   : host   - card to turn on/off
- *          : on_off - !0 to turn on, 0 to turn off
- */
-static void
-cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off)
-{
-	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
-
-	if (on_off) {
-		info->terms = 1;
-		writeb(ALATCH_ENA_TERM, info->alatch);
-	} else {
-		info->terms = 0;
-		writeb(ALATCH_DIS_TERM, info->alatch);
-	}
-}
-
-/* Prototype: void cumanascsi_2_intr(irq, *dev_id, *regs)
- * Purpose  : handle interrupts from Cumana SCSI 2 card
- * Params   : irq    - interrupt number
- *	      dev_id - user-defined (Scsi_Host structure)
- *	      regs   - processor registers at interrupt
- */
-static void
-cumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct cumanascsi2_info *info = dev_id;
-
-	fas216_intr(&info->info);
-}
-
-/* Prototype: fasdmatype_t cumanascsi_2_dma_setup(host, SCpnt, direction, min_type)
- * Purpose  : initialises DMA/PIO
- * Params   : host      - host
- *	      SCpnt     - command
- *	      direction - DMA on to/off of card
- *	      min_type  - minimum DMA support that we must have for this transfer
- * Returns  : type of transfer to be performed
- */
-static fasdmatype_t
-cumanascsi_2_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
-		       fasdmadir_t direction, fasdmatype_t min_type)
-{
-	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
-	struct device *dev = scsi_get_device(host);
-	int dmach = host->dma_channel;
-
-	writeb(ALATCH_DIS_DMA, info->alatch);
-
-	if (dmach != NO_DMA &&
-	    (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
-		int bufs, map_dir, dma_dir, alatch_dir;
-
-		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
-
-		if (direction == DMA_OUT)
-			map_dir = DMA_TO_DEVICE,
-			dma_dir = DMA_MODE_WRITE,
-			alatch_dir = ALATCH_DMA_OUT;
-		else
-			map_dir = DMA_FROM_DEVICE,
-			dma_dir = DMA_MODE_READ,
-			alatch_dir = ALATCH_DMA_IN;
-
-		dma_map_sg(dev, info->sg, bufs + 1, map_dir);
-
-		disable_dma(dmach);
-		set_dma_sg(dmach, info->sg, bufs + 1);
-		writeb(alatch_dir, info->alatch);
-		set_dma_mode(dmach, dma_dir);
-		enable_dma(dmach);
-		writeb(ALATCH_ENA_DMA, info->alatch);
-		writeb(ALATCH_DIS_BIT32, info->alatch);
-		return fasdma_real_all;
-	}
-
-	/*
-	 * If we're not doing DMA,
-	 *  we'll do pseudo DMA
-	 */
-	return fasdma_pio;
-}
-
-/*
- * Prototype: void cumanascsi_2_dma_pseudo(host, SCpnt, direction, transfer)
- * Purpose  : handles pseudo DMA
- * Params   : host      - host
- *	      SCpnt     - command
- *	      direction - DMA on to/off of card
- *	      transfer  - minimum number of bytes we expect to transfer
- */
-static void
-cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
-			fasdmadir_t direction, int transfer)
-{
-	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
-	unsigned int length;
-	unsigned char *addr;
-
-	length = SCp->this_residual;
-	addr = SCp->ptr;
-
-	if (direction == DMA_OUT)
-#if 0
-		while (length > 1) {
-			unsigned long word;
-			unsigned int status = readb(info->status);
-
-			if (status & STATUS_INT)
-				goto end;
-
-			if (!(status & STATUS_DRQ))
-				continue;
-
-			word = *addr | *(addr + 1) << 8;
-			writew(word, info->dmaarea);
-			addr += 2;
-			length -= 2;
-		}
-#else
-		printk ("PSEUDO_OUT???\n");
-#endif
-	else {
-		if (transfer && (transfer & 255)) {
-			while (length >= 256) {
-				unsigned int status = readb(info->status);
-
-				if (status & STATUS_INT)
-					return;
-	    
-				if (!(status & STATUS_DRQ))
-					continue;
-
-				readsw(info->dmaarea, addr, 256 >> 1);
-				addr += 256;
-				length -= 256;
-			}
-		}
-
-		while (length > 0) {
-			unsigned long word;
-			unsigned int status = readb(info->status);
-
-			if (status & STATUS_INT)
-				return;
-
-			if (!(status & STATUS_DRQ))
-				continue;
-
-			word = readw(info->dmaarea);
-			*addr++ = word;
-			if (--length > 0) {
-				*addr++ = word >> 8;
-				length --;
-			}
-		}
-	}
-}
-
-/* Prototype: int cumanascsi_2_dma_stop(host, SCpnt)
- * Purpose  : stops DMA/PIO
- * Params   : host  - host
- *	      SCpnt - command
- */
-static void
-cumanascsi_2_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
-{
-	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
-	if (host->dma_channel != NO_DMA) {
-		writeb(ALATCH_DIS_DMA, info->alatch);
-		disable_dma(host->dma_channel);
-	}
-}
-
-/* Prototype: const char *cumanascsi_2_info(struct Scsi_Host * host)
- * Purpose  : returns a descriptive string about this interface,
- * Params   : host - driver host structure to return info for.
- * Returns  : pointer to a static buffer containing null terminated string.
- */
-const char *cumanascsi_2_info(struct Scsi_Host *host)
-{
-	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
-	static char string[150];
-
-	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
-		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
-		VERSION, info->terms ? "n" : "ff");
-
-	return string;
-}
-
-/* Prototype: int cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
- * Purpose  : Set a driver specific function
- * Params   : host   - host to setup
- *          : buffer - buffer containing string describing operation
- *          : length - length of string
- * Returns  : -EINVAL, or 0
- */
-static int
-cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
-{
-	int ret = length;
-
-	if (length >= 11 && strcmp(buffer, "CUMANASCSI2") == 0) {
-		buffer += 11;
-		length -= 11;
-
-		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
-			if (buffer[5] == '1')
-				cumanascsi_2_terminator_ctl(host, 1);
-			else if (buffer[5] == '0')
-				cumanascsi_2_terminator_ctl(host, 0);
-			else
-				ret = -EINVAL;
-		} else
-			ret = -EINVAL;
-	} else
-		ret = -EINVAL;
-
-	return ret;
-}
-
-/* Prototype: int cumanascsi_2_proc_info(char *buffer, char **start, off_t offset,
- *					 int length, int host_no, int inout)
- * Purpose  : Return information about the driver to a user process accessing
- *	      the /proc filesystem.
- * Params   : buffer - a buffer to write information to
- *	      start  - a pointer into this buffer set by this routine to the start
- *		       of the required information.
- *	      offset - offset into information that we have read upto.
- *	      length - length of buffer
- *	      host_no - host number to return information for
- *	      inout  - 0 for reading, 1 for writing.
- * Returns  : length of data written to buffer.
- */
-int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
-			    int length, int host_no, int inout)
-{
-	int pos, begin;
-	struct Scsi_Host *host;
-	struct cumanascsi2_info *info;
-	Scsi_Device *scd;
-
-	host = scsi_host_hn_get(host_no);
-	if (!host)
-		return 0;
-
-	if (inout == 1)
-		return cumanascsi_2_set_proc_info(host, buffer, length);
-
-	info = (struct cumanascsi2_info *)host->hostdata;
-
-	begin = 0;
-	pos = sprintf(buffer, "Cumana SCSI II driver v%s\n", VERSION);
-	pos += fas216_print_host(&info->info, buffer + pos);
-	pos += sprintf(buffer + pos, "Term    : o%s\n",
-			info->terms ? "n" : "ff");
-
-	pos += fas216_print_stats(&info->info, buffer + pos);
-
-	pos += sprintf(buffer+pos, "\nAttached devices:\n");
-
-	list_for_each_entry(scd, &host->my_devices, siblings) {
-		int len;
-
-		proc_print_scsidevice(scd, buffer, &len, pos);
-		pos += len;
-		pos += sprintf(buffer+pos, "Extensions: ");
-		if (scd->tagged_supported)
-			pos += sprintf(buffer+pos, "TAG %sabled [%d] ",
-				       scd->tagged_queue ? "en" : "dis",
-				       scd->current_tag);
-		pos += sprintf(buffer+pos, "\n");
-
-		if (pos + begin < offset) {
-			begin += pos;
-			pos = 0;
-		}
-		if (pos + begin > offset + length)
-			break;
-	}
-
-	*start = buffer + (offset - begin);
-	pos -= offset - begin;
-	if (pos > length)
-		pos = length;
-
-	return pos;
-}
-
-static Scsi_Host_Template cumanascsi2_template = {
-	.module				= THIS_MODULE,
-	.proc_info			= cumanascsi_2_proc_info,
-	.name				= "Cumana SCSI II",
-	.info				= cumanascsi_2_info,
-	.command			= fas216_command,
-	.queuecommand			= fas216_queue_command,
-	.eh_host_reset_handler		= fas216_eh_host_reset,
-	.eh_bus_reset_handler		= fas216_eh_bus_reset,
-	.eh_device_reset_handler	= fas216_eh_device_reset,
-	.eh_abort_handler		= fas216_eh_abort,
-	.can_queue			= 1,
-	.this_id			= 7,
-	.sg_tablesize			= SG_ALL,
-	.cmd_per_lun			= 1,
-	.use_clustering			= DISABLE_CLUSTERING,
-	.proc_name			= "cumanascsi2",
-};
-
-static int __devinit
-cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct Scsi_Host *host;
-	struct cumanascsi2_info *info;
-	unsigned long resbase, reslen;
-	unsigned char *base;
-	int ret;
-
-	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
-	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
-
-	if (!request_mem_region(resbase, reslen, "cumanascsi2")) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	base = ioremap(resbase, reslen);
-	if (!base) {
-		ret = -ENOMEM;
-		goto out_region;
-	}
-
-	host = scsi_register(&cumanascsi2_template,
-			     sizeof(struct cumanascsi2_info));
-	if (!host) {
-		ret = -ENOMEM;
-		goto out_unmap;
-	}
-
-	host->base	  = (unsigned long)base;
-	host->irq	  = ec->irq;
-	host->dma_channel = ec->dma;
-
-	ecard_set_drvdata(ec, host);
-
-	info = (struct cumanascsi2_info *)host->hostdata;
-	info->ec	= ec;
-	info->dmaarea	= base + CUMANASCSI2_PSEUDODMA;
-	info->status	= base + CUMANASCSI2_STATUS;
-	info->alatch	= base + CUMANASCSI2_ALATCH;
-
-	ec->irqaddr	= info->status;
-	ec->irqmask	= STATUS_INT;
-	ec->irq_data	= base + CUMANASCSI2_ALATCH;
-	ec->ops		= &cumanascsi_2_ops;
-
-	cumanascsi_2_terminator_ctl(host, term[ec->slot_no]);
-
-	info->info.scsi.io_base		= base + CUMANASCSI2_FAS216_OFFSET;
-	info->info.scsi.io_shift	= CUMANASCSI2_FAS216_SHIFT;
-	info->info.scsi.irq		= host->irq;
-	info->info.ifcfg.clockrate	= 40; /* MHz */
-	info->info.ifcfg.select_timeout	= 255;
-	info->info.ifcfg.asyncperiod	= 200; /* ns */
-	info->info.ifcfg.sync_max_depth	= 7;
-	info->info.ifcfg.cntl3		= CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
-	info->info.ifcfg.disconnect_ok	= 1;
-	info->info.ifcfg.wide_max_size	= 0;
-	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
-	info->info.dma.setup		= cumanascsi_2_dma_setup;
-	info->info.dma.pseudo		= cumanascsi_2_dma_pseudo;
-	info->info.dma.stop		= cumanascsi_2_dma_stop;
-
-	ret = fas216_init(host);
-	if (ret)
-		goto out_free;
-
-	ret = request_irq(host->irq, cumanascsi_2_intr,
-			  SA_INTERRUPT, "cumanascsi2", info);
-	if (ret) {
-		printk("scsi%d: IRQ%d not free: %d\n",
-		       host->host_no, host->irq, ret);
-		goto out_release;
-	}
-
-	if (host->dma_channel != NO_DMA) {
-		if (request_dma(host->dma_channel, "cumanascsi2")) {
-			printk("scsi%d: DMA%d not free, using PIO\n",
-			       host->host_no, host->dma_channel);
-			host->dma_channel = NO_DMA;
-		} else {
-			set_dma_speed(host->dma_channel, 180);
-			info->info.ifcfg.capabilities |= FASCAP_DMA;
-		}
-	}
-
-	ret = fas216_add(host, &ec->dev);
-	if (ret == 0)
-		goto out;
-
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, host);
-
- out_release:
-	fas216_release(host);
-
- out_free:
-	scsi_unregister(host);
-
- out_unmap:
-	iounmap(base);
-
- out_region:
-	release_mem_region(resbase, reslen);
-
- out:
-	return ret;
-}
-
-static void __devexit cumanascsi2_remove(struct expansion_card *ec)
-{
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
-	unsigned long resbase, reslen;
-
-	ecard_set_drvdata(ec, NULL);
-	fas216_remove(host);
-
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, info);
-
-	iounmap((void *)host->base);
-
-	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
-	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
-
-	release_mem_region(resbase, reslen);
-
-	fas216_release(host);
-	scsi_unregister(host);
-}
-
-static const struct ecard_id cumanascsi2_cids[] = {
-	{ MANU_CUMANA, PROD_CUMANA_SCSI_2 },
-	{ 0xffff, 0xffff },
-};
-
-static struct ecard_driver cumanascsi2_driver = {
-	.probe		= cumanascsi2_probe,
-	.remove		= __devexit_p(cumanascsi2_remove),
-	.id_table	= cumanascsi2_cids,
-	.drv = {
-		.devclass	= &shost_devclass,
-		.name		= "cumanascsi2",
-	},
-};
-
-static int __init cumanascsi2_init(void)
-{
-	return ecard_register_driver(&cumanascsi2_driver);
-}
-
-static void __exit cumanascsi2_exit(void)
-{
-	ecard_remove_driver(&cumanascsi2_driver);
-}
-
-module_init(cumanascsi2_init);
-module_exit(cumanascsi2_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Cumana SCSI-2 driver for Acorn machines");
-MODULE_PARM(term, "1-8i");
-MODULE_PARM_DESC(term, "SCSI bus termination");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/acorn/scsi/ecoscsi.c b/drivers/acorn/scsi/ecoscsi.c
--- a/drivers/acorn/scsi/ecoscsi.c	Sun Nov 17 17:04:35 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,283 +0,0 @@
-#define AUTOSENSE
-/* #define PSEUDO_DMA */
-
-/*
- * EcoSCSI Generic NCR5380 driver
- *
- * Copyright 1995, Russell King
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
- */
-
-/*
- * Options :
- *
- * PARITY - enable parity checking.  Not supported.
- *
- * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
- *
- * USLEEP - enable support for devices that don't disconnect.  Untested.
- */
-
-/*
- * $Log: ecoscsi.c,v $
- * Revision 1.2  1998/03/08 05:49:47  davem
- * Merge to 2.1.89
- *
- * Revision 1.1  1998/02/23 02:45:24  davem
- * Merge to 2.1.88
- *
- */
-
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/blk.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-
-#define NCR5380_implementation_fields	int port, ctrl
-#define NCR5380_local_declare()		struct Scsi_Host *_instance
-#define NCR5380_setup(instance)		_instance = instance
-
-#define NCR5380_read(reg)		ecoscsi_read(_instance, reg)
-#define NCR5380_write(reg, value)	ecoscsi_write(_instance, reg, value)
-
-#define NCR5380_intr			ecoscsi_intr
-#define NCR5380_queue_command		ecoscsi_queue_command
-#define NCR5380_proc_info		ecoscsi_proc_info
-
-#include "../../scsi/NCR5380.h"
-
-#define ECOSCSI_PUBLIC_RELEASE 1
-
-static char ecoscsi_read(struct Scsi_Host *instance, int reg)
-{
-  int iobase = instance->io_port;
-  outb(reg | 8, iobase);
-  return inb(iobase + 1);
-}
-
-static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
-{
-  int iobase = instance->io_port;
-  outb(reg | 8, iobase);
-  outb(value, iobase + 1);
-}
-
-/*
- * Function : ecoscsi_setup(char *str, int *ints)
- *
- * Purpose : LILO command line initialization of the overrides array,
- *
- * Inputs : str - unused, ints - array of integer parameters with ints[0]
- *	equal to the number of ints.
- *
- */
-
-void ecoscsi_setup(char *str, int *ints) {
-}
-
-/*
- * Function : int ecoscsi_detect(Scsi_Host_Template * tpnt)
- *
- * Purpose : initializes ecoscsi NCR5380 driver based on the
- *	command line / compile time port and irq definitions.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- *
- * Returns : 1 if a host adapter was found, 0 if not.
- *
- */
-
-int ecoscsi_detect(Scsi_Host_Template * tpnt)
-{
-	struct Scsi_Host *host;
-
-	tpnt->proc_name = "ecoscsi";
-
-	host = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
-	if (!host)
-		return 0;
-
-	host->io_port = 0x80ce8000;
-	host->n_io_port = 144;
-	host->irq = IRQ_NONE;
-
-	if ( !(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
-		goto unregister_scsi;
-
-	ecoscsi_write (host, MODE_REG, 0x20);		/* Is it really SCSI? */
-	if (ecoscsi_read (host, MODE_REG) != 0x20) /* Write to a reg.    */
-		goto release_reg;
-
-	ecoscsi_write( host, MODE_REG, 0x00 );		/* it back.	      */
-	if (ecoscsi_read (host, MODE_REG) != 0x00)
-		goto release_reg;
-
-	NCR5380_init(host, 0);
-
-	printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port);
-	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
-		host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE);
-	printk("\nscsi%d:", host->host_no);
-	NCR5380_print_options(host);
-	printk("\n");
-
-	return 1;
-
-release_reg:
-	release_region(host->io_port, host->n_io_port);
-unregister_scsi:
-	scsi_unregister(host);
-	return 0;
-}
-
-int ecoscsi_release (struct Scsi_Host *shpnt)
-{
-	if (shpnt->irq != IRQ_NONE)
-		free_irq (shpnt->irq, NULL);
-	if (shpnt->io_port)
-		release_region (shpnt->io_port, shpnt->n_io_port);
-	return 0;
-}
-
-const char * ecoscsi_info (struct Scsi_Host *spnt)
-{
-	return "";
-}
-
-#if 0
-#define STAT(p) inw(p + 144)
-
-static inline int NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr,
-              int len)
-{
-  int iobase = host->io_port;
-printk("writing %p len %d\n",addr, len);
-  if(!len) return -1;
-
-  while(1)
-  {
-    int status;
-    while(((status = STAT(iobase)) & 0x100)==0);
-  }
-}
-
-static inline int NCR5380_pread(struct Scsi_Host *host, unsigned char *addr,
-              int len)
-{
-  int iobase = host->io_port;
-  int iobase2= host->io_port + 0x100;
-  unsigned char *start = addr;
-  int s;
-printk("reading %p len %d\n",addr, len);
-  outb(inb(iobase + 128), iobase + 135);
-  while(len > 0)
-  {
-    int status,b,i, timeout;
-    timeout = 0x07FFFFFF;
-    while(((status = STAT(iobase)) & 0x100)==0)
-    {
-      timeout--;
-      if(status & 0x200 || !timeout)
-      {
-        printk("status = %p\n",status);
-        outb(0, iobase + 135);
-        return 1;
-      }
-    }
-    if(len >= 128)
-    {
-      for(i=0; i<64; i++)
-      {
-        b = inw(iobase + 136);
-        *addr++ = b;
-        *addr++ = b>>8;
-      }
-      len -= 128;
-    }
-    else
-    {
-      b = inw(iobase + 136);
-      *addr ++ = b;
-      len -= 1;
-      if(len)
-        *addr ++ = b>>8;
-      len -= 1;
-    }
-  }
-  outb(0, iobase + 135);
-  printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
-  return 1;
-}
-#endif
-#undef STAT
-
-int NCR5380_proc_info(char *buffer, char **start, off_t offset,
-		      int length, int hostno, int inout);
-
-#define BOARD_NORMAL	0
-#define BOARD_NCR53C400	1
-
-#include "../../scsi/NCR5380.c"
-
-static Scsi_Host_Template ecoscsi_template =  {
-	.module		= THIS_MODULE,
-	.name		= "Serial Port EcoSCSI NCR5380",
-	.detect		= ecoscsi_detect,
-	.release	= ecoscsi_release,
-	.info		= ecoscsi_info,
-	.queuecommand	= ecoscsi_queue_command,
-	.eh_abort_handler	= NCR5380_abort,
-	.eh_device_reset_handler= NCR5380_device_reset,
-	.eh_bus_reset_handler	= NCR5380_bus_reset,
-	.eh_host_reset_handler	= NCR5380_host_reset,
-	.can_queue	= 16,
-	.this_id	= 7,
-	.sg_tablesize	= SG_ALL,
-	.cmd_per_lun	= 2,
-	.use_clustering	= DISABLE_CLUSTERING
-};
-
-static int __init ecoscsi_init(void)
-{
-	scsi_register_host(&ecoscsi_template);
-	if (ecoscsi_template.present)
-		return 0;
-
-	scsi_unregister_host(&ecoscsi_template);
-	return -ENODEV;
-}
-
-static void __exit ecoscsi_exit(void)
-{
-	scsi_unregister_host(&ecoscsi_template);
-}
-
-module_init(ecoscsi_init);
-module_exit(ecoscsi_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines");
-MODULE_LICENSE("GPL");
-
diff -Nru a/drivers/acorn/scsi/eesox.c b/drivers/acorn/scsi/eesox.c
--- a/drivers/acorn/scsi/eesox.c	Sun Jan 26 11:34:36 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,705 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/eesox.c
- *
- *  Copyright (C) 1997-2003 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.
- *
- *  This driver is based on experimentation.  Hence, it may have made
- *  assumptions about the particular card that I have available, and
- *  may not be reliable!
- *
- *  Changelog:
- *   01-10-1997	RMK		Created, READONLY version
- *   15-02-1998	RMK		READ/WRITE version
- *				added DMA support and hardware definitions
- *   14-03-1998	RMK		Updated DMA support
- *				Added terminator control
- *   15-04-1998	RMK		Only do PIO if FAS216 will allow it.
- *   27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
- *   02-04-2000	RMK	0.0.3	Fixed NO_IRQ/NO_DMA problem, updated for new
- *				error handling code.
- */
-#include <linux/module.h>
-#include <linux/blk.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/dma.h>
-#include <asm/ecard.h>
-#include <asm/pgtable.h>
-
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-#include "fas216.h"
-#include "scsi.h"
-
-#include <scsi/scsicam.h>
-
-#define EESOX_FAS216_OFFSET	0x3000
-#define EESOX_FAS216_SHIFT	5
-
-#define EESOX_DMASTAT		0x2800
-#define EESOX_STAT_INTR		0x01
-#define EESOX_STAT_DMA		0x02
-
-#define EESOX_CONTROL		0x2800
-#define EESOX_INTR_ENABLE	0x04
-#define EESOX_TERM_ENABLE	0x02
-#define EESOX_RESET		0x01
-
-#define EESOX_DMADATA		0x3800
-
-#define VERSION "1.10 (17/01/2003 2.5.59)"
-
-/*
- * Use term=0,1,0,0,0 to turn terminators on/off
- */
-static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
-
-#define NR_SG	256
-
-struct eesoxscsi_info {
-	FAS216_Info		info;
-	struct expansion_card	*ec;
-
-	void			*ctl_port;
-	unsigned int		control;
-	struct scatterlist	sg[NR_SG];	/* Scatter DMA list	*/
-};
-
-/* Prototype: void eesoxscsi_irqenable(ec, irqnr)
- * Purpose  : Enable interrupts on EESOX SCSI card
- * Params   : ec    - expansion card structure
- *          : irqnr - interrupt number
- */
-static void
-eesoxscsi_irqenable(struct expansion_card *ec, int irqnr)
-{
-	struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
-
-	info->control |= EESOX_INTR_ENABLE;
-
-	writeb(info->control, info->ctl_port);
-}
-
-/* Prototype: void eesoxscsi_irqdisable(ec, irqnr)
- * Purpose  : Disable interrupts on EESOX SCSI card
- * Params   : ec    - expansion card structure
- *          : irqnr - interrupt number
- */
-static void
-eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr)
-{
-	struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
-
-	info->control &= ~EESOX_INTR_ENABLE;
-
-	writeb(info->control, info->ctl_port);
-}
-
-static const expansioncard_ops_t eesoxscsi_ops = {
-	.irqenable	= eesoxscsi_irqenable,
-	.irqdisable	= eesoxscsi_irqdisable,
-};
-
-/* Prototype: void eesoxscsi_terminator_ctl(*host, on_off)
- * Purpose  : Turn the EESOX SCSI terminators on or off
- * Params   : host   - card to turn on/off
- *          : on_off - !0 to turn on, 0 to turn off
- */
-static void
-eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
-{
-	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
-	unsigned long flags;
-
-	spin_lock_irqsave(host->host_lock, flags);
-	if (on_off)
-		info->control |= EESOX_TERM_ENABLE;
-	else
-		info->control &= ~EESOX_TERM_ENABLE;
-
-	writeb(info->control, info->ctl_port);
-	spin_unlock_irqrestore(host->host_lock, flags);
-}
-
-/* Prototype: void eesoxscsi_intr(irq, *dev_id, *regs)
- * Purpose  : handle interrupts from EESOX SCSI card
- * Params   : irq    - interrupt number
- *	      dev_id - user-defined (Scsi_Host structure)
- *	      regs   - processor registers at interrupt
- */
-static void
-eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct eesoxscsi_info *info = dev_id;
-
-	fas216_intr(&info->info);
-}
-
-/* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type)
- * Purpose  : initialises DMA/PIO
- * Params   : host      - host
- *	      SCpnt     - command
- *	      direction - DMA on to/off of card
- *	      min_type  - minimum DMA support that we must have for this transfer
- * Returns  : type of transfer to be performed
- */
-static fasdmatype_t
-eesoxscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
-		       fasdmadir_t direction, fasdmatype_t min_type)
-{
-	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
-	struct device *dev = scsi_get_device(host);
-	int dmach = host->dma_channel;
-
-	if (dmach != NO_DMA &&
-	    (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
-		int bufs, map_dir, dma_dir;
-
-		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
-
-		if (direction == DMA_OUT)
-			map_dir = DMA_TO_DEVICE,
-			dma_dir = DMA_MODE_WRITE;
-		else
-			map_dir = DMA_FROM_DEVICE,
-			dma_dir = DMA_MODE_READ;
-
-		dma_map_sg(dev, info->sg, bufs + 1, map_dir);
-
-		disable_dma(dmach);
-		set_dma_sg(dmach, info->sg, bufs + 1);
-		set_dma_mode(dmach, dma_dir);
-		enable_dma(dmach);
-		return fasdma_real_all;
-	}
-	/*
-	 * We don't do DMA, we only do slow PIO
-	 *
-	 * Some day, we will do Pseudo DMA
-	 */
-	return fasdma_pseudo;
-}
-
-static void eesoxscsi_buffer_in(void *buf, int length, void *base)
-{
-	const void *reg_fas = base + EESOX_FAS216_OFFSET;
-	const void *reg_dmastat = base + EESOX_DMASTAT;
-	const void *reg_dmadata = base + EESOX_DMADATA;
-	const register unsigned long mask = 0xffff;
-
-	do {
-		unsigned int status;
-
-		/*
-		 * Interrupt request?
-		 */
-		status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
-		if (status & STAT_INT)
-			break;
-
-		/*
-		 * DMA request active?
-		 */
-		status = readb(reg_dmastat);
-		if (!(status & EESOX_STAT_DMA))
-			continue;
-
-		/*
-		 * Get number of bytes in FIFO
-		 */
-		status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
-		if (status > 16)
-			status = 16;
-		if (status > length)
-			status = length;
-
-		/*
-		 * Align buffer.
-		 */
-		if (((u32)buf) & 2 && status >= 2) {
-			*((u16 *)buf)++ = readl(reg_dmadata);
-			status -= 2;
-			length -= 2;
-		}
-
-		if (status >= 8) {
-			unsigned long l1, l2;
-
-			l1 = readl(reg_dmadata) & mask;
-			l1 |= readl(reg_dmadata) << 16;
-			l2 = readl(reg_dmadata) & mask;
-			l2 |= readl(reg_dmadata) << 16;
-			*((u32 *)buf)++ = l1;
-			*((u32 *)buf)++ = l2;
-			length -= 8;
-			continue;
-		}
-
-		if (status >= 4) {
-			unsigned long l1;
-
-			l1 = readl(reg_dmadata) & mask;
-			l1 |= readl(reg_dmadata) << 16;
-
-			*((u32 *)buf)++ = l1;
-			length -= 4;
-			continue;
-		}
-
-		if (status >= 2) {
-			*((u16 *)buf)++ = readl(reg_dmadata);
-			length -= 2;
-		}
-	} while (length);
-}
-
-static void eesoxscsi_buffer_out(void *buf, int length, void *base)
-{
-	const void *reg_fas = base + EESOX_FAS216_OFFSET;
-	const void *reg_dmastat = base + EESOX_DMASTAT;
-	const void *reg_dmadata = base + EESOX_DMADATA;
-
-	do {
-		unsigned int status;
-
-		/*
-		 * Interrupt request?
-		 */
-		status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
-		if (status & STAT_INT)
-			break;
-
-		/*
-		 * DMA request active?
-		 */
-		status = readb(reg_dmastat);
-		if (!(status & EESOX_STAT_DMA))
-			continue;
-
-		/*
-		 * Get number of bytes in FIFO
-		 */
-		status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
-		if (status > 16)
-			status = 16;
-		status = 16 - status;
-		if (status > length)
-			status = length;
-		status &= ~1;
-
-		/*
-		 * Align buffer.
-		 */
-		if (((u32)buf) & 2 && status >= 2) {
-			writel(*((u16 *)buf)++ << 16, reg_dmadata);
-			status -= 2;
-			length -= 2;
-		}
-
-		if (status >= 8) {
-			unsigned long l1, l2;
-
-			l1 = *((u32 *)buf)++;
-			l2 = *((u32 *)buf)++;
-
-			writel(l1 << 16, reg_dmadata);
-			writel(l1, reg_dmadata);
-			writel(l2 << 16, reg_dmadata);
-			writel(l2, reg_dmadata);
-			length -= 8;
-			continue;
-		}
-
-		if (status >= 4) {
-			unsigned long l1;
-
-			l1 = *((u32 *)buf)++;
-
-			writel(l1 << 16, reg_dmadata);
-			writel(l1, reg_dmadata);
-			length -= 4;
-			continue;
-		}
-
-		if (status >= 2) {
-			writel(*((u16 *)buf)++ << 16, reg_dmadata);
-			length -= 2;
-		}
-	} while (length);
-}
-
-static void
-eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
-		     fasdmadir_t dir, int transfer_size)
-{
-	void *base = (void *)host->base;
-	if (dir == DMA_IN) {
-		eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, base);
-	} else {
-		eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, base);
-	}
-}
-
-/* Prototype: int eesoxscsi_dma_stop(host, SCpnt)
- * Purpose  : stops DMA/PIO
- * Params   : host  - host
- *	      SCpnt - command
- */
-static void
-eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
-{
-	if (host->dma_channel != NO_DMA)
-		disable_dma(host->dma_channel);
-}
-
-/* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host)
- * Purpose  : returns a descriptive string about this interface,
- * Params   : host - driver host structure to return info for.
- * Returns  : pointer to a static buffer containing null terminated string.
- */
-const char *eesoxscsi_info(struct Scsi_Host *host)
-{
-	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
-	static char string[150];
-
-	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
-		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
-		VERSION, info->control & EESOX_TERM_ENABLE ? "n" : "ff");
-
-	return string;
-}
-
-/* Prototype: int eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
- * Purpose  : Set a driver specific function
- * Params   : host   - host to setup
- *          : buffer - buffer containing string describing operation
- *          : length - length of string
- * Returns  : -EINVAL, or 0
- */
-static int
-eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
-{
-	int ret = length;
-
-	if (length >= 9 && strncmp(buffer, "EESOXSCSI", 9) == 0) {
-		buffer += 9;
-		length -= 9;
-
-		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
-			if (buffer[5] == '1')
-				eesoxscsi_terminator_ctl(host, 1);
-			else if (buffer[5] == '0')
-				eesoxscsi_terminator_ctl(host, 0);
-			else
-				ret = -EINVAL;
-		} else
-			ret = -EINVAL;
-	} else
-		ret = -EINVAL;
-
-	return ret;
-}
-
-/* Prototype: int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
- *				      int length, int host_no, int inout)
- * Purpose  : Return information about the driver to a user process accessing
- *	      the /proc filesystem.
- * Params   : buffer - a buffer to write information to
- *	      start  - a pointer into this buffer set by this routine to the start
- *		       of the required information.
- *	      offset - offset into information that we have read upto.
- *	      length - length of buffer
- *	      host_no - host number to return information for
- *	      inout  - 0 for reading, 1 for writing.
- * Returns  : length of data written to buffer.
- */
-int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
-			    int length, int host_no, int inout)
-{
-	int pos, begin;
-	struct Scsi_Host *host;
-	struct eesoxscsi_info *info;
-	Scsi_Device *scd;
-
-	host = scsi_host_hn_get(host_no);
-	if (!host)
-		return 0;
-
-	if (inout == 1)
-		return eesoxscsi_set_proc_info(host, buffer, length);
-
-	info = (struct eesoxscsi_info *)host->hostdata;
-
-	begin = 0;
-	pos = sprintf(buffer, "EESOX SCSI driver v%s\n", VERSION);
-	pos += fas216_print_host(&info->info, buffer + pos);
-	pos += sprintf(buffer + pos, "Term    : o%s\n",
-			info->control & EESOX_TERM_ENABLE ? "n" : "ff");
-
-	pos += fas216_print_stats(&info->info, buffer + pos);
-
-	pos += sprintf(buffer+pos, "\nAttached devices:\n");
-
-	list_for_each_entry(scd, &host->my_devices, siblings) {
-		int len;
-
-		proc_print_scsidevice(scd, buffer, &len, pos);
-		pos += len;
-		pos += sprintf(buffer+pos, "Extensions: ");
-		if (scd->tagged_supported)
-			pos += sprintf(buffer+pos, "TAG %sabled [%d] ",
-					scd->tagged_queue ? "en" : "dis",
-					scd->current_tag);
-		pos += sprintf (buffer+pos, "\n");
-
-		if (pos + begin < offset) {
-			begin += pos;
-			pos = 0;
-		}
-	}
-	*start = buffer + (offset - begin);
-	pos -= offset - begin;
-	if (pos > length)
-		pos = length;
-
-	return pos;
-}
-
-static ssize_t eesoxscsi_show_term(struct device *dev, char *buf)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
-
-	return sprintf(buf, "%d\n", info->control & EESOX_TERM_ENABLE ? 1 : 0);
-}
-
-static ssize_t eesoxscsi_store_term(struct device *dev, const char *buf, size_t len)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
-	unsigned long flags;
-
-	if (len > 1) {
-		spin_lock_irqsave(host->host_lock, flags);
-		if (buf[0] != '0') {
-			info->control |= EESOX_TERM_ENABLE;
-		} else {
-			info->control &= ~EESOX_TERM_ENABLE;
-		}
-		writeb(info->control, info->ctl_port);
-		spin_unlock_irqrestore(host->host_lock, flags);
-	}
-
-	return len;
-}
-
-static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
-		   eesoxscsi_show_term, eesoxscsi_store_term);
-
-static Scsi_Host_Template eesox_template = {
-	.module				= THIS_MODULE,
-	.proc_info			= eesoxscsi_proc_info,
-	.name				= "EESOX SCSI",
-	.info				= eesoxscsi_info,
-	.command			= fas216_command,
-	.queuecommand			= fas216_queue_command,
-	.eh_host_reset_handler		= fas216_eh_host_reset,
-	.eh_bus_reset_handler		= fas216_eh_bus_reset,
-	.eh_device_reset_handler	= fas216_eh_device_reset,
-	.eh_abort_handler		= fas216_eh_abort,
-	.can_queue			= 1,
-	.this_id			= 7,
-	.sg_tablesize			= SG_ALL,
-	.cmd_per_lun			= 1,
-	.use_clustering			= DISABLE_CLUSTERING,
-	.proc_name			= "eesox",
-};
-
-static int __devinit
-eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct Scsi_Host *host;
-	struct eesoxscsi_info *info;
-	unsigned long resbase, reslen;
-	unsigned char *base;
-	int ret;
-
-	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
-	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
-
-	if (!request_mem_region(resbase, reslen, "eesoxscsi")) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	base = ioremap(resbase, reslen);
-	if (!base) {
-		ret = -ENOMEM;
-		goto out_region;
-	}
-
-	host = scsi_register(&eesox_template,
-			     sizeof(struct eesoxscsi_info));
-	if (!host) {
-		ret = -ENOMEM;
-		goto out_unmap;
-	}
-
-	host->base	  = (unsigned long)base;
-	host->irq	  = ec->irq;
-	host->dma_channel = ec->dma;
-
-	ecard_set_drvdata(ec, host);
-
-	info = (struct eesoxscsi_info *)host->hostdata;
-	info->ec	= ec;
-	info->ctl_port	= base + EESOX_CONTROL;
-	info->control	= term[ec->slot_no] ? EESOX_TERM_ENABLE : 0;
-	writeb(info->control, info->ctl_port);
-
-	ec->irqaddr	= base + EESOX_DMASTAT;
-	ec->irqmask	= EESOX_STAT_INTR;
-	ec->irq_data	= info;
-	ec->ops		= &eesoxscsi_ops;
-
-	info->info.scsi.io_base		= base + EESOX_FAS216_OFFSET;
-	info->info.scsi.io_shift	= EESOX_FAS216_SHIFT;
-	info->info.scsi.irq		= host->irq;
-	info->info.ifcfg.clockrate	= 40; /* MHz */
-	info->info.ifcfg.select_timeout	= 255;
-	info->info.ifcfg.asyncperiod	= 200; /* ns */
-	info->info.ifcfg.sync_max_depth	= 7;
-	info->info.ifcfg.cntl3		= CNTL3_FASTSCSI | CNTL3_FASTCLK;
-	info->info.ifcfg.disconnect_ok	= 1;
-	info->info.ifcfg.wide_max_size	= 0;
-	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
-	info->info.dma.setup		= eesoxscsi_dma_setup;
-	info->info.dma.pseudo		= eesoxscsi_dma_pseudo;
-	info->info.dma.stop		= eesoxscsi_dma_stop;
-
-	device_create_file(&ec->dev, &dev_attr_bus_term);
-
-	ret = fas216_init(host);
-	if (ret)
-		goto out_free;
-
-	ret = request_irq(host->irq, eesoxscsi_intr, 0, "eesoxscsi", info);
-	if (ret) {
-		printk("scsi%d: IRQ%d not free: %d\n",
-		       host->host_no, host->irq, ret);
-		goto out_remove;
-	}
-
-	if (host->dma_channel != NO_DMA) {
-		if (request_dma(host->dma_channel, "eesox")) {
-			printk("scsi%d: DMA%d not free, DMA disabled\n",
-			       host->host_no, host->dma_channel);
-			host->dma_channel = NO_DMA;
-		} else {
-			set_dma_speed(host->dma_channel, 180);
-			info->info.ifcfg.capabilities |= FASCAP_DMA;
-			info->info.ifcfg.cntl3 |= CNTL3_BS8;
-		}
-	}
-
-	ret = fas216_add(host, &ec->dev);
-	if (ret == 0)
-		goto out;
-
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, host);
-
- out_remove:
-	fas216_remove(host);
-
- out_free:
-	device_remove_file(&ec->dev, &dev_attr_bus_term);
-	scsi_unregister(host);
-
- out_unmap:
-	iounmap(base);
-
- out_region:
-	release_mem_region(resbase, reslen);
-
- out:
-	return ret;
-}
-
-static void __devexit eesoxscsi_remove(struct expansion_card *ec)
-{
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
-	unsigned long resbase, reslen;
-
-	ecard_set_drvdata(ec, NULL);
-	fas216_remove(host);
-
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, info);
-
-	device_remove_file(&ec->dev, &dev_attr_bus_term);
-
-	iounmap((void *)host->base);
-
-	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
-	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
-
-	release_mem_region(resbase, reslen);
-
-	fas216_release(host);
-	scsi_unregister(host);
-}
-
-static const struct ecard_id eesoxscsi_cids[] = {
-	{ MANU_EESOX, PROD_EESOX_SCSI2 },
-	{ 0xffff, 0xffff },
-};
-
-static struct ecard_driver eesoxscsi_driver = {
-	.probe		= eesoxscsi_probe,
-	.remove		= __devexit_p(eesoxscsi_remove),
-	.id_table	= eesoxscsi_cids,
-	.drv = {
-		.devclass	= &shost_devclass,
-		.name		= "eesoxscsi",
-	},
-};
-
-static int __init eesox_init(void)
-{
-	return ecard_register_driver(&eesoxscsi_driver);
-}
-
-static void __exit eesox_exit(void)
-{
-	ecard_remove_driver(&eesoxscsi_driver);
-}
-
-module_init(eesox_init);
-module_exit(eesox_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
-MODULE_PARM(term, "1-8i");
-MODULE_PARM_DESC(term, "SCSI bus termination");
-MODULE_LICENSE("GPL");
-
diff -Nru a/drivers/acorn/scsi/fas216.c b/drivers/acorn/scsi/fas216.c
--- a/drivers/acorn/scsi/fas216.c	Fri Feb 14 16:23:44 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,3228 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/fas216.c
- *
- *  Copyright (C) 1997-2003 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.
- *
- * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and
- * other sources, including:
- *   the AMD Am53CF94 data sheet
- *   the AMD Am53C94 data sheet
- *
- * This is a generic driver.  To use it, have a look at cumana_2.c.  You
- * should define your own structure that overlays FAS216_Info, eg:
- * struct my_host_data {
- *    FAS216_Info info;
- *    ... my host specific data ...
- * };
- *
- * Changelog:
- *  30-08-1997	RMK	Created
- *  14-09-1997	RMK	Started disconnect support
- *  08-02-1998	RMK	Corrected real DMA support
- *  15-02-1998	RMK	Started sync xfer support
- *  06-04-1998	RMK	Tightened conditions for printing incomplete
- *			transfers
- *  02-05-1998	RMK	Added extra checks in fas216_reset
- *  24-05-1998	RMK	Fixed synchronous transfers with period >= 200ns
- *  27-06-1998	RMK	Changed asm/delay.h to linux/delay.h
- *  26-08-1998	RMK	Improved message support wrt MESSAGE_REJECT
- *  02-04-2000	RMK	Converted to use the new error handling, and
- *			automatically request sense data upon check
- *			condition status from targets.
- */
-#include <linux/module.h>
-#include <linux/blk.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-#include <linux/bitops.h>
-#include <linux/init.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/ecard.h>
-
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-#include "fas216.h"
-#include "scsi.h"
-
-/* NOTE: SCSI2 Synchronous transfers *require* DMA according to
- *  the data sheet.  This restriction is crazy, especially when
- *  you only want to send 16 bytes!  What were the guys who
- *  designed this chip on at that time?  Did they read the SCSI2
- *  spec at all?  The following sections are taken from the SCSI2
- *  standard (s2r10) concerning this:
- *
- * > IMPLEMENTORS NOTES:
- * >   (1)  Re-negotiation at every selection is not recommended, since a
- * >   significant performance impact is likely.
- *
- * >  The implied synchronous agreement shall remain in effect until a BUS DEVICE
- * >  RESET message is received, until a hard reset condition occurs, or until one
- * >  of the two SCSI devices elects to modify the agreement.  The default data
- * >  transfer mode is asynchronous data transfer mode.  The default data transfer
- * >  mode is entered at power on, after a BUS DEVICE RESET message, or after a hard
- * >  reset condition.
- *
- *  In total, this means that once you have elected to use synchronous
- *  transfers, you must always use DMA.
- *
- *  I was thinking that this was a good chip until I found this restriction ;(
- */
-#define SCSI2_SYNC
-#undef  SCSI2_WIDE
-#undef  SCSI2_TAG
-
-#undef DEBUG_CONNECT
-#undef DEBUG_MESSAGES
-
-#undef CHECK_STRUCTURE
-
-#define LOG_CONNECT		(1 << 0)
-#define LOG_BUSSERVICE		(1 << 1)
-#define LOG_FUNCTIONDONE	(1 << 2)
-#define LOG_MESSAGES		(1 << 3)
-#define LOG_BUFFER		(1 << 4)
-#define LOG_ERROR		(1 << 8)
-
-static int level_mask = LOG_ERROR;
-
-static int __init fas216_log_setup(char *str)
-{
-	char *s;
-
-	level_mask = 0;
-
-	while ((s = strsep(&str, ",")) != NULL) {
-		switch (s[0]) {
-		case 'a':
-			if (strcmp(s, "all") == 0)
-				level_mask |= -1;
-			break;
-		case 'b':
-			if (strncmp(s, "bus", 3) == 0)
-				level_mask |= LOG_BUSSERVICE;
-			if (strncmp(s, "buf", 3) == 0)
-				level_mask |= LOG_BUFFER;
-			break;
-		case 'c':
-			level_mask |= LOG_CONNECT;
-			break;
-		case 'e':
-			level_mask |= LOG_ERROR;
-			break;
-		case 'm':
-			level_mask |= LOG_MESSAGES;
-			break;
-		case 'n':
-			if (strcmp(s, "none") == 0)
-				level_mask = 0;
-			break;
-		case 's':
-			level_mask |= LOG_FUNCTIONDONE;
-			break;
-		}
-	}
-	return 1;
-}
-
-__setup("fas216_logging=", fas216_log_setup);
-
-static inline unsigned char fas216_readb(FAS216_Info *info, unsigned int reg)
-{
-	unsigned int off = reg << info->scsi.io_shift;
-	if (info->scsi.io_base)
-		return readb(info->scsi.io_base + off);
-	else
-		return inb(info->scsi.io_port + off);
-}
-
-static inline void fas216_writeb(FAS216_Info *info, unsigned int reg, unsigned int val)
-{
-	unsigned int off = reg << info->scsi.io_shift;
-	if (info->scsi.io_base)
-		writeb(val, info->scsi.io_base + off);
-	else
-		outb(val, info->scsi.io_port + off);
-}
-
-static void fas216_dumpstate(FAS216_Info *info)
-{
-	unsigned char is, stat, inst;
-
-	is   = fas216_readb(info, REG_IS);
-	stat = fas216_readb(info, REG_STAT);
-	inst = fas216_readb(info, REG_INST);
-	
-	printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X"
-	       " INST=%02X IS=%02X CFIS=%02X",
-		fas216_readb(info, REG_CTCL),
-		fas216_readb(info, REG_CTCM),
-		fas216_readb(info, REG_CMD),  stat, inst, is,
-		fas216_readb(info, REG_CFIS));
-	printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n",
-		fas216_readb(info, REG_CNTL1),
-		fas216_readb(info, REG_CNTL2),
-		fas216_readb(info, REG_CNTL3),
-		fas216_readb(info, REG_CTCH));
-}
-
-static void print_SCp(Scsi_Pointer *SCp, const char *prefix, const char *suffix)
-{
-	printk("%sptr %p this_residual 0x%x buffer %p buffers_residual 0x%x%s",
-		prefix, SCp->ptr, SCp->this_residual, SCp->buffer,
-		SCp->buffers_residual, suffix);
-}
-
-static void fas216_dumpinfo(FAS216_Info *info)
-{
-	static int used = 0;
-	int i;
-
-	if (used++)
-		return;
-
-	printk("FAS216_Info=\n");
-	printk("  { magic_start=%lX host=%p SCpnt=%p origSCpnt=%p\n",
-		info->magic_start, info->host, info->SCpnt,
-		info->origSCpnt);
-	printk("    scsi={ io_port=%X io_shift=%X irq=%X cfg={ %X %X %X %X }\n",
-		info->scsi.io_port, info->scsi.io_shift, info->scsi.irq,
-		info->scsi.cfg[0], info->scsi.cfg[1], info->scsi.cfg[2],
-		info->scsi.cfg[3]);
-	printk("           type=%p phase=%X reconnected={ target=%d lun=%d tag=%d }\n",
-		info->scsi.type, info->scsi.phase,
-		info->scsi.reconnected.target,
-		info->scsi.reconnected.lun, info->scsi.reconnected.tag);
-	print_SCp(&info->scsi.SCp, "           SCp={ ", " }\n");
-	printk("      msgs async_stp=%X disconnectable=%d aborting=%d }\n",
-		info->scsi.async_stp,
-		info->scsi.disconnectable, info->scsi.aborting);
-	printk("    stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"
-	       "            disconnects=%X aborts=%X bus_resets=%X host_resets=%X}\n",
-		info->stats.queues, info->stats.removes, info->stats.fins,
-		info->stats.reads, info->stats.writes, info->stats.miscs,
-		info->stats.disconnects, info->stats.aborts, info->stats.bus_resets,
-		info->stats.host_resets);
-	printk("    ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n",
-		info->ifcfg.clockrate, info->ifcfg.select_timeout,
-		info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);
-	for (i = 0; i < 8; i++) {
-		printk("    busyluns[%d]=%08lx dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n",
-			i, info->busyluns[i], i,
-			info->device[i].disconnect_ok, info->device[i].stp,
-			info->device[i].sof, info->device[i].sync_state);
-	}
-	printk("    dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n",
-		info->dma.transfer_type, info->dma.setup,
-		info->dma.pseudo, info->dma.stop);
-	printk("    internal_done=%X magic_end=%lX }\n",
-		info->internal_done, info->magic_end);
-}
-
-#ifdef CHECK_STRUCTURE
-static void __fas216_checkmagic(FAS216_Info *info, const char *func)
-{
-	int corruption = 0;
-	if (info->magic_start != MAGIC) {
-		printk(KERN_CRIT "FAS216 Error: magic at start corrupted\n");
-		corruption++;
-	}
-	if (info->magic_end != MAGIC) {
-		printk(KERN_CRIT "FAS216 Error: magic at end corrupted\n");
-		corruption++;
-	}
-	if (corruption) {
-		fas216_dumpinfo(info);
-		panic("scsi memory space corrupted in %s", func);
-	}
-}
-#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)
-#else
-#define fas216_checkmagic(info)
-#endif
-
-static const char *fas216_bus_phase(int stat)
-{
-	static const char *phases[] = {
-		"DATA OUT", "DATA IN",
-		"COMMAND", "STATUS",
-		"MISC OUT", "MISC IN",
-		"MESG OUT", "MESG IN"
-	};
-
-	return phases[stat & STAT_BUSMASK];
-}
-
-static const char *fas216_drv_phase(FAS216_Info *info)
-{
-	switch (info->scsi.phase) {
-	case PHASE_IDLE:		return "idle";
-	case PHASE_SELECTION:		return "selection";
-	case PHASE_COMMAND:		return "command";
-	case PHASE_RECONNECTED:		return "reconnected";
-	case PHASE_DATAOUT:		return "data out";
-	case PHASE_DATAIN:		return "data in";
-	case PHASE_MSGIN:		return "message in";
-	case PHASE_MSGIN_DISCONNECT:	return "disconnect";
-	case PHASE_MSGOUT_EXPECT:	return "expect message out";
-	case PHASE_MSGOUT:		return "message out";
-	case PHASE_STATUS:		return "status";
-	case PHASE_DONE:		return "done";
-	default:			return "???";
-	}
-}
-
-static char fas216_target(FAS216_Info *info)
-{
-	if (info->SCpnt)
-		return '0' + info->SCpnt->device->id;
-	else
-		return 'H';
-}
-
-static void
-fas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap)
-{
-	static char buf[1024];
-
-	vsnprintf(buf, sizeof(buf), fmt, ap);
-	printk("scsi%d.%c: %s", info->host->host_no, target, buf);
-}
-
-static void
-fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...)
-{
-	va_list args;
-
-	if (level != 0 && !(level & level_mask))
-		return;
-
-	va_start(args, fmt);
-	fas216_do_log(info, '0' + SCpnt->device->id, fmt, args);
-	va_end(args);
-
-	printk(" CDB: ");
-	print_command(SCpnt->cmnd);
-}
-
-static void
-fas216_log_target(FAS216_Info *info, int level, int target, char *fmt, ...)
-{
-	va_list args;
-
-	if (level != 0 && !(level & level_mask))
-		return;
-
-	if (target < 0)
-		target = 'H';
-	else
-		target += '0';
-
-	va_start(args, fmt);
-	fas216_do_log(info, target, fmt, args);
-	va_end(args);
-
-	printk("\n");
-}
-
-static void fas216_log(FAS216_Info *info, int level, char *fmt, ...)
-{
-	va_list args;
-
-	if (level != 0 && !(level & level_mask))
-		return;
-
-	va_start(args, fmt);
-	fas216_do_log(info, fas216_target(info), fmt, args);
-	va_end(args);
-
-	printk("\n");
-}
-
-#define PH_SIZE	32
-
-static struct { int stat, ssr, isr, ph; } ph_list[PH_SIZE];
-static int ph_ptr;
-
-static void add_debug_list(int stat, int ssr, int isr, int ph)
-{
-	ph_list[ph_ptr].stat = stat;
-	ph_list[ph_ptr].ssr = ssr;
-	ph_list[ph_ptr].isr = isr;
-	ph_list[ph_ptr].ph = ph;
-
-	ph_ptr = (ph_ptr + 1) & (PH_SIZE-1);
-}
-
-static struct { int command; void *from; } cmd_list[8];
-static int cmd_ptr;
-
-static void fas216_cmd(FAS216_Info *info, unsigned int command)
-{
-	cmd_list[cmd_ptr].command = command;
-	cmd_list[cmd_ptr].from = __builtin_return_address(0);
-
-	cmd_ptr = (cmd_ptr + 1) & 7;
-
-	fas216_writeb(info, REG_CMD, command);
-}
-
-static void print_debug_list(void)
-{
-	int i;
-
-	i = ph_ptr;
-
-	printk(KERN_ERR "SCSI IRQ trail\n");
-	do {
-		printk(" %02x:%02x:%02x:%1x",
-			ph_list[i].stat, ph_list[i].ssr,
-			ph_list[i].isr, ph_list[i].ph);
-		i = (i + 1) & (PH_SIZE - 1);
-		if (((i ^ ph_ptr) & 7) == 0)
-			printk("\n");
-	} while (i != ph_ptr);
-	if ((i ^ ph_ptr) & 7)
-		printk("\n");
-
-	i = cmd_ptr;
-	printk(KERN_ERR "FAS216 commands: ");
-	do {
-		printk("%02x:%p ", cmd_list[i].command, cmd_list[i].from);
-		i = (i + 1) & 7;
-	} while (i != cmd_ptr);
-	printk("\n");
-}
-
-static void fas216_done(FAS216_Info *info, unsigned int result);
-
-/**
- * fas216_clockrate - calculate clock conversion factor
- * @clock: clock speed in MHz
- *
- * Calculate correct value to be written into clock conversion factor
- * register. Returns CLKF_ value.
- */
-static int fas216_clockrate(int clock)
-{
-	if (clock <= 10 || clock > 40) {
-		printk(KERN_CRIT
-		       "fas216: invalid clock rate: check your driver!\n");
-		clock = -1;
-	} else
-		clock = ((clock - 1) / 5 + 1) & 7;
-
-	return clock;
-}
-
-/**
- * fas216_get_last_msg - retrive last message from the list
- * @info: interface to search
- * @pos: current fifo position
- *
- * Retrieve a last message from the list, using position in fifo.
- */
-static inline unsigned short
-fas216_get_last_msg(FAS216_Info *info, int pos)
-{
-	unsigned short packed_msg = NOP;
-	struct message *msg;
-	int msgnr = 0;
-
-	while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
-		if (pos >= msg->fifo)
-			break;
-	}
-
-	if (msg) {
-		if (msg->msg[0] == EXTENDED_MESSAGE)
-			packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8;
-		else
-			packed_msg = msg->msg[0];
-	}
-
-	fas216_log(info, LOG_MESSAGES,
-		"Message: %04x found at position %02x\n", packed_msg, pos);
-
-	return packed_msg;
-}
-
-/**
- * fas216_syncperiod - calculate STP register value
- * @info: state structure for interface connected to device
- * @ns: period in ns (between subsequent bytes)
- *
- * Calculate value to be loaded into the STP register for a given period
- * in ns. Returns a value suitable for REG_STP.
- */
-static int fas216_syncperiod(FAS216_Info *info, int ns)
-{
-	int value = (info->ifcfg.clockrate * ns) / 1000;
-
-	fas216_checkmagic(info);
-
-	if (value < 4)
-		value = 4;
-	else if (value > 35)
-		value = 35;
-
-	return value & 31;
-}
-
-/**
- * fas216_set_sync - setup FAS216 chip for specified transfer period.
- * @info: state structure for interface connected to device
- * @target: target
- *
- * Correctly setup FAS216 chip for specified transfer period.
- * Notes   : we need to switch the chip out of FASTSCSI mode if we have
- *           a transfer period >= 200ns - otherwise the chip will violate
- *           the SCSI timings.
- */
-static void fas216_set_sync(FAS216_Info *info, int target)
-{
-	unsigned int cntl3;
-
-	fas216_writeb(info, REG_SOF, info->device[target].sof);
-	fas216_writeb(info, REG_STP, info->device[target].stp);
-
-	cntl3 = info->scsi.cfg[2];
-	if (info->device[target].period >= (200 / 4))
-		cntl3 = cntl3 & ~CNTL3_FASTSCSI;
-
-	fas216_writeb(info, REG_CNTL3, cntl3);
-}
-
-/* Synchronous transfer support
- *
- * Note: The SCSI II r10 spec says (5.6.12):
- *
- *  (2)  Due to historical problems with early host adapters that could
- *  not accept an SDTR message, some targets may not initiate synchronous
- *  negotiation after a power cycle as required by this standard.  Host
- *  adapters that support synchronous mode may avoid the ensuing failure
- *  modes when the target is independently power cycled by initiating a
- *  synchronous negotiation on each REQUEST SENSE and INQUIRY command.
- *  This approach increases the SCSI bus overhead and is not recommended
- *  for new implementations.  The correct method is to respond to an
- *  SDTR message with a MESSAGE REJECT message if the either the
- *  initiator or target devices does not support synchronous transfers
- *  or does not want to negotiate for synchronous transfers at the time.
- *  Using the correct method assures compatibility with wide data
- *  transfers and future enhancements.
- *
- * We will always initiate a synchronous transfer negotiation request on
- * every INQUIRY or REQUEST SENSE message, unless the target itself has
- * at some point performed a synchronous transfer negotiation request, or
- * we have synchronous transfers disabled for this device.
- */
-
-/**
- * fas216_handlesync - Handle a synchronous transfer message
- * @info: state structure for interface
- * @msg: message from target
- *
- * Handle a synchronous transfer message from the target
- */
-static void fas216_handlesync(FAS216_Info *info, char *msg)
-{
-	struct fas216_device *dev = &info->device[info->SCpnt->device->id];
-	enum { sync, async, none, reject } res = none;
-
-#ifdef SCSI2_SYNC
-	switch (msg[0]) {
-	case MESSAGE_REJECT:
-		/* Synchronous transfer request failed.
-		 * Note: SCSI II r10:
-		 *
-		 *  SCSI devices that are capable of synchronous
-		 *  data transfers shall not respond to an SDTR
-		 *  message with a MESSAGE REJECT message.
-		 *
-		 * Hence, if we get this condition, we disable
-		 * negotiation for this device.
-		 */
-		if (dev->sync_state == neg_inprogress) {
-			dev->sync_state = neg_invalid;
-			res = async;
-		}
-		break;
-
-	case EXTENDED_MESSAGE:
-		switch (dev->sync_state) {
-		/* We don't accept synchronous transfer requests.
-		 * Respond with a MESSAGE_REJECT to prevent a
-		 * synchronous transfer agreement from being reached.
-		 */
-		case neg_invalid:
-			res = reject;
-			break;
-
-		/* We were not negotiating a synchronous transfer,
-		 * but the device sent us a negotiation request.
-		 * Honour the request by sending back a SDTR
-		 * message containing our capability, limited by
-		 * the targets capability.
-		 */
-		default:
-			fas216_cmd(info, CMD_SETATN);
-			if (msg[4] > info->ifcfg.sync_max_depth)
-				msg[4] = info->ifcfg.sync_max_depth;
-			if (msg[3] < 1000 / info->ifcfg.clockrate)
-				msg[3] = 1000 / info->ifcfg.clockrate;
-
-			msgqueue_flush(&info->scsi.msgs);
-			msgqueue_addmsg(&info->scsi.msgs, 5,
-					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
-					msg[3], msg[4]);
-			info->scsi.phase = PHASE_MSGOUT_EXPECT;
-
-			/* This is wrong.  The agreement is not in effect
-			 * until this message is accepted by the device
-			 */
-			dev->sync_state = neg_targcomplete;
-			res = sync;
-			break;
-
-		/* We initiated the synchronous transfer negotiation,
-		 * and have successfully received a response from the
-		 * target.  The synchronous transfer agreement has been
-		 * reached.  Note: if the values returned are out of our
-		 * bounds, we must reject the message.
-		 */
-		case neg_inprogress:
-			res = reject;
-			if (msg[4] <= info->ifcfg.sync_max_depth &&
-			    msg[3] >= 1000 / info->ifcfg.clockrate) {
-				dev->sync_state = neg_complete;
-				res = sync;
-			}
-			break;
-		}
-	}
-#else
-	res = reject;
-#endif
-
-	switch (res) {
-	case sync:
-		dev->period = msg[3];
-		dev->sof    = msg[4];
-		dev->stp    = fas216_syncperiod(info, msg[3] * 4);
-		fas216_set_sync(info, info->SCpnt->device->id);
-		break;
-
-	case reject:
-		fas216_cmd(info, CMD_SETATN);
-		msgqueue_flush(&info->scsi.msgs);
-		msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
-		info->scsi.phase = PHASE_MSGOUT_EXPECT;
-
-	case async:
-		dev->period = info->ifcfg.asyncperiod / 4;
-		dev->sof    = 0;
-		dev->stp    = info->scsi.async_stp;
-		fas216_set_sync(info, info->SCpnt->device->id);
-		break;
-
-	case none:
-		break;
-	}
-}
-
-/**
- * fas216_handlewide - Handle a wide transfer message
- * @info: state structure for interface
- * @msg: message from target
- *
- * Handle a wide transfer message from the target
- */
-static void fas216_handlewide(FAS216_Info *info, char *msg)
-{
-	struct fas216_device *dev = &info->device[info->SCpnt->device->id];
-	enum { wide, bit8, none, reject } res = none;
-
-#ifdef SCSI2_WIDE
-	switch (msg[0]) {
-	case MESSAGE_REJECT:
-		/* Wide transfer request failed.
-		 * Note: SCSI II r10:
-		 *
-		 *  SCSI devices that are capable of wide
-		 *  data transfers shall not respond to a
-		 *  WDTR message with a MESSAGE REJECT message.
-		 *
-		 * Hence, if we get this condition, we never
-		 * reattempt negotiation for this device.
-		 */
-		if (dev->wide_state == neg_inprogress) {
-			dev->wide_state = neg_invalid;
-			res = bit8;
-		}
-		break;
-
-	case EXTENDED_MESSAGE:
-		switch (dev->wide_state) {
-		/* We don't accept wide data transfer requests.
-		 * Respond with a MESSAGE REJECT to prevent a
-		 * wide data transfer agreement from being reached.
-		 */
-		case neg_invalid:
-			res = reject;
-			break;
-
-		/* We were not negotiating a wide data transfer,
-		 * but the device sent is a negotiation request.
-		 * Honour the request by sending back a WDTR
-		 * message containing our capability, limited by
-		 * the targets capability.
-		 */
-		default:
-			fas216_cmd(info, CMD_SETATN);
-			if (msg[3] > info->ifcfg.wide_max_size)
-				msg[3] = info->ifcfg.wide_max_size;
-
-			msgqueue_flush(&info->scsi.msgs);
-			msgqueue_addmsg(&info->scsi.msgs, 4,
-					EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
-					msg[3]);
-			info->scsi.phase = PHASE_MSGOUT_EXPECT;
-			res = wide;
-			break;
-
-		/* We initiated the wide data transfer negotiation,
-		 * and have successfully received a response from the
-		 * target.  The synchronous transfer agreement has been
-		 * reached.  Note: if the values returned are out of our
-		 * bounds, we must reject the message.
-		 */
-		case neg_inprogress:
-			res = reject;
-			if (msg[3] <= info->ifcfg.wide_max_size) {
-				dev->wide_state = neg_complete;
-				res = wide;
-			}
-			break;
-		}
-	}
-#else
-	res = reject;
-#endif
-
-	switch (res) {
-	case wide:
-		dev->wide_xfer = msg[3];
-		break;
-
-	case reject:
-		fas216_cmd(info, CMD_SETATN);
-		msgqueue_flush(&info->scsi.msgs);
-		msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
-		info->scsi.phase = PHASE_MSGOUT_EXPECT;
-
-	case bit8:
-		dev->wide_xfer = 0;
-		break;
-
-	case none:
-		break;
-	}
-}
-
-/**
- * fas216_updateptrs - update data pointers after transfer suspended/paused
- * @info: interface's local pointer to update
- * @bytes_transferred: number of bytes transferred
- *
- * Update data pointers after transfer suspended/paused
- */
-static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
-{
-	Scsi_Pointer *SCp = &info->scsi.SCp;
-
-	fas216_checkmagic(info);
-
-	BUG_ON(bytes_transferred < 0);
-
-	info->SCpnt->request_bufflen -= bytes_transferred;
-
-	while (bytes_transferred != 0) {
-		if (SCp->this_residual > bytes_transferred)
-			break;
-		/*
-		 * We have used up this buffer.  Move on to the
-		 * next buffer.
-		 */
-		bytes_transferred -= SCp->this_residual;
-		if (!next_SCp(SCp) && bytes_transferred) {
-			printk(KERN_WARNING "scsi%d.%c: out of buffers\n",
-				info->host->host_no, '0' + info->SCpnt->device->id);
-			return;
-		}
-	}
-
-	SCp->this_residual -= bytes_transferred;
-	if (SCp->this_residual)
-		SCp->ptr += bytes_transferred;
-	else
-		SCp->ptr = NULL;
-}
-
-/**
- * fas216_pio - transfer data off of/on to card using programmed IO
- * @info: interface to transfer data to/from
- * @direction: direction to transfer data (DMA_OUT/DMA_IN)
- *
- * Transfer data off of/on to card using programmed IO.
- * Notes: this is incredibly slow.
- */
-static void fas216_pio(FAS216_Info *info, fasdmadir_t direction)
-{
-	Scsi_Pointer *SCp = &info->scsi.SCp;
-
-	fas216_checkmagic(info);
-
-	if (direction == DMA_OUT)
-		fas216_writeb(info, REG_FF, get_next_SCp_byte(SCp));
-	else
-		put_next_SCp_byte(SCp, fas216_readb(info, REG_FF));
-
-	if (SCp->this_residual == 0)
-		next_SCp(SCp);
-}
-
-static void fas216_set_stc(FAS216_Info *info, unsigned int length)
-{
-	fas216_writeb(info, REG_STCL, length);
-	fas216_writeb(info, REG_STCM, length >> 8);
-	fas216_writeb(info, REG_STCH, length >> 16);
-}
-
-static unsigned int fas216_get_ctc(FAS216_Info *info)
-{
-	return fas216_readb(info, REG_CTCL) +
-	       (fas216_readb(info, REG_CTCM) << 8) +
-	       (fas216_readb(info, REG_CTCH) << 16);
-}
-
-/**
- * fas216_cleanuptransfer - clean up after a transfer has completed.
- * @info: interface to clean up
- *
- * Update the data pointers according to the number of bytes transferred
- * on the SCSI bus.
- */
-static void fas216_cleanuptransfer(FAS216_Info *info)
-{
-	unsigned long total, residual, fifo;
-	fasdmatype_t dmatype = info->dma.transfer_type;
-
-	info->dma.transfer_type = fasdma_none;
-
-	/*
-	 * PIO transfers do not need to be cleaned up.
-	 */
-	if (dmatype == fasdma_pio || dmatype == fasdma_none)
-		return;
-
-	if (dmatype == fasdma_real_all)
-		total = info->SCpnt->request_bufflen;
-	else
-		total = info->scsi.SCp.this_residual;
-
-	residual = fas216_get_ctc(info);
-
-	fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
-
-	fas216_log(info, LOG_BUFFER, "cleaning up from previous "
-		   "transfer: length 0x%06x, residual 0x%x, fifo %d",
-		   total, residual, fifo);
-
-	/*
-	 * If we were performing Data-Out, the transfer counter
-	 * counts down each time a byte is transferred by the
-	 * host to the FIFO.  This means we must include the
-	 * bytes left in the FIFO from the transfer counter.
-	 */
-	if (info->scsi.phase == PHASE_DATAOUT)
-		residual += fifo;
-
-	fas216_updateptrs(info, total - residual);
-}
-
-/**
- * fas216_transfer - Perform a DMA/PIO transfer off of/on to card
- * @info: interface from which device disconnected from
- *
- * Start a DMA/PIO transfer off of/on to card
- */
-static void fas216_transfer(FAS216_Info *info)
-{
-	fasdmadir_t direction;
-	fasdmatype_t dmatype;
-
-	fas216_log(info, LOG_BUFFER,
-		   "starttransfer: buffer %p length 0x%06x reqlen 0x%06x",
-		   info->scsi.SCp.ptr, info->scsi.SCp.this_residual,
-		   info->SCpnt->request_bufflen);
-
-	if (!info->scsi.SCp.ptr) {
-		fas216_log(info, LOG_ERROR, "null buffer passed to "
-			   "fas216_starttransfer");
-		print_SCp(&info->scsi.SCp, "SCp: ", "\n");
-		print_SCp(&info->SCpnt->SCp, "Cmnd SCp: ", "\n");
-		return;
-	}
-
-	/*
-	 * If we have a synchronous transfer agreement in effect, we must
-	 * use DMA mode.  If we are using asynchronous transfers, we may
-	 * use DMA mode or PIO mode.
-	 */
-	if (info->device[info->SCpnt->device->id].sof)
-		dmatype = fasdma_real_all;
-	else
-		dmatype = fasdma_pio;
-
-	if (info->scsi.phase == PHASE_DATAOUT)
-		direction = DMA_OUT;
-	else
-		direction = DMA_IN;
-
-	if (info->dma.setup)
-		dmatype = info->dma.setup(info->host, &info->scsi.SCp,
-					  direction, dmatype);
-	info->dma.transfer_type = dmatype;
-
-	if (dmatype == fasdma_real_all)
-		fas216_set_stc(info, info->SCpnt->request_bufflen);
-	else
-		fas216_set_stc(info, info->scsi.SCp.this_residual);
-
-	switch (dmatype) {
-	case fasdma_pio:
-		fas216_log(info, LOG_BUFFER, "PIO transfer");
-		fas216_writeb(info, REG_SOF, 0);
-		fas216_writeb(info, REG_STP, info->scsi.async_stp);
-		fas216_cmd(info, CMD_TRANSFERINFO);
-		fas216_pio(info, direction);
-		break;
-
-	case fasdma_pseudo:
-		fas216_log(info, LOG_BUFFER, "pseudo transfer");
-		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);
-		info->dma.pseudo(info->host, &info->scsi.SCp,
-				 direction, info->SCpnt->transfersize);
-		break;
-
-	case fasdma_real_block:
-		fas216_log(info, LOG_BUFFER, "block dma transfer");
-		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);
-		break;
-
-	case fasdma_real_all:
-		fas216_log(info, LOG_BUFFER, "total dma transfer");
-		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);
-		break;
-
-	default:
-		fas216_log(info, LOG_BUFFER | LOG_ERROR,
-			   "invalid FAS216 DMA type");
-		break;
-	}
-}
-
-/**
- * fas216_stoptransfer - Stop a DMA transfer onto / off of the card
- * @info: interface from which device disconnected from
- *
- * Called when we switch away from DATA IN or DATA OUT phases.
- */
-static void fas216_stoptransfer(FAS216_Info *info)
-{
-	fas216_checkmagic(info);
-
-	if (info->dma.transfer_type == fasdma_real_all ||
-	    info->dma.transfer_type == fasdma_real_block)
-		info->dma.stop(info->host, &info->scsi.SCp);
-
-	fas216_cleanuptransfer(info);
-
-	if (info->scsi.phase == PHASE_DATAIN) {
-		unsigned int fifo;
-
-		/*
-		 * If we were performing Data-In, then the FIFO counter
-		 * contains the number of bytes not transferred via DMA
-		 * from the on-board FIFO.  Read them manually.
-		 */
-		fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
-		while (fifo && info->scsi.SCp.ptr) {
-			*info->scsi.SCp.ptr = fas216_readb(info, REG_FF);
-			fas216_updateptrs(info, 1);
-			fifo--;
-		}
-	} else {
-		/*
-		 * After a Data-Out phase, there may be unsent
-		 * bytes left in the FIFO.  Flush them out.
-		 */
-		fas216_cmd(info, CMD_FLUSHFIFO);
-	}
-}
-
-static void fas216_aborttransfer(FAS216_Info *info)
-{
-	fas216_checkmagic(info);
-
-	if (info->dma.transfer_type == fasdma_real_all ||
-	    info->dma.transfer_type == fasdma_real_block)
-		info->dma.stop(info->host, &info->scsi.SCp);
-
-	info->dma.transfer_type = fasdma_none;
-	fas216_cmd(info, CMD_FLUSHFIFO);
-}
-
-/**
- * fas216_disconnected_intr - handle device disconnection
- * @info: interface from which device disconnected from
- *
- * Handle device disconnection
- */
-static void fas216_disconnect_intr(FAS216_Info *info)
-{
-	fas216_checkmagic(info);
-
-	fas216_log(info, LOG_CONNECT, "disconnect phase=%02x",
-		   info->scsi.phase);
-
-	msgqueue_flush(&info->scsi.msgs);
-
-	fas216_cmd(info, CMD_ENABLESEL);
-
-	switch (info->scsi.phase) {
-	case PHASE_SELECTION:			/* while selecting - no target		*/
-	case PHASE_SELSTEPS:
-		fas216_done(info, DID_NO_CONNECT);
-		break;
-
-	case PHASE_MSGIN_DISCONNECT:		/* message in - disconnecting		*/
-		info->scsi.disconnectable = 1;
-		info->scsi.reconnected.tag = 0;
-		info->scsi.phase = PHASE_IDLE;
-		info->stats.disconnects += 1;
-		break;
-
-	case PHASE_DONE:			/* at end of command - complete		*/
-		fas216_done(info, DID_OK);
-		break;
-
-	case PHASE_MSGOUT:			/* message out - possible ABORT message	*/
-		if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) {
-			info->scsi.aborting = 0;
-			fas216_done(info, DID_ABORT);
-			break;
-		}
-
-	default:				/* huh?					*/
-		printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %s\n",
-			info->host->host_no, fas216_target(info), fas216_drv_phase(info));
-		print_debug_list();
-		fas216_stoptransfer(info);
-		fas216_done(info, DID_ERROR);
-		break;
-	}
-}
-
-/**
- * fas216_reselected_intr - start reconnection of a device
- * @info: interface which was reselected
- *
- * Start reconnection of a device
- */
-static void
-fas216_reselected_intr(FAS216_Info *info)
-{
-	unsigned char target, identify_msg, ok;
-
-	fas216_checkmagic(info);
-
-	if ((info->scsi.phase == PHASE_SELECTION ||
-	     info->scsi.phase == PHASE_SELSTEPS) && info->SCpnt) {
-		Scsi_Cmnd *SCpnt = info->SCpnt;
-
-		info->origSCpnt = SCpnt;
-		info->SCpnt = NULL;
-
-		if (info->device[SCpnt->device->id].wide_state == neg_inprogress)
-			info->device[SCpnt->device->id].wide_state = neg_wait;
-		if (info->device[SCpnt->device->id].sync_state == neg_inprogress)
-			info->device[SCpnt->device->id].sync_state = neg_wait;
-	}
-
-	fas216_log(info, LOG_CONNECT, "reconnect phase=%02X", info->scsi.phase);
-
-	if ((fas216_readb(info, REG_CFIS) & CFIS_CF) != 2) {
-		printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n",
-			info->host->host_no);
-		goto initiator_error;
-	}
-
-	target = fas216_readb(info, REG_FF);
-	identify_msg = fas216_readb(info, REG_FF);
-
-	ok = 1;
-	if (!(target & (1 << info->host->this_id))) {
-		printk(KERN_ERR "scsi%d.H: invalid host id on reselect\n", info->host->host_no);
-		ok = 0;
-	}
-
-	if (!(identify_msg & 0x80)) {
-		printk(KERN_ERR "scsi%d.H: no IDENTIFY message on reselect, got msg %02X\n",
-			info->host->host_no, identify_msg);
-		ok = 0;
-	}
-
-	if (!ok) {
-		/*
-		 * Something went wrong - send an initiator error to
-		 * the target.
-		 */
-		goto initiator_error;
-	}
-
-	target &= ~(1 << info->host->this_id);
-	target = ffs(target) - 1;
-
-	identify_msg &= 7;
-	info->scsi.reconnected.target = target;
-	info->scsi.reconnected.lun    = identify_msg;
-	info->scsi.reconnected.tag    = 0;
-
-	/* set up for synchronous transfers */
-	fas216_set_sync(info, target);
-
-	ok = 0;
-	if (info->scsi.disconnectable && info->SCpnt &&
-	    info->SCpnt->device->id == target && info->SCpnt->device->lun == identify_msg)
-		ok = 1;
-
-	if (!ok && queue_probetgtlun(&info->queues.disconnected, target, identify_msg))
-		ok = 1;
-
-	msgqueue_flush(&info->scsi.msgs);
-	if (ok) {
-		info->scsi.phase = PHASE_RECONNECTED;
-		fas216_writeb(info, REG_SDID, target);
-	} else {
-		/*
-		 * Our command structure not found - abort the
-		 * command on the target.  Since we have no
-		 * record of this command, we can't send
-		 * an INITIATOR DETECTED ERROR message.
-		 */
-		fas216_cmd(info, CMD_SETATN);
-		msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
-		info->scsi.phase = PHASE_MSGOUT_EXPECT;
-	}
-
-	fas216_cmd(info, CMD_MSGACCEPTED);
-	return;
-
- initiator_error:
-	fas216_cmd(info, CMD_SETATN);
-	msgqueue_flush(&info->scsi.msgs);
-	msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
-	info->scsi.phase = PHASE_MSGOUT_EXPECT;
-	fas216_cmd(info, CMD_MSGACCEPTED);
-}
-
-/**
- * fas216_finish_reconnect - finish reconnection sequence for device
- * @info: interface which caused function done interrupt
- *
- * Finish reconnection sequence for device
- */
-static void
-fas216_finish_reconnect(FAS216_Info *info)
-{
-	fas216_checkmagic(info);
-
-	fas216_log(info, LOG_CONNECT, "Connected: %1x %1x %02x, reconnected: %1x %1x %02x",
-		info->SCpnt->device->id, info->SCpnt->device->lun, info->SCpnt->tag,
-		info->scsi.reconnected.target, info->scsi.reconnected.lun,
-		info->scsi.reconnected.tag);
-
-	if (info->scsi.disconnectable && info->SCpnt) {
-		info->scsi.disconnectable = 0;
-		if (info->SCpnt->device->id  == info->scsi.reconnected.target &&
-		    info->SCpnt->device->lun == info->scsi.reconnected.lun &&
-		    info->SCpnt->tag         == info->scsi.reconnected.tag) {
-			fas216_log(info, LOG_CONNECT, "reconnected");
-		} else {
-			queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);
-			fas216_log(info, LOG_CONNECT, "had to move command to disconnected queue");
-			info->SCpnt = NULL;
-		}
-	}
-	if (!info->SCpnt) {
-		info->SCpnt = queue_remove_tgtluntag(&info->queues.disconnected,
-					info->scsi.reconnected.target,
-					info->scsi.reconnected.lun,
-					info->scsi.reconnected.tag);
-		fas216_log(info, LOG_CONNECT, "had to get command");
-	}
-	if (!info->SCpnt) {
-		fas216_cmd(info, CMD_SETATN);
-		msgqueue_flush(&info->scsi.msgs);
-
-#if 0
-		if (info->scsi.reconnected.tag)
-			msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, info->scsi.reconnected.tag);
-		else
-#endif
-			msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
-
-		info->scsi.phase = PHASE_MSGOUT_EXPECT;
-		info->scsi.aborting = 1;
-	} else {
-		/*
-		 * Restore data pointer from SAVED data pointer
-		 */
-		info->scsi.SCp = info->SCpnt->SCp;
-		fas216_log(info, LOG_CONNECT, "data pointers: [%p, %X]",
-			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
-	}
-}
-
-static void fas216_parse_message(FAS216_Info *info, unsigned char *message, int msglen)
-{
-	int i;
-
-	switch (message[0]) {
-	case COMMAND_COMPLETE:
-		if (msglen != 1)
-			goto unrecognised;
-
-		printk(KERN_ERR "scsi%d.%c: command complete with no "
-			"status in MESSAGE_IN?\n",
-			info->host->host_no, fas216_target(info));
-		break;
-
-	case SAVE_POINTERS:
-		if (msglen != 1)
-			goto unrecognised;
-
-		/*
-		 * Save current data pointer to SAVED data pointer
-		 * SCSI II standard says that we must not acknowledge
-		 * this until we have really saved pointers.
-		 * NOTE: we DO NOT save the command nor status pointers
-		 * as required by the SCSI II standard.  These always
-		 * point to the start of their respective areas.
-		 */
-		info->SCpnt->SCp = info->scsi.SCp;
-		info->SCpnt->SCp.sent_command = 0;
-		fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER,
-			"save data pointers: [%p, %X]",
-			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
-		break;
-
-	case RESTORE_POINTERS:
-		if (msglen != 1)
-			goto unrecognised;
-
-		/*
-		 * Restore current data pointer from SAVED data pointer
-		 */
-		info->scsi.SCp = info->SCpnt->SCp;
-		fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER,
-			"restore data pointers: [%p, 0x%x]",
-			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
-		break;
-
-	case DISCONNECT:
-		if (msglen != 1)
-			goto unrecognised;
-
-		info->scsi.phase = PHASE_MSGIN_DISCONNECT;
-		break;
-
-	case MESSAGE_REJECT:
-		if (msglen != 1)
-			goto unrecognised;
-
-		switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) {
-		case EXTENDED_MESSAGE | EXTENDED_SDTR << 8:
-			fas216_handlesync(info, message);
-			break;
-
-		case EXTENDED_MESSAGE | EXTENDED_WDTR << 8:
-			fas216_handlewide(info, message);
-			break;
-
-		default:
-			fas216_log(info, 0, "reject, last message 0x%04x",
-				fas216_get_last_msg(info, info->scsi.msgin_fifo));
-		}
-		break;
-
-	case NOP:
-		break;
-
-	case SIMPLE_QUEUE_TAG:
-		if (msglen < 2)
-			goto unrecognised;
-
-		/* handled above - print a warning since this is untested */
-		fas216_log(info, 0, "reconnect queue tag 0x%02x", message[1]);
-		break;
-
-	case EXTENDED_MESSAGE:
-		if (msglen < 3)
-			goto unrecognised;
-
-		switch (message[2]) {
-		case EXTENDED_SDTR:	/* Sync transfer negotiation request/reply */
-			fas216_handlesync(info, message);
-			break;
-
-		case EXTENDED_WDTR:	/* Wide transfer negotiation request/reply */
-			fas216_handlewide(info, message);
-			break;
-
-		default:
-			goto unrecognised;
-		}
-		break;
-
-	default:
-		goto unrecognised;
-	}
-	return;
-
-unrecognised:
-	fas216_log(info, 0, "unrecognised message, rejecting");
-	printk("scsi%d.%c: message was", info->host->host_no, fas216_target(info));
-	for (i = 0; i < msglen; i++)
-		printk("%s%02X", i & 31 ? " " : "\n  ", message[i]);
-	printk("\n");
-
-	/*
-	 * Something strange seems to be happening here -
-	 * I can't use SETATN since the chip gives me an
-	 * invalid command interrupt when I do.  Weird.
-	 */
-fas216_cmd(info, CMD_NOP);
-fas216_dumpstate(info);
-	fas216_cmd(info, CMD_SETATN);
-	msgqueue_flush(&info->scsi.msgs);
-	msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
-	info->scsi.phase = PHASE_MSGOUT_EXPECT;
-fas216_dumpstate(info);
-}
-
-static int fas216_wait_cmd(FAS216_Info *info, int cmd)
-{
-	int tout;
-	int stat;
-
-	fas216_cmd(info, cmd);
-
-	for (tout = 1000; tout; tout -= 1) {
-		stat = fas216_readb(info, REG_STAT);
-		if (stat & (STAT_INT|STAT_PARITYERROR))
-			break;
-		udelay(1);
-	}
-
-	return stat;
-}
-
-static int fas216_get_msg_byte(FAS216_Info *info)
-{
-	unsigned int stat = fas216_wait_cmd(info, CMD_MSGACCEPTED);
-
-	if ((stat & STAT_INT) == 0)
-		goto timedout;
-
-	if ((stat & STAT_BUSMASK) != STAT_MESGIN)
-		goto unexpected_phase_change;
-
-	fas216_readb(info, REG_INST);
-
-	stat = fas216_wait_cmd(info, CMD_TRANSFERINFO);
-
-	if ((stat & STAT_INT) == 0)
-		goto timedout;
-
-	if (stat & STAT_PARITYERROR)
-		goto parity_error;
-
-	if ((stat & STAT_BUSMASK) != STAT_MESGIN)
-		goto unexpected_phase_change;
-
-	fas216_readb(info, REG_INST);
-
-	return fas216_readb(info, REG_FF);
-
-timedout:
-	fas216_log(info, LOG_ERROR, "timed out waiting for message byte");
-	return -1;
-
-unexpected_phase_change:
-	fas216_log(info, LOG_ERROR, "unexpected phase change: status = %02x", stat);
-	return -2;
-
-parity_error:
-	fas216_log(info, LOG_ERROR, "parity error during message in phase");
-	return -3;
-}
-
-/**
- * fas216_message - handle a function done interrupt from FAS216 chip
- * @info: interface which caused function done interrupt
- *
- * Handle a function done interrupt from FAS216 chip
- */
-static void fas216_message(FAS216_Info *info)
-{
-	unsigned char *message = info->scsi.message;
-	unsigned int msglen = 1;
-	int msgbyte = 0;
-
-	fas216_checkmagic(info);
-
-	message[0] = fas216_readb(info, REG_FF);
-
-	if (message[0] == EXTENDED_MESSAGE) {
-		msgbyte = fas216_get_msg_byte(info);
-
-		if (msgbyte >= 0) {
-			message[1] = msgbyte;
-
-			for (msglen = 2; msglen < message[1] + 2; msglen++) {
-				msgbyte = fas216_get_msg_byte(info);
-
-				if (msgbyte >= 0)
-					message[msglen] = msgbyte;
-				else
-					break;
-			}
-		}
-	}
-
-	if (msgbyte == -3)
-		goto parity_error;
-
-#ifdef DEBUG_MESSAGES
-	{
-		int i;
-
-		printk("scsi%d.%c: message in: ",
-			info->host->host_no, fas216_target(info));
-		for (i = 0; i < msglen; i++)
-			printk("%02X ", message[i]);
-		printk("\n");
-	}
-#endif
-
-	if (info->scsi.phase == PHASE_RECONNECTED) {
-		if (message[0] == SIMPLE_QUEUE_TAG)
-			info->scsi.reconnected.tag = message[1];
-		fas216_finish_reconnect(info);
-		info->scsi.phase = PHASE_MSGIN;
-	}
-
-	fas216_parse_message(info, message, msglen);
-	fas216_cmd(info, CMD_MSGACCEPTED);
-	return;
-
-parity_error:
-	fas216_cmd(info, CMD_SETATN);
-	msgqueue_flush(&info->scsi.msgs);
-	msgqueue_addmsg(&info->scsi.msgs, 1, MSG_PARITY_ERROR);
-	info->scsi.phase = PHASE_MSGOUT_EXPECT;
-	fas216_cmd(info, CMD_MSGACCEPTED);
-	return;
-}
-
-/**
- * fas216_send_command - send command after all message bytes have been sent
- * @info: interface which caused bus service
- *
- * Send a command to a target after all message bytes have been sent
- */
-static void fas216_send_command(FAS216_Info *info)
-{
-	int i;
-
-	fas216_checkmagic(info);
-
-	fas216_cmd(info, CMD_NOP|CMD_WITHDMA);
-	fas216_cmd(info, CMD_FLUSHFIFO);
-
-	/* load command */
-	for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++)
-		fas216_writeb(info, REG_FF, info->SCpnt->cmnd[i]);
-
-	fas216_cmd(info, CMD_TRANSFERINFO);
-
-	info->scsi.phase = PHASE_COMMAND;
-}
-
-/**
- * fas216_send_messageout - handle bus service to send a message
- * @info: interface which caused bus service
- *
- * Handle bus service to send a message.
- * Note: We do not allow the device to change the data direction!
- */
-static void fas216_send_messageout(FAS216_Info *info, int start)
-{
-	unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);
-
-	fas216_checkmagic(info);
-
-	fas216_cmd(info, CMD_FLUSHFIFO);
-
-	if (tot_msglen) {
-		struct message *msg;
-		int msgnr = 0;
-
-		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
-			int i;
-
-			for (i = start; i < msg->length; i++)
-				fas216_writeb(info, REG_FF, msg->msg[i]);
-
-			msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF);
-			start = 0;
-		}
-	} else
-		fas216_writeb(info, REG_FF, NOP);
-
-	fas216_cmd(info, CMD_TRANSFERINFO);
-
-	info->scsi.phase = PHASE_MSGOUT;
-}
-
-/**
- * fas216_busservice_intr - handle bus service interrupt from FAS216 chip
- * @info: interface which caused bus service interrupt
- * @stat: Status register contents
- * @ssr: SCSI Status register contents
- *
- * Handle a bus service interrupt from FAS216 chip
- */
-static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
-{
-	fas216_checkmagic(info);
-
-	fas216_log(info, LOG_BUSSERVICE,
-		   "bus service: stat=%02x ssr=%02x phase=%02x",
-		   stat, ssr, info->scsi.phase);
-
-	switch (info->scsi.phase) {
-	case PHASE_SELECTION:
-		if ((ssr & IS_BITS) != IS_MSGBYTESENT)
-			goto bad_is;
-		break;
-
-	case PHASE_SELSTEPS:
-		switch (ssr & IS_BITS) {
-		case IS_SELARB:
-		case IS_MSGBYTESENT:
-			goto bad_is;
-
-		case IS_NOTCOMMAND:
-		case IS_EARLYPHASE:
-			if ((stat & STAT_BUSMASK) == STAT_MESGIN)
-				break;
-			goto bad_is;
-
-		case IS_COMPLETE:
-			break;
-		}
-
-	default:
-		break;
-	}
-
-	fas216_cmd(info, CMD_NOP);
-
-#define STATE(st,ph) ((ph) << 3 | (st))
-	/* This table describes the legal SCSI state transitions,
-	 * as described by the SCSI II spec.
-	 */
-	switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) {
-						/* Reselmsgin   -> Data In	*/
-	case STATE(STAT_DATAIN, PHASE_RECONNECTED):
-		fas216_finish_reconnect(info);
-	case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In      */
-	case STATE(STAT_DATAIN, PHASE_MSGOUT):  /* Message Out  -> Data In      */
-	case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command      -> Data In      */
-	case STATE(STAT_DATAIN, PHASE_MSGIN):   /* Message In   -> Data In      */
-		info->scsi.phase = PHASE_DATAIN;
-		fas216_transfer(info);
-		return;
-
-	case STATE(STAT_DATAIN, PHASE_DATAIN):  /* Data In      -> Data In      */
-	case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out     -> Data Out     */
-		fas216_cleanuptransfer(info);
-		fas216_transfer(info);
-		return;
-
-						/* Reselmsgin   -> Data Out     */
-	case STATE(STAT_DATAOUT, PHASE_RECONNECTED):
-		fas216_finish_reconnect(info);
-	case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out     */
-	case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out  -> Data Out     */
-	case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command      -> Data Out     */
-	case STATE(STAT_DATAOUT, PHASE_MSGIN):  /* Message In   -> Data Out     */
-		fas216_cmd(info, CMD_FLUSHFIFO);
-		info->scsi.phase = PHASE_DATAOUT;
-		fas216_transfer(info);
-		return;
-
-						/* Reselmsgin   -> Status       */
-	case STATE(STAT_STATUS, PHASE_RECONNECTED):
-		fas216_finish_reconnect(info);
-		goto status;
-	case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out     -> Status       */
-	case STATE(STAT_STATUS, PHASE_DATAIN):  /* Data In      -> Status       */
-		fas216_stoptransfer(info);
-	case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status       */
-	case STATE(STAT_STATUS, PHASE_MSGOUT):  /* Message Out  -> Status       */
-	case STATE(STAT_STATUS, PHASE_COMMAND): /* Command      -> Status       */
-	case STATE(STAT_STATUS, PHASE_MSGIN):   /* Message In   -> Status       */
-	status:
-		fas216_cmd(info, CMD_INITCMDCOMPLETE);
-		info->scsi.phase = PHASE_STATUS;
-		return;
-
-	case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */
-	case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */
-		fas216_stoptransfer(info);
-	case STATE(STAT_MESGIN, PHASE_COMMAND):	/* Command	-> Message In	*/
-	case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */
-	case STATE(STAT_MESGIN, PHASE_MSGOUT):  /* Message Out  -> Message In   */
-		info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
-		fas216_cmd(info, CMD_FLUSHFIFO);
-		fas216_cmd(info, CMD_TRANSFERINFO);
-		info->scsi.phase = PHASE_MSGIN;
-		return;
-
-						/* Reselmsgin   -> Message In   */
-	case STATE(STAT_MESGIN, PHASE_RECONNECTED):
-	case STATE(STAT_MESGIN, PHASE_MSGIN):
-		info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
-		fas216_cmd(info, CMD_TRANSFERINFO);
-		return;
-
-						/* Reselmsgin   -> Command      */
-	case STATE(STAT_COMMAND, PHASE_RECONNECTED):
-		fas216_finish_reconnect(info);
-	case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out  -> Command      */
-	case STATE(STAT_COMMAND, PHASE_MSGIN):  /* Message In   -> Command      */
-		fas216_send_command(info);
-		info->scsi.phase = PHASE_COMMAND;
-		return;
-
-
-	/*
-	 * Selection    -> Message Out
-	 */
-	case STATE(STAT_MESGOUT, PHASE_SELECTION):
-		fas216_send_messageout(info, 1);
-		return;
-
-	/*
-	 * Message Out  -> Message Out
-	 */
-	case STATE(STAT_MESGOUT, PHASE_SELSTEPS):
-	case STATE(STAT_MESGOUT, PHASE_MSGOUT):
-		/*
-		 * If we get another message out phase, this usually
-		 * means some parity error occurred.  Resend complete
-		 * set of messages.  If we have more than one byte to
-		 * send, we need to assert ATN again.
-		 */
-		if (info->device[info->SCpnt->device->id].parity_check) {
-			/*
-			 * We were testing... good, the device
-			 * supports parity checking.
-			 */
-			info->device[info->SCpnt->device->id].parity_check = 0;
-			info->device[info->SCpnt->device->id].parity_enabled = 1;
-			fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
-		}
-
-		if (msgqueue_msglength(&info->scsi.msgs) > 1)
-			fas216_cmd(info, CMD_SETATN);
-		/*FALLTHROUGH*/
-
-	/*
-	 * Any          -> Message Out
-	 */
-	case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):
-		fas216_send_messageout(info, 0);
-		return;
-
-	/* Error recovery rules.
-	 *   These either attempt to abort or retry the operation.
-	 * TODO: we need more of these
-	 */
-	case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command      -> Command      */
-		/* error - we've sent out all the command bytes
-		 * we have.
-		 * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS
-		 * to include the command bytes sent for this to work
-		 * correctly.
-		 */
-		printk(KERN_ERR "scsi%d.%c: "
-			"target trying to receive more command bytes\n",
-			info->host->host_no, fas216_target(info));
-		fas216_cmd(info, CMD_SETATN);
-		fas216_set_stc(info, 15);
-		fas216_cmd(info, CMD_PADBYTES | CMD_WITHDMA);
-		msgqueue_flush(&info->scsi.msgs);
-		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
-		info->scsi.phase = PHASE_MSGOUT_EXPECT;
-		return;
-	}
-
-	if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) {
-		printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n",
-			info->host->host_no, fas216_target(info),
-			fas216_bus_phase(stat));
-		msgqueue_flush(&info->scsi.msgs);
-		fas216_cmd(info, CMD_SETATN);
-		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
-		info->scsi.phase = PHASE_MSGOUT_EXPECT;
-		info->scsi.aborting = 1;
-		fas216_cmd(info, CMD_TRANSFERINFO);
-		return;
-	}
-	printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n",
-		info->host->host_no, fas216_target(info),
-		fas216_bus_phase(stat),
-		fas216_drv_phase(info));
-	print_debug_list();
-	return;
-
-bad_is:
-	fas216_log(info, 0, "bus service at step %d?", ssr & IS_BITS);
-	fas216_dumpstate(info);
-	print_debug_list();
-
-	fas216_done(info, DID_ERROR);
-}
-
-/**
- * fas216_funcdone_intr - handle a function done interrupt from FAS216 chip
- * @info: interface which caused function done interrupt
- * @stat: Status register contents
- * @ssr: SCSI Status register contents
- *
- * Handle a function done interrupt from FAS216 chip
- */
-static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int ssr)
-{
-	unsigned int fifo_len = fas216_readb(info, REG_CFIS) & CFIS_CF;
-	unsigned int status, message;
-
-	fas216_checkmagic(info);
-
-	fas216_log(info, LOG_FUNCTIONDONE,
-		   "function done: stat=%02x ssr=%02x phase=%02x",
-		   stat, ssr, info->scsi.phase);
-
-	switch (info->scsi.phase) {
-	case PHASE_STATUS:			/* status phase - read status and msg	*/
-		if (fifo_len != 2) {
-			fas216_log(info, 0, "odd number of bytes in FIFO: %d", fifo_len);
-		}
-		status = fas216_readb(info, REG_FF);
-		message = fas216_readb(info, REG_FF);
-		info->scsi.SCp.Message = message;
-		info->scsi.SCp.Status = status;
-		info->scsi.phase = PHASE_DONE;
-		fas216_cmd(info, CMD_MSGACCEPTED);
-		break;
-
-	case PHASE_IDLE:			/* reselected?				*/
-	case PHASE_MSGIN:			/* message in phase			*/
-	case PHASE_RECONNECTED:			/* reconnected command			*/
-		if ((stat & STAT_BUSMASK) == STAT_MESGIN) {
-			info->scsi.msgin_fifo = fifo_len;
-			fas216_message(info);
-			break;
-		}
-
-	default:
-		fas216_log(info, 0, "internal phase %s for function done?"
-			"  What do I do with this?",
-			fas216_target(info), fas216_drv_phase(info));
-	}
-}
-
-static void fas216_bus_reset(FAS216_Info *info)
-{
-	neg_t sync_state, wide_state;
-	int i;
-
-	msgqueue_flush(&info->scsi.msgs);
-
-	info->scsi.reconnected.target = 0;
-	info->scsi.reconnected.lun = 0;
-	info->scsi.reconnected.tag = 0;
-
-	wide_state = neg_invalid;
-	sync_state = neg_invalid;
-
-#ifdef SCSI2_WIDE
-	if (info->ifcfg.wide_max_size != 0)
-		wide_state = neg_wait;
-#endif
-#ifdef SCSI2_SYNC
-	if (info->ifcfg.capabilities & (FASCAP_DMA|FASCAP_PSEUDODMA))
-		sync_state = neg_wait;
-#endif
-
-	info->scsi.phase = PHASE_IDLE;
-	info->SCpnt = NULL; /* bug! */
-	memset(&info->scsi.SCp, 0, sizeof(info->scsi.SCp));
-
-	for (i = 0; i < 8; i++) {
-		info->device[i].disconnect_ok	= info->ifcfg.disconnect_ok;
-		info->device[i].sync_state	= sync_state;
-		info->device[i].wide_state	= wide_state;
-		info->device[i].period		= info->ifcfg.asyncperiod / 4;
-		info->device[i].stp		= info->scsi.async_stp;
-		info->device[i].sof		= 0;
-		info->device[i].wide_xfer	= 0;
-	}
-
-	info->rst_bus_status = 1;
-	wake_up(&info->eh_wait);
-}
-
-/**
- * fas216_intr - handle interrupts to progress a command
- * @info: interface to service
- *
- * Handle interrupts from the interface to progress a command
- */
-void fas216_intr(FAS216_Info *info)
-{
-	unsigned char isr, ssr, stat;
-
-	fas216_checkmagic(info);
-
-	stat = fas216_readb(info, REG_STAT);
-	ssr = fas216_readb(info, REG_IS);
-	isr = fas216_readb(info, REG_INST);
-
-	add_debug_list(stat, ssr, isr, info->scsi.phase);
-
-	if (stat & STAT_INT) {
-		if (isr & INST_BUSRESET) {
-			fas216_log(info, 0, "bus reset detected");
-			fas216_bus_reset(info);
-			scsi_report_bus_reset(info->host, 0);
-		} else if (isr & INST_ILLEGALCMD) {
-			fas216_log(info, LOG_ERROR, "illegal command given\n");
-			fas216_dumpstate(info);
-			print_debug_list();
-		} else if (isr & INST_DISCONNECT)
-			fas216_disconnect_intr(info);
-		else if (isr & INST_RESELECTED)		/* reselected			*/
-			fas216_reselected_intr(info);
-		else if (isr & INST_BUSSERVICE)		/* bus service request		*/
-			fas216_busservice_intr(info, stat, ssr);
-		else if (isr & INST_FUNCDONE)		/* function done		*/
-			fas216_funcdone_intr(info, stat, ssr);
-		else
-		    	fas216_log(info, 0, "unknown interrupt received:"
-				" phase %s isr %02X ssr %02X stat %02X",
-				fas216_drv_phase(info), isr, ssr, stat);
-	}
-}
-
-static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
-{
-	int tot_msglen;
-
-	/* following what the ESP driver says */
-	fas216_set_stc(info, 0);
-	fas216_cmd(info, CMD_NOP | CMD_WITHDMA);
-
-	/* flush FIFO */
-	fas216_cmd(info, CMD_FLUSHFIFO);
-
-	/* load bus-id and timeout */
-	fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id));
-	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);
-
-	/* synchronous transfers */
-	fas216_set_sync(info, SCpnt->device->id);
-
-	tot_msglen = msgqueue_msglength(&info->scsi.msgs);
-
-#ifdef DEBUG_MESSAGES
-	{
-		struct message *msg;
-		int msgnr = 0, i;
-
-		printk("scsi%d.%c: message out: ",
-			info->host->host_no, '0' + SCpnt->device->id);
-		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
-			printk("{ ");
-			for (i = 0; i < msg->length; i++)
-				printk("%02x ", msg->msg[i]);
-			printk("} ");
-		}
-		printk("\n");
-	}
-#endif
-
-	if (tot_msglen == 1 || tot_msglen == 3) {
-		/*
-		 * We have an easy message length to send...
-		 */
-		struct message *msg;
-		int msgnr = 0, i;
-
-		info->scsi.phase = PHASE_SELSTEPS;
-
-		/* load message bytes */
-		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
-			for (i = 0; i < msg->length; i++)
-				fas216_writeb(info, REG_FF, msg->msg[i]);
-			msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF);
-		}
-
-		/* load command */
-		for (i = 0; i < SCpnt->cmd_len; i++)
-			fas216_writeb(info, REG_FF, SCpnt->cmnd[i]);
-
-		if (tot_msglen == 1)
-			fas216_cmd(info, CMD_SELECTATN);
-		else
-			fas216_cmd(info, CMD_SELECTATN3);
-	} else {
-		/*
-		 * We have an unusual number of message bytes to send.
-		 *  Load first byte into fifo, and issue SELECT with ATN and
-		 *  stop steps.
-		 */
-		struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0);
-
-		fas216_writeb(info, REG_FF, msg->msg[0]);
-		msg->fifo = 1;
-
-		fas216_cmd(info, CMD_SELECTATNSTOP);
-	}
-}
-
-/*
- * Decide whether we need to perform a parity test on this device.
- * Can also be used to force parity error conditions during initial
- * information transfer phase (message out) for test purposes.
- */
-static int parity_test(FAS216_Info *info, int target)
-{
-#if 0
-	if (target == 3) {
-		info->device[3].parity_check = 0;
-		return 1;
-	}
-#endif
-	return info->device[target].parity_check;
-}
-
-static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
-{
-	int disconnect_ok;
-
-	/*
-	 * claim host busy
-	 */
-	info->scsi.phase = PHASE_SELECTION;
-	info->scsi.SCp = SCpnt->SCp;
-	info->SCpnt = SCpnt;
-	info->dma.transfer_type = fasdma_none;
-
-	if (parity_test(info, SCpnt->device->id))
-		fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_PTE);
-	else
-		fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
-
-	/*
-	 * Don't allow request sense commands to disconnect.
-	 */
-	disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE &&
-			info->device[SCpnt->device->id].disconnect_ok;
-
-	/*
-	 * build outgoing message bytes
-	 */
-	msgqueue_flush(&info->scsi.msgs);
-	msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->device->lun));
-
-	/*
-	 * add tag message if required
-	 */
-	if (SCpnt->tag)
-		msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);
-
-	do {
-#ifdef SCSI2_WIDE
-		if (info->device[SCpnt->device->id].wide_state == neg_wait) {
-			info->device[SCpnt->device->id].wide_state = neg_inprogress;
-			msgqueue_addmsg(&info->scsi.msgs, 4,
-					EXTENDED_MESSAGE, 2, EXTENDED_WDTR,
-					info->ifcfg.wide_max_size);
-			break;
-		}
-#endif
-#ifdef SCSI2_SYNC
-		if ((info->device[SCpnt->device->id].sync_state == neg_wait ||
-		     info->device[SCpnt->device->id].sync_state == neg_complete) &&
-		    (SCpnt->cmnd[0] == REQUEST_SENSE ||
-		     SCpnt->cmnd[0] == INQUIRY)) {
-			info->device[SCpnt->device->id].sync_state = neg_inprogress;
-			msgqueue_addmsg(&info->scsi.msgs, 5,
-					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
-					1000 / info->ifcfg.clockrate,
-					info->ifcfg.sync_max_depth);
-			break;
-		}
-#endif
-	} while (0);
-
-	__fas216_start_command(info, SCpnt);
-}
-
-static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
-{
-#ifdef SCSI2_TAG
-	/*
-	 * tagged queuing - allocate a new tag to this command
-	 */
-	if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE &&
-	    SCpnt->cmnd[0] != INQUIRY) {
-	    SCpnt->device->current_tag += 1;
-		if (SCpnt->device->current_tag == 0)
-		    SCpnt->device->current_tag = 1;
-			SCpnt->tag = SCpnt->device->current_tag;
-	} else
-#endif
-		set_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
-
-	info->stats.removes += 1;
-	switch (SCpnt->cmnd[0]) {
-	case WRITE_6:
-	case WRITE_10:
-	case WRITE_12:
-		info->stats.writes += 1;
-		break;
-	case READ_6:
-	case READ_10:
-	case READ_12:
-		info->stats.reads += 1;
-		break;
-	default:
-		info->stats.miscs += 1;
-		break;
-	}
-}
-
-static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
-{
-	struct message *msg;
-
-	/*
-	 * claim host busy
-	 */
-	info->scsi.phase = PHASE_SELECTION;
-	info->scsi.SCp = SCpnt->SCp;
-	info->SCpnt = SCpnt;
-	info->dma.transfer_type = fasdma_none;
-
-	fas216_log(info, LOG_ERROR, "sending bus device reset");
-
-	msgqueue_flush(&info->scsi.msgs);
-	msgqueue_addmsg(&info->scsi.msgs, 1, BUS_DEVICE_RESET);
-
-	/* following what the ESP driver says */
-	fas216_set_stc(info, 0);
-	fas216_cmd(info, CMD_NOP | CMD_WITHDMA);
-
-	/* flush FIFO */
-	fas216_cmd(info, CMD_FLUSHFIFO);
-
-	/* load bus-id and timeout */
-	fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id));
-	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);
-
-	/* synchronous transfers */
-	fas216_set_sync(info, SCpnt->device->id);
-
-	msg = msgqueue_getmsg(&info->scsi.msgs, 0);
-
-	fas216_writeb(info, REG_FF, BUS_DEVICE_RESET);
-	msg->fifo = 1;
-
-	fas216_cmd(info, CMD_SELECTATNSTOP);
-}
-
-/**
- * fas216_kick - kick a command to the interface
- * @info: our host interface to kick
- *
- * Kick a command to the interface, interface should be idle.
- * Notes: Interrupts are always disabled!
- */
-static void fas216_kick(FAS216_Info *info)
-{
-	Scsi_Cmnd *SCpnt = NULL;
-#define TYPE_OTHER	0
-#define TYPE_RESET	1
-#define TYPE_QUEUE	2
-	int where_from = TYPE_OTHER;
-
-	fas216_checkmagic(info);
-
-	/*
-	 * Obtain the next command to process.
-	 */
-	do {
-		if (info->rstSCpnt) {
-			SCpnt = info->rstSCpnt;
-			/* don't remove it */
-			where_from = TYPE_RESET;
-			break;
-		}
-
-		if (info->reqSCpnt) {
-			SCpnt = info->reqSCpnt;
-			info->reqSCpnt = NULL;
-			break;
-		}
-
-		if (info->origSCpnt) {
-			SCpnt = info->origSCpnt;
-			info->origSCpnt = NULL;
-			break;
-		}
-
-		/* retrieve next command */
-		if (!SCpnt) {
-			SCpnt = queue_remove_exclude(&info->queues.issue,
-						     info->busyluns);
-			where_from = TYPE_QUEUE;
-			break;
-		}
-	} while (0);
-
-	if (!SCpnt) /* no command pending - just exit */
-		return;
-
-	if (info->scsi.disconnectable && info->SCpnt) {
-		fas216_log(info, LOG_CONNECT,
-			"moved command for %d to disconnected queue",
-			info->SCpnt->device->id);
-		queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);
-		info->scsi.disconnectable = 0;
-		info->SCpnt = NULL;
-	}
-
-	fas216_log_command(info, LOG_CONNECT | LOG_MESSAGES, SCpnt,
-			   "starting");
-
-	switch (where_from) {
-	case TYPE_QUEUE:
-		fas216_allocate_tag(info, SCpnt);
-	case TYPE_OTHER:
-		fas216_start_command(info, SCpnt);
-		break;
-	case TYPE_RESET:
-		fas216_do_bus_device_reset(info, SCpnt);
-		break;
-	}
-
-	fas216_log(info, LOG_CONNECT, "select: data pointers [%p, %X]",
-		info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
-
-	/*
-	 * should now get either DISCONNECT or
-	 * (FUNCTION DONE with BUS SERVICE) interrupt
-	 */
-}
-
-/*
- * Clean up from issuing a BUS DEVICE RESET message to a device.
- */
-static void
-fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
-{
-	fas216_log(info, LOG_ERROR, "fas216 device reset complete");
-
-	info->rstSCpnt = NULL;
-	info->rst_dev_status = 1;
-	wake_up(&info->eh_wait);
-}
-
-/**
- * fas216_rq_sns_done - Finish processing automatic request sense command
- * @info: interface that completed
- * @SCpnt: command that completed
- * @result: driver byte of result
- *
- * Finish processing automatic request sense command
- */
-static void
-fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
-{
-	fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
-		   "request sense complete, result=0x%04x%02x%02x",
-		   result, SCpnt->SCp.Message, SCpnt->SCp.Status);
-
-	if (result != DID_OK || SCpnt->SCp.Status != GOOD)
-		/*
-		 * Something went wrong.  Make sure that we don't
-		 * have valid data in the sense buffer that could
-		 * confuse the higher levels.
-		 */
-		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-//printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id);
-//{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); }
-	/*
-	 * Note that we don't set SCpnt->result, since that should
-	 * reflect the status of the command that we were asked by
-	 * the upper layers to process.  This would have been set
-	 * correctly by fas216_std_done.
-	 */
-	SCpnt->scsi_done(SCpnt);
-}
-
-/**
- * fas216_std_done - finish processing of standard command
- * @info: interface that completed
- * @SCpnt: command that completed
- * @result: driver byte of result
- *
- * Finish processing of standard command
- */
-static void
-fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
-{
-	info->stats.fins += 1;
-
-	SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
-			info->scsi.SCp.Status;
-
-	fas216_log_command(info, LOG_CONNECT, SCpnt,
-		"command complete, result=0x%08x", SCpnt->result);
-
-	/*
-	 * If the driver detected an error, we're all done.
-	 */
-	if (host_byte(SCpnt->result) != DID_OK ||
-	    msg_byte(SCpnt->result) != COMMAND_COMPLETE)
-		goto done;
-
-	/*
-	 * If the command returned CHECK_CONDITION or COMMAND_TERMINATED
-	 * status, request the sense information.
-	 */
-	if (status_byte(SCpnt->result) == CHECK_CONDITION ||
-	    status_byte(SCpnt->result) == COMMAND_TERMINATED)
-		goto request_sense;
-
-	/*
-	 * If the command did not complete with GOOD status,
-	 * we are all done here.
-	 */
-	if (status_byte(SCpnt->result) != GOOD)
-		goto done;
-
-	/*
-	 * We have successfully completed a command.  Make sure that
-	 * we do not have any buffers left to transfer.  The world
-	 * is not perfect, and we seem to occasionally hit this.
-	 * It can be indicative of a buggy driver, target or the upper
-	 * levels of the SCSI code.
-	 */
-	if (info->scsi.SCp.ptr) {
-		switch (SCpnt->cmnd[0]) {
-		case INQUIRY:
-		case START_STOP:
-		case MODE_SENSE:
-			break;
-
-		default:
-			printk(KERN_ERR "scsi%d.%c: incomplete data transfer "
-				"detected: res=%08X ptr=%p len=%X CDB: ",
-				info->host->host_no, '0' + SCpnt->device->id,
-				SCpnt->result, info->scsi.SCp.ptr,
-				info->scsi.SCp.this_residual);
-			print_command(SCpnt->cmnd);
-			SCpnt->result &= ~(255 << 16);
-			SCpnt->result |= DID_BAD_TARGET << 16;
-			goto request_sense;
-		}
-	}
-
-done:
-	if (SCpnt->scsi_done) {
-		SCpnt->scsi_done(SCpnt);
-		return;
-	}
-
-	panic("scsi%d.H: null scsi_done function in fas216_done",
-		info->host->host_no);
-
-
-request_sense:
-	if (SCpnt->cmnd[0] == REQUEST_SENSE)
-		goto done;
-
-	fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
-			  "requesting sense");
-	memset(SCpnt->cmnd, 0, sizeof (SCpnt->cmnd));
-	SCpnt->cmnd[0] = REQUEST_SENSE;
-	SCpnt->cmnd[1] = SCpnt->device->lun << 5;
-	SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
-	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
-	SCpnt->SCp.buffer = NULL;
-	SCpnt->SCp.buffers_residual = 0;
-	SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer;
-	SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
-	SCpnt->SCp.Message = 0;
-	SCpnt->SCp.Status = 0;
-	SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
-	SCpnt->sc_data_direction = SCSI_DATA_READ;
-	SCpnt->use_sg = 0;
-	SCpnt->tag = 0;
-	SCpnt->host_scribble = (void *)fas216_rq_sns_done;
-
-	/*
-	 * Place this command into the high priority "request
-	 * sense" slot.  This will be the very next command
-	 * executed, unless a target connects to us.
-	 */
-	if (info->reqSCpnt)
-		printk(KERN_WARNING "scsi%d.%c: loosing request command\n",
-			info->host->host_no, '0' + SCpnt->device->id);
-	info->reqSCpnt = SCpnt;
-}
-
-/**
- * fas216_done - complete processing for current command
- * @info: interface that completed
- * @result: driver byte of result
- *
- * Complete processing for current command
- */
-static void fas216_done(FAS216_Info *info, unsigned int result)
-{
-	void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
-	Scsi_Cmnd *SCpnt;
-	unsigned long flags;
-
-	fas216_checkmagic(info);
-
-	if (!info->SCpnt)
-		goto no_command;
-
-	SCpnt = info->SCpnt;
-	info->SCpnt = NULL;
-    	info->scsi.phase = PHASE_IDLE;
-
-	if (info->scsi.aborting) {
-		fas216_log(info, 0, "uncaught abort - returning DID_ABORT");
-		result = DID_ABORT;
-		info->scsi.aborting = 0;
-	}
-
-	/*
-	 * Sanity check the completion - if we have zero bytes left
-	 * to transfer, we should not have a valid pointer.
-	 */
-	if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) {
-		printk("scsi%d.%c: zero bytes left to transfer, but "
-		       "buffer pointer still valid: ptr=%p len=%08x CDB: ",
-		       info->host->host_no, '0' + SCpnt->device->id,
-		       info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
-		info->scsi.SCp.ptr = NULL;
-		print_command(SCpnt->cmnd);
-	}
-
-	/*
-	 * Clear down this command as completed.  If we need to request
-	 * the sense information, fas216_kick will re-assert the busy
-	 * status.
-	 */
-	info->device[SCpnt->device->id].parity_check = 0;
-	clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
-
-	fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
-	fn(info, SCpnt, result);
-
-	if (info->scsi.irq != NO_IRQ) {
-		spin_lock_irqsave(&info->host_lock, flags);
-		if (info->scsi.phase == PHASE_IDLE)
-			fas216_kick(info);
-		spin_unlock_irqrestore(&info->host_lock, flags);
-	}
-	return;
-
-no_command:
-	panic("scsi%d.H: null command in fas216_done",
-		info->host->host_no);
-}
-
-/**
- * fas216_queue_command - queue a command for adapter to process.
- * @SCpnt: Command to queue
- * @done: done function to call once command is complete
- *
- * Queue a command for adapter to process.
- * Returns: 0 on success, else error.
- * Notes: io_request_lock is held, interrupts are disabled.
- */
-int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
-{
-	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
-	int result;
-
-	fas216_checkmagic(info);
-
-	fas216_log_command(info, LOG_CONNECT, SCpnt,
-			   "received command (%p)", SCpnt);
-
-	SCpnt->scsi_done = done;
-	SCpnt->host_scribble = (void *)fas216_std_done;
-	SCpnt->result = 0;
-
-	init_SCp(SCpnt);
-
-	info->stats.queues += 1;
-	SCpnt->tag = 0;
-
-	spin_lock(&info->host_lock);
-
-	/*
-	 * Add command into execute queue and let it complete under
-	 * whatever scheme we're using.
-	 */
-	result = !queue_add_cmd_ordered(&info->queues.issue, SCpnt);
-
-	/*
-	 * If we successfully added the command,
-	 * kick the interface to get it moving.
-	 */
-	if (result == 0 && info->scsi.phase == PHASE_IDLE)
-		fas216_kick(info);
-	spin_unlock(&info->host_lock);
-
-	fas216_log_target(info, LOG_CONNECT, -1, "queue %s",
-		result ? "failure" : "success");
-
-	return result;
-}
-
-/**
- * fas216_internal_done - trigger restart of a waiting thread in fas216_command
- * @SCpnt: Command to wake
- *
- * Trigger restart of a waiting thread in fas216_command
- */
-static void fas216_internal_done(Scsi_Cmnd *SCpnt)
-{
-	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
-
-	fas216_checkmagic(info);
-
-	info->internal_done = 1;
-}
-
-/**
- * fas216_command - queue a command for adapter to process.
- * @SCpnt: Command to queue
- *
- * Queue a command for adapter to process.
- * Returns: scsi result code.
- * Notes: io_request_lock is held, interrupts are disabled.
- */
-int fas216_command(Scsi_Cmnd *SCpnt)
-{
-	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
-
-	fas216_checkmagic(info);
-
-	/*
-	 * We should only be using this if we don't have an interrupt.
-	 * Provide some "incentive" to use the queueing code.
-	 */
-	if (info->scsi.irq != NO_IRQ)
-		BUG();
-
-	info->internal_done = 0;
-	fas216_queue_command(SCpnt, fas216_internal_done);
-
-	/*
-	 * This wastes time, since we can't return until the command is
-	 * complete. We can't sleep either since we may get re-entered!
-	 * However, we must re-enable interrupts, or else we'll be
-	 * waiting forever.
-	 */
-	spin_unlock_irq(info->host->host_lock);
-
-	while (!info->internal_done) {
-		/*
-		 * If we don't have an IRQ, then we must poll the card for
-		 * it's interrupt, and use that to call this driver's
-		 * interrupt routine.  That way, we keep the command
-		 * progressing.  Maybe we can add some inteligence here
-		 * and go to sleep if we know that the device is going
-		 * to be some time (eg, disconnected).
-		 */
-		if (fas216_readb(info, REG_STAT) & STAT_INT) {
-			spin_lock_irq(info->host->host_lock);
-			fas216_intr(info);
-			spin_unlock_irq(info->host->host_lock);
-		}
-	}
-
-	spin_lock_irq(info->host->host_lock);
-
-	return SCpnt->result;
-}
-
-/*
- * Error handler timeout function.  Indicate that we timed out,
- * and wake up any error handler process so it can continue.
- */
-static void fas216_eh_timer(unsigned long data)
-{
-	FAS216_Info *info = (FAS216_Info *)data;
-
-	fas216_log(info, LOG_ERROR, "error handling timed out\n");
-
-	del_timer(&info->eh_timer);
-
-	if (info->rst_bus_status == 0)
-		info->rst_bus_status = -1;
-	if (info->rst_dev_status == 0)
-		info->rst_dev_status = -1;
-
-	wake_up(&info->eh_wait);
-}
-
-enum res_find {
-	res_failed,		/* not found			*/
-	res_success,		/* command on issue queue	*/
-	res_hw_abort		/* command on disconnected dev	*/
-};
-
-/**
- * fas216_do_abort - decide how to abort a command
- * @SCpnt: command to abort
- *
- * Decide how to abort a command.
- * Returns: abort status
- */
-static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
-{
-	enum res_find res = res_failed;
-
-	if (queue_remove_cmd(&info->queues.issue, SCpnt)) {
-		/*
-		 * The command was on the issue queue, and has not been
-		 * issued yet.  We can remove the command from the queue,
-		 * and acknowledge the abort.  Neither the device nor the
-		 * interface know about the command.
-		 */
-		printk("on issue queue ");
-
-		res = res_success;
-	} else if (queue_remove_cmd(&info->queues.disconnected, SCpnt)) {
-		/*
-		 * The command was on the disconnected queue.  We must
-		 * reconnect with the device if possible, and send it
-		 * an abort message.
-		 */
-		printk("on disconnected queue ");
-
-		res = res_hw_abort;
-	} else if (info->SCpnt == SCpnt) {
-		printk("executing ");
-
-		switch (info->scsi.phase) {
-		/*
-		 * If the interface is idle, and the command is 'disconnectable',
-		 * then it is the same as on the disconnected queue.
-		 */
-		case PHASE_IDLE:
-			if (info->scsi.disconnectable) {
-				info->scsi.disconnectable = 0;
-				info->SCpnt = NULL;
-				res = res_hw_abort;
-			}
-			break;
-
-		default:
-			break;
-		}
-	} else if (info->origSCpnt == SCpnt) {
-		/*
-		 * The command will be executed next, but a command
-		 * is currently using the interface.  This is similar to
-		 * being on the issue queue, except the busylun bit has
-		 * been set.
-		 */
-		info->origSCpnt = NULL;
-		clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
-		printk("waiting for execution ");
-		res = res_success;
-	} else
-		printk("unknown ");
-
-	return res;
-}
-
-/**
- * fas216_eh_abort - abort this command
- * @SCpnt: command to abort
- *
- * Abort this command.
- * Returns: FAILED if unable to abort
- * Notes: io_request_lock is taken, and irqs are disabled
- */
-int fas216_eh_abort(Scsi_Cmnd *SCpnt)
-{
-	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
-	int result = FAILED;
-
-	fas216_checkmagic(info);
-
-	info->stats.aborts += 1;
-
-	printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no);
-	print_command(SCpnt->data_cmnd);
-
-	print_debug_list();
-	fas216_dumpstate(info);
-
-	printk(KERN_WARNING "scsi%d: abort %p ", info->host->host_no, SCpnt);
-
-	switch (fas216_find_command(info, SCpnt)) {
-	/*
-	 * We found the command, and cleared it out.  Either
-	 * the command is still known to be executing on the
-	 * target, or the busylun bit is not set.
-	 */
-	case res_success:
-		printk("success\n");
-		result = SUCCESS;
-		break;
-
-	/*
-	 * We need to reconnect to the target and send it an
-	 * ABORT or ABORT_TAG message.  We can only do this
-	 * if the bus is free.
-	 */
-	case res_hw_abort:
-		
-
-	/*
-	 * We are unable to abort the command for some reason.
-	 */
-	default:
-	case res_failed:
-		printk("failed\n");
-		break;
-	}
-
-	return result;
-}
-
-/**
- * fas216_eh_device_reset - Reset the device associated with this command
- * @SCpnt: command specifing device to reset
- *
- * Reset the device associated with this command.
- * Returns: FAILED if unable to reset.
- * Notes: We won't be re-entered, so we'll only have one device
- * reset on the go at one time.
- */
-int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
-{
-	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
-	unsigned long flags;
-	int i, res = FAILED, target = SCpnt->device->id;
-
-	fas216_log(info, LOG_ERROR, "device reset for target %d", target);
-
-	spin_lock_irqsave(&info->host_lock, flags);
-
-	do {
-		/*
-		 * If we are currently connected to a device, and
-		 * it is the device we want to reset, there is
-		 * nothing we can do here.  Chances are it is stuck,
-		 * and we need a bus reset.
-		 */
-		if (info->SCpnt && !info->scsi.disconnectable &&
-		    info->SCpnt->device->id == SCpnt->device->id)
-			break;
-
-		/*
-		 * We're going to be resetting this device.  Remove
-		 * all pending commands from the driver.  By doing
-		 * so, we guarantee that we won't touch the command
-		 * structures except to process the reset request.
-		 */
-		queue_remove_all_target(&info->queues.issue, target);
-		queue_remove_all_target(&info->queues.disconnected, target);
-		if (info->origSCpnt && info->origSCpnt->device->id == target)
-			info->origSCpnt = NULL;
-		if (info->reqSCpnt && info->reqSCpnt->device->id == target)
-			info->reqSCpnt = NULL;
-		for (i = 0; i < 8; i++)
-			clear_bit(target * 8 + i, info->busyluns);
-
-		/*
-		 * Hijack this SCSI command structure to send
-		 * a bus device reset message to this device.
-		 */
-		SCpnt->host_scribble = (void *)fas216_devicereset_done;
-
-		info->rst_dev_status = 0;
-		info->rstSCpnt = SCpnt;
-
-		if (info->scsi.phase == PHASE_IDLE)
-			fas216_kick(info);
-
-		mod_timer(&info->eh_timer, 30 * HZ);
-		spin_unlock_irqrestore(&info->host_lock, flags);
-
-		/*
-		 * Wait up to 30 seconds for the reset to complete.
-		 */
-		wait_event(info->eh_wait, info->rst_dev_status);
-
-		del_timer_sync(&info->eh_timer);
-		spin_lock_irqsave(&info->host_lock, flags);
-		info->rstSCpnt = NULL;
-
-		if (info->rst_dev_status == 1)
-			res = SUCCESS;
-	} while (0);
-
-	SCpnt->host_scribble = NULL;
-	spin_unlock_irqrestore(&info->host_lock, flags);
-
-	fas216_log(info, LOG_ERROR, "device reset complete: %s\n",
-		   res == SUCCESS ? "success" : "failed");
-
-	return res;
-}
-
-/**
- * fas216_eh_bus_reset - Reset the bus associated with the command
- * @SCpnt: command specifing bus to reset
- *
- * Reset the bus associated with the command.
- * Returns: FAILED if unable to reset.
- * Notes: Further commands are blocked.
- */
-int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
-{
-	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
-	unsigned long flags;
-	Scsi_Device *SDpnt;
-
-	fas216_checkmagic(info);
-	fas216_log(info, LOG_ERROR, "resetting bus");
-
-	info->stats.bus_resets += 1;
-
-	spin_lock_irqsave(&info->host_lock, flags);
-
-	/*
-	 * Stop all activity on this interface.
-	 */
-	fas216_aborttransfer(info);
-	fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]);
-
-	/*
-	 * Clear any pending interrupts.
-	 */
-	while (fas216_readb(info, REG_STAT) & STAT_INT)
-		fas216_readb(info, REG_INST);
-
-	info->rst_bus_status = 0;
-
-	/*
-	 * For each attached hard-reset device, clear out
-	 * all command structures.  Leave the running
-	 * command in place.
-	 */
-	list_for_each_entry(SDpnt, &info->host->my_devices, siblings) {
-		int i;
-
-		if (SDpnt->soft_reset)
-			continue;
-
-		queue_remove_all_target(&info->queues.issue, SDpnt->id);
-		queue_remove_all_target(&info->queues.disconnected, SDpnt->id);
-		if (info->origSCpnt && info->origSCpnt->device->id == SDpnt->id)
-			info->origSCpnt = NULL;
-		if (info->reqSCpnt && info->reqSCpnt->device->id == SDpnt->id)
-			info->reqSCpnt = NULL;
-		info->SCpnt = NULL;
-
-		for (i = 0; i < 8; i++)
-			clear_bit(SDpnt->id * 8 + i, info->busyluns);
-	}
-
-	/*
-	 * Reset the SCSI bus.  Device cleanup happens in
-	 * the interrupt handler.
-	 */
-	fas216_cmd(info, CMD_RESETSCSI);
-
-	mod_timer(&info->eh_timer, jiffies + HZ);
-	spin_unlock_irqrestore(&info->host_lock, flags);
-
-	/*
-	 * Wait one second for the interrupt.
-	 */
-	wait_event(info->eh_wait, info->rst_bus_status);
-	del_timer_sync(&info->eh_timer);
-
-	fas216_log(info, LOG_ERROR, "bus reset complete: %s\n",
-		   info->rst_bus_status == 1 ? "success" : "failed");
-
-	return info->rst_bus_status == 1 ? SUCCESS : FAILED;
-}
-
-/**
- * fas216_init_chip - Initialise FAS216 state after reset
- * @info: state structure for interface
- *
- * Initialise FAS216 state after reset
- */
-static void fas216_init_chip(FAS216_Info *info)
-{
-	fas216_writeb(info, REG_CLKF, fas216_clockrate(info->ifcfg.clockrate));
-	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
-	fas216_writeb(info, REG_CNTL2, info->scsi.cfg[1]);
-	fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]);
-	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);
-	fas216_writeb(info, REG_SOF, 0);
-	fas216_writeb(info, REG_STP, info->scsi.async_stp);
-	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
-}
-
-/**
- * fas216_eh_host_reset - Reset the host associated with this command
- * @SCpnt: command specifing host to reset
- *
- * Reset the host associated with this command.
- * Returns: FAILED if unable to reset.
- * Notes: io_request_lock is taken, and irqs are disabled
- */
-int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
-{
-	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
-
-	fas216_checkmagic(info);
-
-	printk("scsi%d.%c: %s: resetting host\n",
-		info->host->host_no, '0' + SCpnt->device->id, __FUNCTION__);
-
-	/*
-	 * Reset the SCSI chip.
-	 */
-	fas216_cmd(info, CMD_RESETCHIP);
-
-	/*
-	 * Ugly ugly ugly!
-	 * We need to release the host_lock and enable
-	 * IRQs if we sleep, but we must relock and disable
-	 * IRQs after the sleep.
-	 */
-	spin_unlock_irq(info->host->host_lock);
-	scsi_sleep(50 * HZ/100);
-	spin_lock_irq(info->host->host_lock);
-
-	/*
-	 * Release the SCSI reset.
-	 */
-	fas216_cmd(info, CMD_NOP);
-
-	fas216_init_chip(info);
-
-	return SUCCESS;
-}
-
-#define TYPE_UNKNOWN	0
-#define TYPE_NCR53C90	1
-#define TYPE_NCR53C90A	2
-#define TYPE_NCR53C9x	3
-#define TYPE_Am53CF94	4
-#define TYPE_EmFAS216	5
-#define TYPE_QLFAS216	6
-
-static char *chip_types[] = {
-	"unknown",
-	"NS NCR53C90",
-	"NS NCR53C90A",
-	"NS NCR53C9x",
-	"AMD Am53CF94",
-	"Emulex FAS216",
-	"QLogic FAS216"
-};
-
-static int fas216_detect_type(FAS216_Info *info)
-{
-	int family, rev;
-
-	/*
-	 * Reset the chip.
-	 */
-	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
-	udelay(50);
-	fas216_writeb(info, REG_CMD, CMD_NOP);
-
-	/*
-	 * Check to see if control reg 2 is present.
-	 */
-	fas216_writeb(info, REG_CNTL3, 0);
-	fas216_writeb(info, REG_CNTL2, CNTL2_S2FE);
-
-	/*
-	 * If we are unable to read back control reg 2
-	 * correctly, it is not present, and we have a
-	 * NCR53C90.
-	 */
-	if ((fas216_readb(info, REG_CNTL2) & (~0xe0)) != CNTL2_S2FE)
-		return TYPE_NCR53C90;
-
-	/*
-	 * Now, check control register 3
-	 */
-	fas216_writeb(info, REG_CNTL2, 0);
-	fas216_writeb(info, REG_CNTL3, 0);
-	fas216_writeb(info, REG_CNTL3, 5);
-
-	/*
-	 * If we are unable to read the register back
-	 * correctly, we have a NCR53C90A
-	 */
-	if (fas216_readb(info, REG_CNTL3) != 5)
-		return TYPE_NCR53C90A;
-
-	/*
-	 * Now read the ID from the chip.
-	 */
-	fas216_writeb(info, REG_CNTL3, 0);
-
-	fas216_writeb(info, REG_CNTL3, CNTL3_ADIDCHK);
-	fas216_writeb(info, REG_CNTL3, 0);
-
-	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
-	udelay(50);
-	fas216_writeb(info, REG_CMD, CMD_WITHDMA | CMD_NOP);
-
-	fas216_writeb(info, REG_CNTL2, CNTL2_ENF);
-	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
-	udelay(50);
-	fas216_writeb(info, REG_CMD, CMD_NOP);
-
-	rev     = fas216_readb(info, REG_ID);
-	family  = rev >> 3;
-	rev    &= 7;
-
-	switch (family) {
-	case 0x01:
-		if (rev == 4)
-			return TYPE_Am53CF94;
-		break;
-
-	case 0x02:
-		switch (rev) {
-		case 2:
-			return TYPE_EmFAS216;
-		case 3:
-			return TYPE_QLFAS216;
-		}
-		break;
-
-	default:
-		break;
-	}
-	printk("family %x rev %x\n", family, rev);
-	return TYPE_NCR53C9x;
-}
-
-/**
- * fas216_reset_state - Initialise driver internal state
- * @info: state to initialise
- *
- * Initialise driver internal state
- */
-static void fas216_reset_state(FAS216_Info *info)
-{
-	int i;
-
-	fas216_checkmagic(info);
-
-	fas216_bus_reset(info);
-
-	/*
-	 * Clear out all stale info in our state structure
-	 */
-	memset(info->busyluns, 0, sizeof(info->busyluns));
-	info->scsi.disconnectable = 0;
-	info->scsi.aborting = 0;
-
-	for (i = 0; i < 8; i++) {
-		info->device[i].parity_enabled	= 0;
-		info->device[i].parity_check	= 1;
-	}
-
-	/*
-	 * Drain all commands on disconnected queue
-	 */
-	while (queue_remove(&info->queues.disconnected) != NULL);
-
-	/*
-	 * Remove executing commands.
-	 */
-	info->SCpnt     = NULL;
-	info->reqSCpnt  = NULL;
-	info->rstSCpnt  = NULL;
-	info->origSCpnt = NULL;
-}
-
-/**
- * fas216_init - initialise FAS/NCR/AMD SCSI structures.
- * @host: a driver-specific filled-out structure
- *
- * Initialise FAS/NCR/AMD SCSI structures.
- * Returns: 0 on success
- */
-int fas216_init(struct Scsi_Host *host)
-{
-	FAS216_Info *info = (FAS216_Info *)host->hostdata;
-
-	info->magic_start    = MAGIC;
-	info->magic_end      = MAGIC;
-	info->host           = host;
-	info->scsi.cfg[0]    = host->this_id | CNTL1_PERE;
-	info->scsi.cfg[1]    = CNTL2_ENF | CNTL2_S2FE;
-	info->scsi.cfg[2]    = info->ifcfg.cntl3 |
-			       CNTL3_ADIDCHK | CNTL3_G2CB | CNTL3_LBTM;
-	info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod);
-
-	info->rst_dev_status = -1;
-	info->rst_bus_status = -1;
-	init_waitqueue_head(&info->eh_wait);
-	init_timer(&info->eh_timer);
-	info->eh_timer.data  = (unsigned long)info;
-	info->eh_timer.function = fas216_eh_timer;
-	
-	spin_lock_init(&info->host_lock);
-
-	memset(&info->stats, 0, sizeof(info->stats));
-
-	msgqueue_initialise(&info->scsi.msgs);
-
-	if (!queue_initialise(&info->queues.issue))
-		return -ENOMEM;
-
-	if (!queue_initialise(&info->queues.disconnected)) {
-		queue_free(&info->queues.issue);
-		return -ENOMEM;
-	}
-
-	return 0;
-}
-
-/**
- * fas216_add - initialise FAS/NCR/AMD SCSI ic.
- * @host: a driver-specific filled-out structure
- * @dev: parent device
- *
- * Initialise FAS/NCR/AMD SCSI ic.
- * Returns: 0 on success
- */
-int fas216_add(struct Scsi_Host *host, struct device *dev)
-{
-	FAS216_Info *info = (FAS216_Info *)host->hostdata;
-	int type, ret;
-
-	fas216_reset_state(info);
-	type = fas216_detect_type(info);
-	info->scsi.type = chip_types[type];
-
-	udelay(300);
-
-	/*
-	 * Initialise the chip correctly.
-	 */
-	fas216_init_chip(info);
-
-	/*
-	 * Reset the SCSI bus.  We don't want to see
-	 * the resulting reset interrupt, so mask it
-	 * out.
-	 */
-	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_DISR);
-	fas216_writeb(info, REG_CMD, CMD_RESETSCSI);
-
-	/*
-	 * scsi standard says wait 250ms
-	 */
-	spin_unlock_irq(info->host->host_lock);
-	scsi_sleep(100*HZ/100);
-	spin_lock_irq(info->host->host_lock);
-
-	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
-	fas216_readb(info, REG_INST);
-
-	fas216_checkmagic(info);
-
-	ret = scsi_add_host(host, dev);
-	if (ret)
-		fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
-
-	return ret;
-}
-
-void fas216_remove(struct Scsi_Host *host)
-{
-	FAS216_Info *info = (FAS216_Info *)host->hostdata;
-
-	fas216_checkmagic(info);
-	scsi_remove_host(host);
-
-	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
-}
-
-/**
- * fas216_release - release all resources for FAS/NCR/AMD SCSI ic.
- * @host: a driver-specific filled-out structure
- *
- * release all resources and put everything to bed for FAS/NCR/AMD SCSI ic.
- */
-void fas216_release(struct Scsi_Host *host)
-{
-	FAS216_Info *info = (FAS216_Info *)host->hostdata;
-
-	queue_free(&info->queues.disconnected);
-	queue_free(&info->queues.issue);
-}
-
-int fas216_print_host(FAS216_Info *info, char *buffer)
-{
-	return sprintf(buffer,
-			"\n"
-			"Chip    : %s\n"
-			" Address: 0x%08lx\n"
-			" IRQ    : %d\n"
-			" DMA    : %d\n",
-			info->scsi.type, info->host->io_port,
-			info->host->irq, info->host->dma_channel);
-}
-
-int fas216_print_stats(FAS216_Info *info, char *buffer)
-{
-	char *p = buffer;
-
-	p += sprintf(p, "\n"
-			"Command Statistics:\n"
-			" Queued     : %u\n"
-			" Issued     : %u\n"
-			" Completed  : %u\n"
-			" Reads      : %u\n"
-			" Writes     : %u\n"
-			" Others     : %u\n"
-			" Disconnects: %u\n"
-			" Aborts     : %u\n"
-			" Bus resets : %u\n"
-			" Host resets: %u\n",
-			info->stats.queues,	 info->stats.removes,
-			info->stats.fins,	 info->stats.reads,
-			info->stats.writes,	 info->stats.miscs,
-			info->stats.disconnects, info->stats.aborts,
-			info->stats.bus_resets,	 info->stats.host_resets);
-
-	return p - buffer;
-}
-
-int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer)
-{
-	struct fas216_device *dev = &info->device[scd->id];
-	int len = 0;
-	char *p;
-
-	proc_print_scsidevice(scd, buffer, &len, 0);
-	p = buffer + len;
-
-	p += sprintf(p, "  Extensions: ");
-
-	if (scd->tagged_supported)
-		p += sprintf(p, "TAG %sabled [%d] ",
-			     scd->tagged_queue ? "en" : "dis",
-			     scd->current_tag);
-
-	p += sprintf(p, "%s\n", dev->parity_enabled ? "parity" : "");
-
-	p += sprintf(p, "  Transfers : %d-bit ",
-		     8 << dev->wide_xfer);
-
-	if (dev->sof)
-		p += sprintf(p, "sync offset %d, %d ns\n",
-				dev->sof, dev->period * 4);
-	else
-		p += sprintf(p, "async\n");
-
-	return p - buffer;
-}
-
-EXPORT_SYMBOL(fas216_init);
-EXPORT_SYMBOL(fas216_add);
-EXPORT_SYMBOL(fas216_queue_command);
-EXPORT_SYMBOL(fas216_command);
-EXPORT_SYMBOL(fas216_intr);
-EXPORT_SYMBOL(fas216_remove);
-EXPORT_SYMBOL(fas216_release);
-EXPORT_SYMBOL(fas216_eh_abort);
-EXPORT_SYMBOL(fas216_eh_device_reset);
-EXPORT_SYMBOL(fas216_eh_bus_reset);
-EXPORT_SYMBOL(fas216_eh_host_reset);
-EXPORT_SYMBOL(fas216_print_host);
-EXPORT_SYMBOL(fas216_print_stats);
-EXPORT_SYMBOL(fas216_print_device);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver core");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/acorn/scsi/fas216.h b/drivers/acorn/scsi/fas216.h
--- a/drivers/acorn/scsi/fas216.h	Sun Jan 26 11:34:36 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,401 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/fas216.h
- *
- *  Copyright (C) 1997-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.
- *
- *  FAS216 generic driver
- */
-#ifndef FAS216_H
-#define FAS216_H
-
-#ifndef NO_IRQ
-#define NO_IRQ 255
-#endif
-
-#include "queue.h"
-#include "msgqueue.h"
-
-/* FAS register definitions */
-
-/* transfer count low */
-#define REG_CTCL		(0)
-#define REG_STCL		(0)
-
-/* transfer count medium */
-#define REG_CTCM		(1)
-#define REG_STCM		(1)
-
-/* fifo data */
-#define REG_FF			(2)
-
-/* command */
-#define REG_CMD			(3)
-#define CMD_NOP			0x00
-#define CMD_FLUSHFIFO		0x01
-#define CMD_RESETCHIP		0x02
-#define CMD_RESETSCSI		0x03
-
-#define CMD_TRANSFERINFO	0x10
-#define CMD_INITCMDCOMPLETE	0x11
-#define CMD_MSGACCEPTED		0x12
-#define CMD_PADBYTES		0x18
-#define CMD_SETATN		0x1a
-#define CMD_RSETATN		0x1b
-
-#define CMD_SELECTWOATN		0x41
-#define CMD_SELECTATN		0x42
-#define CMD_SELECTATNSTOP	0x43
-#define CMD_ENABLESEL		0x44
-#define CMD_DISABLESEL		0x45
-#define CMD_SELECTATN3		0x46
-#define CMD_RESEL3		0x47
-
-#define CMD_WITHDMA		0x80
-
-/* status register (read) */
-#define REG_STAT		(4)
-#define STAT_IO			(1 << 0)			/* IO phase		*/
-#define STAT_CD			(1 << 1)			/* CD phase		*/
-#define STAT_MSG		(1 << 2)			/* MSG phase		*/
-#define STAT_TRANSFERDONE	(1 << 3)			/* Transfer completed	*/
-#define STAT_TRANSFERCNTZ	(1 << 4)			/* Transfer counter is zero */
-#define STAT_PARITYERROR	(1 << 5)			/* Parity error		*/
-#define STAT_REALBAD		(1 << 6)			/* Something bad	*/
-#define STAT_INT		(1 << 7)			/* Interrupt		*/
-
-#define STAT_BUSMASK		(STAT_MSG|STAT_CD|STAT_IO)
-#define STAT_DATAOUT		(0)				/* Data out		*/
-#define STAT_DATAIN		(STAT_IO)			/* Data in		*/
-#define STAT_COMMAND		(STAT_CD)			/* Command out		*/
-#define STAT_STATUS		(STAT_CD|STAT_IO)		/* Status In		*/
-#define STAT_MESGOUT		(STAT_MSG|STAT_CD)		/* Message out		*/
-#define STAT_MESGIN		(STAT_MSG|STAT_CD|STAT_IO)	/* Message In		*/
-
-/* bus ID for select / reselect */
-#define REG_SDID		(4)
-#define BUSID(target)		((target) & 7)
-
-/* Interrupt status register (read) */
-#define REG_INST		(5)
-#define INST_SELWOATN		(1 << 0)			/* Select w/o ATN	*/
-#define INST_SELATN		(1 << 1)			/* Select w/ATN		*/
-#define INST_RESELECTED		(1 << 2)			/* Reselected		*/
-#define INST_FUNCDONE		(1 << 3)			/* Function done	*/
-#define INST_BUSSERVICE		(1 << 4)			/* Bus service		*/
-#define INST_DISCONNECT		(1 << 5)			/* Disconnect		*/
-#define INST_ILLEGALCMD		(1 << 6)			/* Illegal command	*/
-#define INST_BUSRESET		(1 << 7)			/* SCSI Bus reset	*/
-
-/* Timeout register (write) */
-#define REG_STIM		(5)
-
-/* Sequence step register (read) */
-#define REG_IS			(6)
-#define IS_BITS			0x07
-#define IS_SELARB		0x00				/* Select & Arb ok	*/
-#define IS_MSGBYTESENT		0x01				/* One byte message sent*/
-#define IS_NOTCOMMAND		0x02				/* Not in command state	*/
-#define IS_EARLYPHASE		0x03				/* Early phase change	*/
-#define IS_COMPLETE		0x04				/* Command ok		*/
-#define IS_SOF			0x08				/* Sync off flag	*/
-
-/* Transfer period step (write) */
-#define REG_STP			(6)
-
-/* Synchronous Offset (write) */
-#define REG_SOF			(7)
-
-/* Fifo state register (read) */
-#define REG_CFIS		(7)
-#define CFIS_CF			0x1f				/* Num bytes in FIFO	*/
-#define CFIS_IS			0xe0				/* Step			*/
-
-/* config register 1 */
-#define REG_CNTL1		(8)
-#define CNTL1_CID		(7 << 0)			/* Chip ID			*/
-#define CNTL1_STE		(1 << 3)			/* Self test enable		*/
-#define CNTL1_PERE		(1 << 4)			/* Parity enable reporting en.	*/
-#define CNTL1_PTE		(1 << 5)			/* Parity test enable		*/
-#define CNTL1_DISR		(1 << 6)			/* Disable Irq on SCSI reset	*/
-#define CNTL1_ETM		(1 << 7)			/* Extended Timing Mode		*/
-
-/* Clock conversion factor (read) */
-#define REG_CLKF		(9)
-#define CLKF_F37MHZ		0x00				/* 35.01 - 40 MHz		*/
-#define CLKF_F10MHZ		0x02				/* 10 MHz			*/
-#define CLKF_F12MHZ		0x03				/* 10.01 - 15 MHz		*/
-#define CLKF_F17MHZ		0x04				/* 15.01 - 20 MHz		*/
-#define CLKF_F22MHZ		0x05				/* 20.01 - 25 MHz		*/
-#define CLKF_F27MHZ		0x06				/* 25.01 - 30 MHz		*/
-#define CLKF_F32MHZ		0x07				/* 30.01 - 35 MHz		*/
-
-/* Chip test register (write) */
-#define REG_FTM			(10)
-#define TEST_FTM		0x01				/* Force target mode		*/
-#define TEST_FIM		0x02				/* Force initiator mode		*/
-#define TEST_FHI		0x04				/* Force high impedance mode	*/
-
-/* Configuration register 2 (read/write) */
-#define REG_CNTL2		(11)
-#define CNTL2_PGDP		(1 << 0)			/* Pass Th/Generate Data Parity	*/
-#define CNTL2_PGRP		(1 << 1)			/* Pass Th/Generate Reg Parity	*/
-#define CNTL2_ACDPE		(1 << 2)			/* Abort on Cmd/Data Parity Err	*/
-#define CNTL2_S2FE		(1 << 3)			/* SCSI2 Features Enable	*/
-#define CNTL2_TSDR		(1 << 4)			/* Tristate DREQ		*/
-#define CNTL2_SBO		(1 << 5)			/* Select Byte Order		*/
-#define CNTL2_ENF		(1 << 6)			/* Enable features		*/
-#define CNTL2_DAE		(1 << 7)			/* Data Alignment Enable	*/
-
-/* Configuration register 3 (read/write) */
-#define REG_CNTL3		(12)
-#define CNTL3_BS8		(1 << 0)			/* Burst size 8			*/
-#define CNTL3_MDM		(1 << 1)			/* Modify DMA mode		*/
-#define CNTL3_LBTM		(1 << 2)			/* Last Byte Transfer mode	*/
-#define CNTL3_FASTCLK		(1 << 3)			/* Fast SCSI clocking		*/
-#define CNTL3_FASTSCSI		(1 << 4)			/* Fast SCSI			*/
-#define CNTL3_G2CB		(1 << 5)			/* Group2 SCSI support		*/
-#define CNTL3_QTAG		(1 << 6)			/* Enable 3 byte msgs		*/
-#define CNTL3_ADIDCHK		(1 << 7)			/* Additional ID check		*/
-
-/* High transfer count (read/write) */
-#define REG_CTCH		(14)
-#define REG_STCH		(14)
-
-/* ID register (read only) */
-#define REG_ID			(14)
-
-/* Data alignment */
-#define REG_DAL			(15)
-
-typedef enum {
-	PHASE_IDLE,					/* we're not planning on doing anything	*/
-	PHASE_SELECTION,				/* selecting a device			*/
-	PHASE_SELSTEPS,					/* selection with command steps		*/
-	PHASE_COMMAND,					/* command sent				*/
-	PHASE_MESSAGESENT,				/* selected, and we're sending cmd	*/
-	PHASE_RECONNECTED,				/* reconnected				*/
-	PHASE_DATAOUT,					/* data out to device			*/
-	PHASE_DATAIN,					/* data in from device			*/
-	PHASE_MSGIN,					/* message in from device		*/
-	PHASE_MSGIN_DISCONNECT,				/* disconnecting from bus		*/
-	PHASE_MSGOUT,					/* after message out phase		*/
-	PHASE_MSGOUT_EXPECT,				/* expecting message out		*/
-	PHASE_STATUS,					/* status from device			*/
-	PHASE_DONE					/* Command complete			*/
-} phase_t;
-
-typedef enum {
-	DMA_OUT,					/* DMA from memory to chip		*/
-	DMA_IN						/* DMA from chip to memory		*/
-} fasdmadir_t;
-
-typedef enum {
-	fasdma_none,					/* No dma				*/
-	fasdma_pio,					/* PIO mode				*/
-	fasdma_pseudo,					/* Pseudo DMA				*/
-	fasdma_real_block,				/* Real DMA, on block by block basis	*/
-	fasdma_real_all					/* Real DMA, on request by request	*/
-} fasdmatype_t;
-
-typedef enum {
-	neg_wait,					/* Negociate with device		*/
-	neg_inprogress,					/* Negociation sent			*/
-	neg_complete,					/* Negociation complete			*/
-	neg_targcomplete,				/* Target completed negociation		*/
-	neg_invalid					/* Negociation not supported		*/
-} neg_t;
-
-#define MAGIC	0x441296bdUL
-#define NR_MSGS	8
-
-#define FASCAP_DMA		(1 << 0)
-#define FASCAP_PSEUDODMA	(1 << 1)
-
-typedef struct {
-	unsigned long		magic_start;
-	spinlock_t		host_lock;
-	struct Scsi_Host	*host;			/* host					*/
-	Scsi_Cmnd		*SCpnt;			/* currently processing command		*/
-	Scsi_Cmnd		*origSCpnt;		/* original connecting command		*/
-	Scsi_Cmnd		*reqSCpnt;		/* request sense command		*/
-	Scsi_Cmnd		*rstSCpnt;		/* reset command			*/
-	Scsi_Cmnd		*pending_SCpnt[8];	/* per-device pending commands		*/
-	int			next_pending;		/* next pending device			*/
-
-	/*
-	 * Error recovery
-	 */
-	wait_queue_head_t	eh_wait;
-	struct timer_list	eh_timer;
-	unsigned int		rst_dev_status;
-	unsigned int		rst_bus_status;
-
-	/* driver information */
-	struct {
-		phase_t		phase;			/* current phase			*/
-		void		*io_base;		/* iomem base of FAS216			*/
-		unsigned int	io_port;		/* base address of FAS216		*/
-		unsigned int	io_shift;		/* shift to adjust reg offsets by	*/
-		unsigned char	cfg[4];			/* configuration registers		*/
-		const char	*type;			/* chip type				*/
-		unsigned int	irq;			/* interrupt				*/
-
-		struct {
-			unsigned char	target;		/* reconnected target			*/
-			unsigned char	lun;		/* reconnected lun			*/
-			unsigned char	tag;		/* reconnected tag			*/
-		} reconnected;
-
-		Scsi_Pointer	SCp;			/* current commands data pointer	*/
-
-		MsgQueue_t	msgs;			/* message queue for connected device	*/
-
-		unsigned int	async_stp;		/* Async transfer STP value		*/
-		unsigned char	msgin_fifo;		/* bytes in fifo at time of message in	*/
-		unsigned char	message[256];		/* last message received from device	*/
-
-		unsigned char	disconnectable:1;	/* this command can be disconnected	*/
-		unsigned char	aborting:1;		/* aborting command			*/
-	} scsi;
-
-	/* statistics information */
-	struct {
-		unsigned int	queues;
-		unsigned int	removes;
-		unsigned int	fins;
-		unsigned int	reads;
-		unsigned int	writes;
-		unsigned int	miscs;
-		unsigned int	disconnects;
-		unsigned int	aborts;
-		unsigned int	bus_resets;
-		unsigned int	host_resets;
-	} stats;
-
-	/* configuration information */
-	struct {
-		unsigned char	clockrate;		/* clock rate of FAS device (MHz)	*/
-		unsigned char	select_timeout;		/* timeout (R5)				*/
-		unsigned char	sync_max_depth;		/* Synchronous xfer max fifo depth	*/
-		unsigned char	wide_max_size;		/* Maximum wide transfer size		*/
-		unsigned char	cntl3;			/* Control Reg 3			*/
-		unsigned int	asyncperiod;		/* Async transfer period (ns)		*/
-		unsigned int	capabilities;		/* driver capabilities			*/
-		unsigned int	disconnect_ok:1;	/* Disconnects allowed?			*/
-	} ifcfg;
-
-	/* queue handling */
-	struct {
-	    	Queue_t		issue;			/* issue queue				*/
-    		Queue_t		disconnected;		/* disconnected command queue		*/
-	} queues;
-
-	/* per-device info */
-	struct fas216_device {
-		unsigned char	disconnect_ok:1;	/* device can disconnect		*/
-		unsigned char	parity_enabled:1;	/* parity checking enabled		*/
-		unsigned char	parity_check:1;		/* need to check parity checking	*/
-		unsigned char	period;			/* sync xfer period in (*4ns)		*/
-		unsigned char	stp;			/* synchronous transfer period		*/
-		unsigned char	sof;			/* synchronous offset register		*/
-		unsigned char	wide_xfer;		/* currently negociated wide transfer	*/
-		neg_t		sync_state;		/* synchronous transfer mode		*/
-		neg_t		wide_state;		/* wide transfer mode			*/
-	} device[8];
-	unsigned long	busyluns[64/sizeof(unsigned long)];/* array of bits indicating LUNs busy	*/
-
-	/* dma */
-	struct {
-		fasdmatype_t	transfer_type;		/* current type of DMA transfer		*/
-		fasdmatype_t	(*setup) (struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, fasdmatype_t min_dma);
-		void		(*pseudo)(struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, int transfer);
-		void		(*stop)  (struct Scsi_Host *host, Scsi_Pointer *SCp);
-	} dma;
-
-	/* miscellaneous */
-	int			internal_done;		/* flag to indicate request done */
-
-	unsigned long		magic_end;
-} FAS216_Info;
-
-/* Function: int fas216_init (struct Scsi_Host *instance)
- * Purpose : initialise FAS/NCR/AMD SCSI structures.
- * Params  : instance - a driver-specific filled-out structure
- * Returns : 0 on success
- */
-extern int fas216_init (struct Scsi_Host *instance);
-
-/* Function: int fas216_add (struct Scsi_Host *instance, struct device *dev)
- * Purpose : initialise FAS/NCR/AMD SCSI ic.
- * Params  : instance - a driver-specific filled-out structure
- * Returns : 0 on success
- */
-extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
-
-/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
- * Purpose : queue a command for adapter to process.
- * Params  : SCpnt - Command to queue
- *	     done  - done function to call once command is complete
- * Returns : 0 - success, else error
- */
-extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-
-/* Function: int fas216_command (Scsi_Cmnd *SCpnt)
- * Purpose : queue a command for adapter to process.
- * Params  : SCpnt - Command to queue
- * Returns : scsi result code
- */
-extern int fas216_command (Scsi_Cmnd *);
-
-/* Function: void fas216_intr (FAS216_Info *info)
- * Purpose : handle interrupts from the interface to progress a command
- * Params  : info - interface to service
- */
-extern void fas216_intr (FAS216_Info *info);
-
-extern void fas216_remove (struct Scsi_Host *instance);
-
-/* Function: void fas216_release (struct Scsi_Host *instance)
- * Purpose : release all resources and put everything to bed for FAS/NCR/AMD SCSI ic.
- * Params  : instance - a driver-specific filled-out structure
- * Returns : 0 on success
- */
-extern void fas216_release (struct Scsi_Host *instance);
-
-extern int fas216_print_host(FAS216_Info *info, char *buffer);
-extern int fas216_print_stats(FAS216_Info *info, char *buffer);
-extern int fas216_print_device(FAS216_Info *info, Scsi_Device *scd, char *buffer);
-
-/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
- * Purpose : abort this command
- * Params  : SCpnt - command to abort
- * Returns : FAILED if unable to abort
- */
-extern int fas216_eh_abort(Scsi_Cmnd *SCpnt);
-
-/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the device associated with this command
- * Params  : SCpnt - command specifing device to reset
- * Returns : FAILED if unable to reset
- */
-extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt);
-
-/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the complete bus associated with this command
- * Params  : SCpnt - command specifing bus to reset
- * Returns : FAILED if unable to reset
- */
-extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt);
-
-/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
- * Purpose : Reset the host associated with this command
- * Params  : SCpnt - command specifing host to reset
- * Returns : FAILED if unable to reset
- */
-extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt);
-
-#endif /* FAS216_H */
diff -Nru a/drivers/acorn/scsi/msgqueue.c b/drivers/acorn/scsi/msgqueue.c
--- a/drivers/acorn/scsi/msgqueue.c	Mon Feb  4 23:52:37 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,171 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/msgqueue.c
- *
- *  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 version 2 as
- * published by the Free Software Foundation.
- *
- *  message queue handling
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/stddef.h>
-#include <linux/init.h>
-
-#include "msgqueue.h"
-
-/*
- * Function: struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
- * Purpose : Allocate a message queue entry
- * Params  : msgq - message queue to claim entry for
- * Returns : message queue entry or NULL.
- */
-static struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
-{
-	struct msgqueue_entry *mq;
-
-	if ((mq = msgq->free) != NULL)
-		msgq->free = mq->next;
-
-	return mq;
-}
-
-/*
- * Function: void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq)
- * Purpose : free a message queue entry
- * Params  : msgq - message queue to free entry from
- *	     mq   - message queue entry to free
- */
-static void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq)
-{
-	if (mq) {
-		mq->next = msgq->free;
-		msgq->free = mq;
-	}
-}
-
-/*
- * Function: void msgqueue_initialise(MsgQueue_t *msgq)
- * Purpose : initialise a message queue
- * Params  : msgq - queue to initialise
- */
-void msgqueue_initialise(MsgQueue_t *msgq)
-{
-	int i;
-
-	msgq->qe = NULL;
-	msgq->free = &msgq->entries[0];
-
-	for (i = 0; i < NR_MESSAGES; i++)
-		msgq->entries[i].next = &msgq->entries[i + 1];
-
-	msgq->entries[NR_MESSAGES - 1].next = NULL;
-}
-
-
-/*
- * Function: void msgqueue_free(MsgQueue_t *msgq)
- * Purpose : free a queue
- * Params  : msgq - queue to free
- */
-void msgqueue_free(MsgQueue_t *msgq)
-{
-}
-
-/*
- * Function: int msgqueue_msglength(MsgQueue_t *msgq)
- * Purpose : calculate the total length of all messages on the message queue
- * Params  : msgq - queue to examine
- * Returns : number of bytes of messages in queue
- */
-int msgqueue_msglength(MsgQueue_t *msgq)
-{
-	struct msgqueue_entry *mq = msgq->qe;
-	int length = 0;
-
-	for (mq = msgq->qe; mq; mq = mq->next)
-		length += mq->msg.length;
-
-	return length;
-}
-
-/*
- * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
- * Purpose : return a message
- * Params  : msgq   - queue to obtain message from
- *	   : msgno  - message number
- * Returns : pointer to message string, or NULL
- */
-struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
-{
-	struct msgqueue_entry *mq;
-
-	for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--);
-
-	return mq ? &mq->msg : NULL;
-}
-
-/*
- * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
- * Purpose : add a message onto a message queue
- * Params  : msgq   - queue to add message on
- *	     length - length of message
- *	     ...    - message bytes
- * Returns : != 0 if successful
- */
-int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
-{
-	struct msgqueue_entry *mq = mqe_alloc(msgq);
-	va_list ap;
-
-	if (mq) {
-		struct msgqueue_entry **mqp;
-		int i;
-
-		va_start(ap, length);
-		for (i = 0; i < length; i++)
-			mq->msg.msg[i] = va_arg(ap, unsigned int);
-		va_end(ap);
-
-		mq->msg.length = length;
-		mq->msg.fifo = 0;
-		mq->next = NULL;
-
-		mqp = &msgq->qe;
-		while (*mqp)
-			mqp = &(*mqp)->next;
-
-		*mqp = mq;
-	}
-
-	return mq != NULL;
-}
-
-/*
- * Function: void msgqueue_flush(MsgQueue_t *msgq)
- * Purpose : flush all messages from message queue
- * Params  : msgq - queue to flush
- */
-void msgqueue_flush(MsgQueue_t *msgq)
-{
-	struct msgqueue_entry *mq, *mqnext;
-
-	for (mq = msgq->qe; mq; mq = mqnext) {
-		mqnext = mq->next;
-		mqe_free(msgq, mq);
-	}
-	msgq->qe = NULL;
-}
-
-EXPORT_SYMBOL(msgqueue_initialise);
-EXPORT_SYMBOL(msgqueue_free);
-EXPORT_SYMBOL(msgqueue_msglength);
-EXPORT_SYMBOL(msgqueue_getmsg);
-EXPORT_SYMBOL(msgqueue_addmsg);
-EXPORT_SYMBOL(msgqueue_flush);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("SCSI message queue handling");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/acorn/scsi/msgqueue.h b/drivers/acorn/scsi/msgqueue.h
--- a/drivers/acorn/scsi/msgqueue.h	Tue Feb  5 09:40:17 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,82 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/msgqueue.h
- *
- *  Copyright (C) 1997 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.
- *
- *  message queue handling
- */
-#ifndef MSGQUEUE_H
-#define MSGQUEUE_H
-
-struct message {
-    char msg[8];
-    int length;
-    int fifo;
-};
-
-struct msgqueue_entry {
-    struct message msg;
-    struct msgqueue_entry *next;
-};
-
-#define NR_MESSAGES 4
-
-typedef struct {
-    struct msgqueue_entry *qe;
-    struct msgqueue_entry *free;
-    struct msgqueue_entry entries[NR_MESSAGES];
-} MsgQueue_t;
-
-/*
- * Function: void msgqueue_initialise(MsgQueue_t *msgq)
- * Purpose : initialise a message queue
- * Params  : msgq - queue to initialise
- */
-extern void msgqueue_initialise(MsgQueue_t *msgq);
-
-/*
- * Function: void msgqueue_free(MsgQueue_t *msgq)
- * Purpose : free a queue
- * Params  : msgq - queue to free
- */
-extern void msgqueue_free(MsgQueue_t *msgq);
-
-/*
- * Function: int msgqueue_msglength(MsgQueue_t *msgq)
- * Purpose : calculate the total length of all messages on the message queue
- * Params  : msgq - queue to examine
- * Returns : number of bytes of messages in queue
- */
-extern int msgqueue_msglength(MsgQueue_t *msgq);
-
-/*
- * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
- * Purpose : return a message & its length
- * Params  : msgq   - queue to obtain message from
- *         : msgno  - message number
- * Returns : pointer to message string, or NULL
- */
-extern struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno);
-
-/*
- * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
- * Purpose : add a message onto a message queue
- * Params  : msgq   - queue to add message on
- *	     length - length of message
- *	     ...    - message bytes
- * Returns : != 0 if successful
- */
-extern int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...);
-
-/*
- * Function: void msgqueue_flush(MsgQueue_t *msgq)
- * Purpose : flush all messages from message queue
- * Params  : msgq - queue to flush
- */
-extern void msgqueue_flush(MsgQueue_t *msgq);
-
-#endif
diff -Nru a/drivers/acorn/scsi/oak.c b/drivers/acorn/scsi/oak.c
--- a/drivers/acorn/scsi/oak.c	Sun Jan 26 11:34:37 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,216 +0,0 @@
-/*
- * Oak Generic NCR5380 driver
- *
- * Copyright 1995-2002, Russell King
- */
-
-#include <linux/module.h>
-#include <linux/signal.h>
-#include <linux/sched.h>
-#include <linux/ioport.h>
-#include <linux/delay.h>
-#include <linux/blk.h>
-#include <linux/init.h>
-
-#include <asm/ecard.h>
-#include <asm/io.h>
-#include <asm/system.h>
-
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-
-#define AUTOSENSE
-/*#define PSEUDO_DMA*/
-
-#define OAKSCSI_PUBLIC_RELEASE 1
-
-#define NCR5380_read(reg)		oakscsi_read(_instance, reg)
-#define NCR5380_write(reg, value)	oakscsi_write(_instance, reg, value)
-#define NCR5380_intr			oakscsi_intr
-#define NCR5380_queue_command		oakscsi_queue_command
-#define NCR5380_proc_info		oakscsi_proc_info
-
-int NCR5380_proc_info(char *buffer, char **start, off_t offset,
-		      int length, int hostno, int inout);
-
-#define NCR5380_implementation_fields	int port, ctrl
-#define NCR5380_local_declare()		struct Scsi_Host *_instance
-#define NCR5380_setup(instance)		_instance = instance
-
-#define BOARD_NORMAL	0
-#define BOARD_NCR53C400	1
-
-#include "../../scsi/NCR5380.h"
-
-#undef START_DMA_INITIATOR_RECEIVE_REG
-#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
-
-const char * oakscsi_info (struct Scsi_Host *spnt)
-{
-	return "";
-}
-
-#define STAT(p)   inw(p + 144)
-extern void inswb(int from, void *to, int len);
-
-static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
-              int len)
-{
-  int iobase = instance->io_port;
-printk("writing %p len %d\n",addr, len);
-  if(!len) return -1;
-
-  while(1)
-  {
-    int status;
-    while(((status = STAT(iobase)) & 0x100)==0);
-  }
-}
-
-static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
-              int len)
-{
-  int iobase = instance->io_port;
-printk("reading %p len %d\n", addr, len);
-  while(len > 0)
-  {
-    int status, timeout;
-    unsigned long b;
-    
-    timeout = 0x01FFFFFF;
-    
-    while(((status = STAT(iobase)) & 0x100)==0)
-    {
-      timeout--;
-      if(status & 0x200 || !timeout)
-      {
-        printk("status = %08X\n",status);
-        return 1;
-      }
-    }
-    if(len >= 128)
-    {
-      inswb(iobase + 136, addr, 128);
-      addr += 128;
-      len -= 128;
-    }
-    else
-    {
-      b = (unsigned long) inw(iobase + 136);
-      *addr ++ = b;
-      len -= 1;
-      if(len)
-        *addr ++ = b>>8;
-      len -= 1;
-    }
-  }
-  return 0;
-}
-
-#define oakscsi_read(instance,reg)	(inb((instance)->io_port + (reg)))
-#define oakscsi_write(instance,reg,val)	(outb((val), (instance)->io_port + (reg)))
-
-#undef STAT
-
-#include "../../scsi/NCR5380.c"
-
-static Scsi_Host_Template oakscsi_template = {
-	.module			= THIS_MODULE,
-	.proc_info		= oakscsi_proc_info,
-	.name			= "Oak 16-bit SCSI",
-	.info			= oakscsi_info,
-	.queuecommand		= oakscsi_queue_command,
-	.eh_abort_handler	= NCR5380_abort,
-	.eh_device_reset_handler= NCR5380_device_reset,
-	.eh_bus_reset_handler	= NCR5380_bus_reset,
-	.eh_host_reset_handler	= NCR5380_host_reset,
-	.can_queue		= 16,
-	.this_id		= 7,
-	.sg_tablesize		= SG_ALL,
-	.cmd_per_lun		= 2,
-	.use_clustering		= DISABLE_CLUSTERING,
-	.proc_name		= "oakscsi",
-};
-
-static int __devinit
-oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct Scsi_Host *host;
-	int ret = -ENOMEM;
-
-	host = scsi_register(&oakscsi_template, sizeof(struct NCR5380_hostdata));
-	if (!host)
-		goto out;
-
-	host->io_port = ecard_address(ec, ECARD_MEMC, 0);
-	host->irq = IRQ_NONE;
-	host->n_io_port = 255;
-
-	ret = -EBUSY;
-	if (!request_region (host->io_port, host->n_io_port, "Oak SCSI"))
-		goto unreg;
-
-	NCR5380_init(host, 0);
-
-	printk("scsi%d: at port 0x%08lx irqs disabled",
-		host->host_no, host->io_port);
-	printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
-		host->can_queue, host->cmd_per_lun, OAKSCSI_PUBLIC_RELEASE);
-	printk("\nscsi%d:", host->host_no);
-	NCR5380_print_options(host);
-	printk("\n");
-
-	ret = scsi_add_host(host, &ec->dev);
-	if (ret == 0)
-		goto out;
-
-	release_region(host->io_port, host->n_io_port);
- unreg:
-	scsi_unregister(host);
- out:
-	return ret;
-}
-
-static void __devexit oakscsi_remove(struct expansion_card *ec)
-{
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-
-	ecard_set_drvdata(ec, NULL);
-	scsi_remove_host(host);
-
-	release_region(host->io_port, host->n_io_port);
-	scsi_unregister(host);
-}
-
-static const struct ecard_id oakscsi_cids[] = {
-	{ MANU_OAK, PROD_OAK_SCSI },
-	{ 0xffff, 0xffff }
-};
-
-static struct ecard_driver oakscsi_driver = {
-	.probe		= oakscsi_probe,
-	.remove		= __devexit_p(oakscsi_remove),
-	.id_table	= oakscsi_cids,
-	.drv = {
-		.devclass	= &shost_devclass,
-		.name		= "oakscsi",
-	},
-};
-
-static int __init oakscsi_init(void)
-{
-	return ecard_register_driver(&oakscsi_driver);
-}
-
-static void __exit oakscsi_exit(void)
-{
-	ecard_remove_driver(&oakscsi_driver);
-}
-
-module_init(oakscsi_init);
-module_exit(oakscsi_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Oak SCSI driver");
-MODULE_LICENSE("GPL");
-
diff -Nru a/drivers/acorn/scsi/powertec.c b/drivers/acorn/scsi/powertec.c
--- a/drivers/acorn/scsi/powertec.c	Sun Jan 26 11:34:37 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,500 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/powertec.c
- *
- *  Copyright (C) 1997-2003 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/module.h>
-#include <linux/blk.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/sched.h>
-#include <linux/proc_fs.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/dma-mapping.h>
-
-#include <asm/dma.h>
-#include <asm/ecard.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/pgtable.h>
-
-#include "../../scsi/scsi.h"
-#include "../../scsi/hosts.h"
-#include "fas216.h"
-#include "scsi.h"
-
-#include <scsi/scsicam.h>
-
-#define POWERTEC_FAS216_OFFSET	0x3000
-#define POWERTEC_FAS216_SHIFT	6
-
-#define POWERTEC_INTR_STATUS	0x2000
-#define POWERTEC_INTR_BIT	0x80
-
-#define POWERTEC_RESET_CONTROL	0x1018
-#define POWERTEC_RESET_BIT	1
-
-#define POWERTEC_TERM_CONTROL	0x2018
-#define POWERTEC_TERM_ENABLE	1
-
-#define POWERTEC_INTR_CONTROL	0x101c
-#define POWERTEC_INTR_ENABLE	1
-#define POWERTEC_INTR_DISABLE	0
-
-#define VERSION	"1.10 (19/01/2003 2.5.59)"
-
-/*
- * Use term=0,1,0,0,0 to turn terminators on/off.
- * One entry per slot.
- */
-static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
-
-#define NR_SG	256
-
-struct powertec_info {
-	FAS216_Info		info;
-	struct expansion_card	*ec;
-	void			*term_port;
-	unsigned int		term_ctl;
-	struct scatterlist	sg[NR_SG];
-};
-
-/* Prototype: void powertecscsi_irqenable(ec, irqnr)
- * Purpose  : Enable interrupts on Powertec SCSI card
- * Params   : ec    - expansion card structure
- *          : irqnr - interrupt number
- */
-static void
-powertecscsi_irqenable(struct expansion_card *ec, int irqnr)
-{
-	writeb(POWERTEC_INTR_ENABLE, ec->irq_data);
-}
-
-/* Prototype: void powertecscsi_irqdisable(ec, irqnr)
- * Purpose  : Disable interrupts on Powertec SCSI card
- * Params   : ec    - expansion card structure
- *          : irqnr - interrupt number
- */
-static void
-powertecscsi_irqdisable(struct expansion_card *ec, int irqnr)
-{
-	writeb(POWERTEC_INTR_DISABLE, ec->irq_data);
-}
-
-static const expansioncard_ops_t powertecscsi_ops = {
-	.irqenable	= powertecscsi_irqenable,
-	.irqdisable	= powertecscsi_irqdisable,
-};
-
-/* Prototype: void powertecscsi_terminator_ctl(host, on_off)
- * Purpose  : Turn the Powertec SCSI terminators on or off
- * Params   : host   - card to turn on/off
- *          : on_off - !0 to turn on, 0 to turn off
- */
-static void
-powertecscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
-{
-	struct powertec_info *info = (struct powertec_info *)host->hostdata;
-
-	info->term_ctl = on_off ? POWERTEC_TERM_ENABLE : 0;
-	writeb(info->term_ctl, info->term_port);
-}
-
-/* Prototype: void powertecscsi_intr(irq, *dev_id, *regs)
- * Purpose  : handle interrupts from Powertec SCSI card
- * Params   : irq    - interrupt number
- *	      dev_id - user-defined (Scsi_Host structure)
- *	      regs   - processor registers at interrupt
- */
-static void
-powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct powertec_info *info = dev_id;
-
-	fas216_intr(&info->info);
-}
-
-/* Prototype: fasdmatype_t powertecscsi_dma_setup(host, SCpnt, direction, min_type)
- * Purpose  : initialises DMA/PIO
- * Params   : host      - host
- *	      SCpnt     - command
- *	      direction - DMA on to/off of card
- *	      min_type  - minimum DMA support that we must have for this transfer
- * Returns  : type of transfer to be performed
- */
-static fasdmatype_t
-powertecscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
-		       fasdmadir_t direction, fasdmatype_t min_type)
-{
-	struct powertec_info *info = (struct powertec_info *)host->hostdata;
-	struct device *dev = scsi_get_device(host);
-	int dmach = host->dma_channel;
-
-	if (info->info.ifcfg.capabilities & FASCAP_DMA &&
-	    min_type == fasdma_real_all) {
-		int bufs, map_dir, dma_dir;
-
-		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
-
-		if (direction == DMA_OUT)
-			map_dir = DMA_TO_DEVICE,
-			dma_dir = DMA_MODE_WRITE;
-		else
-			map_dir = DMA_FROM_DEVICE,
-			dma_dir = DMA_MODE_READ;
-
-		dma_map_sg(dev, info->sg, bufs + 1, map_dir);
-
-		disable_dma(dmach);
-		set_dma_sg(dmach, info->sg, bufs + 1);
-		set_dma_mode(dmach, dma_dir);
-		enable_dma(dmach);
-		return fasdma_real_all;
-	}
-
-	/*
-	 * If we're not doing DMA,
-	 *  we'll do slow PIO
-	 */
-	return fasdma_pio;
-}
-
-/* Prototype: int powertecscsi_dma_stop(host, SCpnt)
- * Purpose  : stops DMA/PIO
- * Params   : host  - host
- *	      SCpnt - command
- */
-static void
-powertecscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
-{
-	if (host->dma_channel != NO_DMA)
-		disable_dma(host->dma_channel);
-}
-
-/* Prototype: const char *powertecscsi_info(struct Scsi_Host * host)
- * Purpose  : returns a descriptive string about this interface,
- * Params   : host - driver host structure to return info for.
- * Returns  : pointer to a static buffer containing null terminated string.
- */
-const char *powertecscsi_info(struct Scsi_Host *host)
-{
-	struct powertec_info *info = (struct powertec_info *)host->hostdata;
-	static char string[150];
-
-	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
-		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
-		VERSION, info->term_ctl ? "n" : "ff");
-
-	return string;
-}
-
-/* Prototype: int powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
- * Purpose  : Set a driver specific function
- * Params   : host   - host to setup
- *          : buffer - buffer containing string describing operation
- *          : length - length of string
- * Returns  : -EINVAL, or 0
- */
-static int
-powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
-{
-	int ret = length;
-
-	if (length >= 12 && strncmp(buffer, "POWERTECSCSI", 12) == 0) {
-		buffer += 12;
-		length -= 12;
-
-		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
-			if (buffer[5] == '1')
-				powertecscsi_terminator_ctl(host, 1);
-			else if (buffer[5] == '0')
-				powertecscsi_terminator_ctl(host, 0);
-			else
-				ret = -EINVAL;
-		} else
-			ret = -EINVAL;
-	} else
-		ret = -EINVAL;
-
-	return ret;
-}
-
-/* Prototype: int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
- *					int length, int host_no, int inout)
- * Purpose  : Return information about the driver to a user process accessing
- *	      the /proc filesystem.
- * Params   : buffer  - a buffer to write information to
- *	      start   - a pointer into this buffer set by this routine to the start
- *		        of the required information.
- *	      offset  - offset into information that we have read upto.
- *	      length  - length of buffer
- *	      host_no - host number to return information for
- *	      inout   - 0 for reading, 1 for writing.
- * Returns  : length of data written to buffer.
- */
-int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
-			    int length, int host_no, int inout)
-{
-	int pos, begin;
-	struct Scsi_Host *host;
-	struct powertec_info *info;
-	Scsi_Device *scd;
-
-	host = scsi_host_hn_get(host_no);
-	if (!host)
-		return 0;
-
-	if (inout == 1)
-		return powertecscsi_set_proc_info(host, buffer, length);
-
-	info = (struct powertec_info *)host->hostdata;
-
-	begin = 0;
-	pos = sprintf(buffer, "PowerTec SCSI driver v%s\n", VERSION);
-	pos += fas216_print_host(&info->info, buffer + pos);
-	pos += sprintf(buffer + pos, "Term    : o%s\n",
-			info->term_ctl ? "n" : "ff");
-
-	pos += fas216_print_stats(&info->info, buffer + pos);
-
-	pos += sprintf(buffer+pos, "\nAttached devices:\n");
-
-	list_for_each_entry(scd, &host->my_devices, siblings) {
-		pos += fas216_print_device(&info->info, scd, buffer + pos);
-
-		if (pos + begin < offset) {
-			begin += pos;
-			pos = 0;
-		}
-		if (pos + begin > offset + length)
-			break;
-	}
-
-	*start = buffer + (offset - begin);
-	pos -= offset - begin;
-	if (pos > length)
-		pos = length;
-
-	return pos;
-}
-
-static ssize_t powertecscsi_show_term(struct device *dev, char *buf)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-	struct powertec_info *info = (struct powertec_info *)host->hostdata;
-
-	return sprintf(buf, "%d\n", info->term_ctl ? 1 : 0);
-}
-
-static ssize_t
-powertecscsi_store_term(struct device *dev, const char *buf, size_t len)
-{
-	struct expansion_card *ec = ECARD_DEV(dev);
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-
-	if (len > 1)
-		powertecscsi_terminator_ctl(host, buf[0] != '0');
-
-	return len;
-}
-
-static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
-		   powertecscsi_show_term, powertecscsi_store_term);
-
-static Scsi_Host_Template powertecscsi_template = {
-	.module				= THIS_MODULE,
-	.proc_info			= powertecscsi_proc_info,
-	.name				= "PowerTec SCSI",
-	.info				= powertecscsi_info,
-	.command			= fas216_command,
-	.queuecommand			= fas216_queue_command,
-	.eh_host_reset_handler		= fas216_eh_host_reset,
-	.eh_bus_reset_handler		= fas216_eh_bus_reset,
-	.eh_device_reset_handler	= fas216_eh_device_reset,
-	.eh_abort_handler		= fas216_eh_abort,
-
-	.can_queue			= 8,
-	.this_id			= 7,
-	.sg_tablesize			= SG_ALL,
-	.cmd_per_lun			= 2,
-	.use_clustering			= ENABLE_CLUSTERING,
-	.proc_name			= "powertec",
-};
-
-static int __devinit
-powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
-{
-	struct Scsi_Host *host;
-	struct powertec_info *info;
-	unsigned long resbase, reslen;
-	unsigned char *base;
-	int ret;
-
-	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
-	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
-
-	if (!request_mem_region(resbase, reslen, "powertecscsi")) {
-		ret = -EBUSY;
-		goto out;
-	}
-
-	base = ioremap(resbase, reslen);
-	if (!base) {
-		ret = -ENOMEM;
-		goto out_region;
-	}
-
-	host = scsi_register(&powertecscsi_template,
-			     sizeof (struct powertec_info));
-	if (!host) {
-		ret = -ENOMEM;
-		goto out_unmap;
-	}
-
-	host->base	  = (unsigned long)base;
-	host->irq	  = ec->irq;
-	host->dma_channel = ec->dma;
-
-	ec->irqaddr	= base + POWERTEC_INTR_STATUS;
-	ec->irqmask	= POWERTEC_INTR_BIT;
-	ec->irq_data	= base + POWERTEC_INTR_CONTROL;
-	ec->ops		= &powertecscsi_ops;
-
-	ecard_set_drvdata(ec, host);
-
-	info = (struct powertec_info *)host->hostdata;
-	info->term_port = base + POWERTEC_TERM_CONTROL;
-	powertecscsi_terminator_ctl(host, term[ec->slot_no]);
-
-	device_create_file(&ec->dev, &dev_attr_bus_term);
-
-	info->info.scsi.io_base		= base + POWERTEC_FAS216_OFFSET;
-	info->info.scsi.io_shift	= POWERTEC_FAS216_SHIFT;
-	info->info.scsi.irq		= host->irq;
-	info->info.ifcfg.clockrate	= 40; /* MHz */
-	info->info.ifcfg.select_timeout	= 255;
-	info->info.ifcfg.asyncperiod	= 200; /* ns */
-	info->info.ifcfg.sync_max_depth	= 7;
-	info->info.ifcfg.cntl3		= CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
-	info->info.ifcfg.disconnect_ok	= 1;
-	info->info.ifcfg.wide_max_size	= 0;
-	info->info.ifcfg.capabilities	= 0;
-	info->info.dma.setup		= powertecscsi_dma_setup;
-	info->info.dma.pseudo		= NULL;
-	info->info.dma.stop		= powertecscsi_dma_stop;
-
-	ret = fas216_init(host);
-	if (ret)
-		goto out_free;
-
-	ret = request_irq(host->irq, powertecscsi_intr,
-			  SA_INTERRUPT, "powertec", info);
-	if (ret) {
-		printk("scsi%d: IRQ%d not free: %d\n",
-		       host->host_no, host->irq, ret);
-		goto out_release;
-	}
-
-	if (host->dma_channel != NO_DMA) {
-		if (request_dma(host->dma_channel, "powertec")) {
-			printk("scsi%d: DMA%d not free, using PIO\n",
-			       host->host_no, host->dma_channel);
-			host->dma_channel = NO_DMA;
-		} else {
-			set_dma_speed(host->dma_channel, 180);
-			info->info.ifcfg.capabilities |= FASCAP_DMA;
-		}
-	}
-
-	ret = fas216_add(host, &ec->dev);
-	if (ret == 0)
-		goto out;
-
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, host);
-
- out_release:
-	fas216_release(host);
-
- out_free:
-	device_remove_file(&ec->dev, &dev_attr_bus_term);
-	scsi_unregister(host);
-
- out_unmap:
-	iounmap(base);
-
- out_region:
-	release_mem_region(resbase, reslen);
-
- out:
-	return ret;
-}
-
-static void __devexit powertecscsi_remove(struct expansion_card *ec)
-{
-	struct Scsi_Host *host = ecard_get_drvdata(ec);
-	struct powertecscsi_info *info = (struct powertecscsi_info *)host->hostdata;
-	unsigned long resbase, reslen;
-
-	ecard_set_drvdata(ec, NULL);
-	fas216_remove(host);
-
-	device_remove_file(&ec->dev, &dev_attr_bus_term);
-
-	if (host->dma_channel != NO_DMA)
-		free_dma(host->dma_channel);
-	free_irq(host->irq, info);
-
-	iounmap((void *)host->base);
-
-	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
-	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
-
-	release_mem_region(resbase, reslen);
-
-	fas216_release(host);
-	scsi_unregister(host);
-}
-
-static const struct ecard_id powertecscsi_cids[] = {
-	{ MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI },
-	{ 0xffff, 0xffff },
-};
-
-static struct ecard_driver powertecscsi_driver = {
-	.probe		= powertecscsi_probe,
-	.remove		= __devexit_p(powertecscsi_remove),
-	.id_table	= powertecscsi_cids,
-	.drv = {
-		.devclass	= &shost_devclass,
-		.name		= "powertecscsi",
-	},
-};
-
-static int __init powertecscsi_init(void)
-{
-	return ecard_register_driver(&powertecscsi_driver);
-}
-
-static void __exit powertecscsi_exit(void)
-{
-	ecard_remove_driver(&powertecscsi_driver);
-}
-
-module_init(powertecscsi_init);
-module_exit(powertecscsi_exit);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("Powertec SCSI driver");
-MODULE_PARM(term, "1-8i");
-MODULE_PARM_DESC(term, "SCSI bus termination");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/acorn/scsi/queue.c b/drivers/acorn/scsi/queue.c
--- a/drivers/acorn/scsi/queue.c	Fri Feb 14 16:23:45 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,319 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/queue.c: queue handling primitives
- *
- *  Copyright (C) 1997-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.
- *
- *  Changelog:
- *   15-Sep-1997 RMK	Created.
- *   11-Oct-1997 RMK	Corrected problem with queue_remove_exclude
- *			not updating internal linked list properly
- *			(was causing commands to go missing).
- *   30-Aug-2000 RMK	Use Linux list handling and spinlocks
- */
-#include <linux/module.h>
-#include <linux/blk.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/init.h>
-
-#include "../../scsi/scsi.h"
-
-#define DEBUG
-
-typedef struct queue_entry {
-	struct list_head   list;
-	Scsi_Cmnd	   *SCpnt;
-#ifdef DEBUG
-	unsigned long	   magic;
-#endif
-} QE_t;
-
-#ifdef DEBUG
-#define QUEUE_MAGIC_FREE	0xf7e1c9a3
-#define QUEUE_MAGIC_USED	0xf7e1cc33
-
-#define SET_MAGIC(q,m)	((q)->magic = (m))
-#define BAD_MAGIC(q,m)	((q)->magic != (m))
-#else
-#define SET_MAGIC(q,m)	do { } while (0)
-#define BAD_MAGIC(q,m)	(0)
-#endif
-
-#include "queue.h"
-
-#define NR_QE	32
-
-/*
- * Function: void queue_initialise (Queue_t *queue)
- * Purpose : initialise a queue
- * Params  : queue - queue to initialise
- */
-int queue_initialise (Queue_t *queue)
-{
-	unsigned int nqueues = NR_QE;
-	QE_t *q;
-
-	spin_lock_init(&queue->queue_lock);
-	INIT_LIST_HEAD(&queue->head);
-	INIT_LIST_HEAD(&queue->free);
-
-	/*
-	 * If life was easier, then SCpnt would have a
-	 * host-available list head, and we wouldn't
-	 * need to keep free lists or allocate this
-	 * memory.
-	 */
-	queue->alloc = q = kmalloc(sizeof(QE_t) * nqueues, GFP_KERNEL);
-	if (q) {
-		for (; nqueues; q++, nqueues--) {
-			SET_MAGIC(q, QUEUE_MAGIC_FREE);
-			q->SCpnt = NULL;
-			list_add(&q->list, &queue->free);
-		}
-	}
-
-	return queue->alloc != NULL;
-}
-
-/*
- * Function: void queue_free (Queue_t *queue)
- * Purpose : free a queue
- * Params  : queue - queue to free
- */
-void queue_free (Queue_t *queue)
-{
-	if (!list_empty(&queue->head))
-		printk(KERN_WARNING "freeing non-empty queue %p\n", queue);
-	if (queue->alloc)
-		kfree(queue->alloc);
-}
-     
-
-/*
- * Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
- * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head.
- * Params  : queue - destination queue
- *	     SCpnt - command to add
- *	     head  - add command to head of queue
- * Returns : 0 on error, !0 on success
- */
-int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
-{
-	unsigned long flags;
-	struct list_head *l;
-	QE_t *q;
-	int ret = 0;
-
-	spin_lock_irqsave(&queue->queue_lock, flags);
-	if (list_empty(&queue->free))
-		goto empty;
-
-	l = queue->free.next;
-	list_del(l);
-
-	q = list_entry(l, QE_t, list);
-	if (BAD_MAGIC(q, QUEUE_MAGIC_FREE))
-		BUG();
-
-	SET_MAGIC(q, QUEUE_MAGIC_USED);
-	q->SCpnt = SCpnt;
-
-	if (head)
-		list_add(l, &queue->head);
-	else
-		list_add_tail(l, &queue->head);
-
-	ret = 1;
-empty:
-	spin_unlock_irqrestore(&queue->queue_lock, flags);
-	return ret;
-}
-
-static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
-{
-	QE_t *q;
-
-	/*
-	 * Move the entry from the "used" list onto the "free" list
-	 */
-	list_del(ent);
-	q = list_entry(ent, QE_t, list);
-	if (BAD_MAGIC(q, QUEUE_MAGIC_USED))
-		BUG();
-
-	SET_MAGIC(q, QUEUE_MAGIC_FREE);
-	list_add(ent, &queue->free);
-
-	return q->SCpnt;
-}
-
-/*
- * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude)
- * Purpose : remove a SCSI command from a queue
- * Params  : queue   - queue to remove command from
- *	     exclude - bit array of target&lun which is busy
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
- */
-Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
-{
-	unsigned long flags;
-	struct list_head *l;
-	Scsi_Cmnd *SCpnt = NULL;
-
-	spin_lock_irqsave(&queue->queue_lock, flags);
-	list_for_each(l, &queue->head) {
-		QE_t *q = list_entry(l, QE_t, list);
-		if (!test_bit(q->SCpnt->device->id * 8 + q->SCpnt->device->lun, exclude)) {
-			SCpnt = __queue_remove(queue, l);
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&queue->queue_lock, flags);
-
-	return SCpnt;
-}
-
-/*
- * Function: Scsi_Cmnd *queue_remove (queue)
- * Purpose : removes first SCSI command from a queue
- * Params  : queue   - queue to remove command from
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
- */
-Scsi_Cmnd *queue_remove(Queue_t *queue)
-{
-	unsigned long flags;
-	Scsi_Cmnd *SCpnt = NULL;
-
-	spin_lock_irqsave(&queue->queue_lock, flags);
-	if (!list_empty(&queue->head))
-		SCpnt = __queue_remove(queue, queue->head.next);
-	spin_unlock_irqrestore(&queue->queue_lock, flags);
-
-	return SCpnt;
-}
-
-/*
- * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
- * Purpose : remove a SCSI command from the queue for a specified target/lun/tag
- * Params  : queue  - queue to remove command from
- *	     target - target that we want
- *	     lun    - lun on device
- *	     tag    - tag on device
- * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
- */
-Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag)
-{
-	unsigned long flags;
-	struct list_head *l;
-	Scsi_Cmnd *SCpnt = NULL;
-
-	spin_lock_irqsave(&queue->queue_lock, flags);
-	list_for_each(l, &queue->head) {
-		QE_t *q = list_entry(l, QE_t, list);
-		if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun &&
-		    q->SCpnt->tag == tag) {
-			SCpnt = __queue_remove(queue, l);
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&queue->queue_lock, flags);
-
-	return SCpnt;
-}
-
-/*
- * Function: queue_remove_all_target(queue, target)
- * Purpose : remove all SCSI commands from the queue for a specified target
- * Params  : queue  - queue to remove command from
- *           target - target device id
- * Returns : nothing
- */
-void queue_remove_all_target(Queue_t *queue, int target)
-{
-	unsigned long flags;
-	struct list_head *l;
-
-	spin_lock_irqsave(&queue->queue_lock, flags);
-	list_for_each(l, &queue->head) {
-		QE_t *q = list_entry(l, QE_t, list);
-		if (q->SCpnt->device->id == target)
-			__queue_remove(queue, l);
-	}
-	spin_unlock_irqrestore(&queue->queue_lock, flags);
-}
-
-/*
- * Function: int queue_probetgtlun (queue, target, lun)
- * Purpose : check to see if we have a command in the queue for the specified
- *	     target/lun.
- * Params  : queue  - queue to look in
- *	     target - target we want to probe
- *	     lun    - lun on target
- * Returns : 0 if not found, != 0 if found
- */
-int queue_probetgtlun (Queue_t *queue, int target, int lun)
-{
-	unsigned long flags;
-	struct list_head *l;
-	int found = 0;
-
-	spin_lock_irqsave(&queue->queue_lock, flags);
-	list_for_each(l, &queue->head) {
-		QE_t *q = list_entry(l, QE_t, list);
-		if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun) {
-			found = 1;
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&queue->queue_lock, flags);
-
-	return found;
-}
-
-/*
- * Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
- * Purpose : remove a specific command from the queues
- * Params  : queue - queue to look in
- *	     SCpnt - command to find
- * Returns : 0 if not found
- */
-int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
-{
-	unsigned long flags;
-	struct list_head *l;
-	int found = 0;
-
-	spin_lock_irqsave(&queue->queue_lock, flags);
-	list_for_each(l, &queue->head) {
-		QE_t *q = list_entry(l, QE_t, list);
-		if (q->SCpnt == SCpnt) {
-			__queue_remove(queue, l);
-			found = 1;
-			break;
-		}
-	}
-	spin_unlock_irqrestore(&queue->queue_lock, flags);
-
-	return found;
-}
-
-EXPORT_SYMBOL(queue_initialise);
-EXPORT_SYMBOL(queue_free);
-EXPORT_SYMBOL(__queue_add);
-EXPORT_SYMBOL(queue_remove);
-EXPORT_SYMBOL(queue_remove_exclude);
-EXPORT_SYMBOL(queue_remove_tgtluntag);
-EXPORT_SYMBOL(queue_remove_cmd);
-EXPORT_SYMBOL(queue_remove_all_target);
-EXPORT_SYMBOL(queue_probetgtlun);
-
-MODULE_AUTHOR("Russell King");
-MODULE_DESCRIPTION("SCSI command queueing");
-MODULE_LICENSE("GPL");
diff -Nru a/drivers/acorn/scsi/queue.h b/drivers/acorn/scsi/queue.h
--- a/drivers/acorn/scsi/queue.h	Sun Nov 17 13:36:34 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,105 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/queue.h: queue handling
- *
- *  Copyright (C) 1997 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.
- */
-#ifndef QUEUE_H
-#define QUEUE_H
-
-typedef struct {
-	struct list_head head;
-	struct list_head free;
-	spinlock_t queue_lock;
-	void *alloc;			/* start of allocated mem */
-} Queue_t;
-
-/*
- * Function: void queue_initialise (Queue_t *queue)
- * Purpose : initialise a queue
- * Params  : queue - queue to initialise
- */
-extern int queue_initialise (Queue_t *queue);
-
-/*
- * Function: void queue_free (Queue_t *queue)
- * Purpose : free a queue
- * Params  : queue - queue to free
- */
-extern void queue_free (Queue_t *queue);
-
-/*
- * Function: Scsi_Cmnd *queue_remove (queue)
- * Purpose : removes first SCSI command from a queue
- * Params  : queue   - queue to remove command from
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
- */
-extern Scsi_Cmnd *queue_remove (Queue_t *queue);
-
-/*
- * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude)
- * Purpose : remove a SCSI command from a queue
- * Params  : queue   - queue to remove command from
- *	     exclude - array of busy LUNs
- * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
- */
-extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude);
-
-#define queue_add_cmd_ordered(queue,SCpnt) \
-	__queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE)
-#define queue_add_cmd_tail(queue,SCpnt) \
-	__queue_add(queue,SCpnt,0)
-/*
- * Function: int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
- * Purpose : Add a new command onto a queue
- * Params  : queue - destination queue
- *	     SCpnt - command to add
- *	     head  - add command to head of queue
- * Returns : 0 on error, !0 on success
- */
-extern int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head);
-
-/*
- * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
- * Purpose : remove a SCSI command from the queue for a specified target/lun/tag
- * Params  : queue  - queue to remove command from
- *	     target - target that we want
- *	     lun    - lun on device
- *	     tag    - tag on device
- * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
- */
-extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag);
-
-/*
- * Function: queue_remove_all_target(queue, target)
- * Purpose : remove all SCSI commands from the queue for a specified target
- * Params  : queue  - queue to remove command from
- *           target - target device id
- * Returns : nothing
- */
-extern void queue_remove_all_target(Queue_t *queue, int target);
-
-/*
- * Function: int queue_probetgtlun (queue, target, lun)
- * Purpose : check to see if we have a command in the queue for the specified
- *	     target/lun.
- * Params  : queue  - queue to look in
- *	     target - target we want to probe
- *	     lun    - lun on target
- * Returns : 0 if not found, != 0 if found
- */
-extern int queue_probetgtlun (Queue_t *queue, int target, int lun);
-
-/*
- * Function: int queue_remove_cmd (Queue_t *queue, Scsi_Cmnd *SCpnt)
- * Purpose : remove a specific command from the queues
- * Params  : queue - queue to look in
- *	     SCpnt - command to find
- * Returns : 0 if not found
- */
-int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt);
-
-#endif /* QUEUE_H */
diff -Nru a/drivers/acorn/scsi/scsi.h b/drivers/acorn/scsi/scsi.h
--- a/drivers/acorn/scsi/scsi.h	Wed Mar 19 07:19:28 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,115 +0,0 @@
-/*
- *  linux/drivers/acorn/scsi/scsi.h
- *
- *  Copyright (C) 2002 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.
- *
- *  Commonly used scsi driver functions.
- */
-
-#define BELT_AND_BRACES
-
-/*
- * The scatter-gather list handling.  This contains all
- * the yucky stuff that needs to be fixed properly.
- */
-static inline int copy_SCp_to_sg(struct scatterlist *sg, Scsi_Pointer *SCp, int max)
-{
-	int bufs = SCp->buffers_residual;
-
-	BUG_ON(bufs + 1 > max);
-
-	sg->page   = virt_to_page(SCp->ptr);
-	sg->offset = ((unsigned int)SCp->ptr) & ~PAGE_MASK;
-	sg->length = SCp->this_residual;
-
-	if (bufs)
-		memcpy(sg + 1, SCp->buffer + 1,
-		       sizeof(struct scatterlist) * bufs);
-	return bufs + 1;
-}
-
-static inline int next_SCp(Scsi_Pointer *SCp)
-{
-	int ret = SCp->buffers_residual;
-	if (ret) {
-		SCp->buffer++;
-		SCp->buffers_residual--;
-		SCp->ptr = (char *)
-			 (page_address(SCp->buffer->page) +
-			  SCp->buffer->offset);
-		SCp->this_residual = SCp->buffer->length;
-	} else {
-		SCp->ptr = NULL;
-		SCp->this_residual = 0;
-	}
-	return ret;
-}
-
-static inline unsigned char get_next_SCp_byte(Scsi_Pointer *SCp)
-{
-	char c = *SCp->ptr;
-
-	SCp->ptr += 1;
-	SCp->this_residual -= 1;
-
-	return c;
-}
-
-static inline void put_next_SCp_byte(Scsi_Pointer *SCp, unsigned char c)
-{
-	*SCp->ptr = c;
-	SCp->ptr += 1;
-	SCp->this_residual -= 1;
-}
-
-static inline void init_SCp(Scsi_Cmnd *SCpnt)
-{
-	memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
-
-	if (SCpnt->use_sg) {
-		unsigned long len = 0;
-		int buf;
-
-		SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
-		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
-		SCpnt->SCp.ptr = (char *)
-			 (page_address(SCpnt->SCp.buffer->page) +
-			  SCpnt->SCp.buffer->offset);
-		SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
-
-#ifdef BELT_AND_BRACES
-		/*
-		 * Calculate correct buffer length.  Some commands
-		 * come in with the wrong request_bufflen.
-		 */
-		for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++)
-			len += SCpnt->SCp.buffer[buf].length;
-
-		if (SCpnt->request_bufflen != len)
-			printk(KERN_WARNING "scsi%d.%c: bad request buffer "
-			       "length %d, should be %ld\n", SCpnt->device->host->host_no,
-			       '0' + SCpnt->device->id, SCpnt->request_bufflen, len);
-		SCpnt->request_bufflen = len;
-#endif
-	} else {
-		SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer;
-		SCpnt->SCp.this_residual = SCpnt->request_bufflen;
-	}
-
-	/*
-	 * If the upper SCSI layers pass a buffer, but zero length,
-	 * we aren't interested in the buffer pointer.
-	 */
-	if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) {
-#if 0 //def BELT_AND_BRACES
-		printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for "
-		       "command ", SCpnt->host->host_no, '0' + SCpnt->target);
-		print_command(SCpnt->cmnd);
-#endif
-		SCpnt->SCp.ptr = NULL;
-	}
-}
diff -Nru a/drivers/acpi/acpi_ksyms.c b/drivers/acpi/acpi_ksyms.c
--- a/drivers/acpi/acpi_ksyms.c	Fri Mar 28 14:10:26 2003
+++ b/drivers/acpi/acpi_ksyms.c	Tue May  6 15:50:56 2003
@@ -80,6 +80,7 @@
 EXPORT_SYMBOL(acpi_get_possible_resources);
 EXPORT_SYMBOL(acpi_walk_resources);
 EXPORT_SYMBOL(acpi_set_current_resources);
+EXPORT_SYMBOL(acpi_resource_to_address64);
 EXPORT_SYMBOL(acpi_enable_event);
 EXPORT_SYMBOL(acpi_disable_event);
 EXPORT_SYMBOL(acpi_clear_event);
diff -Nru a/drivers/atm/Kconfig b/drivers/atm/Kconfig
--- a/drivers/atm/Kconfig	Sun Feb  9 17:29:49 2003
+++ b/drivers/atm/Kconfig	Thu May 15 21:12:28 2003
@@ -7,14 +7,14 @@
 
 config ATM_TCP
 	tristate "ATM over TCP"
-	depends on INET
+	depends on INET && ATM
 	help
 	  ATM over TCP driver. Useful mainly for development and for
 	  experiments. If unsure, say N.
 
 config ATM_LANAI
 	tristate "Efficient Networks Speedstream 3010"
-	depends on PCI
+	depends on PCI && ATM
 	help
 	  Supports ATM cards based on the Efficient Networks "Lanai"
 	  chipset such as the Speedstream 3010 and the ENI-25p.  The
@@ -23,7 +23,7 @@
 
 config ATM_ENI
 	tristate "Efficient Networks ENI155P"
-	depends on PCI
+	depends on PCI && ATM
 	---help---
 	  Driver for the Efficient Networks ENI155p series and SMC ATM
 	  Power155 155 Mbps ATM adapters. Both, the versions with 512KB and
@@ -133,7 +133,7 @@
 
 config ATM_FIRESTREAM
 	tristate "Fujitsu FireStream (FS50/FS155) "
-	depends on PCI
+	depends on PCI && ATM
 	help
 	  Driver for the Fujitsu FireStream 155 (MB86697) and
 	  FireStream 50 (MB86695) ATM PCI chips.
@@ -145,7 +145,7 @@
 
 config ATM_ZATM
 	tristate "ZeitNet ZN1221/ZN1225"
-	depends on PCI
+	depends on PCI && ATM
 	help
 	  Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM
 	  adapters.
@@ -182,7 +182,7 @@
 #   fi
 config ATM_NICSTAR
 	tristate "IDT 77201 (NICStAR) (ForeRunnerLE)"
-	depends on PCI
+	depends on PCI && ATM
 	help
 	  The NICStAR chipset family is used in a large number of ATM NICs for
 	  25 and for 155 Mbps, including IDT cards and the Fore ForeRunnerLE
@@ -217,7 +217,7 @@
 
 config ATM_IDT77252
 	tristate "IDT 77252 (NICStAR II)"
-	depends on PCI
+	depends on PCI && ATM
 	help
 	  Driver for the IDT 77252 ATM PCI chips.
 
@@ -253,7 +253,7 @@
 
 config ATM_AMBASSADOR
 	tristate "Madge Ambassador (Collage PCI 155 Server)"
-	depends on PCI
+	depends on PCI && ATM
 	help
 	  This is a driver for ATMizer based ATM card produced by Madge
 	  Networks Ltd. Say Y (or M to compile as a module named ambassador)
@@ -277,7 +277,7 @@
 
 config ATM_HORIZON
 	tristate "Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)"
-	depends on PCI
+	depends on PCI && ATM
 	help
 	  This is a driver for the Horizon chipset ATM adapter cards once
 	  produced by Madge Networks Ltd. Say Y (or M to compile as a module
@@ -301,7 +301,7 @@
 
 config ATM_IA
 	tristate "Interphase ATM PCI x575/x525/x531"
-	depends on PCI
+	depends on PCI && ATM
 	---help---
 	  This is a driver for the Interphase (i)ChipSAR adapter cards
 	  which include a variety of variants in term of the size of the
@@ -334,7 +334,7 @@
 
 config ATM_FORE200E_MAYBE
 	tristate "FORE Systems 200E-series"
-	depends on PCI || SBUS
+	depends on (PCI || SBUS) && ATM
 	---help---
 	  This is a driver for the FORE Systems 200E-series ATM adapter
 	  cards. It simultaneously supports PCA-200E and SBA-200E models
@@ -439,6 +439,20 @@
 	depends on (PCI || SBUS) && (ATM_FORE200E_PCA || ATM_FORE200E_SBA)
 	default m if ATM_FORE200E_MAYBE!=y
 	default y if ATM_FORE200E_MAYBE=y
+
+config ATM_HE
+	tristate "ForeRunner HE Series"
+	depends on PCI && ATM
+	help
+	  This is a driver for the Marconi ForeRunner HE-series ATM adapter
+	  cards. It simultaneously supports the 155 and 622 versions.
+
+config ATM_HE_USE_SUNI
+	bool "Use S/UNI PHY driver"
+	depends on ATM_HE
+	help
+	  Support for the S/UNI-Ultra and S/UNI-622 found in the ForeRunner
+	  HE cards.  This driver provides carrier detection some statistics.
 
 endmenu
 
diff -Nru a/drivers/atm/Makefile b/drivers/atm/Makefile
--- a/drivers/atm/Makefile	Sat Mar  8 13:46:23 2003
+++ b/drivers/atm/Makefile	Wed May  7 12:23:04 2003
@@ -49,6 +49,10 @@
     CONFIG_ATM_FORE200E_SBA_FW	:= $(obj)/sba200e_ecd.bin2
   endif
 endif
+obj-$(CONFIG_ATM_HE)		+= he.o
+ifeq ($(CONFIG_ATM_HE_USE_SUNI),y)
+  obj-$(CONFIG_ATM_HE)		+= suni.o
+endif
 
 # FORE Systems 200E-series firmware magic
 $(obj)/fore200e_pca_fw.c: $(patsubst "%", %, $(CONFIG_ATM_FORE200E_PCA_FW)) \
diff -Nru a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
--- a/drivers/atm/ambassador.c	Thu Apr 24 05:17:22 2003
+++ b/drivers/atm/ambassador.c	Tue May  6 00:43:07 2003
@@ -290,12 +290,11 @@
 /********** microcode **********/
 
 #ifdef AMB_NEW_MICROCODE
-#define UCODE(x) UCODE1(atmsar12.,x)
+#define UCODE(x) UCODE2(atmsar12.x)
 #else
-#define UCODE(x) UCODE1(atmsar11.,x)
+#define UCODE(x) UCODE2(atmsar11.x)
 #endif
 #define UCODE2(x) #x
-#define UCODE1(x,y) UCODE2(x ## y)
 
 static u32 __initdata ucode_start = 
 #include UCODE(start)
diff -Nru a/drivers/atm/atmtcp.c b/drivers/atm/atmtcp.c
--- a/drivers/atm/atmtcp.c	Wed Jan  8 04:03:28 2003
+++ b/drivers/atm/atmtcp.c	Thu May 15 17:20:17 2003
@@ -153,6 +153,7 @@
 
 static int atmtcp_v_ioctl(struct atm_dev *dev,unsigned int cmd,void *arg)
 {
+	unsigned long flags;
 	struct atm_cirange ci;
 	struct atm_vcc *vcc;
 
@@ -162,9 +163,14 @@
 	if (ci.vci_bits == ATM_CI_MAX) ci.vci_bits = MAX_VCI_BITS;
 	if (ci.vpi_bits > MAX_VPI_BITS || ci.vpi_bits < 0 ||
 	    ci.vci_bits > MAX_VCI_BITS || ci.vci_bits < 0) return -EINVAL;
+	spin_lock_irqsave(&dev->lock, flags);
 	for (vcc = dev->vccs; vcc; vcc = vcc->next)
 		if ((vcc->vpi >> ci.vpi_bits) ||
-		    (vcc->vci >> ci.vci_bits)) return -EBUSY;
+		    (vcc->vci >> ci.vci_bits)) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			return -EBUSY;
+		}
+	spin_unlock_irqrestore(&dev->lock, flags);
 	dev->ci_range = ci;
 	return 0;
 }
@@ -227,6 +233,7 @@
 
 static void atmtcp_c_close(struct atm_vcc *vcc)
 {
+	unsigned long flags;
 	struct atm_dev *atmtcp_dev;
 	struct atmtcp_dev_data *dev_data;
 	struct atm_vcc *walk;
@@ -239,13 +246,16 @@
 	kfree(dev_data);
 	shutdown_atm_dev(atmtcp_dev);
 	vcc->dev_data = NULL;
+	spin_lock_irqsave(&atmtcp_dev->lock, flags);
 	for (walk = atmtcp_dev->vccs; walk; walk = walk->next)
 		wake_up(&walk->sleep);
+	spin_unlock_irqrestore(&atmtcp_dev->lock, flags);
 }
 
 
 static int atmtcp_c_send(struct atm_vcc *vcc,struct sk_buff *skb)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct atmtcp_hdr *hdr;
 	struct atm_vcc *out_vcc;
@@ -260,11 +270,13 @@
 		    (struct atmtcp_control *) skb->data);
 		goto done;
 	}
+	spin_lock_irqsave(&dev->lock, flags);
 	for (out_vcc = dev->vccs; out_vcc; out_vcc = out_vcc->next)
 		if (out_vcc->vpi == ntohs(hdr->vpi) &&
 		    out_vcc->vci == ntohs(hdr->vci) &&
 		    out_vcc->qos.rxtp.traffic_class != ATM_NONE)
 			break;
+	spin_unlock_irqrestore(&dev->lock, flags);
 	if (!out_vcc) {
 		atomic_inc(&vcc->stats->tx_err);
 		goto done;
@@ -318,6 +330,7 @@
 	.ops		= &atmtcp_c_dev_ops,
 	.type		= "atmtcp",
 	.number		= 999,
+	.lock		= SPIN_LOCK_UNLOCKED
 };
 
 
@@ -350,9 +363,12 @@
 	struct atm_dev *dev;
 
 	dev = NULL;
-	if (itf != -1) dev = atm_find_dev(itf);
+	if (itf != -1) dev = atm_dev_lookup(itf);
 	if (dev) {
-		if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE;
+		if (dev->ops != &atmtcp_v_dev_ops) {
+			atm_dev_release(dev);
+			return -EMEDIUMTYPE;
+		}
 		if (PRIV(dev)->vcc) return -EBUSY;
 	}
 	else {
@@ -383,14 +399,18 @@
 	struct atm_dev *dev;
 	struct atmtcp_dev_data *dev_data;
 
-	dev = atm_find_dev(itf);
+	dev = atm_dev_lookup(itf);
 	if (!dev) return -ENODEV;
-	if (dev->ops != &atmtcp_v_dev_ops) return -EMEDIUMTYPE;
+	if (dev->ops != &atmtcp_v_dev_ops) {
+		atm_dev_release(dev);
+		return -EMEDIUMTYPE;
+	}
 	dev_data = PRIV(dev);
 	if (!dev_data->persist) return 0;
 	dev_data->persist = 0;
 	if (PRIV(dev)->vcc) return 0;
 	kfree(dev_data);
+	atm_dev_release(dev);
 	shutdown_atm_dev(dev);
 	return 0;
 }
diff -Nru a/drivers/atm/eni.c b/drivers/atm/eni.c
--- a/drivers/atm/eni.c	Thu Apr 24 05:17:22 2003
+++ b/drivers/atm/eni.c	Thu May 15 17:20:17 2003
@@ -1100,9 +1100,9 @@
 	dma_rd = eni_in(MID_DMA_RD_TX);
 	dma_size = 3; /* JK for descriptor and final fill, plus final size
 			 mis-alignment fix */
-DPRINTK("iovcnt = %d\n",ATM_SKB(skb)->iovcnt);
-	if (!ATM_SKB(skb)->iovcnt) dma_size += 5;
-	else dma_size += 5*ATM_SKB(skb)->iovcnt;
+DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags);
+	if (!skb_shinfo(skb)->nr_frags) dma_size += 5;
+	else dma_size += 5*(skb_shinfo(skb)->nr_frags+1);
 	if (dma_size > TX_DMA_BUF) {
 		printk(KERN_CRIT DEV_LABEL "(itf %d): needs %d DMA entries "
 		    "(got only %d)\n",vcc->dev->number,dma_size,TX_DMA_BUF);
@@ -1123,15 +1123,20 @@
 	     MID_DMA_COUNT_SHIFT) | (tx->index << MID_DMA_CHAN_SHIFT) |
 	     MID_DT_JK;
 	j++;
-	if (!ATM_SKB(skb)->iovcnt)
+	if (!skb_shinfo(skb)->nr_frags)
 		if (aal5) put_dma(tx->index,eni_dev->dma,&j,paddr,skb->len);
 		else put_dma(tx->index,eni_dev->dma,&j,paddr+4,skb->len-4);
 	else {
 DPRINTK("doing direct send\n"); /* @@@ well, this doesn't work anyway */
-		for (i = 0; i < ATM_SKB(skb)->iovcnt; i++)
-			put_dma(tx->index,eni_dev->dma,&j,(unsigned long)
-			    ((struct iovec *) skb->data)[i].iov_base,
-			    ((struct iovec *) skb->data)[i].iov_len);
+		for (i = -1; i < skb_shinfo(skb)->nr_frags; i++)
+			if (i == -1)
+				put_dma(tx->index,eni_dev->dma,&j,(unsigned long)
+				    skb->data,
+				    skb->len - skb->data_len);
+			else
+				put_dma(tx->index,eni_dev->dma,&j,(unsigned long)
+				    skb_shinfo(skb)->frags[i].page + skb_shinfo(skb)->frags[i].page_offset,
+				    skb_shinfo(skb)->frags[i].size);
 	}
 	if (skb->len & 3)
 		put_dma(tx->index,eni_dev->dma,&j,zeroes,4-(skb->len & 3));
@@ -1882,8 +1887,10 @@
 
 static int get_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
+	unsigned long flags;
 	struct atm_vcc *walk;
 
+	spin_lock_irqsave(&vcc->dev->lock, flags);
 	if (*vpi == ATM_VPI_ANY) *vpi = 0;
 	if (*vci == ATM_VCI_ANY) {
 		for (*vci = ATM_NOT_RSV_VCI; *vci < NR_VCI; (*vci)++) {
@@ -1902,17 +1909,29 @@
 			}
 			break;
 		}
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
 		return *vci == NR_VCI ? -EADDRINUSE : 0;
 	}
-	if (*vci == ATM_VCI_UNSPEC) return 0;
+	if (*vci == ATM_VCI_UNSPEC) {
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		return 0;
+	}
 	if (vcc->qos.rxtp.traffic_class != ATM_NONE &&
-	    ENI_DEV(vcc->dev)->rx_map[*vci])
+	    ENI_DEV(vcc->dev)->rx_map[*vci]) {
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
 		return -EADDRINUSE;
-	if (vcc->qos.txtp.traffic_class == ATM_NONE) return 0;
+	}
+	if (vcc->qos.txtp.traffic_class == ATM_NONE) {
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		return 0;
+	}
 	for (walk = vcc->dev->vccs; walk; walk = walk->next)
 		if (test_bit(ATM_VF_ADDR,&walk->flags) && walk->vci == *vci &&
-		    walk->qos.txtp.traffic_class != ATM_NONE)
+		    walk->qos.txtp.traffic_class != ATM_NONE) {
+			spin_unlock_irqrestore(&vcc->dev->lock, flags);
 			return -EADDRINUSE;
+		}
+	spin_unlock_irqrestore(&vcc->dev->lock, flags);
 	return 0;
 }
 
@@ -2120,6 +2139,7 @@
 
 static int eni_proc_read(struct atm_dev *dev,loff_t *pos,char *page)
 {
+	unsigned long flags;
 	static const char *signal[] = { "LOST","unknown","okay" };
 	struct eni_dev *eni_dev = ENI_DEV(dev);
 	struct atm_vcc *vcc;
@@ -2192,6 +2212,7 @@
 		return sprintf(page,"%10sbacklog %u packets\n","",
 		    skb_queue_len(&tx->backlog));
 	}
+	spin_lock_irqsave(&dev->lock, flags);
 	for (vcc = dev->vccs; vcc; vcc = vcc->next) {
 		struct eni_vcc *eni_vcc = ENI_VCC(vcc);
 		int length;
@@ -2210,8 +2231,10 @@
 			length += sprintf(page+length,"tx[%d], txing %d bytes",
 			    eni_vcc->tx->index,eni_vcc->txing);
 		page[length] = '\n';
+		spin_unlock_irqrestore(&dev->lock, flags);
 		return length+1;
 	}
+	spin_unlock_irqrestore(&dev->lock, flags);
 	for (i = 0; i < eni_dev->free_len; i++) {
 		struct eni_free *fe = eni_dev->free_list+i;
 		unsigned long offset;
diff -Nru a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
--- a/drivers/atm/fore200e.c	Thu Apr 24 05:17:22 2003
+++ b/drivers/atm/fore200e.c	Thu May 15 17:20:17 2003
@@ -1074,13 +1074,16 @@
 static struct atm_vcc* 
 fore200e_find_vcc(struct fore200e* fore200e, struct rpd* rpd)
 {
+    unsigned long flags;
     struct atm_vcc* vcc;
 
+    spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
     for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
 
 	if (vcc->vpi == rpd->atm_header.vpi && vcc->vci == rpd->atm_header.vci)
 	    break;
     }
+    spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
     
     return vcc;
 }
@@ -1352,9 +1355,13 @@
 static int
 fore200e_walk_vccs(struct atm_vcc *vcc, short *vpi, int *vci)
 {
+    unsigned long flags;
     struct atm_vcc* walk;
 
     /* find a free VPI */
+
+    spin_lock_irqsave(&vcc->dev->lock, flags);
+
     if (*vpi == ATM_VPI_ANY) {
 
 	for (*vpi = 0, walk = vcc->dev->vccs; walk; walk = walk->next) {
@@ -1378,6 +1385,8 @@
 	}
     }
 
+    spin_unlock_irqrestore(&vcc->dev->lock, flags);
+
     return 0;
 }
 
@@ -2638,6 +2647,7 @@
 static int
 fore200e_proc_read(struct atm_dev *dev,loff_t* pos,char* page)
 {
+    unsigned long flags;
     struct fore200e* fore200e  = FORE200E_DEV(dev);
     int              len, left = *pos;
 
@@ -2884,6 +2894,7 @@
 	len = sprintf(page,"\n"    
 		      " VCCs:\n  address\tVPI.VCI:AAL\t(min/max tx PDU size) (min/max rx PDU size)\n");
 	
+	spin_lock_irqsave(&fore200e->atm_dev->lock, flags);
 	for (vcc = fore200e->atm_dev->vccs; vcc; vcc = vcc->next) {
 
 	    fore200e_vcc = FORE200E_VCC(vcc);
@@ -2898,6 +2909,7 @@
 			   fore200e_vcc->rx_max_pdu
 		);
 	}
+	spin_unlock_irqrestore(&fore200e->atm_dev->lock, flags);
 
 	return len;
     }
diff -Nru a/drivers/atm/he.c b/drivers/atm/he.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/atm/he.c	Thu May 15 17:20:17 2003
@@ -0,0 +1,3266 @@
+/* $Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $ */
+
+/*
+
+  he.c
+
+  ForeRunnerHE ATM Adapter driver for ATM on Linux
+  Copyright (C) 1999-2001  Naval Research Laboratory
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/*
+
+  he.c
+
+  ForeRunnerHE ATM Adapter driver for ATM on Linux
+  Copyright (C) 1999-2001  Naval Research Laboratory
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation is hereby granted, provided that both the copyright
+  notice and this permission notice appear in all copies of the software,
+  derivative works or modified versions, and any portions thereof, and
+  that both notices appear in supporting documentation.
+
+  NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
+  DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
+  RESULTING FROM THE USE OF THIS SOFTWARE.
+
+  This driver was written using the "Programmer's Reference Manual for
+  ForeRunnerHE(tm)", MANU0361-01 - Rev. A, 08/21/98.
+
+  AUTHORS:
+	chas williams <chas@cmf.nrl.navy.mil>
+	eric kinzie <ekinzie@cmf.nrl.navy.mil>
+
+  NOTES:
+	4096 supported 'connections'
+	group 0 is used for all traffic
+	interrupt queue 0 is used for all interrupts
+	aal0 support (based on work from ulrich.u.muller@nokia.com)
+
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/version.h>
+#include <linux/kernel.h>
+#include <linux/skbuff.h>
+#include <linux/pci.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/byteorder.h>
+#include <asm/uaccess.h>
+
+#include <linux/atmdev.h>
+#include <linux/atm.h>
+#include <linux/sonet.h>
+#ifndef ATM_OC12_PCR
+#define ATM_OC12_PCR (622080000/1080*1040/8/53)
+#endif
+
+#ifdef BUS_INT_WAR
+void sn_add_polled_interrupt(int irq, int interval);
+void sn_delete_polled_interrupt(int irq);
+#endif
+
+#define USE_TASKLET
+#define USE_HE_FIND_VCC
+#undef USE_SCATTERGATHER
+#undef USE_CHECKSUM_HW			/* still confused about this */
+#define USE_RBPS
+#undef USE_RBPS_POOL			/* if memory is tight try this */
+#undef USE_RBPL_POOL			/* if memory is tight try this */
+#define USE_TPD_POOL
+/* #undef CONFIG_ATM_HE_USE_SUNI */
+
+/* compatibility */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,69)
+typedef void irqreturn_t;
+#define IRQ_NONE
+#define IRQ_HANDLED
+#define IRQ_RETVAL(x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,9)
+#define __devexit_p(func)		func
+#endif
+
+#ifndef MODULE_LICENSE
+#define MODULE_LICENSE(x)
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,3)
+#define pci_set_drvdata(pci_dev, data)	(pci_dev)->driver_data = (data)
+#define pci_get_drvdata(pci_dev)	(pci_dev)->driver_data
+#endif
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,44)
+#define pci_pool_create(a, b, c, d, e)	pci_pool_create(a, b, c, d, e, SLAB_KERNEL)
+#endif
+
+#include "he.h"
+
+#include "suni.h"
+
+#include <linux/atm_he.h>
+
+#define hprintk(fmt,args...)	printk(KERN_ERR DEV_LABEL "%d: " fmt, he_dev->number , ##args)
+
+#undef DEBUG
+#ifdef DEBUG
+#define HPRINTK(fmt,args...)	hprintk(fmt,args)
+#else
+#define HPRINTK(fmt,args...)	do { } while(0)
+#endif /* DEBUG */
+
+
+/* version definition */
+
+static char *version = "$Id: he.c,v 1.18 2003/05/06 22:57:15 chas Exp $";
+
+/* declarations */
+
+static int he_open(struct atm_vcc *vcc, short vpi, int vci);
+static void he_close(struct atm_vcc *vcc);
+static int he_send(struct atm_vcc *vcc, struct sk_buff *skb);
+static int he_sg_send(struct atm_vcc *vcc, unsigned long start, unsigned long size);
+static int he_ioctl(struct atm_dev *dev, unsigned int cmd, void *arg);
+static irqreturn_t he_irq_handler(int irq, void *dev_id, struct pt_regs *regs);
+static void he_tasklet(unsigned long data);
+static int he_proc_read(struct atm_dev *dev,loff_t *pos,char *page);
+static int he_start(struct atm_dev *dev);
+static void he_stop(struct he_dev *dev);
+static void he_phy_put(struct atm_dev *, unsigned char, unsigned long);
+static unsigned char he_phy_get(struct atm_dev *, unsigned long);
+
+static u8 read_prom_byte(struct he_dev *he_dev, int addr);
+
+/* globals */
+
+struct he_dev *he_devs = NULL;
+static short disable64 = -1;
+static short nvpibits = -1;
+static short nvcibits = -1;
+static short rx_skb_reserve = 16;
+static short irq_coalesce = 1;
+static short sdh = 1;
+
+static struct atmdev_ops he_ops =
+{
+   open:	he_open,
+   close:	he_close,	
+   ioctl:	he_ioctl,	
+   send:	he_send,
+   sg_send:	he_sg_send,	
+   phy_put:	he_phy_put,
+   phy_get:	he_phy_get,
+   proc_read:	he_proc_read,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,1)
+   owner:	THIS_MODULE
+#endif
+};
+
+/* see the comments in he.h about global_lock */
+
+#define HE_SPIN_LOCK(dev, flags)	spin_lock_irqsave(&(dev)->global_lock, flags)
+#define HE_SPIN_UNLOCK(dev, flags)	spin_unlock_irqrestore(&(dev)->global_lock, flags)
+
+#define he_writel(dev, val, reg)	do { writel(val, (dev)->membase + (reg)); wmb(); } while(0)
+#define he_readl(dev, reg)		readl((dev)->membase + (reg))
+
+/* section 2.12 connection memory access */
+
+static __inline__ void
+he_writel_internal(struct he_dev *he_dev, unsigned val, unsigned addr,
+								unsigned flags)
+{
+	he_writel(he_dev, val, CON_DAT);
+#ifdef CONFIG_IA64_SGI_SN2
+	(void) he_readl(he_dev, CON_DAT);
+#endif
+	he_writel(he_dev, flags | CON_CTL_WRITE | CON_CTL_ADDR(addr), CON_CTL);
+	while(he_readl(he_dev, CON_CTL) & CON_CTL_BUSY);
+}
+
+#define he_writel_rcm(dev, val, reg) 				\
+			he_writel_internal(dev, val, reg, CON_CTL_RCM)
+
+#define he_writel_tcm(dev, val, reg) 				\
+			he_writel_internal(dev, val, reg, CON_CTL_TCM)
+
+#define he_writel_mbox(dev, val, reg) 				\
+			he_writel_internal(dev, val, reg, CON_CTL_MBOX)
+
+static unsigned
+he_readl_internal(struct he_dev *he_dev, unsigned addr, unsigned flags)
+{
+	he_writel(he_dev, flags | CON_CTL_READ | CON_CTL_ADDR(addr), CON_CTL);
+	while(he_readl(he_dev, CON_CTL) & CON_CTL_BUSY);
+	return he_readl(he_dev, CON_DAT);
+}
+
+#define he_readl_rcm(dev, reg) \
+			he_readl_internal(dev, reg, CON_CTL_RCM)
+
+#define he_readl_tcm(dev, reg) \
+			he_readl_internal(dev, reg, CON_CTL_TCM)
+
+#define he_readl_mbox(dev, reg) \
+			he_readl_internal(dev, reg, CON_CTL_MBOX)
+
+
+/* figure 2.2 connection id */
+
+#define he_mkcid(dev, vpi, vci)		(((vpi<<(dev)->vcibits) | vci) & 0x1fff)
+
+/* 2.5.1 per connection transmit state registers */
+
+#define he_writel_tsr0(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 0)
+#define he_readl_tsr0(dev, cid) \
+		he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 0)
+
+#define he_writel_tsr1(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 1)
+
+#define he_writel_tsr2(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 2)
+
+#define he_writel_tsr3(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 3)
+
+#define he_writel_tsr4(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 4)
+
+	/* from page 2-20
+	 *
+	 * NOTE While the transmit connection is active, bits 23 through 0
+	 *      of this register must not be written by the host.  Byte
+	 *      enables should be used during normal operation when writing
+	 *      the most significant byte.
+	 */
+
+#define he_writel_tsr4_upper(dev, val, cid) \
+		he_writel_internal(dev, val, CONFIG_TSRA | (cid<<3) | 4, \
+							CON_CTL_TCM \
+							| CON_BYTE_DISABLE_2 \
+							| CON_BYTE_DISABLE_1 \
+							| CON_BYTE_DISABLE_0)
+
+#define he_readl_tsr4(dev, cid) \
+		he_readl_tcm(dev, CONFIG_TSRA | (cid<<3) | 4)
+
+#define he_writel_tsr5(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 5)
+
+#define he_writel_tsr6(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 6)
+
+#define he_writel_tsr7(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRA | (cid<<3) | 7)
+
+
+#define he_writel_tsr8(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 0)
+
+#define he_writel_tsr9(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 1)
+
+#define he_writel_tsr10(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 2)
+
+#define he_writel_tsr11(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRB | (cid<<2) | 3)
+
+
+#define he_writel_tsr12(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<1) | 0)
+
+#define he_writel_tsr13(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRC | (cid<<1) | 1)
+
+
+#define he_writel_tsr14(dev, val, cid) \
+		he_writel_tcm(dev, val, CONFIG_TSRD | cid)
+
+#define he_writel_tsr14_upper(dev, val, cid) \
+		he_writel_internal(dev, val, CONFIG_TSRD | cid, \
+							CON_CTL_TCM \
+							| CON_BYTE_DISABLE_2 \
+							| CON_BYTE_DISABLE_1 \
+							| CON_BYTE_DISABLE_0)
+
+/* 2.7.1 per connection receive state registers */
+
+#define he_writel_rsr0(dev, val, cid) \
+		he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 0)
+#define he_readl_rsr0(dev, cid) \
+		he_readl_rcm(dev, 0x00000 | (cid<<3) | 0)
+
+#define he_writel_rsr1(dev, val, cid) \
+		he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 1)
+
+#define he_writel_rsr2(dev, val, cid) \
+		he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 2)
+
+#define he_writel_rsr3(dev, val, cid) \
+		he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 3)
+
+#define he_writel_rsr4(dev, val, cid) \
+		he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 4)
+
+#define he_writel_rsr5(dev, val, cid) \
+		he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 5)
+
+#define he_writel_rsr6(dev, val, cid) \
+		he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 6)
+
+#define he_writel_rsr7(dev, val, cid) \
+		he_writel_rcm(dev, val, 0x00000 | (cid<<3) | 7)
+
+static __inline__ struct atm_vcc*
+he_find_vcc(struct he_dev *he_dev, unsigned cid)
+{
+	unsigned long flags;
+	struct atm_vcc *vcc;
+	short vpi;
+	int vci;
+
+	vpi = cid >> he_dev->vcibits;
+	vci = cid & ((1<<he_dev->vcibits)-1);
+
+	spin_lock_irqsave(&he_dev->atm_dev->lock, flags);
+	for (vcc = he_dev->atm_dev->vccs; vcc; vcc = vcc->next)
+		if (vcc->vci == vci && vcc->vpi == vpi
+			&& vcc->qos.rxtp.traffic_class != ATM_NONE) {
+				spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+				return vcc;
+			}
+
+	spin_unlock_irqrestore(&he_dev->atm_dev->lock, flags);
+	return NULL;
+}
+
+static int __devinit
+he_init_one(struct pci_dev *pci_dev, const struct pci_device_id *pci_ent)
+{
+	struct atm_dev *atm_dev = NULL;
+	struct he_dev *he_dev = NULL;
+	int err = 0;
+
+	printk(KERN_INFO "he: %s\n", version);
+
+	if (pci_enable_device(pci_dev)) return -EIO;
+	if (pci_set_dma_mask(pci_dev, HE_DMA_MASK) != 0) {
+		printk(KERN_WARNING "he: no suitable dma available\n");
+		err = -EIO;
+		goto init_one_failure;
+	}
+
+	atm_dev = atm_dev_register(DEV_LABEL, &he_ops, -1, 0);
+	if (!atm_dev) {
+		err = -ENODEV;
+		goto init_one_failure;
+	}
+	pci_set_drvdata(pci_dev, atm_dev);
+
+	he_dev = (struct he_dev *) kmalloc(sizeof(struct he_dev),
+							GFP_KERNEL);
+	if (!he_dev) {
+		err = -ENOMEM;
+		goto init_one_failure;
+	}
+	memset(he_dev, 0, sizeof(struct he_dev));
+
+	he_dev->pci_dev = pci_dev;
+	he_dev->atm_dev = atm_dev;
+	he_dev->atm_dev->dev_data = he_dev;
+	HE_DEV(atm_dev) = he_dev;
+	he_dev->number = atm_dev->number;
+	if (he_start(atm_dev)) {
+		he_stop(he_dev);
+		err = -ENODEV;
+		goto init_one_failure;
+	}
+	he_dev->next = NULL;
+	if (he_devs) he_dev->next = he_devs;
+	he_devs = he_dev;
+	return 0;
+
+init_one_failure:
+	if (atm_dev)
+		atm_dev_deregister(atm_dev);
+	if (he_dev)
+		kfree(he_dev);
+	pci_disable_device(pci_dev);
+	return err;
+}
+
+static void __devexit
+he_remove_one (struct pci_dev *pci_dev)
+{
+	struct atm_dev *atm_dev;
+	struct he_dev *he_dev;
+
+	atm_dev = pci_get_drvdata(pci_dev);
+	he_dev = HE_DEV(atm_dev);
+
+	/* need to remove from he_devs */
+
+	he_stop(he_dev);
+	atm_dev_deregister(atm_dev);
+	kfree(he_dev);
+
+	pci_set_drvdata(pci_dev, NULL);
+	pci_disable_device(pci_dev);
+}
+
+
+static unsigned
+rate_to_atmf(unsigned rate)		/* cps to atm forum format */
+{
+#define NONZERO (1<<14)
+
+        unsigned exp = 0;
+
+        if (rate == 0) return(0);
+
+        rate <<= 9;
+        while (rate > 0x3ff)
+        {
+                ++exp;
+                rate >>= 1;
+        }
+
+        return (NONZERO | (exp << 9) | (rate & 0x1ff));
+}
+
+static void __init
+he_init_rx_lbfp0(struct he_dev *he_dev)
+{
+        unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
+        unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
+        unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD;
+        unsigned row_offset = he_dev->r0_startrow * he_dev->bytes_per_row;
+        
+	lbufd_index = 0;
+        lbm_offset = he_readl(he_dev, RCMLBM_BA);
+
+	he_writel(he_dev, lbufd_index, RLBF0_H);
+
+        for (i = 0, lbuf_count = 0; i < he_dev->r0_numbuffs; ++i)
+        {
+		lbufd_index += 2;
+                lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32;
+
+		he_writel_rcm(he_dev, lbuf_addr, lbm_offset);
+		he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1);
+
+                if (++lbuf_count == lbufs_per_row)
+                {
+                        lbuf_count = 0;
+                        row_offset += he_dev->bytes_per_row;
+                }
+		lbm_offset += 4;
+        }
+                
+        he_writel(he_dev, lbufd_index - 2, RLBF0_T);
+	he_writel(he_dev, he_dev->r0_numbuffs, RLBF0_C);
+}
+
+static void __init
+he_init_rx_lbfp1(struct he_dev *he_dev)
+{
+        unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
+        unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
+        unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD;
+        unsigned row_offset = he_dev->r1_startrow * he_dev->bytes_per_row;
+        
+	lbufd_index = 1;
+        lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index);
+
+	he_writel(he_dev, lbufd_index, RLBF1_H);
+
+        for (i = 0, lbuf_count = 0; i < he_dev->r1_numbuffs; ++i)
+        {
+		lbufd_index += 2;
+                lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32;
+
+		he_writel_rcm(he_dev, lbuf_addr, lbm_offset);
+		he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1);
+
+                if (++lbuf_count == lbufs_per_row)
+                {
+                        lbuf_count = 0;
+                        row_offset += he_dev->bytes_per_row;
+                }
+		lbm_offset += 4;
+        }
+                
+        he_writel(he_dev, lbufd_index - 2, RLBF1_T);
+	he_writel(he_dev, he_dev->r1_numbuffs, RLBF1_C);
+}
+
+static void __init
+he_init_tx_lbfp(struct he_dev *he_dev)
+{
+        unsigned i, lbm_offset, lbufd_index, lbuf_addr, lbuf_count;
+        unsigned lbufs_per_row = he_dev->cells_per_row / he_dev->cells_per_lbuf;
+        unsigned lbuf_bufsize = he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD;
+        unsigned row_offset = he_dev->tx_startrow * he_dev->bytes_per_row;
+        
+	lbufd_index = he_dev->r0_numbuffs + he_dev->r1_numbuffs;
+        lbm_offset = he_readl(he_dev, RCMLBM_BA) + (2 * lbufd_index);
+
+	he_writel(he_dev, lbufd_index, TLBF_H);
+
+        for (i = 0, lbuf_count = 0; i < he_dev->tx_numbuffs; ++i)
+        {
+		lbufd_index += 1;
+                lbuf_addr = (row_offset + (lbuf_count * lbuf_bufsize)) / 32;
+
+		he_writel_rcm(he_dev, lbuf_addr, lbm_offset);
+		he_writel_rcm(he_dev, lbufd_index, lbm_offset + 1);
+
+                if (++lbuf_count == lbufs_per_row)
+                {
+                        lbuf_count = 0;
+                        row_offset += he_dev->bytes_per_row;
+                }
+		lbm_offset += 2;
+        }
+                
+        he_writel(he_dev, lbufd_index - 1, TLBF_T);
+}
+
+static int __init
+he_init_tpdrq(struct he_dev *he_dev)
+{
+	he_dev->tpdrq_base = pci_alloc_consistent(he_dev->pci_dev,
+		CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq), &he_dev->tpdrq_phys);
+	if (he_dev->tpdrq_base == NULL) 
+	{
+		hprintk("failed to alloc tpdrq\n");
+		return -ENOMEM;
+	}
+	memset(he_dev->tpdrq_base, 0,
+				CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq));
+
+	he_dev->tpdrq_tail = he_dev->tpdrq_base;
+	he_dev->tpdrq_head = he_dev->tpdrq_base;
+
+	he_writel(he_dev, he_dev->tpdrq_phys, TPDRQ_B_H);
+	he_writel(he_dev, 0, TPDRQ_T);	
+	he_writel(he_dev, CONFIG_TPDRQ_SIZE - 1, TPDRQ_S);
+
+	return 0;
+}
+
+static void __init
+he_init_cs_block(struct he_dev *he_dev)
+{
+	unsigned clock, rate, delta;
+	int reg;
+
+	/* 5.1.7 cs block initialization */
+
+	for(reg = 0; reg < 0x20; ++reg)
+		he_writel_mbox(he_dev, 0x0, CS_STTIM0 + reg);
+
+	/* rate grid timer reload values */
+
+	clock = he_is622(he_dev) ? 66667000 : 50000000;
+	rate = he_dev->atm_dev->link_rate;
+	delta = rate / 16 / 2;
+
+	for(reg = 0; reg < 0x10; ++reg)
+	{
+		/* 2.4 internal transmit function
+		 *
+	 	 * we initialize the first row in the rate grid.
+		 * values are period (in clock cycles) of timer
+		 */
+		unsigned period = clock / rate;
+
+		he_writel_mbox(he_dev, period, CS_TGRLD0 + reg);
+		rate -= delta;
+	}
+
+	if (he_is622(he_dev))
+	{
+		/* table 5.2 (4 cells per lbuf) */
+		he_writel_mbox(he_dev, 0x000800fa, CS_ERTHR0);
+		he_writel_mbox(he_dev, 0x000c33cb, CS_ERTHR1);
+		he_writel_mbox(he_dev, 0x0010101b, CS_ERTHR2);
+		he_writel_mbox(he_dev, 0x00181dac, CS_ERTHR3);
+		he_writel_mbox(he_dev, 0x00280600, CS_ERTHR4);
+
+		/* table 5.3, 5.4, 5.5, 5.6, 5.7 */
+		he_writel_mbox(he_dev, 0x023de8b3, CS_ERCTL0);
+		he_writel_mbox(he_dev, 0x1801, CS_ERCTL1);
+		he_writel_mbox(he_dev, 0x68b3, CS_ERCTL2);
+		he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0);
+		he_writel_mbox(he_dev, 0x68b3, CS_ERSTAT1);
+		he_writel_mbox(he_dev, 0x14585, CS_RTFWR);
+
+		he_writel_mbox(he_dev, 0x4680, CS_RTATR);
+
+		/* table 5.8 */
+		he_writel_mbox(he_dev, 0x00159ece, CS_TFBSET);
+		he_writel_mbox(he_dev, 0x68b3, CS_WCRMAX);
+		he_writel_mbox(he_dev, 0x5eb3, CS_WCRMIN);
+		he_writel_mbox(he_dev, 0xe8b3, CS_WCRINC);
+		he_writel_mbox(he_dev, 0xdeb3, CS_WCRDEC);
+		he_writel_mbox(he_dev, 0x68b3, CS_WCRCEIL);
+
+		/* table 5.9 */
+		he_writel_mbox(he_dev, 0x5, CS_OTPPER);
+		he_writel_mbox(he_dev, 0x14, CS_OTWPER);
+	}
+	else
+	{
+		/* table 5.1 (4 cells per lbuf) */
+		he_writel_mbox(he_dev, 0x000400ea, CS_ERTHR0);
+		he_writel_mbox(he_dev, 0x00063388, CS_ERTHR1);
+		he_writel_mbox(he_dev, 0x00081018, CS_ERTHR2);
+		he_writel_mbox(he_dev, 0x000c1dac, CS_ERTHR3);
+		he_writel_mbox(he_dev, 0x0014051a, CS_ERTHR4);
+
+		/* table 5.3, 5.4, 5.5, 5.6, 5.7 */
+		he_writel_mbox(he_dev, 0x0235e4b1, CS_ERCTL0);
+		he_writel_mbox(he_dev, 0x4701, CS_ERCTL1);
+		he_writel_mbox(he_dev, 0x64b1, CS_ERCTL2);
+		he_writel_mbox(he_dev, 0x1280, CS_ERSTAT0);
+		he_writel_mbox(he_dev, 0x64b1, CS_ERSTAT1);
+		he_writel_mbox(he_dev, 0xf424, CS_RTFWR);
+
+		he_writel_mbox(he_dev, 0x4680, CS_RTATR);
+
+		/* table 5.8 */
+		he_writel_mbox(he_dev, 0x000563b7, CS_TFBSET);
+		he_writel_mbox(he_dev, 0x64b1, CS_WCRMAX);
+		he_writel_mbox(he_dev, 0x5ab1, CS_WCRMIN);
+		he_writel_mbox(he_dev, 0xe4b1, CS_WCRINC);
+		he_writel_mbox(he_dev, 0xdab1, CS_WCRDEC);
+		he_writel_mbox(he_dev, 0x64b1, CS_WCRCEIL);
+
+		/* table 5.9 */
+		he_writel_mbox(he_dev, 0x6, CS_OTPPER);
+		he_writel_mbox(he_dev, 0x1e, CS_OTWPER);
+
+	}
+
+	he_writel_mbox(he_dev, 0x8, CS_OTTLIM);
+
+	for(reg = 0; reg < 0x8; ++reg)
+		he_writel_mbox(he_dev, 0x0, CS_HGRRT0 + reg);
+
+}
+
+static void __init
+he_init_cs_block_rcm(struct he_dev *he_dev)
+{
+	unsigned rategrid[16][16];
+	unsigned rate, delta;
+	int i, j, reg;
+
+	unsigned rate_atmf, exp, man;
+	unsigned long long rate_cps;
+        int mult, buf, buf_limit = 4;
+
+	/* initialize rate grid group table */
+
+	for (reg = 0x0; reg < 0xff; ++reg)
+		he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg);
+
+	/* initialize rate controller groups */
+
+	for (reg = 0x100; reg < 0x1ff; ++reg)
+		he_writel_rcm(he_dev, 0x0, CONFIG_RCMABR + reg);
+	
+	/* initialize tNrm lookup table */
+
+	/* the manual makes reference to a routine in a sample driver
+	   for proper configuration; fortunately, we only need this
+	   in order to support abr connection */
+	
+	/* initialize rate to group table */
+
+	rate = he_dev->atm_dev->link_rate;
+	delta = rate / 32;
+
+	/*
+	 * 2.4 transmit internal functions
+	 * 
+	 * we construct a copy of the rate grid used by the scheduler
+	 * in order to construct the rate to group table below
+	 */
+
+	for (j = 0; j < 16; j++)
+	{
+		rategrid[0][j] = rate;
+		rate -= delta;
+	}
+
+	for (i = 1; i < 16; i++)
+		for (j = 0; j < 16; j++)
+			if (i > 14)
+				rategrid[i][j] = rategrid[i - 1][j] / 4;
+			else
+				rategrid[i][j] = rategrid[i - 1][j] / 2;
+
+	/*
+	 * 2.4 transmit internal function
+	 *
+	 * this table maps the upper 5 bits of exponent and mantissa
+	 * of the atm forum representation of the rate into an index
+	 * on rate grid  
+	 */
+
+	rate_atmf = 0;
+	while (rate_atmf < 0x400)
+	{
+		man = (rate_atmf & 0x1f) << 4;
+		exp = rate_atmf >> 5;
+
+		/* 
+			instead of '/ 512', use '>> 9' to prevent a call
+			to divdu3 on x86 platforms
+		*/
+		rate_cps = (unsigned long long) (1 << exp) * (man + 512) >> 9;
+
+		if (rate_cps < 10) rate_cps = 10;
+				/* 2.2.1 minimum payload rate is 10 cps */
+
+		for (i = 255; i > 0; i--)
+			if (rategrid[i/16][i%16] >= rate_cps) break;
+				/* pick nearest rate instead? */
+
+		/*
+		 * each table entry is 16 bits: (rate grid index (8 bits)
+		 * and a buffer limit (8 bits)
+		 * there are two table entries in each 32-bit register
+		 */
+
+#ifdef notdef
+                buf = rate_cps * he_dev->tx_numbuffs /
+				(he_dev->atm_dev->link_rate * 2);
+#else
+		/* this is pretty, but avoids _divdu3 and is mostly correct */
+                buf = 0;
+                mult = he_dev->atm_dev->link_rate / ATM_OC3_PCR;
+                if (rate_cps > (68 * mult)) buf = 1;
+                if (rate_cps > (136 * mult)) buf = 2;
+                if (rate_cps > (204 * mult)) buf = 3;
+                if (rate_cps > (272 * mult)) buf = 4;
+#endif
+                if (buf > buf_limit) buf = buf_limit;
+		reg = (reg<<16) | ((i<<8) | buf);
+
+#define RTGTBL_OFFSET 0x400
+	  
+		if (rate_atmf & 0x1)
+			he_writel_rcm(he_dev, reg,
+				CONFIG_RCMABR + RTGTBL_OFFSET + (rate_atmf>>1));
+
+		++rate_atmf;
+	}
+}
+
+static int __init
+he_init_group(struct he_dev *he_dev, int group)
+{
+	int i;
+
+#ifdef USE_RBPS
+	/* small buffer pool */
+#ifdef USE_RBPS_POOL
+	he_dev->rbps_pool = pci_pool_create("rbps", he_dev->pci_dev,
+			CONFIG_RBPS_BUFSIZE, 8, 0);
+	if (he_dev->rbps_pool == NULL)
+	{
+		hprintk("unable to create rbps pages\n");
+		return -ENOMEM;
+	}
+#else /* !USE_RBPS_POOL */
+	he_dev->rbps_pages = pci_alloc_consistent(he_dev->pci_dev,
+		CONFIG_RBPS_SIZE * CONFIG_RBPS_BUFSIZE, &he_dev->rbps_pages_phys);
+	if (he_dev->rbps_pages == NULL) {
+		hprintk("unable to create rbps page pool\n");
+		return -ENOMEM;
+	}
+#endif /* USE_RBPS_POOL */
+
+	he_dev->rbps_base = pci_alloc_consistent(he_dev->pci_dev,
+		CONFIG_RBPS_SIZE * sizeof(struct he_rbp), &he_dev->rbps_phys);
+	if (he_dev->rbps_base == NULL)
+	{
+		hprintk("failed to alloc rbps\n");
+		return -ENOMEM;
+	}
+	memset(he_dev->rbps_base, 0, CONFIG_RBPS_SIZE * sizeof(struct he_rbp));
+	he_dev->rbps_virt = kmalloc(CONFIG_RBPS_SIZE * sizeof(struct he_virt), GFP_KERNEL);
+
+	for (i = 0; i < CONFIG_RBPS_SIZE; ++i)
+	{
+		dma_addr_t dma_handle;
+		void *cpuaddr;
+
+#ifdef USE_RBPS_POOL 
+		cpuaddr = pci_pool_alloc(he_dev->rbps_pool, SLAB_KERNEL|SLAB_DMA, &dma_handle);
+		if (cpuaddr == NULL)
+			return -ENOMEM;
+#else
+		cpuaddr = he_dev->rbps_pages + (i * CONFIG_RBPS_BUFSIZE);
+		dma_handle = he_dev->rbps_pages_phys + (i * CONFIG_RBPS_BUFSIZE);
+#endif
+
+		he_dev->rbps_virt[i].virt = cpuaddr;
+		he_dev->rbps_base[i].status = RBP_LOANED | RBP_SMALLBUF | (i << RBP_INDEX_OFF);
+		he_dev->rbps_base[i].phys = dma_handle;
+
+	}
+	he_dev->rbps_tail = &he_dev->rbps_base[CONFIG_RBPS_SIZE-1];
+
+	he_writel(he_dev, he_dev->rbps_phys, G0_RBPS_S + (group * 32));
+	he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail),
+						G0_RBPS_T + (group * 32));
+	he_writel(he_dev, CONFIG_RBPS_BUFSIZE/4,
+						G0_RBPS_BS + (group * 32));
+	he_writel(he_dev,
+			RBP_THRESH(CONFIG_RBPS_THRESH) |
+			RBP_QSIZE(CONFIG_RBPS_SIZE-1) |
+			RBP_INT_ENB,
+						G0_RBPS_QI + (group * 32));
+#else /* !USE_RBPS */
+	he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32));
+	he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32));
+	he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32));
+	he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0),
+						G0_RBPS_BS + (group * 32));
+#endif /* USE_RBPS */
+
+	/* large buffer pool */
+#ifdef USE_RBPL_POOL
+	he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev,
+			CONFIG_RBPL_BUFSIZE, 8, 0);
+	if (he_dev->rbpl_pool == NULL)
+	{
+		hprintk("unable to create rbpl pool\n");
+		return -ENOMEM;
+	}
+#else /* !USE_RBPL_POOL */
+	he_dev->rbpl_pages = (void *) pci_alloc_consistent(he_dev->pci_dev,
+		CONFIG_RBPL_SIZE * CONFIG_RBPL_BUFSIZE, &he_dev->rbpl_pages_phys);
+	if (he_dev->rbpl_pages == NULL)
+	{
+		hprintk("unable to create rbpl pages\n");
+		return -ENOMEM;
+	}
+#endif /* USE_RBPL_POOL */
+
+	he_dev->rbpl_base = pci_alloc_consistent(he_dev->pci_dev,
+		CONFIG_RBPL_SIZE * sizeof(struct he_rbp), &he_dev->rbpl_phys);
+	if (he_dev->rbpl_base == NULL)
+	{
+		hprintk("failed to alloc rbpl\n");
+		return -ENOMEM;
+	}
+	memset(he_dev->rbpl_base, 0, CONFIG_RBPL_SIZE * sizeof(struct he_rbp));
+	he_dev->rbpl_virt = kmalloc(CONFIG_RBPL_SIZE * sizeof(struct he_virt), GFP_KERNEL);
+
+	for (i = 0; i < CONFIG_RBPL_SIZE; ++i)
+	{
+		dma_addr_t dma_handle;
+		void *cpuaddr;
+
+#ifdef USE_RBPL_POOL
+		cpuaddr = pci_pool_alloc(he_dev->rbpl_pool, SLAB_KERNEL|SLAB_DMA, &dma_handle);
+		if (cpuaddr == NULL)
+			return -ENOMEM;
+#else
+		cpuaddr = he_dev->rbpl_pages + (i * CONFIG_RBPL_BUFSIZE);
+		dma_handle = he_dev->rbpl_pages_phys + (i * CONFIG_RBPL_BUFSIZE);
+#endif
+
+		he_dev->rbpl_virt[i].virt = cpuaddr;
+		he_dev->rbpl_base[i].status = RBP_LOANED | (i << RBP_INDEX_OFF);
+		he_dev->rbpl_base[i].phys = dma_handle;
+
+	}
+	he_dev->rbpl_tail = &he_dev->rbpl_base[CONFIG_RBPL_SIZE-1];
+
+	he_writel(he_dev, he_dev->rbpl_phys, G0_RBPL_S + (group * 32));
+	he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail),
+						G0_RBPL_T + (group * 32));
+	he_writel(he_dev, CONFIG_RBPL_BUFSIZE/4,
+						G0_RBPL_BS + (group * 32));
+	he_writel(he_dev,
+			RBP_THRESH(CONFIG_RBPL_THRESH) |
+			RBP_QSIZE(CONFIG_RBPL_SIZE-1) |
+			RBP_INT_ENB,
+						G0_RBPL_QI + (group * 32));
+
+	/* rx buffer ready queue */
+
+	he_dev->rbrq_base = pci_alloc_consistent(he_dev->pci_dev,
+		CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq), &he_dev->rbrq_phys);
+	if (he_dev->rbrq_base == NULL)
+	{
+		hprintk("failed to allocate rbrq\n");
+		return -ENOMEM;
+	}
+	memset(he_dev->rbrq_base, 0, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq));
+
+	he_dev->rbrq_head = he_dev->rbrq_base;
+	he_writel(he_dev, he_dev->rbrq_phys, G0_RBRQ_ST + (group * 16));
+	he_writel(he_dev, 0, G0_RBRQ_H + (group * 16));
+	he_writel(he_dev,
+		RBRQ_THRESH(CONFIG_RBRQ_THRESH) | RBRQ_SIZE(CONFIG_RBRQ_SIZE-1),
+						G0_RBRQ_Q + (group * 16));
+	if (irq_coalesce)
+	{
+		hprintk("coalescing interrupts\n");
+		he_writel(he_dev, RBRQ_TIME(768) | RBRQ_COUNT(7),
+						G0_RBRQ_I + (group * 16));
+	}
+	else
+		he_writel(he_dev, RBRQ_TIME(0) | RBRQ_COUNT(1),
+						G0_RBRQ_I + (group * 16));
+
+	/* tx buffer ready queue */
+
+	he_dev->tbrq_base = pci_alloc_consistent(he_dev->pci_dev,
+		CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq), &he_dev->tbrq_phys);
+	if (he_dev->tbrq_base == NULL)
+	{
+		hprintk("failed to allocate tbrq\n");
+		return -ENOMEM;
+	}
+	memset(he_dev->tbrq_base, 0, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq));
+
+	he_dev->tbrq_head = he_dev->tbrq_base;
+
+	he_writel(he_dev, he_dev->tbrq_phys, G0_TBRQ_B_T + (group * 16));
+	he_writel(he_dev, 0, G0_TBRQ_H + (group * 16));
+	he_writel(he_dev, CONFIG_TBRQ_SIZE - 1, G0_TBRQ_S + (group * 16));
+	he_writel(he_dev, CONFIG_TBRQ_THRESH, G0_TBRQ_THRESH + (group * 16));
+
+	return 0;
+}
+
+static int __init
+he_init_irq(struct he_dev *he_dev)
+{
+	int i;
+
+	/* 2.9.3.5  tail offset for each interrupt queue is located after the
+		    end of the interrupt queue */
+
+        he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev,
+			(CONFIG_IRQ_SIZE+1) * sizeof(struct he_irq), &he_dev->irq_phys);
+	if (he_dev->irq_base == NULL)
+	{
+		hprintk("failed to allocate irq\n");
+		return -ENOMEM;
+	}
+	he_dev->irq_tailoffset = (unsigned *)
+					&he_dev->irq_base[CONFIG_IRQ_SIZE];
+	*he_dev->irq_tailoffset = 0;
+	he_dev->irq_head = he_dev->irq_base;
+	he_dev->irq_tail = he_dev->irq_base;
+
+	for(i=0; i < CONFIG_IRQ_SIZE; ++i)
+		he_dev->irq_base[i].isw = ITYPE_INVALID;
+
+	he_writel(he_dev, he_dev->irq_phys, IRQ0_BASE);
+	he_writel(he_dev,
+		IRQ_SIZE(CONFIG_IRQ_SIZE) | IRQ_THRESH(CONFIG_IRQ_THRESH),
+								IRQ0_HEAD);
+	he_writel(he_dev, IRQ_INT_A | IRQ_TYPE_LINE, IRQ0_CNTL);
+	he_writel(he_dev, 0x0, IRQ0_DATA);
+
+	he_writel(he_dev, 0x0, IRQ1_BASE);
+	he_writel(he_dev, 0x0, IRQ1_HEAD);
+	he_writel(he_dev, 0x0, IRQ1_CNTL);
+	he_writel(he_dev, 0x0, IRQ1_DATA);
+
+	he_writel(he_dev, 0x0, IRQ2_BASE);
+	he_writel(he_dev, 0x0, IRQ2_HEAD);
+	he_writel(he_dev, 0x0, IRQ2_CNTL);
+	he_writel(he_dev, 0x0, IRQ2_DATA);
+
+	he_writel(he_dev, 0x0, IRQ3_BASE);
+	he_writel(he_dev, 0x0, IRQ3_HEAD);
+	he_writel(he_dev, 0x0, IRQ3_CNTL);
+	he_writel(he_dev, 0x0, IRQ3_DATA);
+
+	/* 2.9.3.2 interrupt queue mapping registers */
+
+	he_writel(he_dev, 0x0, GRP_10_MAP);
+	he_writel(he_dev, 0x0, GRP_32_MAP);
+	he_writel(he_dev, 0x0, GRP_54_MAP);
+	he_writel(he_dev, 0x0, GRP_76_MAP);
+
+	if (request_irq(he_dev->pci_dev->irq, he_irq_handler, SA_INTERRUPT|SA_SHIRQ, DEV_LABEL, he_dev))
+	{
+		hprintk("irq %d already in use\n", he_dev->pci_dev->irq);
+		return -EINVAL;
+        }   
+
+	he_dev->irq = he_dev->pci_dev->irq;
+
+#ifdef BUS_INT_WAR
+        HPRINTK("sn_add_polled_interrupt(irq %d, 1)\n", he_dev->irq);
+        sn_add_polled_interrupt(he_dev->irq, 1);
+#endif
+
+	return 0;
+}
+
+static int __init
+he_start(struct atm_dev *dev)
+{
+        struct he_dev *he_dev;
+        struct pci_dev *pci_dev;
+
+	u16 command;
+	u32 gen_cntl_0, host_cntl, lb_swap;
+	u8 cache_size, timer;
+	
+	unsigned err;
+	unsigned int status, reg;
+	int i, group;
+
+        he_dev = HE_DEV(dev);
+        pci_dev = he_dev->pci_dev;
+
+	he_dev->membase = pci_dev->resource[0].start;
+	HPRINTK("membase = 0x%lx  irq = %d.\n", he_dev->membase, pci_dev->irq);
+
+	/*
+	 * pci bus controller initialization 
+	 */
+
+	/* 4.3 pci bus controller-specific initialization */
+	if (pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0) != 0)
+	{
+		hprintk("can't read GEN_CNTL_0\n");
+		return -EINVAL;
+	}
+	gen_cntl_0 |= (MRL_ENB | MRM_ENB | IGNORE_TIMEOUT);
+	if (pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0) != 0)
+	{
+		hprintk("can't write GEN_CNTL_0.\n");
+		return -EINVAL;
+	}
+
+	if (pci_read_config_word(pci_dev, PCI_COMMAND, &command) != 0)
+	{
+		hprintk("can't read PCI_COMMAND.\n");
+		return -EINVAL;
+	}
+
+	command |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE);
+	if (pci_write_config_word(pci_dev, PCI_COMMAND, command) != 0)
+	{
+		hprintk("can't enable memory.\n");
+		return -EINVAL;
+	}
+
+	if (pci_read_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, &cache_size))
+	{
+		hprintk("can't read cache line size?\n");
+		return -EINVAL;
+	}
+
+	if (cache_size < 16)
+	{
+		cache_size = 16;
+		if (pci_write_config_byte(pci_dev, PCI_CACHE_LINE_SIZE, cache_size))
+			hprintk("can't set cache line size to %d\n", cache_size);
+	}
+
+	if (pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER, &timer))
+	{
+		hprintk("can't read latency timer?\n");
+		return -EINVAL;
+	}
+
+	/* from table 3.9
+	 *
+	 * LAT_TIMER = 1 + AVG_LAT + BURST_SIZE/BUS_SIZE
+	 * 
+	 * AVG_LAT: The average first data read/write latency [maximum 16 clock cycles]
+	 * BURST_SIZE: 1536 bytes (read) for 622, 768 bytes (read) for 155 [192 clock cycles]
+	 *
+	 */ 
+#define LAT_TIMER 209
+	if (timer < LAT_TIMER)
+	{
+		HPRINTK("latency timer was %d, setting to %d\n", timer, LAT_TIMER);
+		timer = LAT_TIMER;
+		if (pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, timer))
+			hprintk("can't set latency timer to %d\n", timer);
+	}
+
+	if (!(he_dev->membase = (unsigned long) ioremap(he_dev->membase, HE_REGMAP_SIZE))) {
+		hprintk("can't set up page mapping\n");
+		return -EINVAL;
+	}
+	      
+	/* 4.4 card reset */
+	he_writel(he_dev, 0x0, RESET_CNTL);
+	he_writel(he_dev, 0xff, RESET_CNTL);
+
+	udelay(16*1000);	/* 16 ms */
+	status = he_readl(he_dev, RESET_CNTL);
+	if ((status & BOARD_RST_STATUS) == 0)
+	{
+		hprintk("reset failed\n");
+		return -EINVAL;
+	}
+
+	/* 4.5 set bus width */
+	host_cntl = he_readl(he_dev, HOST_CNTL);
+	if (host_cntl & PCI_BUS_SIZE64)
+		gen_cntl_0 |= ENBL_64;
+	else
+		gen_cntl_0 &= ~ENBL_64;
+
+	if (disable64 == 1)
+	{
+		hprintk("disabling 64-bit pci bus transfers\n");
+		gen_cntl_0 &= ~ENBL_64;
+	}
+
+	if (gen_cntl_0 & ENBL_64) hprintk("64-bit transfers enabled\n");
+
+	pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0);
+
+	/* 4.7 read prom contents */
+	for(i=0; i<PROD_ID_LEN; ++i)
+		he_dev->prod_id[i] = read_prom_byte(he_dev, PROD_ID + i);
+
+	he_dev->media = read_prom_byte(he_dev, MEDIA);
+
+	for(i=0; i<6; ++i)
+		dev->esi[i] = read_prom_byte(he_dev, MAC_ADDR + i);
+
+	hprintk("%s%s, %x:%x:%x:%x:%x:%x\n",
+				he_dev->prod_id,
+					he_dev->media & 0x40 ? "SM" : "MM",
+						dev->esi[0],
+						dev->esi[1],
+						dev->esi[2],
+						dev->esi[3],
+						dev->esi[4],
+						dev->esi[5]);
+	he_dev->atm_dev->link_rate = he_is622(he_dev) ?
+						ATM_OC12_PCR : ATM_OC3_PCR;
+
+	/* 4.6 set host endianess */
+	lb_swap = he_readl(he_dev, LB_SWAP);
+	if (he_is622(he_dev))
+		lb_swap &= ~XFER_SIZE;		/* 4 cells */
+	else
+		lb_swap |= XFER_SIZE;		/* 8 cells */
+#ifdef __BIG_ENDIAN
+	lb_swap |= DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST;
+#else
+	lb_swap &= ~(DESC_WR_SWAP | INTR_SWAP | BIG_ENDIAN_HOST |
+			DATA_WR_SWAP | DATA_RD_SWAP | DESC_RD_SWAP);
+#endif /* __BIG_ENDIAN */
+	he_writel(he_dev, lb_swap, LB_SWAP);
+
+	/* 4.8 sdram controller initialization */
+	he_writel(he_dev, he_is622(he_dev) ? LB_64_ENB : 0x0, SDRAM_CTL);
+
+	/* 4.9 initialize rnum value */
+	lb_swap |= SWAP_RNUM_MAX(0xf);
+	he_writel(he_dev, lb_swap, LB_SWAP);
+
+	/* 4.10 initialize the interrupt queues */
+	if ((err = he_init_irq(he_dev)) != 0) return err;
+
+#ifdef USE_TASKLET
+	tasklet_init(&he_dev->tasklet, he_tasklet, (unsigned long) he_dev);
+#endif
+	spin_lock_init(&he_dev->global_lock);
+
+	/* 4.11 enable pci bus controller state machines */
+	host_cntl |= (OUTFF_ENB | CMDFF_ENB |
+				QUICK_RD_RETRY | QUICK_WR_RETRY | PERR_INT_ENB);
+	he_writel(he_dev, host_cntl, HOST_CNTL);
+
+	gen_cntl_0 |= INT_PROC_ENBL|INIT_ENB;
+	pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0);
+
+	/*
+	 * atm network controller initialization
+	 */
+
+	/* 5.1.1 generic configuration state */
+
+	/*
+	 *		local (cell) buffer memory map
+	 *                    
+	 *             HE155                          HE622
+	 *                                                      
+	 *        0 ____________1023 bytes  0 _______________________2047 bytes
+	 *         |            |            |                   |   |
+	 *         |  utility   |            |        rx0        |   |
+	 *        5|____________|         255|___________________| u |
+	 *        6|            |         256|                   | t |
+	 *         |            |            |                   | i |
+	 *         |    rx0     |     row    |        tx         | l |
+	 *         |            |            |                   | i |
+	 *         |            |         767|___________________| t |
+	 *      517|____________|         768|                   | y |
+	 * row  518|            |            |        rx1        |   |
+	 *         |            |        1023|___________________|___|
+	 *         |            |
+	 *         |    tx      |
+	 *         |            |
+	 *         |            |
+	 *     1535|____________|
+	 *     1536|            |
+	 *         |    rx1     |
+	 *     2047|____________|
+	 *
+	 */
+
+	/* total 4096 connections */
+	he_dev->vcibits = CONFIG_DEFAULT_VCIBITS;
+	he_dev->vpibits = CONFIG_DEFAULT_VPIBITS;
+
+	if (nvpibits != -1 && nvcibits != -1 && nvpibits+nvcibits != HE_MAXCIDBITS)
+	{
+		hprintk("nvpibits + nvcibits != %d\n", HE_MAXCIDBITS);
+		return -ENODEV;
+	}
+
+	if (nvpibits != -1)
+	{
+		he_dev->vpibits = nvpibits;
+		he_dev->vcibits = HE_MAXCIDBITS - nvpibits;
+	}
+
+	if (nvcibits != -1)
+	{
+		he_dev->vcibits = nvcibits;
+		he_dev->vpibits = HE_MAXCIDBITS - nvcibits;
+	}
+
+
+	if (he_is622(he_dev))
+	{
+		he_dev->cells_per_row = 40;
+		he_dev->bytes_per_row = 2048;
+		he_dev->r0_numrows = 256;
+		he_dev->tx_numrows = 512;
+		he_dev->r1_numrows = 256;
+		he_dev->r0_startrow = 0;
+		he_dev->tx_startrow = 256;
+		he_dev->r1_startrow = 768;
+	}
+	else
+	{
+		he_dev->cells_per_row = 20;
+		he_dev->bytes_per_row = 1024;
+		he_dev->r0_numrows = 512;
+		he_dev->tx_numrows = 1018;
+		he_dev->r1_numrows = 512;
+		he_dev->r0_startrow = 6;
+		he_dev->tx_startrow = 518;
+		he_dev->r1_startrow = 1536;
+	}
+
+	he_dev->cells_per_lbuf = 4;
+	he_dev->buffer_limit = 4;
+	he_dev->r0_numbuffs = he_dev->r0_numrows *
+				he_dev->cells_per_row / he_dev->cells_per_lbuf;
+	if (he_dev->r0_numbuffs > 2560) he_dev->r0_numbuffs = 2560;
+
+	he_dev->r1_numbuffs = he_dev->r1_numrows *
+				he_dev->cells_per_row / he_dev->cells_per_lbuf;
+	if (he_dev->r1_numbuffs > 2560) he_dev->r1_numbuffs = 2560;
+
+	he_dev->tx_numbuffs = he_dev->tx_numrows *
+				he_dev->cells_per_row / he_dev->cells_per_lbuf;
+	if (he_dev->tx_numbuffs > 5120) he_dev->tx_numbuffs = 5120;
+
+	/* 5.1.2 configure hardware dependent registers */
+
+	he_writel(he_dev, 
+		SLICE_X(0x2) | ARB_RNUM_MAX(0xf) | TH_PRTY(0x3) |
+		RH_PRTY(0x3) | TL_PRTY(0x2) | RL_PRTY(0x1) |
+		(he_is622(he_dev) ? BUS_MULTI(0x28) : BUS_MULTI(0x46)) |
+		(he_is622(he_dev) ? NET_PREF(0x50) : NET_PREF(0x8c)),
+								LBARB);
+
+	he_writel(he_dev, BANK_ON |
+		(he_is622(he_dev) ? (REF_RATE(0x384) | WIDE_DATA) : REF_RATE(0x150)),
+								SDRAMCON);
+
+	he_writel(he_dev,
+		(he_is622(he_dev) ? RM_BANK_WAIT(1) : RM_BANK_WAIT(0)) |
+						RM_RW_WAIT(1), RCMCONFIG);
+	he_writel(he_dev,
+		(he_is622(he_dev) ? TM_BANK_WAIT(2) : TM_BANK_WAIT(1)) |
+						TM_RW_WAIT(1), TCMCONFIG);
+
+	he_writel(he_dev, he_dev->cells_per_lbuf * ATM_CELL_PAYLOAD, LB_CONFIG);
+
+	he_writel(he_dev, 
+		(he_is622(he_dev) ? UT_RD_DELAY(8) : UT_RD_DELAY(0)) |
+		(he_is622(he_dev) ? RC_UT_MODE(0) : RC_UT_MODE(1)) |
+		RX_VALVP(he_dev->vpibits) |
+		RX_VALVC(he_dev->vcibits),			 RC_CONFIG);
+
+	he_writel(he_dev, DRF_THRESH(0x20) |
+		(he_is622(he_dev) ? TX_UT_MODE(0) : TX_UT_MODE(1)) |
+		TX_VCI_MASK(he_dev->vcibits) |
+		LBFREE_CNT(he_dev->tx_numbuffs), 		TX_CONFIG);
+
+	he_writel(he_dev, 0x0, TXAAL5_PROTO);
+
+	he_writel(he_dev, PHY_INT_ENB |
+		(he_is622(he_dev) ? PTMR_PRE(67-1) : PTMR_PRE(50-1)),
+								RH_CONFIG);
+
+	/* 5.1.3 initialize connection memory */
+
+	for(i=0; i < TCM_MEM_SIZE; ++i)
+		he_writel_tcm(he_dev, 0, i);
+
+	for(i=0; i < RCM_MEM_SIZE; ++i)
+		he_writel_rcm(he_dev, 0, i);
+
+	/*
+	 *	transmit connection memory map
+	 *
+	 *                  tx memory
+	 *          0x0 ___________________
+	 *             |                   |
+	 *             |                   |
+	 *             |       TSRa        |
+	 *             |                   |
+	 *             |                   |
+	 *       0x8000|___________________|
+	 *             |                   |
+	 *             |       TSRb        |
+	 *       0xc000|___________________|
+	 *             |                   |
+	 *             |       TSRc        |
+	 *       0xe000|___________________|
+	 *             |       TSRd        |
+	 *       0xf000|___________________|
+	 *             |       tmABR       |
+	 *      0x10000|___________________|
+	 *             |                   |
+	 *             |       tmTPD       |
+	 *             |___________________|
+	 *             |                   |
+	 *                      ....
+	 *      0x1ffff|___________________|
+	 *
+	 *
+	 */
+
+	he_writel(he_dev, CONFIG_TSRB, TSRB_BA);
+	he_writel(he_dev, CONFIG_TSRC, TSRC_BA);
+	he_writel(he_dev, CONFIG_TSRD, TSRD_BA);
+	he_writel(he_dev, CONFIG_TMABR, TMABR_BA);
+	he_writel(he_dev, CONFIG_TPDBA, TPD_BA);
+
+
+	/*
+	 *	receive connection memory map
+	 *
+	 *          0x0 ___________________
+	 *             |                   |
+	 *             |                   |
+	 *             |       RSRa        |
+	 *             |                   |
+	 *             |                   |
+	 *       0x8000|___________________|
+	 *             |                   |
+	 *             |             rx0/1 |
+	 *             |       LBM         |   link lists of local
+	 *             |             tx    |   buffer memory 
+	 *             |                   |
+	 *       0xd000|___________________|
+	 *             |                   |
+	 *             |      rmABR        |
+	 *       0xe000|___________________|
+	 *             |                   |
+	 *             |       RSRb        |
+	 *             |___________________|
+	 *             |                   |
+	 *                      ....
+	 *       0xffff|___________________|
+	 */
+
+	he_writel(he_dev, 0x08000, RCMLBM_BA);
+	he_writel(he_dev, 0x0e000, RCMRSRB_BA);
+	he_writel(he_dev, 0x0d800, RCMABR_BA);
+
+	/* 5.1.4 initialize local buffer free pools linked lists */
+
+	he_init_rx_lbfp0(he_dev);
+	he_init_rx_lbfp1(he_dev);
+
+	he_writel(he_dev, 0x0, RLBC_H);
+	he_writel(he_dev, 0x0, RLBC_T);
+	he_writel(he_dev, 0x0, RLBC_H2);
+
+	he_writel(he_dev, 512, RXTHRSH);	/* 10% of r0+r1 buffers */
+	he_writel(he_dev, 256, LITHRSH); 	/* 5% of r0+r1 buffers */
+
+	he_init_tx_lbfp(he_dev);
+
+	he_writel(he_dev, he_is622(he_dev) ? 0x104780 : 0x800, UBUFF_BA);
+
+	/* 5.1.5 initialize intermediate receive queues */
+
+	if (he_is622(he_dev))
+	{
+		he_writel(he_dev, 0x000f, G0_INMQ_S);
+		he_writel(he_dev, 0x200f, G0_INMQ_L);
+
+		he_writel(he_dev, 0x001f, G1_INMQ_S);
+		he_writel(he_dev, 0x201f, G1_INMQ_L);
+
+		he_writel(he_dev, 0x002f, G2_INMQ_S);
+		he_writel(he_dev, 0x202f, G2_INMQ_L);
+
+		he_writel(he_dev, 0x003f, G3_INMQ_S);
+		he_writel(he_dev, 0x203f, G3_INMQ_L);
+
+		he_writel(he_dev, 0x004f, G4_INMQ_S);
+		he_writel(he_dev, 0x204f, G4_INMQ_L);
+
+		he_writel(he_dev, 0x005f, G5_INMQ_S);
+		he_writel(he_dev, 0x205f, G5_INMQ_L);
+
+		he_writel(he_dev, 0x006f, G6_INMQ_S);
+		he_writel(he_dev, 0x206f, G6_INMQ_L);
+
+		he_writel(he_dev, 0x007f, G7_INMQ_S);
+		he_writel(he_dev, 0x207f, G7_INMQ_L);
+	}
+	else
+	{
+		he_writel(he_dev, 0x0000, G0_INMQ_S);
+		he_writel(he_dev, 0x0008, G0_INMQ_L);
+
+		he_writel(he_dev, 0x0001, G1_INMQ_S);
+		he_writel(he_dev, 0x0009, G1_INMQ_L);
+
+		he_writel(he_dev, 0x0002, G2_INMQ_S);
+		he_writel(he_dev, 0x000a, G2_INMQ_L);
+
+		he_writel(he_dev, 0x0003, G3_INMQ_S);
+		he_writel(he_dev, 0x000b, G3_INMQ_L);
+
+		he_writel(he_dev, 0x0004, G4_INMQ_S);
+		he_writel(he_dev, 0x000c, G4_INMQ_L);
+
+		he_writel(he_dev, 0x0005, G5_INMQ_S);
+		he_writel(he_dev, 0x000d, G5_INMQ_L);
+
+		he_writel(he_dev, 0x0006, G6_INMQ_S);
+		he_writel(he_dev, 0x000e, G6_INMQ_L);
+
+		he_writel(he_dev, 0x0007, G7_INMQ_S);
+		he_writel(he_dev, 0x000f, G7_INMQ_L);
+	}
+
+	/* 5.1.6 application tunable parameters */
+
+	he_writel(he_dev, 0x0, MCC);
+	he_writel(he_dev, 0x0, OEC);
+	he_writel(he_dev, 0x0, DCC);
+	he_writel(he_dev, 0x0, CEC);
+	
+	/* 5.1.7 cs block initialization */
+
+	he_init_cs_block(he_dev);
+
+	/* 5.1.8 cs block connection memory initialization */
+	
+	he_init_cs_block_rcm(he_dev);
+
+	/* 5.1.10 initialize host structures */
+
+	he_init_tpdrq(he_dev);
+
+#ifdef USE_TPD_POOL
+	he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev,
+		sizeof(struct he_tpd), TPD_ALIGNMENT, 0);
+	if (he_dev->tpd_pool == NULL)
+	{
+		hprintk("unable to create tpd pci_pool\n");
+		return -ENOMEM;         
+	}
+
+	INIT_LIST_HEAD(&he_dev->outstanding_tpds);
+#else
+	he_dev->tpd_base = (void *) pci_alloc_consistent(he_dev->pci_dev,
+			CONFIG_NUMTPDS * sizeof(struct he_tpd), &he_dev->tpd_base_phys);
+	if (!he_dev->tpd_base)
+		return -ENOMEM;
+
+	for(i = 0; i < CONFIG_NUMTPDS; ++i)
+	{
+		he_dev->tpd_base[i].status = (i << TPD_ADDR_SHIFT);
+		he_dev->tpd_base[i].inuse = 0;
+	}
+		
+	he_dev->tpd_head = he_dev->tpd_base;
+	he_dev->tpd_end = &he_dev->tpd_base[CONFIG_NUMTPDS-1];
+#endif
+
+	if (he_init_group(he_dev, 0) != 0)
+		return -ENOMEM;
+
+	for (group = 1; group < HE_NUM_GROUPS; ++group)
+	{
+		he_writel(he_dev, 0x0, G0_RBPS_S + (group * 32));
+		he_writel(he_dev, 0x0, G0_RBPS_T + (group * 32));
+		he_writel(he_dev, 0x0, G0_RBPS_QI + (group * 32));
+		he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0),
+						G0_RBPS_BS + (group * 32));
+
+		he_writel(he_dev, 0x0, G0_RBPL_S + (group * 32));
+		he_writel(he_dev, 0x0, G0_RBPL_T + (group * 32));
+		he_writel(he_dev, RBP_THRESH(0x1) | RBP_QSIZE(0x0),
+						G0_RBPL_QI + (group * 32));
+		he_writel(he_dev, 0x0, G0_RBPL_BS + (group * 32));
+
+		he_writel(he_dev, 0x0, G0_RBRQ_ST + (group * 16));
+		he_writel(he_dev, 0x0, G0_RBRQ_H + (group * 16));
+		he_writel(he_dev, RBRQ_THRESH(0x1) | RBRQ_SIZE(0x0),
+						G0_RBRQ_Q + (group * 16));
+		he_writel(he_dev, 0x0, G0_RBRQ_I + (group * 16));
+
+		he_writel(he_dev, 0x0, G0_TBRQ_B_T + (group * 16));
+		he_writel(he_dev, 0x0, G0_TBRQ_H + (group * 16));
+		he_writel(he_dev, TBRQ_THRESH(0x1),
+						G0_TBRQ_THRESH + (group * 16));
+		he_writel(he_dev, 0x0, G0_TBRQ_S + (group * 16));
+	}
+
+	/* host status page */
+
+	he_dev->hsp = pci_alloc_consistent(he_dev->pci_dev,
+				sizeof(struct he_hsp), &he_dev->hsp_phys);
+	if (he_dev->hsp == NULL)
+	{
+		hprintk("failed to allocate host status page\n");
+		return -ENOMEM;
+	}
+	memset(he_dev->hsp, 0, sizeof(struct he_hsp));
+	he_writel(he_dev, he_dev->hsp_phys, HSP_BA);
+
+	/* initialize framer */
+
+#ifdef CONFIG_ATM_HE_USE_SUNI
+	suni_init(he_dev->atm_dev);
+	if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->start)
+		he_dev->atm_dev->phy->start(he_dev->atm_dev);
+#endif /* CONFIG_ATM_HE_USE_SUNI */
+
+	if (sdh)
+	{
+		/* this really should be in suni.c but for now... */
+
+		int val;
+
+		val = he_phy_get(he_dev->atm_dev, SUNI_TPOP_APM);
+		val = (val & ~SUNI_TPOP_APM_S) | ( 0x2 << SUNI_TPOP_APM_S_SHIFT);
+		he_phy_put(he_dev->atm_dev, val, SUNI_TPOP_APM);
+	}
+
+	/* 5.1.12 enable transmit and receive */
+
+	reg = he_readl_mbox(he_dev, CS_ERCTL0);
+	reg |= TX_ENABLE|ER_ENABLE;
+	he_writel_mbox(he_dev, reg, CS_ERCTL0);
+
+	reg = he_readl(he_dev, RC_CONFIG);
+	reg |= RX_ENABLE;
+	he_writel(he_dev, reg, RC_CONFIG);
+
+#ifndef USE_HE_FIND_VCC
+	he_dev->he_vcc_table = kmalloc(sizeof(struct he_vcc_table) * 
+			(1 << (he_dev->vcibits + he_dev->vpibits)), GFP_KERNEL);
+	if (he_dev->he_vcc_table == NULL)
+	{
+		hprintk("failed to alloc he_vcc_table\n");
+		return -ENOMEM;
+	}
+	memset(he_dev->he_vcc_table, 0, sizeof(struct he_vcc_table) *
+				(1 << (he_dev->vcibits + he_dev->vpibits)));
+#endif
+
+	for (i = 0; i < HE_NUM_CS_STPER; ++i)
+	{
+		he_dev->cs_stper[i].inuse = 0;
+		he_dev->cs_stper[i].pcr = -1;
+	}
+	he_dev->total_bw = 0;
+
+
+	/* atm linux initialization */
+
+	he_dev->atm_dev->ci_range.vpi_bits = he_dev->vpibits;
+	he_dev->atm_dev->ci_range.vci_bits = he_dev->vcibits;
+
+	he_dev->irq_peak = 0;
+	he_dev->rbrq_peak = 0;
+        he_dev->rbpl_peak = 0;
+        he_dev->tbrq_peak = 0;
+
+	HPRINTK("hell bent for leather!\n");
+
+	return 0;
+}
+
+static void
+he_stop(struct he_dev *he_dev)
+{
+	u16 command;
+	u32 gen_cntl_0, reg;
+	struct pci_dev *pci_dev;
+
+	pci_dev = he_dev->pci_dev;
+
+	/* disable interrupts */
+
+	if (he_dev->membase)
+	{
+		pci_read_config_dword(pci_dev, GEN_CNTL_0, &gen_cntl_0);
+		gen_cntl_0 &= ~(INT_PROC_ENBL | INIT_ENB);
+		pci_write_config_dword(pci_dev, GEN_CNTL_0, gen_cntl_0);
+
+#ifdef USE_TASKLET
+		tasklet_disable(&he_dev->tasklet);
+#endif
+
+		/* disable recv and transmit */
+
+		reg = he_readl_mbox(he_dev, CS_ERCTL0);
+		reg &= ~(TX_ENABLE|ER_ENABLE);
+		he_writel_mbox(he_dev, reg, CS_ERCTL0);
+
+		reg = he_readl(he_dev, RC_CONFIG);
+		reg &= ~(RX_ENABLE);
+		he_writel(he_dev, reg, RC_CONFIG);
+	}
+
+#ifdef CONFIG_ATM_HE_USE_SUNI
+	if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->stop)
+		he_dev->atm_dev->phy->stop(he_dev->atm_dev);
+#endif /* CONFIG_ATM_HE_USE_SUNI */
+
+	if (he_dev->irq)
+	{
+#ifdef BUS_INT_WAR
+		sn_delete_polled_interrupt(he_dev->irq);
+#endif
+		free_irq(he_dev->irq, he_dev);
+	}
+
+	if (he_dev->irq_base)
+		pci_free_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1)
+			* sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys);
+
+	if (he_dev->hsp)
+		pci_free_consistent(he_dev->pci_dev, sizeof(struct he_hsp),
+						he_dev->hsp, he_dev->hsp_phys);
+
+	if (he_dev->rbpl_base)
+	{
+#ifdef USE_RBPL_POOL
+		for (i=0; i<CONFIG_RBPL_SIZE; ++i)
+		{
+			void *cpuaddr = he_dev->rbpl_virt[i].virt;
+			dma_addr_t dma_handle = he_dev->rbpl_base[i].phys;
+
+			pci_pool_free(he_dev->rbpl_pool, cpuaddr, dma_handle);
+		}
+#else
+		pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE
+			* CONFIG_RBPL_BUFSIZE, he_dev->rbpl_pages, he_dev->rbpl_pages_phys);
+#endif
+		pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE
+			* sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys);
+	}
+
+#ifdef USE_RBPL_POOL
+	if (he_dev->rbpl_pool)
+		pci_pool_destroy(he_dev->rbpl_pool);
+#endif
+
+#ifdef USE_RBPS
+	if (he_dev->rbps_base)
+	{
+#ifdef USE_RBPS_POOL
+		for (i=0; i<CONFIG_RBPS_SIZE; ++i)
+		{
+			void *cpuaddr = he_dev->rbps_virt[i].virt;
+			dma_addr_t dma_handle = he_dev->rbps_base[i].phys;
+
+			pci_pool_free(he_dev->rbps_pool, cpuaddr, dma_handle);
+		}
+#else
+		pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE
+			* CONFIG_RBPS_BUFSIZE, he_dev->rbps_pages, he_dev->rbps_pages_phys);
+#endif
+		pci_free_consistent(he_dev->pci_dev, CONFIG_RBPS_SIZE
+			* sizeof(struct he_rbp), he_dev->rbps_base, he_dev->rbps_phys);
+	}
+
+#ifdef USE_RBPS_POOL
+	if (he_dev->rbps_pool)
+		pci_pool_destroy(he_dev->rbps_pool);
+#endif
+
+#endif /* USE_RBPS */
+
+	if (he_dev->rbrq_base)
+		pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq),
+							he_dev->rbrq_base, he_dev->rbrq_phys);
+
+	if (he_dev->tbrq_base)
+		pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
+							he_dev->tbrq_base, he_dev->tbrq_phys);
+
+	if (he_dev->tpdrq_base)
+		pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
+							he_dev->tpdrq_base, he_dev->tpdrq_phys);
+
+#ifdef USE_TPD_POOL
+	if (he_dev->tpd_pool)
+		pci_pool_destroy(he_dev->tpd_pool);
+#else
+	if (he_dev->tpd_base)
+		pci_free_consistent(he_dev->pci_dev, CONFIG_NUMTPDS * sizeof(struct he_tpd),
+							he_dev->tpd_base, he_dev->tpd_base_phys);
+#endif
+
+#ifndef USE_HE_FIND_VCC
+	if (he_dev->he_vcc_table)
+		kfree(he_dev->he_vcc_table);
+#endif
+
+	if (he_dev->pci_dev)
+	{
+		pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command);
+		command &= ~(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER);
+		pci_write_config_word(he_dev->pci_dev, PCI_COMMAND, command);
+	}
+	
+	if (he_dev->membase) iounmap((void *) he_dev->membase);
+}
+
+static struct he_tpd *
+__alloc_tpd(struct he_dev *he_dev)
+{
+#ifdef USE_TPD_POOL
+	struct he_tpd *tpd;
+	dma_addr_t dma_handle; 
+
+	tpd = pci_pool_alloc(he_dev->tpd_pool, SLAB_ATOMIC|SLAB_DMA, &dma_handle);              
+	if (tpd == NULL)
+		return NULL;
+			
+	tpd->status = TPD_ADDR(dma_handle);
+	tpd->reserved = 0; 
+	tpd->iovec[0].addr = 0; tpd->iovec[0].len = 0;
+	tpd->iovec[1].addr = 0; tpd->iovec[1].len = 0;
+	tpd->iovec[2].addr = 0; tpd->iovec[2].len = 0;
+
+	return tpd;
+#else
+	int i;
+
+	for(i = 0; i < CONFIG_NUMTPDS; ++i)
+	{
+		++he_dev->tpd_head;
+		if (he_dev->tpd_head > he_dev->tpd_end) {
+			he_dev->tpd_head = he_dev->tpd_base;
+		}
+
+		if (!he_dev->tpd_head->inuse) {
+			he_dev->tpd_head->inuse = 1;
+			he_dev->tpd_head->status &= TPD_MASK;
+			he_dev->tpd_head->iovec[0].addr = 0; he_dev->tpd_head->iovec[0].len = 0;
+			he_dev->tpd_head->iovec[1].addr = 0; he_dev->tpd_head->iovec[1].len = 0;
+			he_dev->tpd_head->iovec[2].addr = 0; he_dev->tpd_head->iovec[2].len = 0;
+			return he_dev->tpd_head;
+		}
+	}
+	hprintk("out of tpds -- increase CONFIG_NUMTPDS (%d)\n", CONFIG_NUMTPDS);
+	return NULL;
+#endif
+}
+
+#define AAL5_LEN(buf,len) 						\
+			((((unsigned char *)(buf))[(len)-6]<<8) |	\
+				(((unsigned char *)(buf))[(len)-5]))
+
+/* 2.10.1.2 receive
+ *
+ * aal5 packets can optionally return the tcp checksum in the lower
+ * 16 bits of the crc (RSR0_TCP_CKSUM)
+ */
+
+#define TCP_CKSUM(buf,len) 						\
+			((((unsigned char *)(buf))[(len)-2]<<8) |	\
+				(((unsigned char *)(buf))[(len-1)]))
+
+static int
+he_service_rbrq(struct he_dev *he_dev, int group)
+{
+	struct he_rbrq *rbrq_tail = (struct he_rbrq *)
+				((unsigned long)he_dev->rbrq_base |
+					he_dev->hsp->group[group].rbrq_tail);
+	struct he_rbp *rbp = NULL;
+	unsigned cid, lastcid = -1;
+	unsigned buf_len = 0;
+	struct sk_buff *skb;
+	struct atm_vcc *vcc = NULL;
+	struct he_vcc *he_vcc;
+	struct he_iovec *iov;
+	int pdus_assembled = 0;
+	int updated = 0;
+
+	while (he_dev->rbrq_head != rbrq_tail)
+	{
+		++updated;
+
+		HPRINTK("%p rbrq%d 0x%x len=%d cid=0x%x %s%s%s%s%s%s\n",
+			he_dev->rbrq_head, group,
+			RBRQ_ADDR(he_dev->rbrq_head),
+			RBRQ_BUFLEN(he_dev->rbrq_head),
+			RBRQ_CID(he_dev->rbrq_head),
+			RBRQ_CRC_ERR(he_dev->rbrq_head) ? " CRC_ERR" : "",
+			RBRQ_LEN_ERR(he_dev->rbrq_head) ? " LEN_ERR" : "",
+			RBRQ_END_PDU(he_dev->rbrq_head) ? " END_PDU" : "",
+			RBRQ_AAL5_PROT(he_dev->rbrq_head) ? " AAL5_PROT" : "",
+			RBRQ_CON_CLOSED(he_dev->rbrq_head) ? " CON_CLOSED" : "",
+			RBRQ_HBUF_ERR(he_dev->rbrq_head) ? " HBUF_ERR" : "");
+
+#ifdef USE_RBPS
+		if (RBRQ_ADDR(he_dev->rbrq_head) & RBP_SMALLBUF)
+			rbp = &he_dev->rbps_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
+		else
+#endif
+			rbp = &he_dev->rbpl_base[RBP_INDEX(RBRQ_ADDR(he_dev->rbrq_head))];
+		
+		buf_len = RBRQ_BUFLEN(he_dev->rbrq_head) * 4;
+		cid = RBRQ_CID(he_dev->rbrq_head);
+
+#ifdef USE_HE_FIND_VCC
+		if (cid != lastcid)
+			vcc = he_find_vcc(he_dev, cid);
+		lastcid = cid;
+#else
+		vcc = HE_LOOKUP_VCC(he_dev, cid);
+#endif
+		if (vcc == NULL)
+		{
+			hprintk("vcc == NULL  (cid 0x%x)\n", cid);
+			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
+					rbp->status &= ~RBP_LOANED;
+					
+			goto next_rbrq_entry;
+		}
+
+		he_vcc = HE_VCC(vcc);
+		if (he_vcc == NULL)
+		{
+			hprintk("he_vcc == NULL  (cid 0x%x)\n", cid);
+			if (!RBRQ_HBUF_ERR(he_dev->rbrq_head))
+					rbp->status &= ~RBP_LOANED;
+			goto next_rbrq_entry;
+		}
+
+		if (RBRQ_HBUF_ERR(he_dev->rbrq_head))
+		{
+			hprintk("HBUF_ERR!  (cid 0x%x)\n", cid);
+				atomic_inc(&vcc->stats->rx_drop);
+			goto return_host_buffers;
+		}
+
+		he_vcc->iov_tail->iov_base = RBRQ_ADDR(he_dev->rbrq_head);
+		he_vcc->iov_tail->iov_len = buf_len;
+		he_vcc->pdu_len += buf_len;
+		++he_vcc->iov_tail;
+
+		if (RBRQ_CON_CLOSED(he_dev->rbrq_head))
+		{
+			lastcid = -1;
+			HPRINTK("wake_up rx_waitq  (cid 0x%x)\n", cid);
+			wake_up(&he_vcc->rx_waitq);
+			goto return_host_buffers;
+		}
+
+#ifdef notdef
+		if ((he_vcc->iov_tail - he_vcc->iov_head) > HE_MAXIOV)
+		{
+			hprintk("iovec full!  cid 0x%x\n", cid);
+			goto return_host_buffers;
+		}
+#endif
+		if (!RBRQ_END_PDU(he_dev->rbrq_head)) goto next_rbrq_entry;
+
+		if (RBRQ_LEN_ERR(he_dev->rbrq_head)
+				|| RBRQ_CRC_ERR(he_dev->rbrq_head))
+		{
+			HPRINTK("%s%s (%d.%d)\n",
+				RBRQ_CRC_ERR(he_dev->rbrq_head)
+							? "CRC_ERR " : "",
+				RBRQ_LEN_ERR(he_dev->rbrq_head)
+							? "LEN_ERR" : "",
+							vcc->vpi, vcc->vci);
+			atomic_inc(&vcc->stats->rx_err);
+			goto return_host_buffers;
+		}
+
+		skb = atm_alloc_charge(vcc, he_vcc->pdu_len + rx_skb_reserve,
+							GFP_ATOMIC);
+		if (!skb)
+		{
+			HPRINTK("charge failed (%d.%d)\n", vcc->vpi, vcc->vci);
+			goto return_host_buffers;
+		}
+
+		if (rx_skb_reserve > 0) skb_reserve(skb, rx_skb_reserve);
+
+		do_gettimeofday(&skb->stamp);
+
+		for(iov = he_vcc->iov_head;
+				iov < he_vcc->iov_tail; ++iov)
+		{
+#ifdef USE_RBPS
+			if (iov->iov_base & RBP_SMALLBUF)
+				memcpy(skb_put(skb, iov->iov_len),
+					he_dev->rbps_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
+			else
+#endif
+				memcpy(skb_put(skb, iov->iov_len),
+					he_dev->rbpl_virt[RBP_INDEX(iov->iov_base)].virt, iov->iov_len);
+		}
+
+		switch(vcc->qos.aal)
+		{
+			case ATM_AAL0:
+				/* 2.10.1.5 raw cell receive */
+				skb->len = ATM_AAL0_SDU;
+				skb->tail = skb->data + skb->len;
+				break;
+			case ATM_AAL5:
+				/* 2.10.1.2 aal5 receive */
+
+				skb->len = AAL5_LEN(skb->data, he_vcc->pdu_len);
+				skb->tail = skb->data + skb->len;
+#ifdef USE_CHECKSUM_HW
+				if (vcc->vpi == 0 && vcc->vci >= ATM_NOT_RSV_VCI) 
+				{
+					skb->ip_summed = CHECKSUM_HW;
+					skb->csum = TCP_CKSUM(skb->data,
+							he_vcc->pdu_len);
+				}
+#endif
+				break;
+		}
+
+#ifdef should_never_happen
+		if (skb->len > vcc->qos.rxtp.max_sdu)
+			hprintk("pdu_len (%d) > vcc->qos.rxtp.max_sdu (%d)!  cid 0x%x\n", skb->len, vcc->qos.rxtp.max_sdu, cid);
+#endif
+
+#ifdef notdef
+		ATM_SKB(skb)->vcc = vcc;
+#endif
+		vcc->push(vcc, skb);
+
+		atomic_inc(&vcc->stats->rx);
+
+return_host_buffers:
+		++pdus_assembled;
+
+		for(iov = he_vcc->iov_head;
+				iov < he_vcc->iov_tail; ++iov)
+		{
+#ifdef USE_RBPS
+			if (iov->iov_base & RBP_SMALLBUF)
+				rbp = &he_dev->rbps_base[RBP_INDEX(iov->iov_base)];
+			else
+#endif
+				rbp = &he_dev->rbpl_base[RBP_INDEX(iov->iov_base)];
+
+			rbp->status &= ~RBP_LOANED;
+		}
+
+		he_vcc->iov_tail = he_vcc->iov_head;
+		he_vcc->pdu_len = 0;
+
+next_rbrq_entry:
+		he_dev->rbrq_head = (struct he_rbrq *)
+				((unsigned long) he_dev->rbrq_base |
+					RBRQ_MASK(++he_dev->rbrq_head));
+
+	}
+
+	if (updated)
+	{
+		if (updated > he_dev->rbrq_peak) he_dev->rbrq_peak = updated;
+
+		he_writel(he_dev, RBRQ_MASK(he_dev->rbrq_head),
+						G0_RBRQ_H + (group * 16));
+#ifdef CONFIG_IA64_SGI_SN2
+		(void) he_readl(he_dev, G0_RBRQ_H + (group * 16));
+#endif
+	}
+
+	return pdus_assembled;
+}
+
+static void
+he_service_tbrq(struct he_dev *he_dev, int group)
+{
+	struct he_tbrq *tbrq_tail = (struct he_tbrq *)
+				((unsigned long)he_dev->tbrq_base |
+					he_dev->hsp->group[group].tbrq_tail);
+	struct he_tpd *tpd;
+	int slot, updated = 0;
+#ifdef USE_TPD_POOL
+	struct list_head *p;
+#endif
+
+	/* 2.1.6 transmit buffer return queue */
+
+	while (he_dev->tbrq_head != tbrq_tail)
+	{
+		++updated;
+
+		HPRINTK("tbrq%d 0x%x%s%s\n",
+			group,
+			TBRQ_TPD(he_dev->tbrq_head), 
+			TBRQ_EOS(he_dev->tbrq_head) ? " EOS" : "",
+			TBRQ_MULTIPLE(he_dev->tbrq_head) ? " MULTIPLE" : "");
+#ifdef USE_TPD_POOL
+		tpd = NULL;
+		p = &he_dev->outstanding_tpds;
+		while ((p = p->next) != &he_dev->outstanding_tpds)
+		{
+			struct he_tpd *__tpd = list_entry(p, struct he_tpd, entry);
+			if (TPD_ADDR(__tpd->status) == TBRQ_TPD(he_dev->tbrq_head))
+			{
+				tpd = __tpd;
+				list_del(&__tpd->entry);
+				break;
+			}
+		}
+
+		if (tpd == NULL)
+		{
+			hprintk("unable to locate tpd for dma buffer %x\n",
+						TBRQ_TPD(he_dev->tbrq_head));
+			goto next_tbrq_entry;
+		}
+#else
+		tpd = &he_dev->tpd_base[ TPD_INDEX(TBRQ_TPD(he_dev->tbrq_head)) ];
+#endif
+
+		if (TBRQ_EOS(he_dev->tbrq_head))
+		{
+			HPRINTK("wake_up(tx_waitq) cid 0x%x\n",
+				he_mkcid(he_dev, tpd->vcc->vpi, tpd->vcc->vci));
+			if (tpd->vcc)
+				wake_up(&HE_VCC(tpd->vcc)->tx_waitq);
+
+			goto next_tbrq_entry;
+		}
+
+		for(slot = 0; slot < TPD_MAXIOV; ++slot)
+		{
+			if (tpd->iovec[slot].addr)
+				pci_unmap_single(he_dev->pci_dev,
+					tpd->iovec[slot].addr,
+					tpd->iovec[slot].len & TPD_LEN_MASK,
+							PCI_DMA_TODEVICE);
+			if (tpd->iovec[slot].len & TPD_LST) break;
+				
+		}
+
+		if (tpd->skb)	/* && !TBRQ_MULTIPLE(he_dev->tbrq_head) */
+		{
+			if (tpd->vcc && tpd->vcc->pop)
+				tpd->vcc->pop(tpd->vcc, tpd->skb);
+			else
+				dev_kfree_skb_any(tpd->skb);
+		}
+
+next_tbrq_entry:
+#ifdef USE_TPD_POOL
+		if (tpd) pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
+#else
+		tpd->inuse = 0;
+#endif
+		he_dev->tbrq_head = (struct he_tbrq *)
+				((unsigned long) he_dev->tbrq_base |
+					TBRQ_MASK(++he_dev->tbrq_head));
+	}
+
+	if (updated)
+	{
+		if (updated > he_dev->tbrq_peak) he_dev->tbrq_peak = updated;
+
+		he_writel(he_dev, TBRQ_MASK(he_dev->tbrq_head),
+						G0_TBRQ_H + (group * 16));
+#ifdef CONFIG_IA64_SGI_SN2
+		(void) he_readl(he_dev, G0_TBRQ_H + (group * 16));
+#endif
+	}
+}
+
+
+static void
+he_service_rbpl(struct he_dev *he_dev, int group)
+{
+	struct he_rbp *newtail;
+	struct he_rbp *rbpl_head;
+	int moved = 0;
+
+	rbpl_head = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
+					RBPL_MASK(he_readl(he_dev, G0_RBPL_S)));
+
+	for(;;)
+	{
+		newtail = (struct he_rbp *) ((unsigned long)he_dev->rbpl_base |
+						RBPL_MASK(he_dev->rbpl_tail+1));
+
+		/* table 3.42 -- rbpl_tail should never be set to rbpl_head */
+		if ((newtail == rbpl_head) || (newtail->status & RBP_LOANED))
+			break;
+
+		newtail->status |= RBP_LOANED;
+		he_dev->rbpl_tail = newtail;
+		++moved;
+
+	} 
+
+	if (moved) {
+		he_writel(he_dev, RBPL_MASK(he_dev->rbpl_tail), G0_RBPL_T);
+#ifdef CONFIG_IA64_SGI_SN2
+                (void) he_readl(he_dev, G0_RBPL_T);
+#endif
+	}
+}
+
+#ifdef USE_RBPS
+static void
+he_service_rbps(struct he_dev *he_dev, int group)
+{
+	struct he_rbp *newtail;
+	struct he_rbp *rbps_head;
+	int moved = 0;
+
+	rbps_head = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
+					RBPS_MASK(he_readl(he_dev, G0_RBPS_S)));
+
+	for(;;)
+	{
+		newtail = (struct he_rbp *) ((unsigned long)he_dev->rbps_base |
+						RBPS_MASK(he_dev->rbps_tail+1));
+
+		/* table 3.42 -- rbps_tail should never be set to rbps_head */
+		if ((newtail == rbps_head) || (newtail->status & RBP_LOANED))
+			break;
+
+		newtail->status |= RBP_LOANED;
+		he_dev->rbps_tail = newtail;
+		++moved;
+
+	} 
+
+	if (moved) {
+		he_writel(he_dev, RBPS_MASK(he_dev->rbps_tail), G0_RBPS_T);
+#ifdef CONFIG_IA64_SGI_SN2
+                (void) he_readl(he_dev, G0_RBPS_T);
+#endif
+	}
+}
+#endif /* USE_RBPS */
+
+static void
+he_tasklet(unsigned long data)
+{
+	unsigned long flags;
+	struct he_dev *he_dev = (struct he_dev *) data;
+	int group, type;
+	int updated = 0;
+
+	HPRINTK("tasklet (0x%lx)\n", data);
+#ifdef USE_TASKLET
+	HE_SPIN_LOCK(he_dev, flags);
+#endif
+
+	while(he_dev->irq_head != he_dev->irq_tail)
+	{
+		++updated;
+
+		type = ITYPE_TYPE(he_dev->irq_head->isw);
+		group = ITYPE_GROUP(he_dev->irq_head->isw);
+
+		switch (type)
+		{
+			case ITYPE_RBRQ_THRESH:
+				hprintk("rbrq%d threshold\n", group);
+			case ITYPE_RBRQ_TIMER:
+				if (he_service_rbrq(he_dev, group))
+				{
+					he_service_rbpl(he_dev, group);
+#ifdef USE_RBPS
+					he_service_rbps(he_dev, group);
+#endif /* USE_RBPS */
+				}
+				break;
+			case ITYPE_TBRQ_THRESH:
+				hprintk("tbrq%d threshold\n", group);
+			case ITYPE_TPD_COMPLETE:
+				he_service_tbrq(he_dev, group);
+				break;
+			case ITYPE_RBPL_THRESH:
+				he_service_rbpl(he_dev, group);
+				break;
+			case ITYPE_RBPS_THRESH:
+#ifdef USE_RBPS
+				he_service_rbps(he_dev, group);
+#endif /* USE_RBPS */
+				break;
+			case ITYPE_PHY:
+#ifdef CONFIG_ATM_HE_USE_SUNI
+				HE_SPIN_UNLOCK(he_dev, flags);
+				if (he_dev->atm_dev->phy && he_dev->atm_dev->phy->interrupt)
+					he_dev->atm_dev->phy->interrupt(he_dev->atm_dev);
+				HE_SPIN_LOCK(he_dev, flags);
+#endif
+				HPRINTK("phy interrupt\n");
+				break;
+			case ITYPE_OTHER:
+				switch (type|group)
+				{
+					case ITYPE_PARITY:
+						hprintk("parity error\n");
+						break;
+					case ITYPE_ABORT:
+						hprintk("abort 0x%x\n", he_readl(he_dev, ABORT_ADDR));
+						break;
+				}
+				break;
+			default:
+				if (he_dev->irq_head->isw == ITYPE_INVALID)
+				{
+					/* see 8.1.1 -- check all queues */
+
+					HPRINTK("isw not updated 0x%x\n",
+						he_dev->irq_head->isw);
+
+					he_service_rbrq(he_dev, 0);
+					he_service_rbpl(he_dev, 0);
+#ifdef USE_RBPS
+					he_service_rbps(he_dev, 0);
+#endif /* USE_RBPS */
+					he_service_tbrq(he_dev, 0);
+				}
+				else
+					hprintk("bad isw = 0x%x?\n",
+						he_dev->irq_head->isw);
+		}
+
+		he_dev->irq_head->isw = ITYPE_INVALID;
+
+		he_dev->irq_head = (struct he_irq *) NEXT_ENTRY(he_dev->irq_base, he_dev->irq_head, IRQ_MASK);
+	}
+
+	if (updated)
+	{
+		if (updated > he_dev->irq_peak) he_dev->irq_peak = updated;
+
+		he_writel(he_dev,
+			IRQ_SIZE(CONFIG_IRQ_SIZE) |
+			IRQ_THRESH(CONFIG_IRQ_THRESH) |
+			IRQ_TAIL(he_dev->irq_tail), IRQ0_HEAD);
+		(void) he_readl(he_dev, INT_FIFO); /* 8.1.2 controller errata */
+	}
+#ifdef USE_TASKLET
+	HE_SPIN_UNLOCK(he_dev, flags);
+#endif
+}
+
+static irqreturn_t
+he_irq_handler(int irq, void *dev_id, struct pt_regs *regs)
+{
+	unsigned long flags;
+	struct he_dev *he_dev = (struct he_dev * )dev_id;
+	int handled = 0;
+
+	if (he_dev == NULL)
+		return IRQ_NONE;
+
+	HE_SPIN_LOCK(he_dev, flags);
+
+	he_dev->irq_tail = (struct he_irq *) (((unsigned long)he_dev->irq_base) |
+						(*he_dev->irq_tailoffset << 2));
+
+	if (he_dev->irq_tail == he_dev->irq_head)
+	{
+		HPRINTK("tailoffset not updated?\n");
+		he_dev->irq_tail = (struct he_irq *) ((unsigned long)he_dev->irq_base |
+			((he_readl(he_dev, IRQ0_BASE) & IRQ_MASK) << 2));
+		(void) he_readl(he_dev, INT_FIFO);	/* 8.1.2 controller errata */
+	}
+
+#ifdef DEBUG
+	if (he_dev->irq_head == he_dev->irq_tail /* && !IRQ_PENDING */)
+		hprintk("spurious (or shared) interrupt?\n");
+#endif
+
+	if (he_dev->irq_head != he_dev->irq_tail)
+	{
+		handled = 1;
+#ifdef USE_TASKLET
+		tasklet_schedule(&he_dev->tasklet);
+#else
+		he_tasklet((unsigned long) he_dev);
+#endif
+		he_writel(he_dev, INT_CLEAR_A, INT_FIFO);
+							/* clear interrupt */
+#ifdef CONFIG_IA64_SGI_SN2
+		(void) he_readl(he_dev, INT_FIFO);
+#endif
+	}
+	HE_SPIN_UNLOCK(he_dev, flags);
+	return IRQ_RETVAL(handled);
+
+}
+
+static __inline__ void
+__enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid)
+{
+	struct he_tpdrq *new_tail;
+
+	HPRINTK("tpdrq %p cid 0x%x -> tpdrq_tail %p\n",
+					tpd, cid, he_dev->tpdrq_tail);
+
+	/* new_tail = he_dev->tpdrq_tail; */
+	new_tail = (struct he_tpdrq *) ((unsigned long) he_dev->tpdrq_base |
+					TPDRQ_MASK(he_dev->tpdrq_tail+1));
+
+	/*
+	 * check to see if we are about to set the tail == head
+	 * if true, update the head pointer from the adapter
+	 * to see if this is really the case (reading the queue
+	 * head for every enqueue would be unnecessarily slow)
+	 */
+
+	if (new_tail == he_dev->tpdrq_head)
+	{
+		he_dev->tpdrq_head = (struct he_tpdrq *)
+			(((unsigned long)he_dev->tpdrq_base) |
+				TPDRQ_MASK(he_readl(he_dev, TPDRQ_B_H)));
+
+		if (new_tail == he_dev->tpdrq_head)
+		{
+			hprintk("tpdrq full (cid 0x%x)\n", cid);
+			/*
+			 * FIXME
+			 * push tpd onto a transmit backlog queue
+			 * after service_tbrq, service the backlog
+			 * for now, we just drop the pdu
+			 */
+			if (tpd->skb)
+			{
+				if (tpd->vcc->pop)
+					tpd->vcc->pop(tpd->vcc, tpd->skb);
+				else
+					dev_kfree_skb_any(tpd->skb);
+				atomic_inc(&tpd->vcc->stats->tx_err);
+			}
+#ifdef USE_TPD_POOL
+			pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
+#else
+			tpd->inuse = 0;
+#endif
+			return;
+		}
+	}
+
+	/* 2.1.5 transmit packet descriptor ready queue */
+#ifdef USE_TPD_POOL
+	list_add_tail(&tpd->entry, &he_dev->outstanding_tpds);
+	he_dev->tpdrq_tail->tpd = TPD_ADDR(tpd->status);
+#else
+	he_dev->tpdrq_tail->tpd = he_dev->tpd_base_phys +
+				(TPD_INDEX(tpd->status) * sizeof(struct he_tpd));
+#endif
+	he_dev->tpdrq_tail->cid = cid;
+	wmb();
+
+	he_dev->tpdrq_tail = new_tail;
+
+	he_writel(he_dev, TPDRQ_MASK(he_dev->tpdrq_tail), TPDRQ_T);
+#ifdef CONFIG_IA64_SGI_SN2
+	(void) he_readl(he_dev, TPDRQ_T);
+#endif
+}
+
+static int
+he_open(struct atm_vcc *vcc, short vpi, int vci)
+{
+	unsigned long flags;
+	struct he_dev *he_dev = HE_DEV(vcc->dev);
+	struct he_vcc *he_vcc;
+	int err = 0;
+	unsigned cid, rsr0, rsr1, rsr4, tsr0, tsr0_aal, tsr4, period, reg, clock;
+
+	
+	if ((err = atm_find_ci(vcc, &vpi, &vci)))
+	{
+		HPRINTK("atm_find_ci err = %d\n", err);
+		return err;
+	}
+	if (vci == ATM_VCI_UNSPEC || vpi == ATM_VPI_UNSPEC) return 0;
+	vcc->vpi = vpi;
+	vcc->vci = vci;
+
+	HPRINTK("open vcc %p %d.%d\n", vcc, vpi, vci);
+
+	set_bit(ATM_VF_ADDR, &vcc->flags);
+
+	cid = he_mkcid(he_dev, vpi, vci);
+
+	he_vcc = (struct he_vcc *) kmalloc(sizeof(struct he_vcc), GFP_ATOMIC);
+	if (he_vcc == NULL)
+	{
+		hprintk("unable to allocate he_vcc during open\n");
+		return -ENOMEM;
+	}
+
+	he_vcc->iov_tail = he_vcc->iov_head;
+	he_vcc->pdu_len = 0;
+	he_vcc->rc_index = -1;
+
+	init_waitqueue_head(&he_vcc->rx_waitq);
+	init_waitqueue_head(&he_vcc->tx_waitq);
+
+	HE_VCC(vcc) = he_vcc;
+
+	if (vcc->qos.txtp.traffic_class != ATM_NONE)
+	{
+		int pcr_goal;
+
+                pcr_goal = atm_pcr_goal(&vcc->qos.txtp);
+                if (pcr_goal == 0)
+                        pcr_goal = he_dev->atm_dev->link_rate;
+                if (pcr_goal < 0)	/* means round down, technically */
+                        pcr_goal = -pcr_goal;
+
+		HPRINTK("open tx cid 0x%x pcr_goal %d\n", cid, pcr_goal);
+
+		switch (vcc->qos.aal)
+		{
+			case ATM_AAL5:
+				tsr0_aal = TSR0_AAL5;
+				tsr4 = TSR4_AAL5;
+				break;
+			case ATM_AAL0:
+				tsr0_aal = TSR0_AAL0_SDU;
+				tsr4 = TSR4_AAL0_SDU;
+				break;
+			default:
+				err = -EINVAL;
+				goto open_failed;
+		}
+
+		HE_SPIN_LOCK(he_dev, flags);
+		tsr0 = he_readl_tsr0(he_dev, cid);
+		HE_SPIN_UNLOCK(he_dev, flags);
+
+		if (TSR0_CONN_STATE(tsr0) != 0)
+		{
+			hprintk("cid 0x%x not idle (tsr0 = 0x%x)\n", cid, tsr0);
+			err = -EBUSY;
+			goto open_failed;
+		}
+
+		switch(vcc->qos.txtp.traffic_class)
+		{
+			case ATM_UBR:
+				/* 2.3.3.1 open connection ubr */
+
+				tsr0 = TSR0_UBR | TSR0_GROUP(0) | tsr0_aal |
+					TSR0_USE_WMIN | TSR0_UPDATE_GER;
+				break;
+
+			case ATM_CBR:
+				/* 2.3.3.2 open connection cbr */
+
+				/* 8.2.3 cbr scheduler wrap problem -- limit to 90% total link rate */
+				if ((he_dev->total_bw + pcr_goal)
+					> (he_dev->atm_dev->link_rate * 9 / 10))
+				{
+					err = -EBUSY;
+					goto open_failed;
+				}
+
+				HE_SPIN_LOCK(he_dev, flags);			/* also protects he_dev->cs_stper[] */
+
+				/* find an unused cs_stper register */
+				for(reg = 0; reg < HE_NUM_CS_STPER; ++reg)
+					if (he_dev->cs_stper[reg].inuse == 0 || 
+						he_dev->cs_stper[reg].pcr == pcr_goal)
+					break;
+
+				if (reg == HE_NUM_CS_STPER)
+				{
+					err = -EBUSY;
+					HE_SPIN_UNLOCK(he_dev, flags);
+					goto open_failed;
+				}
+
+				he_dev->total_bw += pcr_goal;
+
+				he_vcc->rc_index = reg;
+				++he_dev->cs_stper[reg].inuse;
+				he_dev->cs_stper[reg].pcr = pcr_goal;
+
+				clock = he_is622(he_dev) ? 66667000 : 50000000;
+				period = clock / pcr_goal;
+				
+				HPRINTK("rc_index = %d period = %d\n",
+								reg, period);
+
+				he_writel_mbox(he_dev, rate_to_atmf(period/2),
+							CS_STPER0 + reg);
+				HE_SPIN_UNLOCK(he_dev, flags);
+
+				tsr0 = TSR0_CBR | TSR0_GROUP(0) | tsr0_aal |
+							TSR0_RC_INDEX(reg);
+
+				break;
+			default:
+				err = -EINVAL;
+				goto open_failed;
+		}
+
+		HE_SPIN_LOCK(he_dev, flags);
+
+		he_writel_tsr0(he_dev, tsr0, cid);
+		he_writel_tsr4(he_dev, tsr4 | 1, cid);
+		he_writel_tsr1(he_dev, TSR1_MCR(rate_to_atmf(0)) |
+					TSR1_PCR(rate_to_atmf(pcr_goal)), cid);
+		he_writel_tsr2(he_dev, TSR2_ACR(rate_to_atmf(pcr_goal)), cid);
+		he_writel_tsr9(he_dev, TSR9_OPEN_CONN, cid);
+
+		he_writel_tsr3(he_dev, 0x0, cid);
+		he_writel_tsr5(he_dev, 0x0, cid);
+		he_writel_tsr6(he_dev, 0x0, cid);
+		he_writel_tsr7(he_dev, 0x0, cid);
+		he_writel_tsr8(he_dev, 0x0, cid);
+		he_writel_tsr10(he_dev, 0x0, cid);
+		he_writel_tsr11(he_dev, 0x0, cid);
+		he_writel_tsr12(he_dev, 0x0, cid);
+		he_writel_tsr13(he_dev, 0x0, cid);
+		he_writel_tsr14(he_dev, 0x0, cid);
+#ifdef CONFIG_IA64_SGI_SN2
+		(void) he_readl_tsr0(he_dev, cid);
+#endif
+		HE_SPIN_UNLOCK(he_dev, flags);
+	}
+
+	if (vcc->qos.rxtp.traffic_class != ATM_NONE)
+	{
+		unsigned aal;
+
+		HPRINTK("open rx cid 0x%x (rx_waitq %p)\n", cid,
+		 				&HE_VCC(vcc)->rx_waitq);
+
+		switch (vcc->qos.aal)
+		{
+			case ATM_AAL5:
+				aal = RSR0_AAL5;
+				break;
+			case ATM_AAL0:
+				aal = RSR0_RAWCELL;
+				break;
+			default:
+				err = -EINVAL;
+				goto open_failed;
+		}
+
+		HE_SPIN_LOCK(he_dev, flags);
+
+		rsr0 = he_readl_rsr0(he_dev, cid);
+		if (rsr0 & RSR0_OPEN_CONN)
+		{
+			HE_SPIN_UNLOCK(he_dev, flags);
+
+			hprintk("cid 0x%x not idle (rsr0 = 0x%x)\n", cid, rsr0);
+			err = -EBUSY;
+			goto open_failed;
+		}
+
+#ifdef USE_RBPS
+		rsr1 = RSR1_GROUP(0);
+		rsr4 = RSR4_GROUP(0);
+#else /* !USE_RBPS */
+		rsr1 = RSR1_GROUP(0)|RSR1_RBPL_ONLY;
+		rsr4 = RSR4_GROUP(0)|RSR4_RBPL_ONLY;
+#endif /* USE_RBPS */
+		rsr0 = vcc->qos.rxtp.traffic_class == ATM_UBR ? 
+				(RSR0_EPD_ENABLE|RSR0_PPD_ENABLE) : 0;
+
+#ifdef USE_CHECKSUM_HW
+		if (vpi == 0 && vci >= ATM_NOT_RSV_VCI) rsr0 |= RSR0_TCP_CKSUM;
+#endif
+
+		he_writel_rsr4(he_dev, rsr4, cid);
+		he_writel_rsr1(he_dev, rsr1, cid);
+		/* 5.1.11 last parameter initialized should be
+		          the open/closed indication in rsr0 */
+		he_writel_rsr0(he_dev,
+			rsr0 | RSR0_START_PDU | RSR0_OPEN_CONN | aal, cid);
+#ifdef CONFIG_IA64_SGI_SN2
+		(void) he_readl_rsr0(he_dev, cid);
+#endif
+
+		HE_SPIN_UNLOCK(he_dev, flags);
+
+#ifndef USE_HE_FIND_VCC
+		HE_LOOKUP_VCC(he_dev, cid) = vcc;
+#endif
+	}
+
+open_failed:
+
+	if (err)
+	{
+		if (he_vcc) kfree(he_vcc);
+		clear_bit(ATM_VF_ADDR, &vcc->flags);
+	}
+	else
+		set_bit(ATM_VF_READY, &vcc->flags);
+
+	return err;
+}
+
+static void
+he_close(struct atm_vcc *vcc)
+{
+	unsigned long flags;
+	DECLARE_WAITQUEUE(wait, current);
+	struct he_dev *he_dev = HE_DEV(vcc->dev);
+	struct he_tpd *tpd;
+	unsigned cid;
+	struct he_vcc *he_vcc = HE_VCC(vcc);
+#define MAX_RETRY 30
+	int retry = 0, sleep = 1, tx_inuse;
+
+	HPRINTK("close vcc %p %d.%d\n", vcc, vcc->vpi, vcc->vci);
+
+	clear_bit(ATM_VF_READY, &vcc->flags);
+	cid = he_mkcid(he_dev, vcc->vpi, vcc->vci);
+
+	if (vcc->qos.rxtp.traffic_class != ATM_NONE)
+	{
+		int timeout;
+
+		HPRINTK("close rx cid 0x%x\n", cid);
+
+		/* 2.7.2.2 close receive operation */
+
+		/* wait for previous close (if any) to finish */
+
+		HE_SPIN_LOCK(he_dev, flags);
+		while(he_readl(he_dev, RCC_STAT) & RCC_BUSY)
+		{
+			HPRINTK("close cid 0x%x RCC_BUSY\n", cid);
+			udelay(250);
+		}
+
+		add_wait_queue(&he_vcc->rx_waitq, &wait);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+
+		he_writel_rsr0(he_dev, RSR0_CLOSE_CONN, cid);
+#ifdef CONFIG_IA64_SGI_SN2
+		(void) he_readl_rsr0(he_dev, cid);
+#endif
+		he_writel_mbox(he_dev, cid, RXCON_CLOSE);
+		HE_SPIN_UNLOCK(he_dev, flags);
+
+		timeout = schedule_timeout(30*HZ);
+
+		remove_wait_queue(&he_vcc->rx_waitq, &wait);
+		set_current_state(TASK_RUNNING);
+
+		if (timeout == 0)
+			hprintk("close rx timeout cid 0x%x\n", cid);
+
+#ifndef USE_HE_FIND_VCC
+		HE_LOOKUP_VCC(he_dev, cid) = NULL;
+#endif
+		HPRINTK("close rx cid 0x%x complete\n", cid);
+
+	}
+
+	if (vcc->qos.txtp.traffic_class != ATM_NONE)
+	{
+		volatile unsigned tsr4, tsr0;
+		int timeout;
+
+		HPRINTK("close tx cid 0x%x\n", cid);
+		
+		/* 2.1.2
+		 *
+		 * ... the host must first stop queueing packets to the TPDRQ
+		 * on the connection to be closed, then wait for all outstanding
+		 * packets to be transmitted and their buffers returned to the
+		 * TBRQ. When the last packet on the connection arrives in the
+		 * TBRQ, the host issues the close command to the adapter.
+		 */
+
+		while (((tx_inuse = atomic_read(&vcc->sk->wmem_alloc)) > 0)
+							&& (retry < MAX_RETRY))
+		{
+			set_current_state(TASK_UNINTERRUPTIBLE);
+			(void) schedule_timeout(sleep);
+			set_current_state(TASK_RUNNING);
+			if (sleep < HZ) sleep = sleep * 2;
+
+			++retry;
+		}
+
+		if (tx_inuse) hprintk("close tx cid 0x%x tx_inuse = %d\n",
+								cid, tx_inuse);
+
+		/* 2.3.1.1 generic close operations with flush */
+
+		HE_SPIN_LOCK(he_dev, flags);
+		he_writel_tsr4_upper(he_dev, TSR4_FLUSH_CONN, cid);
+					/* also clears TSR4_SESSION_ENDED */
+#ifdef CONFIG_IA64_SGI_SN2
+		(void) he_readl_tsr4(he_dev, cid);
+#endif
+
+		switch(vcc->qos.txtp.traffic_class)
+		{
+			case ATM_UBR:
+				he_writel_tsr1(he_dev, 
+					TSR1_MCR(rate_to_atmf(200000))
+					| TSR1_PCR(0), cid);
+				break;
+			case ATM_CBR:
+				he_writel_tsr14_upper(he_dev, TSR14_DELETE, cid);
+				break;
+		}
+
+
+		tpd = __alloc_tpd(he_dev);
+		if (tpd == NULL)
+		{
+			hprintk("close tx he_alloc_tpd failed cid 0x%x\n", cid);
+			goto close_tx_incomplete;
+		}
+		tpd->status |= TPD_EOS | TPD_INT;
+		tpd->skb = NULL;
+		tpd->vcc = vcc;
+		wmb();
+
+		add_wait_queue(&he_vcc->tx_waitq, &wait);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		__enqueue_tpd(he_dev, tpd, cid);
+		HE_SPIN_UNLOCK(he_dev, flags);
+
+		timeout = schedule_timeout(30*HZ);
+
+		remove_wait_queue(&he_vcc->tx_waitq, &wait);
+		set_current_state(TASK_RUNNING);
+
+		if (timeout == 0)
+		{
+			hprintk("close tx timeout cid 0x%x\n", cid);
+			goto close_tx_incomplete;
+		}
+
+		HE_SPIN_LOCK(he_dev, flags);
+		while (!((tsr4 = he_readl_tsr4(he_dev, cid))
+							& TSR4_SESSION_ENDED))
+		{
+			HPRINTK("close tx cid 0x%x !TSR4_SESSION_ENDED (tsr4 = 0x%x)\n", cid, tsr4);
+			udelay(250);
+		}
+
+		while (TSR0_CONN_STATE(tsr0 = he_readl_tsr0(he_dev, cid)) != 0)
+		{
+			HPRINTK("close tx cid 0x%x TSR0_CONN_STATE != 0 (tsr0 = 0x%x)\n", cid, tsr0);
+			udelay(250);
+		}
+
+close_tx_incomplete:
+
+		if (vcc->qos.txtp.traffic_class == ATM_CBR)
+		{
+			int reg = he_vcc->rc_index;
+
+			HPRINTK("cs_stper reg = %d\n", reg);
+
+			if (he_dev->cs_stper[reg].inuse == 0)
+				hprintk("cs_stper[%d].inuse = 0!\n", reg);
+			else
+				--he_dev->cs_stper[reg].inuse;
+
+			he_dev->total_bw -= he_dev->cs_stper[reg].pcr;
+		}
+		HE_SPIN_UNLOCK(he_dev, flags);
+
+		HPRINTK("close tx cid 0x%x complete\n", cid);
+	}
+
+	kfree(he_vcc);
+
+	clear_bit(ATM_VF_ADDR, &vcc->flags);
+}
+
+static int
+he_sg_send(struct atm_vcc *vcc, unsigned long start, unsigned long size)
+{
+#ifdef USE_SCATTERGATHER
+	return 1;
+#else
+	return 0;
+#endif
+}
+
+static int
+he_send(struct atm_vcc *vcc, struct sk_buff *skb)
+{
+	unsigned long flags;
+	struct he_dev *he_dev = HE_DEV(vcc->dev);
+	unsigned cid = he_mkcid(he_dev, vcc->vpi, vcc->vci);
+	struct he_tpd *tpd;
+#ifdef USE_SCATTERGATHER
+	int i, slot = 0;
+#endif
+
+#define HE_TPD_BUFSIZE 0xffff
+
+	HPRINTK("send %d.%d\n", vcc->vpi, vcc->vci);
+
+	if ((skb->len > HE_TPD_BUFSIZE) ||
+		((vcc->qos.aal == ATM_AAL0) && (skb->len != ATM_AAL0_SDU)))
+	{
+		hprintk("buffer too large (or small) -- %d bytes\n", skb->len );
+		if (vcc->pop)
+			vcc->pop(vcc, skb);
+		else
+			dev_kfree_skb_any(skb);
+		atomic_inc(&vcc->stats->tx_err);
+		return -EINVAL;
+	}
+
+#ifndef USE_SCATTERGATHER
+	if (skb_shinfo(skb)->nr_frags)
+	{
+		hprintk("no scatter/gather support\n");
+		if (vcc->pop)
+			vcc->pop(vcc, skb);
+		else
+			dev_kfree_skb_any(skb);
+		atomic_inc(&vcc->stats->tx_err);
+		return -EINVAL;
+	}
+#endif
+	HE_SPIN_LOCK(he_dev, flags);
+
+	tpd = __alloc_tpd(he_dev);
+	if (tpd == NULL)
+	{
+		if (vcc->pop)
+			vcc->pop(vcc, skb);
+		else
+			dev_kfree_skb_any(skb);
+		atomic_inc(&vcc->stats->tx_err);
+		HE_SPIN_UNLOCK(he_dev, flags);
+		return -ENOMEM;
+	}
+
+	if (vcc->qos.aal == ATM_AAL5)
+		tpd->status |= TPD_CELLTYPE(TPD_USERCELL);
+	else
+	{
+		char *pti_clp = (void *) (skb->data + 3);
+		int clp, pti;
+
+		pti = (*pti_clp & ATM_HDR_PTI_MASK) >> ATM_HDR_PTI_SHIFT; 
+		clp = (*pti_clp & ATM_HDR_CLP);
+		tpd->status |= TPD_CELLTYPE(pti);
+		if (clp) tpd->status |= TPD_CLP;
+
+		skb_pull(skb, ATM_AAL0_SDU - ATM_CELL_PAYLOAD);
+	}
+
+#ifdef USE_SCATTERGATHER
+	tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, skb->data,
+				skb->len - skb->data_len, PCI_DMA_TODEVICE);
+	tpd->iovec[slot].len = skb->len - skb->data_len;
+	++slot;
+
+	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
+	{
+		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+
+		if (slot == TPD_MAXIOV)		/* send tpd; start new tpd */
+		{
+			tpd->vcc = vcc;
+			tpd->skb = NULL;	/* not the last fragment
+						   so dont ->push() yet */
+			wmb();
+
+			__enqueue_tpd(he_dev, tpd, cid);
+			tpd = __alloc_tpd(he_dev);
+			if (tpd == NULL)
+			{
+				if (vcc->pop)
+					vcc->pop(vcc, skb);
+				else
+					dev_kfree_skb_any(skb);
+				atomic_inc(&vcc->stats->tx_err);
+				HE_SPIN_UNLOCK(he_dev, flags);
+				return -ENOMEM;
+			}
+			tpd->status |= TPD_USERCELL;
+			slot = 0;
+		}
+
+		tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev,
+			(void *) page_address(frag->page) + frag->page_offset,
+				frag->size, PCI_DMA_TODEVICE);
+		tpd->iovec[slot].len = frag->size;
+		++slot;
+
+	}
+
+	tpd->iovec[slot-1].len |= TPD_LST;
+#else
+	tpd->address0 = pci_map_single(he_dev->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+	tpd->length0 = skb->len | TPD_LST;
+#endif
+	tpd->status |= TPD_INT;
+
+	tpd->vcc = vcc;
+	tpd->skb = skb;
+	wmb();
+	ATM_SKB(skb)->vcc = vcc;
+
+	__enqueue_tpd(he_dev, tpd, cid);
+	HE_SPIN_UNLOCK(he_dev, flags);
+
+	atomic_inc(&vcc->stats->tx);
+
+	return 0;
+}
+
+static int
+he_ioctl(struct atm_dev *atm_dev, unsigned int cmd, void *arg)
+{
+	unsigned long flags;
+	struct he_dev *he_dev = HE_DEV(atm_dev);
+	struct he_ioctl_reg reg;
+	int err = 0;
+
+	switch (cmd)
+	{
+		case HE_GET_REG:
+			if (!capable(CAP_NET_ADMIN)) return -EPERM;
+
+			copy_from_user(&reg, (struct he_ioctl_reg *) arg,
+						sizeof(struct he_ioctl_reg));
+			HE_SPIN_LOCK(he_dev, flags);
+			switch (reg.type)
+			{
+				case HE_REGTYPE_PCI:
+					reg.val = he_readl(he_dev, reg.addr);
+					break;
+				case HE_REGTYPE_RCM:
+					reg.val =
+						he_readl_rcm(he_dev, reg.addr);
+					break;
+				case HE_REGTYPE_TCM:
+					reg.val =
+						he_readl_tcm(he_dev, reg.addr);
+					break;
+				case HE_REGTYPE_MBOX:
+					reg.val =
+						he_readl_mbox(he_dev, reg.addr);
+					break;
+				default:
+					err = -EINVAL;
+					break;
+			}
+			HE_SPIN_UNLOCK(he_dev, flags);
+			if (err == 0) copy_to_user((struct he_ioctl_reg *) arg, &reg,
+							sizeof(struct he_ioctl_reg));
+			break;
+		default:
+#ifdef CONFIG_ATM_HE_USE_SUNI
+			if (atm_dev->phy && atm_dev->phy->ioctl)
+				err = atm_dev->phy->ioctl(atm_dev, cmd, arg);
+#else /* CONFIG_ATM_HE_USE_SUNI */
+			return -EINVAL;
+#endif /* CONFIG_ATM_HE_USE_SUNI */
+			break;
+	}
+
+	return err;
+}
+
+static void
+he_phy_put(struct atm_dev *atm_dev, unsigned char val, unsigned long addr)
+{
+	unsigned long flags;
+	struct he_dev *he_dev = HE_DEV(atm_dev);
+
+	HPRINTK("phy_put(val 0x%x, addr 0x%lx)\n", val, addr);
+
+	HE_SPIN_LOCK(he_dev, flags);
+        he_writel(he_dev, val, FRAMER + (addr*4));
+#ifdef CONFIG_IA64_SGI_SN2
+	(void) he_readl(he_dev, FRAMER + (addr*4));
+#endif
+	HE_SPIN_UNLOCK(he_dev, flags);
+}
+ 
+        
+static unsigned char
+he_phy_get(struct atm_dev *atm_dev, unsigned long addr)
+{ 
+	unsigned long flags;
+	struct he_dev *he_dev = HE_DEV(atm_dev);
+	unsigned reg;
+
+	HE_SPIN_LOCK(he_dev, flags);
+        reg = he_readl(he_dev, FRAMER + (addr*4));
+	HE_SPIN_UNLOCK(he_dev, flags);
+
+	HPRINTK("phy_get(addr 0x%lx) =0x%x\n", addr, reg);
+	return reg;
+}
+
+static int
+he_proc_read(struct atm_dev *dev, loff_t *pos, char *page)
+{
+	unsigned long flags;
+	struct he_dev *he_dev = HE_DEV(dev);
+	int left, i;
+#ifdef notdef
+	struct he_rbrq *rbrq_tail;
+	struct he_tpdrq *tpdrq_head;
+        int rbpl_head, rbpl_tail;
+#endif
+	static long mcc = 0, oec = 0, dcc = 0, cec = 0;
+
+
+	left = *pos;
+	if (!left--)
+		return sprintf(page, "%s\n", version);
+
+	if (!left--)
+		return sprintf(page, "%s%s\n\n",
+			he_dev->prod_id, he_dev->media & 0x40 ? "SM" : "MM");
+
+	if (!left--)
+		return sprintf(page, "Mismatched Cells  VPI/VCI Not Open  Dropped Cells  RCM Dropped Cells\n");
+
+	HE_SPIN_LOCK(he_dev, flags);
+	mcc += he_readl(he_dev, MCC);
+	oec += he_readl(he_dev, OEC);
+	dcc += he_readl(he_dev, DCC);
+	cec += he_readl(he_dev, CEC);
+	HE_SPIN_UNLOCK(he_dev, flags);
+
+	if (!left--)
+		return sprintf(page, "%16ld  %16ld  %13ld  %17ld\n\n", 
+							mcc, oec, dcc, cec);
+
+	if (!left--)
+		return sprintf(page, "irq_size = %d  inuse = ?  peak = %d\n",
+				CONFIG_IRQ_SIZE, he_dev->irq_peak);
+
+	if (!left--)
+		return sprintf(page, "tpdrq_size = %d  inuse = ?\n",
+						CONFIG_TPDRQ_SIZE);
+
+	if (!left--)
+		return sprintf(page, "rbrq_size = %d  inuse = ?  peak = %d\n",
+				CONFIG_RBRQ_SIZE, he_dev->rbrq_peak);
+
+	if (!left--)
+		return sprintf(page, "tbrq_size = %d  peak = %d\n",
+					CONFIG_TBRQ_SIZE, he_dev->tbrq_peak);
+
+
+#ifdef notdef
+        rbpl_head = RBPL_MASK(he_readl(he_dev, G0_RBPL_S));
+        rbpl_tail = RBPL_MASK(he_readl(he_dev, G0_RBPL_T));
+
+	inuse = rbpl_head - rbpl_tail;
+	if (inuse < 0) inuse += CONFIG_RBPL_SIZE * sizeof(struct he_rbp);
+	inuse /= sizeof(struct he_rbp);
+
+	if (!left--)
+		return sprintf(page, "rbpl_size = %d  inuse = %d\n\n",
+						CONFIG_RBPL_SIZE, inuse);
+#endif
+
+	if (!left--)
+		return sprintf(page, "rate controller periods (cbr)\n                 pcr  #vc\n");
+
+	for (i = 0; i < HE_NUM_CS_STPER; ++i)
+		if (!left--)
+			return sprintf(page, "cs_stper%-2d  %8ld  %3d\n", i,
+						he_dev->cs_stper[i].pcr,
+						he_dev->cs_stper[i].inuse);
+
+	if (!left--)
+		return sprintf(page, "total bw (cbr): %d  (limit %d)\n",
+			he_dev->total_bw, he_dev->atm_dev->link_rate * 10 / 9);
+
+	return 0;
+}
+
+/* eeprom routines  -- see 4.7 */
+
+u8
+read_prom_byte(struct he_dev *he_dev, int addr)
+{
+	u32 val = 0, tmp_read = 0;
+	int i, j = 0;
+	u8 byte_read = 0;
+
+	val = readl(he_dev->membase + HOST_CNTL);
+	val &= 0xFFFFE0FF;
+       
+	/* Turn on write enable */
+	val |= 0x800;
+	he_writel(he_dev, val, HOST_CNTL);
+       
+	/* Send READ instruction */
+	for (i=0; i<sizeof(readtab)/sizeof(readtab[0]); i++) {
+		he_writel(he_dev, val | readtab[i], HOST_CNTL);
+		udelay(EEPROM_DELAY);
+	}
+       
+        /* Next, we need to send the byte address to read from */
+	for (i=7; i>=0; i--) {
+		he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL);
+		udelay(EEPROM_DELAY);
+		he_writel(he_dev, val | clocktab[j++] | (((addr >> i) & 1) << 9), HOST_CNTL);
+		udelay(EEPROM_DELAY);
+	}
+       
+	j=0;
+
+	val &= 0xFFFFF7FF;      /* Turn off write enable */
+	he_writel(he_dev, val, HOST_CNTL);
+       
+	/* Now, we can read data from the EEPROM by clocking it in */
+	for (i=7; i>=0; i--) {
+		he_writel(he_dev, val | clocktab[j++], HOST_CNTL);
+	        udelay(EEPROM_DELAY);
+	        tmp_read = he_readl(he_dev, HOST_CNTL);
+	        byte_read |= (unsigned char)
+	                        ((tmp_read & ID_DOUT)
+	                         >> ID_DOFFSET << i);
+		he_writel(he_dev, val | clocktab[j++], HOST_CNTL);
+		udelay(EEPROM_DELAY);
+	}
+       
+	he_writel(he_dev, val | ID_CS, HOST_CNTL);
+	udelay(EEPROM_DELAY);
+
+        return (byte_read);
+}
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("chas williams <chas@cmf.nrl.navy.mil>");
+MODULE_DESCRIPTION("ForeRunnerHE ATM Adapter driver");
+MODULE_PARM(disable64, "h");
+MODULE_PARM_DESC(disable64, "disable 64-bit pci bus transfers");
+MODULE_PARM(nvpibits, "i");
+MODULE_PARM_DESC(nvpibits, "numbers of bits for vpi (default 0)");
+MODULE_PARM(nvcibits, "i");
+MODULE_PARM_DESC(nvcibits, "numbers of bits for vci (default 12)");
+MODULE_PARM(rx_skb_reserve, "i");
+MODULE_PARM_DESC(rx_skb_reserve, "padding for receive skb (default 16)");
+MODULE_PARM(irq_coalesce, "i");
+MODULE_PARM_DESC(irq_coalesce, "use interrupt coalescing (default 1)");
+MODULE_PARM(sdh, "i");
+MODULE_PARM_DESC(sdh, "use SDH framing (default 0)");
+
+static struct pci_device_id he_pci_tbl[] __devinitdata = {
+	{ PCI_VENDOR_ID_FORE, PCI_DEVICE_ID_FORE_HE, PCI_ANY_ID, PCI_ANY_ID,
+	  0, 0, 0 },
+        { 0, }
+};
+
+static struct pci_driver he_driver = {
+	.name =		"he",
+	.probe =	he_init_one,
+	.remove =	__devexit_p(he_remove_one),
+	.id_table =	he_pci_tbl,
+};
+
+static int __init he_init(void)
+{
+        return pci_module_init(&he_driver);
+}
+
+static void __exit he_cleanup(void)
+{
+        pci_unregister_driver(&he_driver);
+}
+
+module_init(he_init);
+module_exit(he_cleanup);
diff -Nru a/drivers/atm/he.h b/drivers/atm/he.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/atm/he.h	Thu May  8 18:22:41 2003
@@ -0,0 +1,938 @@
+/* $Id: he.h,v 1.4 2003/05/06 22:48:00 chas Exp $ */
+
+/*
+
+  he.h
+
+  ForeRunnerHE ATM Adapter driver for ATM on Linux
+  Copyright (C) 1999-2001  Naval Research Laboratory
+
+  This library is free software; you can redistribute it and/or
+  modify it under the terms of the GNU Lesser General Public
+  License as published by the Free Software Foundation; either
+  version 2.1 of the License, or (at your option) any later version.
+
+  This library 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
+  Lesser General Public License for more details.
+
+  You should have received a copy of the GNU Lesser General Public
+  License along with this library; if not, write to the Free Software
+  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+*/
+
+/*
+
+  he.h
+
+  ForeRunnerHE ATM Adapter driver for ATM on Linux
+  Copyright (C) 1999-2000  Naval Research Laboratory
+
+  Permission to use, copy, modify and distribute this software and its
+  documentation is hereby granted, provided that both the copyright
+  notice and this permission notice appear in all copies of the software,
+  derivative works or modified versions, and any portions thereof, and
+  that both notices appear in supporting documentation.
+
+  NRL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION AND
+  DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES WHATSOEVER
+  RESULTING FROM THE USE OF THIS SOFTWARE.
+
+ */
+
+#ifndef _HE_H_
+#define _HE_H_
+
+#define DEV_LABEL       "he"
+
+#define CONFIG_DEFAULT_VCIBITS	12
+#define CONFIG_DEFAULT_VPIBITS	0
+
+#define CONFIG_IRQ_SIZE		128
+#define CONFIG_IRQ_THRESH	(CONFIG_IRQ_SIZE/2)
+
+#define CONFIG_NUMTPDS		256
+
+#define CONFIG_TPDRQ_SIZE	512
+#define TPDRQ_MASK(x)		(((unsigned long)(x))&((CONFIG_TPDRQ_SIZE<<3)-1))
+
+#define CONFIG_RBRQ_SIZE	512
+#define CONFIG_RBRQ_THRESH	400
+#define RBRQ_MASK(x)		(((unsigned long)(x))&((CONFIG_RBRQ_SIZE<<3)-1))
+
+#define CONFIG_TBRQ_SIZE	512
+#define CONFIG_TBRQ_THRESH	400
+#define TBRQ_MASK(x)		(((unsigned long)(x))&((CONFIG_TBRQ_SIZE<<2)-1))
+
+#define CONFIG_RBPL_SIZE	512
+#define CONFIG_RBPL_THRESH	64
+#define CONFIG_RBPL_BUFSIZE	4096
+#define RBPL_MASK(x)		(((unsigned long)(x))&((CONFIG_RBPL_SIZE<<3)-1))
+
+#define CONFIG_RBPS_SIZE	1024
+#define CONFIG_RBPS_THRESH	64
+#define CONFIG_RBPS_BUFSIZE	128
+#define RBPS_MASK(x)		(((unsigned long)(x))&((CONFIG_RBPS_SIZE<<3)-1))
+
+/* 5.1.3 initialize connection memory */
+
+#define CONFIG_RSRA		0x00000
+#define CONFIG_RCMLBM		0x08000
+#define CONFIG_RCMABR		0x0d800
+#define CONFIG_RSRB		0x0e000
+
+#define CONFIG_TSRA		0x00000
+#define CONFIG_TSRB		0x08000
+#define CONFIG_TSRC		0x0c000
+#define CONFIG_TSRD		0x0e000
+#define CONFIG_TMABR		0x0f000
+#define CONFIG_TPDBA		0x10000
+
+#define HE_MAXCIDBITS		12
+
+/* 2.9.3.3 interrupt encodings */
+
+struct he_irq {
+	volatile u32 isw;
+};
+
+#define IRQ_ALIGNMENT		0x1000
+
+#define NEXT_ENTRY(base, tail, mask) \
+				(((unsigned long)base)|(((unsigned long)(tail+1))&mask))
+
+#define ITYPE_INVALID		0xffffffff
+#define ITYPE_TBRQ_THRESH	(0<<3)
+#define ITYPE_TPD_COMPLETE	(1<<3)
+#define ITYPE_RBPS_THRESH	(2<<3)
+#define ITYPE_RBPL_THRESH	(3<<3)
+#define ITYPE_RBRQ_THRESH	(4<<3)
+#define ITYPE_RBRQ_TIMER	(5<<3)
+#define ITYPE_PHY		(6<<3)
+#define ITYPE_OTHER		0x80
+#define ITYPE_PARITY		0x81
+#define ITYPE_ABORT		0x82
+
+#define ITYPE_GROUP(x)		(x & 0x7)
+#define ITYPE_TYPE(x)		(x & 0xf8)
+
+#define HE_NUM_GROUPS 8
+
+/* 2.1.4 transmit packet descriptor */
+
+struct he_tpd {
+
+	/* read by the adapter */
+
+	volatile u32 status;
+	volatile u32 reserved;
+
+#define TPD_MAXIOV	3
+	struct {
+		u32 addr, len;
+	} iovec[TPD_MAXIOV];
+
+#define address0 iovec[0].addr
+#define length0 iovec[0].len
+
+	/* linux-atm extensions */
+
+	struct sk_buff *skb;
+	struct atm_vcc *vcc;
+
+#ifdef USE_TPD_POOL
+	struct list_head entry;
+#else
+	u32 inuse;
+	char padding[32 - sizeof(u32) - (2*sizeof(void*))];
+#endif
+};
+
+#define TPD_ALIGNMENT	64
+#define TPD_LEN_MASK	0xffff
+
+#define TPD_ADDR_SHIFT  6
+#define TPD_MASK	0xffffffc0
+#define TPD_ADDR(x)	((x) & TPD_MASK)
+#define TPD_INDEX(x)	(TPD_ADDR(x) >> TPD_ADDR_SHIFT)
+
+
+/* table 2.3 transmit buffer return elements */
+
+struct he_tbrq {
+	volatile u32 tbre;
+};
+
+#define TBRQ_ALIGNMENT	CONFIG_TBRQ_SIZE
+
+#define TBRQ_TPD(tbrq)		((tbrq)->tbre & 0xffffffc0)
+#define TBRQ_EOS(tbrq)		((tbrq)->tbre & (1<<3))
+#define TBRQ_MULTIPLE(tbrq)	((tbrq)->tbre & (1))
+
+/* table 2.21 receive buffer return queue element field organization */
+
+struct he_rbrq {
+	volatile u32 addr;
+	volatile u32 cidlen;
+};
+
+#define RBRQ_ALIGNMENT	CONFIG_RBRQ_SIZE
+
+#define RBRQ_ADDR(rbrq)		((rbrq)->addr & 0xffffffc0)
+#define RBRQ_CRC_ERR(rbrq)	((rbrq)->addr & (1<<5))
+#define RBRQ_LEN_ERR(rbrq)	((rbrq)->addr & (1<<4))
+#define RBRQ_END_PDU(rbrq)	((rbrq)->addr & (1<<3))
+#define RBRQ_AAL5_PROT(rbrq)	((rbrq)->addr & (1<<2))
+#define RBRQ_CON_CLOSED(rbrq)	((rbrq)->addr & (1<<1))
+#define RBRQ_HBUF_ERR(rbrq)	((rbrq)->addr & 1)
+#define RBRQ_CID(rbrq)		(((rbrq)->cidlen >> 16) & 0x1fff)
+#define RBRQ_BUFLEN(rbrq)	((rbrq)->cidlen & 0xffff)
+
+/* figure 2.3 transmit packet descriptor ready queue */
+
+struct he_tpdrq {
+	volatile u32 tpd;
+	volatile u32 cid;
+};
+
+#define TPDRQ_ALIGNMENT CONFIG_TPDRQ_SIZE
+
+/* table 2.30 host status page detail */
+
+#define HSP_ALIGNMENT	0x400		/* must align on 1k boundary */
+
+struct he_hsp {
+	struct he_hsp_entry {
+		volatile u32 tbrq_tail; 
+		volatile u32 reserved1[15];
+		volatile u32 rbrq_tail; 
+		volatile u32 reserved2[15];
+	} group[HE_NUM_GROUPS];
+};
+
+/* figure 2.9 receive buffer pools */
+
+struct he_rbp {
+	volatile u32 phys;
+	volatile u32 status;
+};
+
+/* NOTE: it is suggested that virt be the virtual address of the host
+   buffer.  on a 64-bit machine, this would not work.  Instead, we
+   store the real virtual address in another list, and store an index
+   (and buffer status) in the virt member.
+*/
+
+#define RBP_INDEX_OFF	6
+#define RBP_INDEX(x)	(((long)(x) >> RBP_INDEX_OFF) & 0xffff)
+#define RBP_LOANED	0x80000000
+#define RBP_SMALLBUF	0x40000000
+
+struct he_virt {
+	void *virt;
+};
+
+#define RBPL_ALIGNMENT CONFIG_RBPL_SIZE
+#define RBPS_ALIGNMENT CONFIG_RBPS_SIZE
+
+#ifdef notyet
+struct he_group {
+	u32 rpbs_size, rpbs_qsize;
+	struct he_rbp rbps_ba;
+
+	u32 rpbl_size, rpbl_qsize;
+	struct he_rpb_entry *rbpl_ba;
+};
+#endif
+
+#define HE_LOOKUP_VCC(dev, cid) ((dev)->he_vcc_table[(cid)].vcc)
+
+struct he_vcc_table 
+{
+	struct atm_vcc *vcc;
+};
+
+struct he_cs_stper
+{
+	long pcr;
+	int inuse;
+};
+
+#define HE_NUM_CS_STPER		16
+
+struct he_dev {
+	unsigned int number;
+	unsigned int irq;
+	unsigned long membase;
+
+	char prod_id[30];
+	char mac_addr[6];
+	int media;			/*  
+					 *  0x26 = HE155 MM 
+					 *  0x27 = HE622 MM 
+					 *  0x46 = HE155 SM 
+					 *  0x47 = HE622 SM 
+					 */
+
+
+	unsigned int vcibits, vpibits;
+	unsigned int cells_per_row;
+	unsigned int bytes_per_row;
+	unsigned int cells_per_lbuf;
+	unsigned int r0_numrows, r0_startrow, r0_numbuffs;
+	unsigned int r1_numrows, r1_startrow, r1_numbuffs;
+	unsigned int tx_numrows, tx_startrow, tx_numbuffs;
+	unsigned int buffer_limit;
+
+	struct he_vcc_table *he_vcc_table;
+
+#ifdef notyet
+	struct he_group group[HE_NUM_GROUPS];
+#endif
+	struct he_cs_stper cs_stper[HE_NUM_CS_STPER];
+	unsigned total_bw;
+
+	dma_addr_t irq_phys;
+	struct he_irq *irq_base, *irq_head, *irq_tail;
+	volatile unsigned *irq_tailoffset;
+	int irq_peak;
+
+#ifdef USE_TASKLET
+	struct tasklet_struct tasklet;
+#endif
+#ifdef USE_TPD_POOL
+	struct pci_pool *tpd_pool;
+	struct list_head outstanding_tpds;
+#else
+	struct he_tpd *tpd_head, *tpd_base, *tpd_end;
+	dma_addr_t tpd_base_phys;
+#endif
+
+	dma_addr_t tpdrq_phys;
+	struct he_tpdrq *tpdrq_base, *tpdrq_tail, *tpdrq_head;
+
+	spinlock_t global_lock;		/* 8.1.5 pci transaction ordering
+					  error problem */
+	dma_addr_t rbrq_phys;
+	struct he_rbrq *rbrq_base, *rbrq_head;
+	int rbrq_peak;
+
+#ifdef USE_RBPL_POOL
+	struct pci_pool *rbpl_pool;
+#else
+	void *rbpl_pages;
+	dma_addr_t rbpl_pages_phys;
+#endif
+	dma_addr_t rbpl_phys;
+	struct he_rbp *rbpl_base, *rbpl_tail;
+	struct he_virt *rbpl_virt;
+	int rbpl_peak;
+
+#ifdef USE_RBPS
+#ifdef USE_RBPS_POOL
+	struct pci_pool *rbps_pool;
+#else
+	void *rbps_pages;
+	dma_addr_t rbps_pages_phys;
+#endif
+#endif
+	dma_addr_t rbps_phys;
+	struct he_rbp *rbps_base, *rbps_tail;
+	struct he_virt *rbps_virt;
+	int rbps_peak;
+
+	dma_addr_t tbrq_phys;
+	struct he_tbrq *tbrq_base, *tbrq_head;
+	int tbrq_peak;
+
+	dma_addr_t hsp_phys;
+	struct he_hsp *hsp;
+
+	struct pci_dev *pci_dev;
+	struct atm_dev *atm_dev;
+	struct he_dev *next;
+};
+
+struct he_iovec
+{
+	u32 iov_base;
+	u32 iov_len;
+};
+
+#define HE_MAXIOV 20
+
+struct he_vcc
+{
+	struct he_iovec iov_head[HE_MAXIOV];
+	struct he_iovec *iov_tail;
+	int pdu_len;
+
+	int rc_index;
+
+	wait_queue_head_t rx_waitq;
+	wait_queue_head_t tx_waitq;
+};
+
+#define HE_VCC(vcc)	((struct he_vcc *)(vcc->dev_data))
+
+#define PCI_VENDOR_ID_FORE	0x1127
+#define PCI_DEVICE_ID_FORE_HE	0x400
+
+#define HE_DMA_MASK		0xffffffff
+
+#define GEN_CNTL_0				0x40
+#define  INT_PROC_ENBL		(1<<25)
+#define  SLAVE_ENDIAN_MODE	(1<<16)
+#define  MRL_ENB		(1<<5)
+#define  MRM_ENB		(1<<4)
+#define  INIT_ENB		(1<<2)
+#define  IGNORE_TIMEOUT		(1<<1)
+#define  ENBL_64		(1<<0)
+
+#define MIN_PCI_LATENCY		32	/* errata 8.1.3 */
+
+#define HE_DEV(dev) ((struct he_dev *) (dev)->dev_data)
+
+#define he_is622(dev)	((dev)->media & 0x1)
+
+#define HE_REGMAP_SIZE	0x100000
+
+#define RESET_CNTL	0x80000
+#define  BOARD_RST_STATUS	(1<<6)
+
+#define HOST_CNTL	0x80004
+#define  PCI_BUS_SIZE64			(1<<27)
+#define  DESC_RD_STATIC_64		(1<<26)
+#define  DATA_RD_STATIC_64		(1<<25)
+#define  DATA_WR_STATIC_64		(1<<24)
+#define  ID_CS				(1<<12)
+#define  ID_WREN			(1<<11)
+#define  ID_DOUT			(1<<10)
+#define   ID_DOFFSET			10
+#define  ID_DIN				(1<<9)
+#define  ID_CLOCK			(1<<8)
+#define  QUICK_RD_RETRY			(1<<7)
+#define  QUICK_WR_RETRY			(1<<6)
+#define  OUTFF_ENB			(1<<5)
+#define  CMDFF_ENB			(1<<4)
+#define  PERR_INT_ENB			(1<<2)
+#define  IGNORE_INTR			(1<<0)
+
+#define LB_SWAP		0x80008
+#define  SWAP_RNUM_MAX(x)	(x<<27)
+#define  DATA_WR_SWAP		(1<<20)
+#define  DESC_RD_SWAP		(1<<19)
+#define  DATA_RD_SWAP		(1<<18)
+#define  INTR_SWAP		(1<<17)
+#define  DESC_WR_SWAP		(1<<16)
+#define  SDRAM_INIT		(1<<15)
+#define  BIG_ENDIAN_HOST	(1<<14)
+#define  XFER_SIZE		(1<<7)
+
+#define LB_MEM_ADDR	0x8000c
+#define LB_MEM_DATA	0x80010
+
+#define LB_MEM_ACCESS	0x80014
+#define  LB_MEM_HNDSHK		(1<<30)
+#define  LM_MEM_WRITE		(0x7)
+#define  LM_MEM_READ		(0x3)
+
+#define SDRAM_CTL	0x80018
+#define  LB_64_ENB		(1<<3)
+#define  LB_TWR			(1<<2)
+#define  LB_TRP			(1<<1)
+#define  LB_TRAS		(1<<0)
+
+#define INT_FIFO	0x8001c
+#define  INT_MASK_D		(1<<15)
+#define  INT_MASK_C		(1<<14)
+#define  INT_MASK_B		(1<<13)
+#define  INT_MASK_A		(1<<12)
+#define  INT_CLEAR_D		(1<<11)
+#define  INT_CLEAR_C		(1<<10)
+#define  INT_CLEAR_B		(1<<9)
+#define  INT_CLEAR_A		(1<<8)
+
+#define ABORT_ADDR	0x80020
+
+#define IRQ0_BASE	0x80080
+#define  IRQ_BASE(x)		(x<<12)
+#define  IRQ_MASK		((CONFIG_IRQ_SIZE<<2)-1)	/* was 0x3ff */
+#define  IRQ_TAIL(x)		(((unsigned long)(x)) & IRQ_MASK)
+#define IRQ0_HEAD	0x80084
+#define  IRQ_SIZE(x)		(x<<22)
+#define  IRQ_THRESH(x)		(x<<12)
+#define  IRQ_HEAD(x)		(x<<2)
+/* #define  IRQ_PENDING		(1) 		conflict with linux/irq.h */
+#define IRQ0_CNTL	0x80088
+#define  IRQ_ADDRSEL(x)		(x<<2)
+#define  IRQ_INT_A		(0<<2)
+#define  IRQ_INT_B		(1<<2)
+#define  IRQ_INT_C		(2<<2)
+#define  IRQ_INT_D		(3<<2)
+#define  IRQ_TYPE_ADDR		0x1
+#define  IRQ_TYPE_LINE		0x0
+#define IRQ0_DATA	0x8008c
+
+#define IRQ1_BASE	0x80090
+#define IRQ1_HEAD	0x80094
+#define IRQ1_CNTL	0x80098
+#define IRQ1_DATA	0x8009c
+
+#define IRQ2_BASE	0x800a0
+#define IRQ2_HEAD	0x800a4
+#define IRQ2_CNTL	0x800a8
+#define IRQ2_DATA	0x800ac
+
+#define IRQ3_BASE	0x800b0
+#define IRQ3_HEAD	0x800b4
+#define IRQ3_CNTL	0x800b8
+#define IRQ3_DATA	0x800bc
+
+#define GRP_10_MAP	0x800c0
+#define GRP_32_MAP	0x800c4
+#define GRP_54_MAP	0x800c8
+#define GRP_76_MAP	0x800cc
+
+#define	G0_RBPS_S	0x80400
+#define G0_RBPS_T	0x80404
+#define  RBP_TAIL(x)		((x)<<3)
+#define  RBP_MASK(x)		((x)|0x1fff)
+#define G0_RBPS_QI	0x80408
+#define  RBP_QSIZE(x)		((x)<<14)
+#define  RBP_INT_ENB		(1<<13)
+#define  RBP_THRESH(x)		(x)
+#define G0_RBPS_BS	0x8040c
+#define G0_RBPL_S	0x80410
+#define G0_RBPL_T	0x80414
+#define G0_RBPL_QI	0x80418 
+#define G0_RBPL_BS	0x8041c
+
+#define	G1_RBPS_S	0x80420
+#define G1_RBPS_T	0x80424
+#define G1_RBPS_QI	0x80428
+#define G1_RBPS_BS	0x8042c
+#define G1_RBPL_S	0x80430
+#define G1_RBPL_T	0x80434
+#define G1_RBPL_QI	0x80438
+#define G1_RBPL_BS	0x8043c
+
+#define	G2_RBPS_S	0x80440
+#define G2_RBPS_T	0x80444
+#define G2_RBPS_QI	0x80448
+#define G2_RBPS_BS	0x8044c
+#define G2_RBPL_S	0x80450
+#define G2_RBPL_T	0x80454
+#define G2_RBPL_QI	0x80458
+#define G2_RBPL_BS	0x8045c
+
+#define	G3_RBPS_S	0x80460
+#define G3_RBPS_T	0x80464
+#define G3_RBPS_QI	0x80468
+#define G3_RBPS_BS	0x8046c
+#define G3_RBPL_S	0x80470
+#define G3_RBPL_T	0x80474
+#define G3_RBPL_QI	0x80478
+#define G3_RBPL_BS	0x8047c
+
+#define	G4_RBPS_S	0x80480
+#define G4_RBPS_T	0x80484
+#define G4_RBPS_QI	0x80488
+#define G4_RBPS_BS	0x8048c
+#define G4_RBPL_S	0x80490
+#define G4_RBPL_T	0x80494
+#define G4_RBPL_QI	0x80498
+#define G4_RBPL_BS	0x8049c
+
+#define	G5_RBPS_S	0x804a0
+#define G5_RBPS_T	0x804a4
+#define G5_RBPS_QI	0x804a8
+#define G5_RBPS_BS	0x804ac
+#define G5_RBPL_S	0x804b0
+#define G5_RBPL_T	0x804b4
+#define G5_RBPL_QI	0x804b8
+#define G5_RBPL_BS	0x804bc
+
+#define	G6_RBPS_S	0x804c0
+#define G6_RBPS_T	0x804c4
+#define G6_RBPS_QI	0x804c8
+#define G6_RBPS_BS	0x804cc
+#define G6_RBPL_S	0x804d0
+#define G6_RBPL_T	0x804d4
+#define G6_RBPL_QI	0x804d8
+#define G6_RBPL_BS	0x804dc
+
+#define	G7_RBPS_S	0x804e0
+#define G7_RBPS_T	0x804e4
+#define G7_RBPS_QI	0x804e8
+#define G7_RBPS_BS	0x804ec
+
+#define G7_RBPL_S	0x804f0
+#define G7_RBPL_T	0x804f4
+#define G7_RBPL_QI	0x804f8
+#define G7_RBPL_BS	0x804fc
+
+#define G0_RBRQ_ST	0x80500
+#define G0_RBRQ_H	0x80504
+#define G0_RBRQ_Q	0x80508
+#define  RBRQ_THRESH(x)		((x)<<13)
+#define  RBRQ_SIZE(x)		(x)
+#define G0_RBRQ_I	0x8050c
+#define  RBRQ_TIME(x)		((x)<<8)
+#define  RBRQ_COUNT(x)		(x)
+
+/* fill in 1 ... 7 later */
+
+#define G0_TBRQ_B_T	0x80600
+#define G0_TBRQ_H	0x80604
+#define G0_TBRQ_S	0x80608
+#define G0_TBRQ_THRESH	0x8060c
+#define  TBRQ_THRESH(x)		(x)
+
+/* fill in 1 ... 7 later */
+
+#define RH_CONFIG	0x805c0
+#define  PHY_INT_ENB	(1<<10)
+#define  OAM_GID(x)	(x<<7)
+#define  PTMR_PRE(x)	(x)
+
+#define G0_INMQ_S	0x80580
+#define G0_INMQ_L	0x80584
+#define G1_INMQ_S	0x80588
+#define G1_INMQ_L	0x8058c
+#define G2_INMQ_S	0x80590
+#define G2_INMQ_L	0x80594
+#define G3_INMQ_S	0x80598
+#define G3_INMQ_L	0x8059c
+#define G4_INMQ_S	0x805a0
+#define G4_INMQ_L	0x805a4
+#define G5_INMQ_S	0x805a8
+#define G5_INMQ_L	0x805ac
+#define G6_INMQ_S	0x805b0
+#define G6_INMQ_L	0x805b4
+#define G7_INMQ_S	0x805b8
+#define G7_INMQ_L	0x805bc
+
+#define TPDRQ_B_H	0x80680
+#define TPDRQ_T		0x80684
+#define TPDRQ_S		0x80688
+
+#define UBUFF_BA	0x8068c
+
+#define RLBF0_H		0x806c0
+#define RLBF0_T		0x806c4
+#define RLBF1_H		0x806c8
+#define RLBF1_T		0x806cc
+#define RLBC_H		0x806d0
+#define RLBC_T		0x806d4
+#define RLBC_H2		0x806d8
+#define TLBF_H		0x806e0
+#define TLBF_T		0x806e4
+#define RLBF0_C		0x806e8
+#define RLBF1_C		0x806ec
+#define RXTHRSH		0x806f0
+#define LITHRSH		0x806f4
+
+#define LBARB		0x80700
+#define  SLICE_X(x)		 (x<<28)
+#define  ARB_RNUM_MAX(x)	 (x<<23)
+#define  TH_PRTY(x)		 (x<<21)
+#define  RH_PRTY(x)		 (x<<19)
+#define  TL_PRTY(x)		 (x<<17)
+#define  RL_PRTY(x)		 (x<<15)
+#define  BUS_MULTI(x)		 (x<<8)
+#define  NET_PREF(x)		 (x)
+
+#define SDRAMCON	0x80704
+#define	 BANK_ON		(1<<14)
+#define	 WIDE_DATA		(1<<13)
+#define	 TWR_WAIT		(1<<12)
+#define	 TRP_WAIT		(1<<11)
+#define	 TRAS_WAIT		(1<<10)
+#define	 REF_RATE(x)		(x)
+
+#define LBSTAT		0x80708
+
+#define RCC_STAT	0x8070c
+#define  RCC_BUSY		(1)
+
+#define TCMCONFIG	0x80740
+#define  TM_DESL2		(1<<10)
+#define	 TM_BANK_WAIT(x)	(x<<6)
+#define	 TM_ADD_BANK4(x)	(x<<4)
+#define  TM_PAR_CHECK(x)	(x<<3)
+#define  TM_RW_WAIT(x)		(x<<2)
+#define  TM_SRAM_TYPE(x)	(x)
+
+#define TSRB_BA		0x80744	
+#define TSRC_BA		0x80748	
+#define TMABR_BA	0x8074c	
+#define TPD_BA		0x80750	
+#define TSRD_BA		0x80758	
+
+#define TX_CONFIG	0x80760
+#define  DRF_THRESH(x)		(x<<22)
+#define  TX_UT_MODE(x)		(x<<21)
+#define  TX_VCI_MASK(x)		(x<<17)
+#define  LBFREE_CNT(x)		(x)
+
+#define TXAAL5_PROTO	0x80764
+#define  CPCS_UU(x)		(x<<8)
+#define  CPI(x)			(x)
+
+#define RCMCONFIG	0x80780
+#define  RM_DESL2(x)		(x<<10)
+#define  RM_BANK_WAIT(x)	(x<<6)
+#define  RM_ADD_BANK(x)		(x<<4)
+#define  RM_PAR_CHECK(x)	(x<<3)
+#define  RM_RW_WAIT(x)		(x<<2)
+#define  RM_SRAM_TYPE(x)	(x)
+
+#define RCMRSRB_BA	0x80784
+#define RCMLBM_BA	0x80788
+#define RCMABR_BA	0x8078c
+
+#define RC_CONFIG	0x807c0
+#define  UT_RD_DELAY(x)		(x<<11)
+#define  WRAP_MODE(x)		(x<<10)
+#define  RC_UT_MODE(x)		(x<<9)
+#define  RX_ENABLE		(1<<8)
+#define  RX_VALVP(x)		(x<<4)
+#define  RX_VALVC(x)		(x)
+
+#define MCC		0x807c4
+#define OEC		0x807c8
+#define DCC		0x807cc
+#define CEC		0x807d0
+
+#define HSP_BA		0x807f0
+
+#define LB_CONFIG	0x807f4
+#define  LB_SIZE(x)		(x)
+
+#define CON_DAT		0x807f8
+#define CON_CTL		0x807fc
+#define  CON_CTL_MBOX		(2<<30)
+#define  CON_CTL_TCM		(1<<30)
+#define  CON_CTL_RCM		(0<<30)
+#define  CON_CTL_WRITE		(1<<29)
+#define  CON_CTL_READ		(0<<29)
+#define  CON_CTL_BUSY		(1<<28)
+#define  CON_BYTE_DISABLE_3	(1<<22)		/* 24..31 */
+#define  CON_BYTE_DISABLE_2	(1<<21)		/* 16..23 */
+#define  CON_BYTE_DISABLE_1	(1<<20)		/* 8..15 */
+#define  CON_BYTE_DISABLE_0	(1<<19)		/* 0..7 */
+#define  CON_CTL_ADDR(x)	(x)
+
+#define FRAMER		0x80800		/* to 0x80bfc */
+
+/* 3.3 network controller (internal) mailbox registers */
+
+#define CS_STPER0	0x0
+	/* ... */
+#define CS_STPER31	0x01f
+
+#define CS_STTIM0	0x020
+	/* ... */
+#define CS_STTIM31	0x03f
+
+#define CS_TGRLD0	0x040
+	/* ... */
+#define CS_TGRLD15	0x04f
+
+#define CS_ERTHR0	0x050
+#define CS_ERTHR1	0x051
+#define CS_ERTHR2	0x052
+#define CS_ERTHR3	0x053
+#define CS_ERTHR4	0x054
+#define CS_ERCTL0	0x055
+#define  TX_ENABLE		(1<<28)
+#define  ER_ENABLE		(1<<27)
+#define CS_ERCTL1	0x056
+#define CS_ERCTL2	0x057
+#define CS_ERSTAT0	0x058
+#define CS_ERSTAT1	0x059
+
+#define CS_RTCCT	0x060
+#define CS_RTFWC	0x061
+#define CS_RTFWR	0x062
+#define CS_RTFTC	0x063
+#define CS_RTATR	0x064
+
+#define CS_TFBSET	0x070
+#define CS_TFBADD	0x071
+#define CS_TFBSUB	0x072
+#define CS_WCRMAX	0x073
+#define CS_WCRMIN	0x074
+#define CS_WCRINC	0x075
+#define CS_WCRDEC	0x076
+#define CS_WCRCEIL	0x077
+#define CS_BWDCNT	0x078
+
+#define CS_OTPPER	0x080
+#define CS_OTWPER	0x081
+#define CS_OTTLIM	0x082
+#define CS_OTTCNT	0x083
+
+#define CS_HGRRT0	0x090
+	/* ... */
+#define CS_HGRRT7	0x097
+
+#define CS_ORPTRS	0x0a0
+
+#define RXCON_CLOSE	0x100
+
+
+#define RCM_MEM_SIZE	0x10000		/* 1M of 32-bit registers */
+#define TCM_MEM_SIZE	0x20000		/* 2M of 32-bit registers */
+
+/* 2.5 transmit connection memory registers */
+
+#define TSR0_CONN_STATE(x)	((x>>28) & 0x7)
+#define TSR0_USE_WMIN		(1<<23)
+#define TSR0_GROUP(x)		((x & 0x7)<<18)
+#define TSR0_ABR		(2<<16)
+#define TSR0_UBR		(1<<16)
+#define TSR0_CBR		(0<<16)
+#define TSR0_PROT		(1<<15)
+#define TSR0_AAL0_SDU		(2<<12)
+#define TSR0_AAL0		(1<<12)
+#define TSR0_AAL5		(0<<12)
+#define TSR0_HALT_ER		(1<<11)
+#define TSR0_MARK_CI		(1<<10)
+#define TSR0_MARK_ER		(1<<9)
+#define TSR0_UPDATE_GER		(1<<8)
+#define TSR0_RC_INDEX(x)	(x & 0x1F)
+
+#define TSR1_PCR(x)		((x & 0x7FFF)<<16)
+#define TSR1_MCR(x)		(x & 0x7FFF)
+
+#define TSR2_ACR(x)		((x & 0x7FFF)<<16)
+
+#define TSR3_NRM_CNT(x)		((x & 0xFF)<<24)
+#define TSR3_CRM_CNT(x)		(x & 0xFFFF)
+
+#define TSR4_FLUSH_CONN		(1<<31)
+#define TSR4_SESSION_ENDED	(1<<30)
+#define TSR4_CRC10		(1<<28)
+#define TSR4_NULL_CRC10		(1<<27)
+#define TSR4_PROT		(1<<26)
+#define TSR4_AAL0_SDU		(2<<23)
+#define TSR4_AAL0		(1<<23)
+#define TSR4_AAL5		(0<<23)
+
+#define TSR9_OPEN_CONN		(1<<20)
+
+#define TSR11_ICR(x)		((x & 0x7FFF)<<16)
+#define TSR11_TRM(x)		((x & 0x7)<<13)
+#define TSR11_NRM(x)		((x & 0x7)<<10)
+#define TSR11_ADTF(x)		(x & 0x3FF)
+
+#define TSR13_RDF(x)		((x & 0xF)<<23)
+#define TSR13_RIF(x)		((x & 0xF)<<19)
+#define TSR13_CDF(x)		((x & 0x7)<<16)
+#define TSR13_CRM(x)		(x & 0xFFFF)
+
+#define TSR14_DELETE		(1<<31)
+#define TSR14_ABR_CLOSE		(1<<16)
+
+/* 2.7.1 per connection receieve state registers */
+
+#define RSR0_START_PDU	(1<<10)
+#define RSR0_OPEN_CONN	(1<<6)
+#define RSR0_CLOSE_CONN	(0<<6)
+#define RSR0_PPD_ENABLE	(1<<5)
+#define RSR0_EPD_ENABLE	(1<<4)
+#define RSR0_TCP_CKSUM	(1<<3)
+#define RSR0_AAL5		(0)
+#define RSR0_AAL0		(1)
+#define RSR0_AAL0_SDU		(2)
+#define RSR0_RAWCELL		(3)
+#define RSR0_RAWCELL_CRC10	(4)
+
+#define RSR1_AQI_ENABLE	(1<<20)
+#define RSR1_RBPL_ONLY	(1<<19)
+#define RSR1_GROUP(x)	((x)<<16)
+
+#define RSR4_AQI_ENABLE (1<<30)
+#define RSR4_GROUP(x)	((x)<<27)
+#define RSR4_RBPL_ONLY	(1<<26)
+
+/* 2.1.4 transmit packet descriptor */
+
+#define	TPD_USERCELL		0x0
+#define	TPD_SEGMENT_OAMF5	0x4
+#define	TPD_END2END_OAMF5	0x5
+#define	TPD_RMCELL		0x6
+#define TPD_CELLTYPE(x)		(x<<3)
+#define TPD_EOS			(1<<2)
+#define TPD_CLP			(1<<1)
+#define TPD_INT			(1<<0)
+#define TPD_LST		(1<<31)
+
+/* table 4.3 serial eeprom information */
+
+#define PROD_ID		0x08	/* char[] */
+#define  PROD_ID_LEN	30
+#define HW_REV		0x26	/* char[] */
+#define M_SN		0x3a	/* integer */
+#define MEDIA		0x3e	/* integer */
+#define  HE155MM	0x26
+#define  HE155SM	0x27
+#define  HE622MM	0x46
+#define  HE622SM	0x47
+#define MAC_ADDR	0x42	/* char[] */
+
+#define CS_LOW		0x0
+#define CS_HIGH		ID_CS /* HOST_CNTL_ID_PROM_SEL */
+#define CLK_LOW		0x0
+#define CLK_HIGH	ID_CLOCK /* HOST_CNTL_ID_PROM_CLOCK */
+#define SI_HIGH		ID_DIN /* HOST_CNTL_ID_PROM_DATA_IN */
+#define EEPROM_DELAY	400 /* microseconds */
+
+/* Read from EEPROM = 0000 0011b */
+unsigned int readtab[] = {
+	CS_HIGH | CLK_HIGH,
+	CS_LOW | CLK_LOW,
+	CLK_HIGH,               /* 0 */
+	CLK_LOW,
+	CLK_HIGH,               /* 0 */
+	CLK_LOW,
+	CLK_HIGH,               /* 0 */
+	CLK_LOW,
+	CLK_HIGH,               /* 0 */
+	CLK_LOW,
+	CLK_HIGH,               /* 0 */
+	CLK_LOW,
+	CLK_HIGH,               /* 0 */
+	CLK_LOW | SI_HIGH,
+	CLK_HIGH | SI_HIGH,     /* 1 */
+	CLK_LOW | SI_HIGH,
+	CLK_HIGH | SI_HIGH      /* 1 */
+};     
+ 
+/* Clock to read from/write to the EEPROM */
+unsigned int clocktab[] = {
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW,
+	CLK_HIGH,
+	CLK_LOW
+};     
+
+
+#endif /* _HE_H_ */
diff -Nru a/drivers/atm/horizon.c b/drivers/atm/horizon.c
--- a/drivers/atm/horizon.c	Thu Apr 24 05:17:22 2003
+++ b/drivers/atm/horizon.c	Wed May  7 12:47:27 2003
@@ -1768,17 +1768,20 @@
   
   {
     unsigned int tx_len = skb->len;
-    unsigned int tx_iovcnt = ATM_SKB(skb)->iovcnt;
+    unsigned int tx_iovcnt = skb_shinfo(skb)->nr_frags;
     // remember this so we can free it later
     dev->tx_skb = skb;
     
     if (tx_iovcnt) {
       // scatter gather transfer
       dev->tx_regions = tx_iovcnt;
-      dev->tx_iovec = (struct iovec *) skb->data;
+      dev->tx_iovec = 0;		/* @@@ needs rewritten */
       dev->tx_bytes = 0;
       PRINTD (DBG_TX|DBG_BUS, "TX start scatter-gather transfer (iovec %p, len %d)",
 	      skb->data, tx_len);
+      tx_release (dev);
+      hrz_kfree_skb (skb);
+      return -EIO;
     } else {
       // simple transfer
       dev->tx_regions = 0;
diff -Nru a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
--- a/drivers/atm/idt77252.c	Thu Apr 24 05:17:22 2003
+++ b/drivers/atm/idt77252.c	Thu May 15 17:20:17 2003
@@ -1986,7 +1986,7 @@
 		return -EINVAL;
 	}
 
-	if (ATM_SKB(skb)->iovcnt != 0) {
+	if (skb_shinfo(skb)->nr_frags != 0) {
 		printk("%s: No scatter-gather yet.\n", card->name);
 		atomic_inc(&vcc->stats->tx_err);
 		dev_kfree_skb(skb);
@@ -2023,8 +2023,7 @@
 		atomic_inc(&vcc->stats->tx_err);
 		return -ENOMEM;
 	}
-	atomic_add(skb->truesize + ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
-	ATM_SKB(skb)->iovcnt = 0;
+	atomic_add(skb->truesize, &vcc->sk->wmem_alloc);
 
 	memcpy(skb_put(skb, 52), cell, 52);
 
@@ -2403,8 +2402,10 @@
 static int
 idt77252_find_vcc(struct atm_vcc *vcc, short *vpi, int *vci)
 {
+	unsigned long flags;
 	struct atm_vcc *walk;
 
+	spin_lock_irqsave(&vcc->dev->lock, flags);
 	if (*vpi == ATM_VPI_ANY) {
 		*vpi = 0;
 		walk = vcc->dev->vccs;
@@ -2431,6 +2432,7 @@
 		}
 	}
 
+	spin_unlock_irqrestore(&vcc->dev->lock, flags);
 	return 0;
 }
 
diff -Nru a/drivers/atm/iphase.c b/drivers/atm/iphase.c
--- a/drivers/atm/iphase.c	Thu Apr 24 05:17:22 2003
+++ b/drivers/atm/iphase.c	Sat May 10 09:08:32 2003
@@ -1167,7 +1167,6 @@
 	skb_put(skb,len);  
         // pwang_test
         ATM_SKB(skb)->vcc = vcc;
-        ATM_SKB(skb)->iovcnt = 0;
         ATM_DESC(skb) = desc;        
 	skb_queue_tail(&iadev->rx_dma_q, skb);  
 
@@ -2778,7 +2777,7 @@
 	     if (!capable(CAP_NET_ADMIN)) return -EPERM;
              tmps = (u16 *)ia_cmds.buf;
              for(i=0; i<0x80; i+=2, tmps++)
-                if(put_user(*(u16*)(iadev->seg_reg+i), tmps)) return -EFAULT;
+                if(put_user((u16)(readl(iadev->seg_reg+i) & 0xffff), tmps)) return -EFAULT;
              ia_cmds.status = 0;
              ia_cmds.len = 0x80;
              break;
@@ -2786,26 +2785,33 @@
 	     if (!capable(CAP_NET_ADMIN)) return -EPERM;
              tmps = (u16 *)ia_cmds.buf;
              for(i=0; i<0x80; i+=2, tmps++)
-                if(put_user(*(u16*)(iadev->reass_reg+i), tmps)) return -EFAULT;
+                if(put_user((u16)(readl(iadev->reass_reg+i) & 0xffff), tmps)) return -EFAULT;
              ia_cmds.status = 0;
              ia_cmds.len = 0x80;
              break;
           case MEMDUMP_FFL:
           {  
-             ia_regs_t       regs_local;
-             ffredn_t        *ffL = &regs_local.ffredn;
-             rfredn_t        *rfL = &regs_local.rfredn;
+             ia_regs_t       *regs_local;
+             ffredn_t        *ffL;
+             rfredn_t        *rfL;
                      
 	     if (!capable(CAP_NET_ADMIN)) return -EPERM;
+	     regs_local = kmalloc(sizeof(*regs_local), GFP_KERNEL);
+	     if (!regs_local) return -ENOMEM;
+	     ffL = &regs_local->ffredn;
+	     rfL = &regs_local->rfredn;
              /* Copy real rfred registers into the local copy */
  	     for (i=0; i<(sizeof (rfredn_t))/4; i++)
-                ((u_int *)rfL)[i] = ((u_int *)iadev->reass_reg)[i] & 0xffff;
+                ((u_int *)rfL)[i] = readl(iadev->reass_reg + i) & 0xffff;
              	/* Copy real ffred registers into the local copy */
 	     for (i=0; i<(sizeof (ffredn_t))/4; i++)
-                ((u_int *)ffL)[i] = ((u_int *)iadev->seg_reg)[i] & 0xffff;
+                ((u_int *)ffL)[i] = readl(iadev->seg_reg + i) & 0xffff;
 
-             if (copy_to_user(ia_cmds.buf, &regs_local,sizeof(ia_regs_t)))
+             if (copy_to_user(ia_cmds.buf, regs_local,sizeof(ia_regs_t))) {
+                kfree(regs_local);
                 return -EFAULT;
+             }
+             kfree(regs_local);
              printk("Board %d registers dumped\n", board);
              ia_cmds.status = 0;                  
 	 }	
diff -Nru a/drivers/atm/lanai.c b/drivers/atm/lanai.c
--- a/drivers/atm/lanai.c	Thu Apr 24 05:17:22 2003
+++ b/drivers/atm/lanai.c	Wed May  7 12:33:34 2003
@@ -2846,7 +2846,6 @@
 	.phy_get	= NULL,
 	.feedback	= NULL,
 	.change_qos	= lanai_change_qos,
-	.free_rx_skb	= NULL,
 	.proc_read	= lanai_proc_read
 };
 
diff -Nru a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
--- a/drivers/atm/nicstar.c	Thu Apr 24 05:17:22 2003
+++ b/drivers/atm/nicstar.c	Wed May  7 12:47:27 2003
@@ -882,9 +882,14 @@
       return error;
    }
       
-   if (ns_parse_mac(mac[i], card->atmdev->esi))
+   if (ns_parse_mac(mac[i], card->atmdev->esi)) {
       nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET,
                          card->atmdev->esi, 6);
+      if (memcmp(card->atmdev->esi, "\x00\x00\x00\x00\x00\x00", 6) == 0) {
+         nicstar_read_eprom(card->membase, NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT,
+                         card->atmdev->esi, 6);
+      }
+   }
 
    printk("nicstar%d: MAC address %02X:%02X:%02X:%02X:%02X:%02X\n", i,
           card->atmdev->esi[0], card->atmdev->esi[1], card->atmdev->esi[2],
@@ -1601,9 +1606,9 @@
 	        card->index);
          iovb = vc->rx_iov;
          recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	                       ATM_SKB(iovb)->iovcnt);
-         ATM_SKB(iovb)->iovcnt = 0;
-         ATM_SKB(iovb)->vcc = NULL;
+	                       NS_SKB(iovb)->iovcnt);
+         NS_SKB(iovb)->iovcnt = 0;
+         NS_SKB(iovb)->vcc = NULL;
          ns_grab_int_lock(card, flags);
          recycle_iov_buf(card, iovb);
          spin_unlock_irqrestore(&card->int_lock, flags);
@@ -1801,7 +1806,7 @@
       return -EINVAL;
    }
    
-   if (ATM_SKB(skb)->iovcnt != 0)
+   if (skb_shinfo(skb)->nr_frags != 0)
    {
       printk("nicstar%d: No scatter-gather yet.\n", card->index);
       atomic_inc(&vcc->stats->tx_err);
@@ -2226,30 +2231,30 @@
 	    }
 	 }
       vc->rx_iov = iovb;
-      ATM_SKB(iovb)->iovcnt = 0;
+      NS_SKB(iovb)->iovcnt = 0;
       iovb->len = 0;
       iovb->tail = iovb->data = iovb->head;
-      ATM_SKB(iovb)->vcc = vcc;
+      NS_SKB(iovb)->vcc = vcc;
       /* IMPORTANT: a pointer to the sk_buff containing the small or large
                     buffer is stored as iovec base, NOT a pointer to the 
 	            small or large buffer itself. */
    }
-   else if (ATM_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
+   else if (NS_SKB(iovb)->iovcnt >= NS_MAX_IOVECS)
    {
       printk("nicstar%d: received too big AAL5 SDU.\n", card->index);
       atomic_inc(&vcc->stats->rx_err);
       recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data, NS_MAX_IOVECS);
-      ATM_SKB(iovb)->iovcnt = 0;
+      NS_SKB(iovb)->iovcnt = 0;
       iovb->len = 0;
       iovb->tail = iovb->data = iovb->head;
-      ATM_SKB(iovb)->vcc = vcc;
+      NS_SKB(iovb)->vcc = vcc;
    }
-   iov = &((struct iovec *) iovb->data)[ATM_SKB(iovb)->iovcnt++];
+   iov = &((struct iovec *) iovb->data)[NS_SKB(iovb)->iovcnt++];
    iov->iov_base = (void *) skb;
    iov->iov_len = ns_rsqe_cellcount(rsqe) * 48;
    iovb->len += iov->iov_len;
 
-   if (ATM_SKB(iovb)->iovcnt == 1)
+   if (NS_SKB(iovb)->iovcnt == 1)
    {
       if (skb->list != &card->sbpool.queue)
       {
@@ -2263,7 +2268,7 @@
          return;
       }
    }
-   else /* ATM_SKB(iovb)->iovcnt >= 2 */
+   else /* NS_SKB(iovb)->iovcnt >= 2 */
    {
       if (skb->list != &card->lbpool.queue)
       {
@@ -2272,7 +2277,7 @@
          which_list(card, skb);
          atomic_inc(&vcc->stats->rx_err);
          recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	                       ATM_SKB(iovb)->iovcnt);
+	                       NS_SKB(iovb)->iovcnt);
          vc->rx_iov = NULL;
          recycle_iov_buf(card, iovb);
 	 return;
@@ -2296,7 +2301,7 @@
             printk(".\n");
          atomic_inc(&vcc->stats->rx_err);
          recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	   ATM_SKB(iovb)->iovcnt);
+	   NS_SKB(iovb)->iovcnt);
 	 vc->rx_iov = NULL;
          recycle_iov_buf(card, iovb);
 	 return;
@@ -2304,7 +2309,7 @@
 
       /* By this point we (hopefully) have a complete SDU without errors. */
 
-      if (ATM_SKB(iovb)->iovcnt == 1)	/* Just a small buffer */
+      if (NS_SKB(iovb)->iovcnt == 1)	/* Just a small buffer */
       {
          /* skb points to a small buffer */
          if (!atm_charge(vcc, skb->truesize))
@@ -2326,7 +2331,7 @@
             atomic_inc(&vcc->stats->rx);
          }
       }
-      else if (ATM_SKB(iovb)->iovcnt == 2)	/* One small plus one large buffer */
+      else if (NS_SKB(iovb)->iovcnt == 2)	/* One small plus one large buffer */
       {
          struct sk_buff *sb;
 
@@ -2403,7 +2408,7 @@
                printk("nicstar%d: Out of huge buffers.\n", card->index);
                atomic_inc(&vcc->stats->rx_drop);
                recycle_iovec_rx_bufs(card, (struct iovec *) iovb->data,
-	                             ATM_SKB(iovb)->iovcnt);
+	                             NS_SKB(iovb)->iovcnt);
                vc->rx_iov = NULL;
                recycle_iov_buf(card, iovb);
                return;
@@ -2441,7 +2446,7 @@
 
          if (!atm_charge(vcc, hb->truesize))
 	 {
-            recycle_iovec_rx_bufs(card, iov, ATM_SKB(iovb)->iovcnt);
+            recycle_iovec_rx_bufs(card, iov, NS_SKB(iovb)->iovcnt);
             if (card->hbpool.count < card->hbnr.max)
             {
                skb_queue_tail(&card->hbpool.queue, hb);
@@ -2464,7 +2469,7 @@
                         0, 0);
 
             /* Copy all large buffers to the huge buffer and free them */
-            for (j = 1; j < ATM_SKB(iovb)->iovcnt; j++)
+            for (j = 1; j < NS_SKB(iovb)->iovcnt; j++)
             {
                lb = (struct sk_buff *) iov->iov_base;
                tocopy = MIN(remaining, iov->iov_len);
diff -Nru a/drivers/atm/nicstar.h b/drivers/atm/nicstar.h
--- a/drivers/atm/nicstar.h	Mon Feb  4 23:53:47 2002
+++ b/drivers/atm/nicstar.h	Wed May  7 12:47:27 2003
@@ -96,6 +96,7 @@
 /* ESI stuff ******************************************************************/
 
 #define NICSTAR_EPROM_MAC_ADDR_OFFSET 0x6C
+#define NICSTAR_EPROM_MAC_ADDR_OFFSET_ALT 0xF6
 
 
 /* #defines *******************************************************************/
@@ -747,6 +748,15 @@
                				   SCD. 0x00000000 for UBR/VBR/ABR */
    int tbd_count;
 } vc_map;
+
+
+struct ns_skb_data
+{
+	struct atm_vcc *vcc;
+	int iovcnt;
+};
+
+#define NS_SKB(skb) (((struct ns_skb_data *) (skb)->cb))
 
 
 typedef struct ns_dev
diff -Nru a/drivers/atm/zatm.c b/drivers/atm/zatm.c
--- a/drivers/atm/zatm.c	Thu Apr 24 05:17:22 2003
+++ b/drivers/atm/zatm.c	Wed May  7 12:47:28 2003
@@ -827,10 +827,10 @@
 	vcc = ATM_SKB(skb)->vcc;
 	zatm_dev = ZATM_DEV(vcc->dev);
 	zatm_vcc = ZATM_VCC(vcc);
-	EVENT("iovcnt=%d\n",ATM_SKB(skb)->iovcnt,0);
+	EVENT("iovcnt=%d\n",skb_shinfo(skb)->nr_frags,0);
 	save_flags(flags);
 	cli();
-	if (!ATM_SKB(skb)->iovcnt) {
+	if (!skb_shinfo(skb)->nr_frags) {
 		if (zatm_vcc->txing == RING_ENTRIES-1) {
 			restore_flags(flags);
 			return RING_BUSY;
diff -Nru a/drivers/base/base.h b/drivers/base/base.h
--- a/drivers/base/base.h	Mon Apr 28 23:05:22 2003
+++ b/drivers/base/base.h	Tue May 13 16:40:04 2003
@@ -1,5 +1,3 @@
-extern struct semaphore device_sem;
-
 extern int bus_add_device(struct device * dev);
 extern void bus_remove_device(struct device * dev);
 
diff -Nru a/drivers/base/class.c b/drivers/base/class.c
--- a/drivers/base/class.c	Mon Apr 28 23:05:22 2003
+++ b/drivers/base/class.c	Fri May  9 09:23:52 2003
@@ -133,6 +133,21 @@
 		sysfs_remove_link(&class_dev->kobj, "device");
 }
 
+static int class_device_driver_link(struct class_device * class_dev)
+{
+	if ((class_dev->dev) && (class_dev->dev->driver))
+		return sysfs_create_link(&class_dev->kobj,
+					 &class_dev->dev->driver->kobj, "driver");
+	return 0;
+}
+
+static void class_device_driver_unlink(struct class_device * class_dev)
+{
+	if ((class_dev->dev) && (class_dev->dev->driver))
+		sysfs_remove_link(&class_dev->kobj, "driver");
+}
+
+
 #define to_class_dev(obj) container_of(obj,struct class_device,kobj)
 #define to_class_dev_attr(_attr) container_of(_attr,struct class_device_attribute,attr)
 
@@ -244,7 +259,6 @@
 
 	/* first, register with generic layer. */
 	strncpy(class_dev->kobj.name, class_dev->class_id, KOBJ_NAME_LEN);
-	kobj_set_kset_s(class_dev, class_subsys);
 	kobj_set_kset_s(class_dev, class_obj_subsys);
 	if (parent)
 		class_dev->kobj.parent = &parent->subsys.kset.kobj;
@@ -265,6 +279,7 @@
 	}
 
 	class_device_dev_link(class_dev);
+	class_device_driver_link(class_dev);
 
  register_done:
 	if (error && parent)
@@ -298,6 +313,7 @@
 
 	if (class_dev->dev) {
 		class_device_dev_unlink(class_dev);
+		class_device_driver_unlink(class_dev);
 		put_device(class_dev->dev);
 	}
 	
diff -Nru a/drivers/base/core.c b/drivers/base/core.c
--- a/drivers/base/core.c	Mon Apr 28 23:05:23 2003
+++ b/drivers/base/core.c	Tue May 13 16:40:04 2003
@@ -21,9 +21,6 @@
 int (*platform_notify)(struct device * dev) = NULL;
 int (*platform_notify_remove)(struct device * dev) = NULL;
 
-DECLARE_MUTEX(device_sem);
-
-
 /*
  * sysfs bindings for devices.
  */
@@ -180,6 +177,7 @@
 
 void device_initialize(struct device *dev)
 {
+	kobj_set_kset_s(dev,devices_subsys);
 	kobject_init(&dev->kobj);
 	INIT_LIST_HEAD(&dev->node);
 	INIT_LIST_HEAD(&dev->children);
@@ -214,7 +212,6 @@
 
 	/* first, register with generic layer. */
 	strncpy(dev->kobj.name,dev->bus_id,KOBJ_NAME_LEN);
-	kobj_set_kset_s(dev,devices_subsys);
 	if (parent)
 		dev->kobj.parent = &parent->kobj;
 
@@ -222,11 +219,11 @@
 		goto register_done;
 
 	/* now take care of our own registration */
-	if (parent) {
-		down(&device_sem);
+
+	down_write(&devices_subsys.rwsem);
+	if (parent)
 		list_add_tail(&dev->node,&parent->children);
-		up(&device_sem);
-	}
+	up_write(&devices_subsys.rwsem);
 
 	bus_add_device(dev);
 
@@ -304,11 +301,10 @@
 {
 	struct device * parent = dev->parent;
 
-	if (parent) {
-		down(&device_sem);
+	down_write(&devices_subsys.rwsem);
+	if (parent)
 		list_del_init(&dev->node);
-		up(&device_sem);
-	}
+	up_write(&devices_subsys.rwsem);
 
 	/* Notify the platform of the removal, in case they
 	 * need to do anything...
diff -Nru a/drivers/block/DAC960.c b/drivers/block/DAC960.c
--- a/drivers/block/DAC960.c	Mon Apr 28 08:02:45 2003
+++ b/drivers/block/DAC960.c	Sat May 17 14:10:00 2003
@@ -48,8 +48,7 @@
 
 static DAC960_Controller_T *DAC960_Controllers[DAC960_MaxControllers];
 static int DAC960_ControllerCount;
-static PROC_DirectoryEntry_T *DAC960_ProcDirectoryEntry;
-
+static struct proc_dir_entry *DAC960_ProcDirectoryEntry;
 
 static long disk_size(DAC960_Controller_T *p, int drive_nr)
 {
@@ -103,7 +102,7 @@
 	int drive_nr = (int)disk->private_data;
 	struct hd_geometry g, *loc = (struct hd_geometry *)arg;
 
-	if (file->f_flags & O_NONBLOCK)
+	if (file && (file->f_flags & O_NONBLOCK))
 		return DAC960_UserIOCTL(inode, file, cmd, arg);
 
 	if (cmd != HDIO_GETGEO || !loc)
@@ -759,12 +758,15 @@
 {
   DAC960_Controller_T *Controller = Command->Controller;
   DECLARE_COMPLETION(Completion);
-  unsigned long ProcessorFlags;
+  unsigned long flags;
   Command->Completion = &Completion;
-  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   DAC960_QueueCommand(Command);
-  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-  if (in_interrupt()) return;
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
+ 
+  if (in_interrupt())
+	  return;
   wait_for_completion(&Completion);
 }
 
@@ -1132,7 +1134,7 @@
 {
   void *ControllerBaseAddress = Controller->BaseAddress;
   DAC960_HardwareType_T hw_type = Controller->HardwareType;
-  PCI_Device_T	*PCI_Device = Controller->PCIDevice;
+  struct pci_dev *PCI_Device = Controller->PCIDevice;
   struct dma_loaf *DmaPages = &Controller->DmaPages;
   size_t DmaPagesSize;
   size_t CommandMailboxesSize;
@@ -1337,7 +1339,7 @@
 						      *Controller)
 {
   void *ControllerBaseAddress = Controller->BaseAddress;
-  PCI_Device_T	*PCI_Device = Controller->PCIDevice;
+  struct pci_dev *PCI_Device = Controller->PCIDevice;
   struct dma_loaf *DmaPages = &Controller->DmaPages;
   size_t DmaPagesSize;
   size_t CommandMailboxesSize;
@@ -1915,8 +1917,8 @@
   dma_addr_t SCSI_NewInquiryUnitSerialNumberDMA[DAC960_V1_MaxChannels];
   DAC960_SCSI_Inquiry_UnitSerialNumber_T *SCSI_NewInquiryUnitSerialNumberCPU[DAC960_V1_MaxChannels];
 
-  Completion_T Completions[DAC960_V1_MaxChannels];
-  unsigned long ProcessorFlags;
+  struct completion Completions[DAC960_V1_MaxChannels];
+  unsigned long flags;
   int Channel, TargetID;
 
   if (!init_dma_loaf(Controller->PCIDevice, &local_dma, 
@@ -1951,7 +1953,7 @@
   	  DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel];
   	  dma_addr_t DCDB_dma = DCDBs_dma[Channel];
 	  DAC960_Command_T *Command = Controller->Commands[Channel];
-          Completion_T *Completion = &Completions[Channel];
+          struct completion *Completion = &Completions[Channel];
 
 	  init_completion(Completion);
 	  DAC960_V1_ClearCommand(Command);
@@ -1977,9 +1979,10 @@
 	  DCDB->CDB[3] = 0; /* Reserved */
 	  DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T);
 	  DCDB->CDB[5] = 0; /* Control */
-	  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+
+	  spin_lock_irqsave(&Controller->queue_lock, flags);
 	  DAC960_QueueCommand(Command);
-	  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	  spin_unlock_irqrestore(&Controller->queue_lock, flags);
 	}
       /*
        * Wait for the problems submitted in the previous loop
@@ -1999,7 +2002,7 @@
 	    &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
 	  DAC960_Command_T *Command = Controller->Commands[Channel];
   	  DAC960_V1_DCDB_T *DCDB = DCDBs_cpu[Channel];
-          Completion_T *Completion = &Completions[Channel];
+          struct completion *Completion = &Completions[Channel];
 
 	  wait_for_completion(Completion);
 
@@ -2021,9 +2024,10 @@
 	  DCDB->CDB[3] = 0; /* Reserved */
 	  DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
 	  DCDB->CDB[5] = 0; /* Control */
-	  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+
+	  spin_lock_irqsave(&Controller->queue_lock, flags);
 	  DAC960_QueueCommand(Command);
-	  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	  spin_unlock_irqrestore(&Controller->queue_lock, flags);
 	  wait_for_completion(Completion);
 
 	  if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion) {
@@ -2457,7 +2461,7 @@
 static boolean DAC960_RegisterBlockDevice(DAC960_Controller_T *Controller)
 {
   int MajorNumber = DAC960_MAJOR + Controller->ControllerNumber;
-  RequestQueue_T *RequestQueue;
+  struct request_queue *RequestQueue;
   int n;
 
   /*
@@ -2642,11 +2646,13 @@
 */
 
 static DAC960_Controller_T * 
-DAC960_DetectController(PCI_Device_T *PCI_Device,
-					const struct pci_device_id *entry)
+DAC960_DetectController(struct pci_dev *PCI_Device,
+			const struct pci_device_id *entry)
 {
-  struct DAC960_privdata *privdata = (struct DAC960_privdata *)entry->driver_data;
-  irqreturn_t (*InterruptHandler)(int, void *, Registers_T *) = privdata->InterruptHandler;
+  struct DAC960_privdata *privdata =
+	  	(struct DAC960_privdata *)entry->driver_data;
+  irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *) =
+	  	privdata->InterruptHandler;
   unsigned int MemoryWindowSize = privdata->MemoryWindowSize;
   DAC960_Controller_T *Controller = NULL;
   unsigned char DeviceFunction = PCI_Device->devfn;
@@ -3001,7 +3007,7 @@
 {
   if (Controller->ControllerInitialized)
     {
-      unsigned long ProcessorFlags;
+      unsigned long flags;
 
       /*
        * Acquiring and releasing lock here eliminates
@@ -3019,9 +3025,11 @@
        * commands that complete from this time on will NOT return
        * their command structure to the free list.
        */
-      DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+
+      spin_lock_irqsave(&Controller->queue_lock, flags);
       Controller->ShutdownMonitoringTimer = 1;
-      DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+      spin_unlock_irqrestore(&Controller->queue_lock, flags);
+
       del_timer_sync(&Controller->MonitoringTimer);
       if (Controller->FirmwareType == DAC960_V1_Controller)
 	{
@@ -3088,7 +3096,7 @@
   DAC960_Finalize finalizes the DAC960 Driver.
 */
 
-static void DAC960_Remove(PCI_Device_T *PCI_Device)
+static void DAC960_Remove(struct pci_dev *PCI_Device)
 {
   int Controller_Number = (int)pci_get_drvdata(PCI_Device);
   DAC960_Controller_T *Controller = DAC960_Controllers[Controller_Number];
@@ -3236,8 +3244,8 @@
 static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
 				     boolean WaitForCommand)
 {
-  RequestQueue_T *RequestQueue = &Controller->RequestQueue;
-  IO_Request_T *Request;
+  struct request_queue *RequestQueue = &Controller->RequestQueue;
+  struct request *Request;
   DAC960_Command_T *Command;
 
   if (!Controller->ControllerInitialized)
@@ -3293,7 +3301,7 @@
 static void DAC960_queue_partial_rw(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
-  IO_Request_T *Request = Command->Request;
+  struct request *Request = Command->Request;
 
   if (Command->DmaDirection == PCI_DMA_FROMDEVICE)
     Command->CommandType = DAC960_ReadRetryCommand;
@@ -3324,43 +3332,17 @@
   return;
 }
 
-
-/*
-  DAC960_ProcessRequests attempts to remove as many I/O Requests as possible
-  from Controller's I/O Request Queue and queue them to the Controller.
-*/
-
-static inline void DAC960_ProcessRequests(DAC960_Controller_T *Controller)
-{
-  int Counter = 0;
-  while (DAC960_ProcessRequest(Controller, Counter++ == 0)) ;
-}
-
-
 /*
   DAC960_RequestFunction is the I/O Request Function for DAC960 Controllers.
 */
 
-static void DAC960_RequestFunction(RequestQueue_T *RequestQueue)
+static void DAC960_RequestFunction(struct request_queue *RequestQueue)
 {
-  DAC960_Controller_T *Controller =
-    (DAC960_Controller_T *) RequestQueue->queuedata;
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockRF(Controller, &ProcessorFlags);
-  /*
-    Process I/O Requests for Controller.
-  */
-  DAC960_ProcessRequests(Controller);
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockRF(Controller, &ProcessorFlags);
+	int i = 0;
+	while (DAC960_ProcessRequest(RequestQueue->queuedata, (i++ == 0)))
+		;
 }
 
-
 /*
   DAC960_ProcessCompletedBuffer performs completion processing for an
   individual Buffer.
@@ -3369,7 +3351,7 @@
 static inline boolean DAC960_ProcessCompletedRequest(DAC960_Command_T *Command,
 						 boolean SuccessfulIO)
 {
-	IO_Request_T *Request = Command->Request;
+	struct request *Request = Command->Request;
 	int UpToDate;
 
 	UpToDate = 0;
@@ -5174,20 +5156,14 @@
 
 static irqreturn_t DAC960_BA_InterruptHandler(int IRQ_Channel,
 				       void *DeviceIdentifier,
-				       Registers_T *InterruptRegisters)
+				       struct pt_regs *InterruptRegisters)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
   void *ControllerBaseAddress = Controller->BaseAddress;
   DAC960_V2_StatusMailbox_T *NextStatusMailbox;
-  ProcessorFlags_T ProcessorFlags;
+  unsigned long flags;
 
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
-  /*
-    Process Hardware Interrupts for Controller.
-  */
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   DAC960_BA_AcknowledgeInterrupt(ControllerBaseAddress);
   NextStatusMailbox = Controller->V2.NextStatusMailbox;
   while (NextStatusMailbox->Fields.CommandIdentifier > 0)
@@ -5210,11 +5186,9 @@
     Attempt to remove additional I/O Requests from the Controller's
     I/O Request Queue and queue them to the Controller.
   */
-  while (DAC960_ProcessRequest(Controller, false)) ;
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+  while (DAC960_ProcessRequest(Controller, false))
+	  ;
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   return IRQ_HANDLED;
 }
 
@@ -5226,19 +5200,14 @@
 
 static irqreturn_t DAC960_LP_InterruptHandler(int IRQ_Channel,
 				       void *DeviceIdentifier,
-				       Registers_T *InterruptRegisters)
+				       struct pt_regs *InterruptRegisters)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
   void *ControllerBaseAddress = Controller->BaseAddress;
   DAC960_V2_StatusMailbox_T *NextStatusMailbox;
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
-  /*
-    Process Hardware Interrupts for Controller.
-  */
+  unsigned long flags;
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   DAC960_LP_AcknowledgeInterrupt(ControllerBaseAddress);
   NextStatusMailbox = Controller->V2.NextStatusMailbox;
   while (NextStatusMailbox->Fields.CommandIdentifier > 0)
@@ -5261,11 +5230,9 @@
     Attempt to remove additional I/O Requests from the Controller's
     I/O Request Queue and queue them to the Controller.
   */
-  while (DAC960_ProcessRequest(Controller, false)) ;
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+  while (DAC960_ProcessRequest(Controller, false))
+	  ;
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   return IRQ_HANDLED;
 }
 
@@ -5277,19 +5244,14 @@
 
 static irqreturn_t DAC960_LA_InterruptHandler(int IRQ_Channel,
 				       void *DeviceIdentifier,
-				       Registers_T *InterruptRegisters)
+				       struct pt_regs *InterruptRegisters)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
   void *ControllerBaseAddress = Controller->BaseAddress;
   DAC960_V1_StatusMailbox_T *NextStatusMailbox;
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
-  /*
-    Process Hardware Interrupts for Controller.
-  */
+  unsigned long flags;
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   DAC960_LA_AcknowledgeInterrupt(ControllerBaseAddress);
   NextStatusMailbox = Controller->V1.NextStatusMailbox;
   while (NextStatusMailbox->Fields.Valid)
@@ -5308,11 +5270,9 @@
     Attempt to remove additional I/O Requests from the Controller's
     I/O Request Queue and queue them to the Controller.
   */
-  while (DAC960_ProcessRequest(Controller, false)) ;
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+  while (DAC960_ProcessRequest(Controller, false))
+	  ;
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   return IRQ_HANDLED;
 }
 
@@ -5324,19 +5284,14 @@
 
 static irqreturn_t DAC960_PG_InterruptHandler(int IRQ_Channel,
 				       void *DeviceIdentifier,
-				       Registers_T *InterruptRegisters)
+				       struct pt_regs *InterruptRegisters)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
   void *ControllerBaseAddress = Controller->BaseAddress;
   DAC960_V1_StatusMailbox_T *NextStatusMailbox;
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
-  /*
-    Process Hardware Interrupts for Controller.
-  */
+  unsigned long flags;
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   DAC960_PG_AcknowledgeInterrupt(ControllerBaseAddress);
   NextStatusMailbox = Controller->V1.NextStatusMailbox;
   while (NextStatusMailbox->Fields.Valid)
@@ -5355,11 +5310,9 @@
     Attempt to remove additional I/O Requests from the Controller's
     I/O Request Queue and queue them to the Controller.
   */
-  while (DAC960_ProcessRequest(Controller, false)) ;
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+  while (DAC960_ProcessRequest(Controller, false))
+	  ;
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   return IRQ_HANDLED;
 }
 
@@ -5371,18 +5324,13 @@
 
 static irqreturn_t DAC960_PD_InterruptHandler(int IRQ_Channel,
 				       void *DeviceIdentifier,
-				       Registers_T *InterruptRegisters)
+				       struct pt_regs *InterruptRegisters)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
   void *ControllerBaseAddress = Controller->BaseAddress;
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
-  /*
-    Process Hardware Interrupts for Controller.
-  */
+  unsigned long flags;
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   while (DAC960_PD_StatusAvailableP(ControllerBaseAddress))
     {
       DAC960_V1_CommandIdentifier_T CommandIdentifier =
@@ -5398,11 +5346,9 @@
     Attempt to remove additional I/O Requests from the Controller's
     I/O Request Queue and queue them to the Controller.
   */
-  while (DAC960_ProcessRequest(Controller, false)) ;
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+  while (DAC960_ProcessRequest(Controller, false))
+	  ;
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   return IRQ_HANDLED;
 }
 
@@ -5418,18 +5364,13 @@
 
 static irqreturn_t DAC960_P_InterruptHandler(int IRQ_Channel,
 				      void *DeviceIdentifier,
-				      Registers_T *InterruptRegisters)
+				      struct pt_regs *InterruptRegisters)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
   void *ControllerBaseAddress = Controller->BaseAddress;
-  ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
-  /*
-    Process Hardware Interrupts for Controller.
-  */
+  unsigned long flags;
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   while (DAC960_PD_StatusAvailableP(ControllerBaseAddress))
     {
       DAC960_V1_CommandIdentifier_T CommandIdentifier =
@@ -5480,11 +5421,9 @@
     Attempt to remove additional I/O Requests from the Controller's
     I/O Request Queue and queue them to the Controller.
   */
-  while (DAC960_ProcessRequest(Controller, false)) ;
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+  while (DAC960_ProcessRequest(Controller, false))
+	  ;
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   return IRQ_HANDLED;
 }
 
@@ -5547,13 +5486,11 @@
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData;
   DAC960_Command_T *Command;
-  ProcessorFlags_T ProcessorFlags;
+  unsigned long flags;
+
   if (Controller->FirmwareType == DAC960_V1_Controller)
     {
-      /*
-	Acquire exclusive access to Controller.
-      */
-      DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+      spin_lock_irqsave(&Controller->queue_lock, flags);
       /*
 	Queue a Status Monitoring Command to Controller.
       */
@@ -5561,10 +5498,7 @@
       if (Command != NULL)
 	DAC960_V1_QueueMonitoringCommand(Command);
       else Controller->MonitoringCommandDeferred = true;
-      /*
-	Release exclusive access to Controller.
-      */
-      DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+      spin_unlock_irqrestore(&Controller->queue_lock, flags);
     }
   else
     {
@@ -5613,10 +5547,8 @@
 	}
       Controller->V2.StatusChangeCounter = StatusChangeCounter;
       Controller->PrimaryMonitoringTime = jiffies;
-      /*
-	Acquire exclusive access to Controller.
-      */
-      DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+
+      spin_lock_irqsave(&Controller->queue_lock, flags);
       /*
 	Queue a Status Monitoring Command to Controller.
       */
@@ -5624,10 +5556,7 @@
       if (Command != NULL)
 	DAC960_V2_QueueMonitoringCommand(Command);
       else Controller->MonitoringCommandDeferred = true;
-      /*
-	Release exclusive access to Controller.
-      */
-      DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+      spin_unlock_irqrestore(&Controller->queue_lock, flags);
       /*
 	Wake up any processes waiting on a Health Status Buffer change.
       */
@@ -5639,7 +5568,7 @@
   DAC960_UserIOCTL is the User IOCTL Function for the DAC960 Driver.
 */
 
-static int DAC960_UserIOCTL(Inode_T *Inode, File_T *File,
+static int DAC960_UserIOCTL(struct inode *inode, struct file *file,
 			    unsigned int Request, unsigned long Argument)
 {
   int ErrorCode = 0;
@@ -5691,7 +5620,7 @@
 	DAC960_V1_DCDB_T DCDB;
 	DAC960_V1_DCDB_T *DCDB_IOBUF = NULL;
 	dma_addr_t	DCDB_IOBUFDMA;
-	ProcessorFlags_T ProcessorFlags;
+	unsigned long flags;
 	int ControllerNumber, DataTransferLength;
 	unsigned char *DataTransferBuffer = NULL;
 	dma_addr_t DataTransferBufferDMA;
@@ -5764,7 +5693,7 @@
 	  }
 	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
-	    DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	    spin_lock_irqsave(&Controller->queue_lock, flags);
 	    while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
 	      DAC960_WaitForCommand(Controller);
 	    while (Controller->V1.DirectCommandActive[DCDB.Channel]
@@ -5778,7 +5707,7 @@
 	      }
 	    Controller->V1.DirectCommandActive[DCDB.Channel]
 					      [DCDB.TargetID] = true;
-	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	    spin_unlock_irqrestore(&Controller->queue_lock, flags);
 	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_ImmediateCommand;
 	    memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
@@ -5789,10 +5718,10 @@
 	  }
 	else
 	  {
-	    DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	    spin_lock_irqsave(&Controller->queue_lock, flags);
 	    while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
 	      DAC960_WaitForCommand(Controller);
-	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	    spin_unlock_irqrestore(&Controller->queue_lock, flags);
 	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_ImmediateCommand;
 	    memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
@@ -5803,9 +5732,9 @@
 	  }
 	DAC960_ExecuteCommand(Command);
 	CommandStatus = Command->V1.CommandStatus;
-	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	spin_lock_irqsave(&Controller->queue_lock, flags);
 	DAC960_DeallocateCommand(Command);
-	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	spin_unlock_irqrestore(&Controller->queue_lock, flags);
 	if (DataTransferLength > 0)
 	  {
 	    if (copy_to_user(UserCommand.DataTransferBuffer,
@@ -5848,7 +5777,7 @@
 	DAC960_Command_T *Command = NULL;
 	DAC960_V2_CommandMailbox_T *CommandMailbox;
 	DAC960_V2_CommandStatus_T CommandStatus;
-	ProcessorFlags_T ProcessorFlags;
+	unsigned long flags;
 	int ControllerNumber, DataTransferLength;
 	int DataTransferResidue, RequestSenseLength;
 	unsigned char *DataTransferBuffer = NULL;
@@ -5900,10 +5829,10 @@
 	      }
 	    memset(RequestSenseBuffer, 0, RequestSenseLength);
 	  }
-	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	spin_lock_irqsave(&Controller->queue_lock, flags);
 	while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
 	  DAC960_WaitForCommand(Controller);
-	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	spin_unlock_irqrestore(&Controller->queue_lock, flags);
 	DAC960_V2_ClearCommand(Command);
 	Command->CommandType = DAC960_ImmediateCommand;
 	CommandMailbox = &Command->V2.CommandMailbox;
@@ -5951,9 +5880,9 @@
 	CommandStatus = Command->V2.CommandStatus;
 	RequestSenseLength = Command->V2.RequestSenseLength;
 	DataTransferResidue = Command->V2.DataTransferResidue;
-	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	spin_lock_irqsave(&Controller->queue_lock, flags);
 	DAC960_DeallocateCommand(Command);
-	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	spin_unlock_irqrestore(&Controller->queue_lock, flags);
 	if (RequestSenseLength > UserCommand.RequestSenseLength)
 	  RequestSenseLength = UserCommand.RequestSenseLength;
 	if (copy_to_user(&UserSpaceUserCommand->DataTransferLength,
@@ -6302,12 +6231,13 @@
 {
   DAC960_Command_T *Command;
   DAC960_V1_CommandMailbox_T *CommandMailbox;
-  ProcessorFlags_T ProcessorFlags;
+  unsigned long flags;
   unsigned char Channel, TargetID, LogicalDriveNumber;
-  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
     DAC960_WaitForCommand(Controller);
-  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   Controller->UserStatusLength = 0;
   DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
@@ -6497,9 +6427,10 @@
     }
   else DAC960_UserCritical("Illegal User Command: '%s'\n",
 			   Controller, UserCommand);
-  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   DAC960_DeallocateCommand(Command);
-  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   return true;
 }
 
@@ -6562,13 +6493,14 @@
 {
   DAC960_Command_T *Command;
   DAC960_V2_CommandMailbox_T *CommandMailbox;
-  ProcessorFlags_T ProcessorFlags;
+  unsigned long flags;
   unsigned char Channel, TargetID, LogicalDriveNumber;
   unsigned short LogicalDeviceNumber;
-  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
     DAC960_WaitForCommand(Controller);
-  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   Controller->UserStatusLength = 0;
   DAC960_V2_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
@@ -6758,9 +6690,10 @@
     Controller->SuppressEnclosureMessages = true;
   else DAC960_UserCritical("Illegal User Command: '%s'\n",
 			   Controller, UserCommand);
-  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+
+  spin_lock_irqsave(&Controller->queue_lock, flags);
   DAC960_DeallocateCommand(Command);
-  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  spin_unlock_irqrestore(&Controller->queue_lock, flags);
   return true;
 }
 
@@ -6893,7 +6826,7 @@
   DAC960_ProcWriteUserCommand implements writing /proc/rd/cN/user_command.
 */
 
-static int DAC960_ProcWriteUserCommand(File_T *File, const char *Buffer,
+static int DAC960_ProcWriteUserCommand(struct file *file, const char *Buffer,
 				       unsigned long Count, void *Data)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
@@ -6921,9 +6854,9 @@
 
 static void DAC960_CreateProcEntries(DAC960_Controller_T *Controller)
 {
-	PROC_DirectoryEntry_T *StatusProcEntry;
-	PROC_DirectoryEntry_T *ControllerProcEntry;
-	PROC_DirectoryEntry_T *UserCommandProcEntry;
+	struct proc_dir_entry *StatusProcEntry;
+	struct proc_dir_entry *ControllerProcEntry;
+	struct proc_dir_entry *UserCommandProcEntry;
 
 	if (DAC960_ProcDirectoryEntry == NULL) {
   		DAC960_ProcDirectoryEntry = proc_mkdir("rd", NULL);
diff -Nru a/drivers/block/DAC960.h b/drivers/block/DAC960.h
--- a/drivers/block/DAC960.h	Mon Apr 28 08:02:45 2003
+++ b/drivers/block/DAC960.h	Wed May 14 23:43:51 2003
@@ -2203,33 +2203,10 @@
   DAC960_Message(DAC960_UserCriticalLevel, Format, ##Arguments)
 
 
-/*
-  Define types for some of the structures that interface with the rest
-  of the Linux Kernel and I/O Subsystem.
-*/
-
-typedef struct file File_T;
-typedef struct block_device_operations BlockDeviceOperations_T;
-typedef struct completion Completion_T;
-typedef struct hd_geometry DiskGeometry_T;
-typedef struct inode Inode_T;
-typedef struct inode_operations InodeOperations_T;
-typedef kdev_t KernelDevice_T;
-typedef struct list_head ListHead_T;
-typedef struct pci_dev PCI_Device_T;
-typedef struct proc_dir_entry PROC_DirectoryEntry_T;
-typedef unsigned long ProcessorFlags_T;
-typedef struct pt_regs Registers_T;
-typedef struct request IO_Request_T;
-typedef request_queue_t RequestQueue_T;
-typedef struct super_block SuperBlock_T;
-typedef struct timer_list Timer_T;
-typedef wait_queue_head_t WaitQueue_T;
-
 struct DAC960_privdata {
 	DAC960_HardwareType_T	HardwareType;
 	DAC960_FirmwareType_T	FirmwareType;
-	irqreturn_t (*InterruptHandler)(int, void *, Registers_T *);
+	irqreturn_t (*InterruptHandler)(int, void *, struct pt_regs *);
 	unsigned int		MemoryWindowSize;
 };
 
@@ -2295,14 +2272,14 @@
   DAC960_CommandType_T CommandType;
   struct DAC960_Controller *Controller;
   struct DAC960_Command *Next;
-  Completion_T *Completion;
+  struct completion *Completion;
   unsigned int LogicalDriveNumber;
   unsigned int BlockNumber;
   unsigned int BlockCount;
   unsigned int SegmentCount;
   int	DmaDirection;
   struct scatterlist *cmd_sglist;
-  IO_Request_T *Request;
+  struct request *Request;
   struct pci_dev *PciDevice;
   union {
     struct {
@@ -2344,7 +2321,7 @@
   DAC960_HardwareType_T HardwareType;
   DAC960_IO_Address_T IO_Address;
   DAC960_PCI_Address_T PCI_Address;
-  PCI_Device_T  *PCIDevice;
+  struct pci_dev *PCIDevice;
   unsigned char ControllerNumber;
   unsigned char ControllerName[4];
   unsigned char ModelName[20];
@@ -2383,19 +2360,19 @@
   boolean DriveSpinUpMessageDisplayed;
   boolean MonitoringAlertMode;
   boolean SuppressEnclosureMessages;
-  Timer_T MonitoringTimer;
+  struct timer_list MonitoringTimer;
   struct gendisk *disks[DAC960_MaxLogicalDrives];
   struct pci_pool *ScatterGatherPool;
   DAC960_Command_T *FreeCommands;
   unsigned char *CombinedStatusBuffer;
   unsigned char *CurrentStatusBuffer;
-  RequestQueue_T RequestQueue;
+  struct request_queue RequestQueue;
   spinlock_t queue_lock;
-  WaitQueue_T CommandWaitQueue;
-  WaitQueue_T HealthStatusWaitQueue;
+  wait_queue_head_t CommandWaitQueue;
+  wait_queue_head_t HealthStatusWaitQueue;
   DAC960_Command_T InitialCommand;
   DAC960_Command_T *Commands[DAC960_MaxDriverQueueDepth];
-  PROC_DirectoryEntry_T *ControllerProcEntry;
+  struct proc_dir_entry *ControllerProcEntry;
   boolean LogicalDriveInitiallyAccessible[DAC960_MaxLogicalDrives];
   void (*QueueCommand)(DAC960_Command_T *Command);
   boolean (*ReadControllerConfiguration)(struct DAC960_Controller *);
@@ -2596,85 +2573,6 @@
 }
 
 /*
-  DAC960_AcquireControllerLock acquires exclusive access to Controller.
-	Reference the queue_lock through the controller structure,
-	rather than through the request queue.  These macros are
-        used to mutex on the controller structure during initialization,
-	BEFORE the request queue is allocated and initialized in
-	DAC960_RegisterBlockDevice().
-*/
-
-static inline
-void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller,
-				  ProcessorFlags_T *ProcessorFlags)
-{
-  spin_lock_irqsave(&Controller->queue_lock, *ProcessorFlags);
-}
-
-
-/*
-  DAC960_ReleaseControllerLock releases exclusive access to Controller.
-*/
-
-static inline
-void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller,
-				  ProcessorFlags_T *ProcessorFlags)
-{
-  spin_unlock_irqrestore(&Controller->queue_lock, *ProcessorFlags);
-}
-
-
-/*
-  DAC960_AcquireControllerLockRF acquires exclusive access to Controller,
-  but is only called from the request function with the queue lock held.
-*/
-
-static inline
-void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
-  DAC960_ReleaseControllerLockRF releases exclusive access to Controller,
-  but is only called from the request function with the queue lock held.
-*/
-
-static inline
-void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
-{
-}
-
-
-/*
-  DAC960_AcquireControllerLockIH acquires exclusive access to Controller,
-  but is only called from the interrupt handler.
-*/
-
-static inline
-void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
-{
-  spin_lock_irqsave(&Controller->queue_lock, *ProcessorFlags);
-}
-
-
-/*
-  DAC960_ReleaseControllerLockIH releases exclusive access to Controller,
-  but is only called from the interrupt handler.
-*/
-
-static inline
-void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
-{
-  spin_unlock_irqrestore(&Controller->queue_lock, *ProcessorFlags);
-}
-
-
-/*
   Define the DAC960 BA Series Controller Interface Register Offsets.
 */
 
@@ -4230,17 +4128,18 @@
 static void DAC960_FinalizeController(DAC960_Controller_T *);
 static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *);
 static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *); 
-static void DAC960_RequestFunction(RequestQueue_T *);
-static irqreturn_t DAC960_BA_InterruptHandler(int, void *, Registers_T *);
-static irqreturn_t DAC960_LP_InterruptHandler(int, void *, Registers_T *);
-static irqreturn_t DAC960_LA_InterruptHandler(int, void *, Registers_T *);
-static irqreturn_t DAC960_PG_InterruptHandler(int, void *, Registers_T *);
-static irqreturn_t DAC960_PD_InterruptHandler(int, void *, Registers_T *);
-static irqreturn_t DAC960_P_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_RequestFunction(struct request_queue *);
+static irqreturn_t DAC960_BA_InterruptHandler(int, void *, struct pt_regs *);
+static irqreturn_t DAC960_LP_InterruptHandler(int, void *, struct pt_regs *);
+static irqreturn_t DAC960_LA_InterruptHandler(int, void *, struct pt_regs *);
+static irqreturn_t DAC960_PG_InterruptHandler(int, void *, struct pt_regs *);
+static irqreturn_t DAC960_PD_InterruptHandler(int, void *, struct pt_regs *);
+static irqreturn_t DAC960_P_InterruptHandler(int, void *, struct pt_regs *);
 static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *);
 static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *);
 static void DAC960_MonitoringTimerFunction(unsigned long);
-static int DAC960_UserIOCTL(Inode_T *, File_T *, unsigned int, unsigned long);
+static int DAC960_UserIOCTL(struct inode *, struct file *,
+			    unsigned int, unsigned long);
 static void DAC960_Message(DAC960_MessageLevel_T, unsigned char *,
 			   DAC960_Controller_T *, ...);
 static void DAC960_CreateProcEntries(DAC960_Controller_T *);
diff -Nru a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
--- a/drivers/block/acsi_slm.c	Sat Mar 22 07:38:04 2003
+++ b/drivers/block/acsi_slm.c	Wed May  7 08:47:29 2003
@@ -1008,11 +1008,8 @@
 	
 	devfs_mk_dir("slm");
 	for (i = 0; i < MAX_SLM; i++) {
-		char name[16];
-		sprintf(name, "slm/%d", i);
-		devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-			       ACSI_MAJOR, i, S_IFCHR | S_IRUSR | S_IWUSR,
-			       &slm_fops, NULL);
+		devfs_mk_cdev(MKDEV(ACSI_MAJOR, i),
+				S_IFCHR|S_IRUSR|S_IWUSR, "slm/%d", i);
 	}
 	return 0;
 }
diff -Nru a/drivers/block/cciss_scsi.c b/drivers/block/cciss_scsi.c
--- a/drivers/block/cciss_scsi.c	Thu Feb 27 06:38:23 2003
+++ b/drivers/block/cciss_scsi.c	Wed May 14 23:48:56 2003
@@ -51,8 +51,6 @@
 	int cmd_type);
 
 
-int __init cciss_scsi_detect(Scsi_Host_Template *tpnt);
-int cciss_scsi_release(struct Scsi_Host *sh);
 const char *cciss_scsi_info(struct Scsi_Host *sa);
 
 int cciss_scsi_proc_info(
@@ -84,22 +82,17 @@
 	{ .name = "cciss7", .ndevices = 0 },
 };
 
-/* We need one Scsi_Host_Template *per controller* instead of 
-   the usual one Scsi_Host_Template per controller *type*. This 
-   is so PCI hot plug could have a remote possibility of still
-   working even with the SCSI system.  It's so 
-   scsi_unregister_host will differentiate the controllers. 
-   When register_scsi_module is called, each host template is 
-   customized (name change) in cciss_register_scsi() (that's
-   called from cciss_engage_scsi, called from
-   cciss.c:cciss_proc_write(), on "engage scsi" being received
-   from user space.) */
-
-static 
-Scsi_Host_Template driver_template[MAX_CTLR] =
-{
-	CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI,
-	CCISS_SCSI, CCISS_SCSI, CCISS_SCSI, CCISS_SCSI,
+static Scsi_Host_Template cciss_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "cciss",
+	.proc_name		= "cciss",
+	.proc_info		= cciss_scsi_proc_info,
+	.queuecommand		= cciss_scsi_queue_command,
+	.can_queue		= SCSI_CCISS_CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= MAXSGENTRIES,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
 };
 
 #pragma pack(1)
@@ -700,60 +693,31 @@
 	scsi_cmd_free(ctlr, cp);
 }
 
-/* cciss_scsi_detect is called from the scsi mid layer.  
-   The scsi mid layer (scsi_register_host) is
-   called from cciss.c:cciss_init_one().  */
-
-int __init 
-cciss_scsi_detect(Scsi_Host_Template *tpnt)
+static int __init 
+cciss_scsi_detect(int ctlr)
 {
-	int i;
 	struct Scsi_Host *sh;
 
-	/* Tell the kernel we want to be a SCSI driver... */
-	sh = scsi_register(tpnt, sizeof(struct ctlr_info *));
-	if (sh == NULL) return 0;
+	sh = scsi_register(&cciss_driver_template, sizeof(struct ctlr_info *));
+	if (sh == NULL)
+		return 0;
 
 	sh->io_port = 0;	// good enough?  FIXME, 
 	sh->n_io_port = 0;	// I don't think we use these two...
 
 	sh->this_id = SELF_SCSI_ID;  
 
-	/* This is a bit kludgey, using the adapter name to figure out */
-	/* which scsi host template we've got, won't scale beyond 9 ctlrs. */
-	i = tpnt->name[5] - '0';
-
-#	if MAX_CTLR > 9
-#		error "cciss_scsi.c: MAX_CTLR > 9, code maintenance needed."
-#	endif	
-
-	if (i<0 || i>=MAX_CTLR || hba[i] == NULL) {
-		/* we didn't find ourself... we shouldn't get here. */
-		printk("cciss_scsi_detect: could not find ourself in hba[]\n");
-		return 0;
-	}
-
 	((struct cciss_scsi_adapter_data_t *) 
-		hba[i]->scsi_ctlr)->scsi_host = (void *) sh;
-	sh->hostdata[0] = (unsigned long) hba[i];
-	sh->irq = hba[i]->intr;
+		hba[ctlr]->scsi_ctlr)->scsi_host = (void *) sh;
+	sh->hostdata[0] = (unsigned long) hba[ctlr];
+	sh->irq = hba[ctlr]->intr;
 	sh->unique_id = sh->irq;
-	scsi_set_device(sh, &hba[i]->pdev->dev);
+	scsi_add_host(sh, &hba[ctlr]->pdev->dev);
 
-	return 1;	/* Say we have 1 scsi adapter, this will be */
-			/* called multiple times, once for each adapter */
-			/* from cciss.c:cciss_init_one().  We do it this */
-			/* way for PCI-hot plug reasons. (we don't know how */
-			/* many adapters we have total, so we say we have */
-			/* 1, each of a unique type.) */
+	return 1;
 }
 
 static void __exit cleanup_cciss_module(void);
-int
-cciss_scsi_release(struct Scsi_Host *sh)
-{
-	return 0;
-}
 
 static void
 cciss_unmap_one(struct pci_dev *pdev,
@@ -1082,7 +1046,7 @@
 	}
 	else {
 		printk(KERN_ERR  "cciss: Report physical LUNs failed.\n");
-		return;
+		goto out;
 	}
 
 
@@ -1127,7 +1091,7 @@
 	}
 
 	adjust_cciss_scsi_table(cntl_num, hostno, currentsd, ncurrent);
-
+out:
 	kfree(inq_buff);
 	kfree(ld_buff);
 	return;
@@ -1382,33 +1346,6 @@
 }
 
 static void 
-init_driver_template(int ctlr)
-{
-	memset(&driver_template[ctlr], 0, sizeof(driver_template[ctlr]));
-	driver_template[ctlr].name = ccissscsi[ctlr].name;
-	driver_template[ctlr].proc_name = ccissscsi[ctlr].name;
-	driver_template[ctlr].detect = cciss_scsi_detect;
-	driver_template[ctlr].release = cciss_scsi_release;
-	driver_template[ctlr].proc_info = cciss_scsi_proc_info;
-	driver_template[ctlr].queuecommand = cciss_scsi_queue_command;
-	driver_template[ctlr].eh_abort_handler = NULL;
-	driver_template[ctlr].eh_device_reset_handler = NULL;
-	driver_template[ctlr].can_queue = SCSI_CCISS_CAN_QUEUE;
-	driver_template[ctlr].this_id = 7;
-	driver_template[ctlr].sg_tablesize = MAXSGENTRIES;
-	driver_template[ctlr].cmd_per_lun = 1;
-	driver_template[ctlr].use_clustering = DISABLE_CLUSTERING;
-	driver_template[ctlr].module = THIS_MODULE;
-
-	/* set scsi_host to NULL so our detect routine will 
-	   find us on register */
-
-	((struct cciss_scsi_adapter_data_t *) 
-		hba[ctlr]->scsi_ctlr)->scsi_host = NULL;
-
-}
-
-static void 
 cciss_unregister_scsi(int ctlr)
 {
 	struct cciss_scsi_adapter_data_t *sa;
@@ -1422,15 +1359,18 @@
 	stk = &sa->cmd_stack; 
 
 	/* if we weren't ever actually registered, don't unregister */ 
-	if (((struct cciss_scsi_adapter_data_t *) 
-		hba[ctlr]->scsi_ctlr)->registered) {
+	if (sa->registered) {
 		spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
-		scsi_unregister_host(&driver_template[ctlr]);
+		scsi_remove_host(sa->scsi_host);
+		scsi_unregister(sa->scsi_host);
 		spin_lock_irqsave(CCISS_LOCK(ctlr), flags);
 	}
-	init_driver_template(ctlr);
+
+	/* set scsi_host to NULL so our detect routine will 
+	   find us on register */
+	sa->scsi_host = NULL;
 	scsi_cmd_stack_free(ctlr);
-	kfree(hba[ctlr]->scsi_ctlr);
+	kfree(sa);
 	spin_unlock_irqrestore(CCISS_LOCK(ctlr), flags);
 }
 
@@ -1440,9 +1380,6 @@
 	unsigned long flags;
 
 	CPQ_TAPE_LOCK(ctlr, flags);
-	driver_template[ctlr].name = ccissscsi[ctlr].name;
-	driver_template[ctlr].proc_name = ccissscsi[ctlr].name;
-	driver_template[ctlr].module = THIS_MODULE;;
 
 	/* Since this is really a block driver, the SCSI core may not be 
 	   initialized at init time, in which case, calling scsi_register_host
@@ -1454,7 +1391,7 @@
 		((struct cciss_scsi_adapter_data_t *) 
 			hba[ctlr]->scsi_ctlr)->registered = 1;
 		CPQ_TAPE_UNLOCK(ctlr, flags);
-		return scsi_register_host(&driver_template[ctlr]);
+		return cciss_scsi_detect(ctlr);
 	}
 	CPQ_TAPE_UNLOCK(ctlr, flags);
 	printk(KERN_INFO 
@@ -1489,8 +1426,8 @@
 static void
 cciss_proc_tape_report(int ctlr, unsigned char *buffer, off_t *pos, off_t *len)
 {
+	unsigned long flags;
 	int size;
-	unsigned int flags;
 
 	*pos = *pos -1; *len = *len - 1; // cut off the last trailing newline
 
diff -Nru a/drivers/block/cciss_scsi.h b/drivers/block/cciss_scsi.h
--- a/drivers/block/cciss_scsi.h	Thu Oct 24 17:29:19 2002
+++ b/drivers/block/cciss_scsi.h	Wed May  7 07:15:32 2003
@@ -38,23 +38,6 @@
 
 #define SCSI_CCISS_CAN_QUEUE 2
 
-/* this notation works fine for static initializations (as is the usual
-   case for linux scsi drivers), but not so well for dynamic settings,
-   so, if you change this, you also have to change cciss_unregister_scsi()
-   in cciss_scsi.c  */
-#define CCISS_SCSI {    \
-	name:           	"",				\
-	detect:         	cciss_scsi_detect,		\
-	release:        	cciss_scsi_release,		\
-	proc_info:           	cciss_scsi_proc_info,		\
-	queuecommand:   	cciss_scsi_queue_command,	\
-	can_queue:      	SCSI_CCISS_CAN_QUEUE,		\
-	this_id:        	7,				\
-	sg_tablesize:   	MAXSGENTRIES, 			\
-	cmd_per_lun:		1,				\
-	use_clustering:		DISABLE_CLUSTERING,\
-} 
-
 /* 
 	info:           	cciss_scsi_info,		\
 
diff -Nru a/drivers/block/deadline-iosched.c b/drivers/block/deadline-iosched.c
--- a/drivers/block/deadline-iosched.c	Fri Mar 14 07:55:04 2003
+++ b/drivers/block/deadline-iosched.c	Fri May  9 02:36:46 2003
@@ -28,7 +28,7 @@
 static int fifo_batch = 16;       /* # of sequential requests treated as one
 				     by the above parameters. For throughput. */
 
-static const int deadline_hash_shift = 10;
+static const int deadline_hash_shift = 5;
 #define DL_HASH_BLOCK(sec)	((sec) >> 3)
 #define DL_HASH_FN(sec)		(hash_long(DL_HASH_BLOCK((sec)), deadline_hash_shift))
 #define DL_HASH_ENTRIES		(1 << deadline_hash_shift)
@@ -71,6 +71,8 @@
 	int fifo_batch;
 	int writes_starved;
 	int front_merges;
+
+	mempool_t *drq_pool;
 };
 
 /*
@@ -130,6 +132,21 @@
 	list_add(&drq->hash, &dd->hash[DL_HASH_FN(rq_hash_key(rq))]);
 }
 
+/*
+ * move hot entry to front of chain
+ */
+static inline void
+deadline_hot_drq_hash(struct deadline_data *dd, struct deadline_rq *drq)
+{
+	struct request *rq = drq->request;
+	struct list_head *head = &dd->hash[DL_HASH_FN(rq_hash_key(rq))];
+
+	if (ON_HASH(drq) && drq->hash.prev != head) {
+		list_del(&drq->hash);
+		list_add(&drq->hash, head);
+	}
+}
+
 static struct request *
 deadline_find_drq_hash(struct deadline_data *dd, sector_t offset)
 {
@@ -353,6 +370,8 @@
 out:
 	q->last_merge = &__rq->queuelist;
 out_insert:
+	if (ret)
+		deadline_hot_drq_hash(dd, RQ_DATA(__rq));
 	*insert = &__rq->queuelist;
 	return ret;
 }
@@ -673,28 +692,11 @@
 static void deadline_exit(request_queue_t *q, elevator_t *e)
 {
 	struct deadline_data *dd = e->elevator_data;
-	struct deadline_rq *drq;
-	struct request *rq;
-	int i;
 
 	BUG_ON(!list_empty(&dd->fifo_list[READ]));
 	BUG_ON(!list_empty(&dd->fifo_list[WRITE]));
 
-	for (i = READ; i <= WRITE; i++) {
-		struct request_list *rl = &q->rq[i];
-		struct list_head *entry;
-
-		list_for_each(entry, &rl->free) {
-			rq = list_entry_rq(entry);
-
-			if ((drq = RQ_DATA(rq)) == NULL)
-				continue;
-
-			rq->elevator_private = NULL;
-			kmem_cache_free(drq_pool, drq);
-		}
-	}
-
+	mempool_destroy(dd->drq_pool);
 	kfree(dd->hash);
 	kfree(dd);
 }
@@ -706,9 +708,7 @@
 static int deadline_init(request_queue_t *q, elevator_t *e)
 {
 	struct deadline_data *dd;
-	struct deadline_rq *drq;
-	struct request *rq;
-	int i, ret = 0;
+	int i;
 
 	if (!drq_pool)
 		return -ENOMEM;
@@ -724,6 +724,13 @@
 		return -ENOMEM;
 	}
 
+	dd->drq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, drq_pool);
+	if (!dd->drq_pool) {
+		kfree(dd->hash);
+		kfree(dd);
+		return -ENOMEM;
+	}
+
 	for (i = 0; i < DL_HASH_ENTRIES; i++)
 		INIT_LIST_HEAD(&dd->hash[i]);
 
@@ -739,33 +746,41 @@
 	dd->front_merges = 1;
 	dd->fifo_batch = fifo_batch;
 	e->elevator_data = dd;
+	return 0;
+}
 
-	for (i = READ; i <= WRITE; i++) {
-		struct request_list *rl = &q->rq[i];
-		struct list_head *entry;
-
-		list_for_each(entry, &rl->free) {
-			rq = list_entry_rq(entry);
-
-			drq = kmem_cache_alloc(drq_pool, GFP_KERNEL);
-			if (!drq) {
-				ret = -ENOMEM;
-				break;
-			}
+static void deadline_put_request(request_queue_t *q, struct request *rq)
+{
+	struct deadline_data *dd = q->elevator.elevator_data;
+	struct deadline_rq *drq = RQ_DATA(rq);
 
-			memset(drq, 0, sizeof(*drq));
-			INIT_LIST_HEAD(&drq->fifo);
-			INIT_LIST_HEAD(&drq->hash);
-			RB_CLEAR(&drq->rb_node);
-			drq->request = rq;
-			rq->elevator_private = drq;
-		}
+	if (drq) {
+		mempool_free(drq, dd->drq_pool);
+		rq->elevator_private = NULL;
 	}
+}
 
-	if (ret)
-		deadline_exit(q, e);
+static int
+deadline_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+{
+	struct deadline_data *dd = q->elevator.elevator_data;
+	struct deadline_rq *drq;
 
-	return ret;
+	drq = mempool_alloc(dd->drq_pool, gfp_mask);
+	if (drq) {
+		RB_CLEAR(&drq->rb_node);
+		drq->request = rq;
+
+		INIT_LIST_HEAD(&drq->hash);
+		drq->hash_valid_count = 0;
+
+		INIT_LIST_HEAD(&drq->fifo);
+
+		rq->elevator_private = drq;
+		return 0;
+	}
+
+	return 1;
 }
 
 /*
@@ -916,6 +931,8 @@
 	.elevator_queue_empty_fn =	deadline_queue_empty,
 	.elevator_former_req_fn =	deadline_former_request,
 	.elevator_latter_req_fn =	deadline_latter_request,
+	.elevator_set_req_fn =		deadline_set_request,
+	.elevator_put_req_fn = 		deadline_put_request,
 	.elevator_init_fn =		deadline_init,
 	.elevator_exit_fn =		deadline_exit,
 
diff -Nru a/drivers/block/elevator.c b/drivers/block/elevator.c
--- a/drivers/block/elevator.c	Sun Feb 16 03:32:35 2003
+++ b/drivers/block/elevator.c	Fri May  9 02:36:46 2003
@@ -408,6 +408,25 @@
 	return NULL;
 }
 
+int elv_set_request(request_queue_t *q, struct request *rq, int gfp_mask)
+{
+	elevator_t *e = &q->elevator;
+
+	if (e->elevator_set_req_fn)
+		return e->elevator_set_req_fn(q, rq, gfp_mask);
+
+	rq->elevator_private = NULL;
+	return 0;
+}
+
+void elv_put_request(request_queue_t *q, struct request *rq)
+{
+	elevator_t *e = &q->elevator;
+
+	if (e->elevator_put_req_fn)
+		e->elevator_put_req_fn(q, rq);
+}
+
 int elv_register_queue(struct gendisk *disk)
 {
 	request_queue_t *q = disk->queue;
diff -Nru a/drivers/block/genhd.c b/drivers/block/genhd.c
--- a/drivers/block/genhd.c	Sun May  4 01:38:05 2003
+++ b/drivers/block/genhd.c	Sat May 17 12:39:13 2003
@@ -367,9 +367,7 @@
 
 static struct gendisk *base_probe(dev_t dev, int *part, void *data)
 {
-	char name[30];
-	sprintf(name, "block-major-%d", MAJOR(dev));
-	request_module(name);
+	request_module("block-major-%d", MAJOR(dev));
 	return NULL;
 }
 
diff -Nru a/drivers/block/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
--- a/drivers/block/ll_rw_blk.c	Thu Apr 24 03:23:09 2003
+++ b/drivers/block/ll_rw_blk.c	Thu May  8 02:30:11 2003
@@ -48,12 +48,6 @@
  */
 static int queue_nr_requests;
 
-/*
- * How many free requests must be available before we wake a process which
- * is waiting for a request?
- */
-static int batch_requests;
-
 unsigned long blk_max_low_pfn, blk_max_pfn;
 int blk_nohighio = 0;
 
@@ -419,7 +413,7 @@
 {
 	struct blk_queue_tag *bqt = q->queue_tags;
 
-	if(unlikely(bqt == NULL || bqt->max_depth < tag))
+	if (unlikely(bqt == NULL || bqt->max_depth < tag))
 		return NULL;
 
 	return bqt->tag_index[tag];
@@ -1122,26 +1116,6 @@
 	spin_unlock_irq(&blk_plug_lock);
 }
 
-static int __blk_cleanup_queue(struct request_list *list)
-{
-	struct list_head *head = &list->free;
-	struct request *rq;
-	int i = 0;
-
-	while (!list_empty(head)) {
-		rq = list_entry(head->next, struct request, queuelist);
-		list_del_init(&rq->queuelist);
-		kmem_cache_free(request_cachep, rq);
-		i++;
-	}
-
-	if (i != list->count)
-		printk("request list leak!\n");
-
-	list->count = 0;
-	return i;
-}
-
 /**
  * blk_cleanup_queue: - release a &request_queue_t when it is no longer needed
  * @q:    the request queue to be released
@@ -1158,18 +1132,14 @@
  **/
 void blk_cleanup_queue(request_queue_t * q)
 {
-	int count = (queue_nr_requests*2);
+	struct request_list *rl = &q->rq;
 
 	elevator_exit(q);
 
-	count -= __blk_cleanup_queue(&q->rq[READ]);
-	count -= __blk_cleanup_queue(&q->rq[WRITE]);
-
 	del_timer_sync(&q->unplug_timer);
 	flush_scheduled_work();
 
-	if (count)
-		printk("blk_cleanup_queue: leaked requests (%d)\n", count);
+	mempool_destroy(rl->rq_pool);
 
 	if (blk_queue_tagged(q))
 		blk_queue_free_tags(q);
@@ -1179,42 +1149,16 @@
 
 static int blk_init_free_list(request_queue_t *q)
 {
-	struct request_list *rl;
-	struct request *rq;
-	int i;
+	struct request_list *rl = &q->rq;
 
-	INIT_LIST_HEAD(&q->rq[READ].free);
-	INIT_LIST_HEAD(&q->rq[WRITE].free);
-	q->rq[READ].count = 0;
-	q->rq[WRITE].count = 0;
+	rl->count[READ] = rl->count[WRITE] = 0;
 
-	/*
-	 * Divide requests in half between read and write
-	 */
-	rl = &q->rq[READ];
-	for (i = 0; i < (queue_nr_requests*2); i++) {
-		rq = kmem_cache_alloc(request_cachep, SLAB_KERNEL);
-		if (!rq)
-			goto nomem;
-
-		/*
-		 * half way through, switch to WRITE list
-		 */
-		if (i == queue_nr_requests)
-			rl = &q->rq[WRITE];
+	rl->rq_pool = mempool_create(BLKDEV_MIN_RQ, mempool_alloc_slab, mempool_free_slab, request_cachep);
 
-		memset(rq, 0, sizeof(struct request));
-		rq->rq_status = RQ_INACTIVE;
-		list_add(&rq->queuelist, &rl->free);
-		rl->count++;
-	}
+	if (!rl->rq_pool)
+		return -ENOMEM;
 
-	init_waitqueue_head(&q->rq[READ].wait);
-	init_waitqueue_head(&q->rq[WRITE].wait);
 	return 0;
-nomem:
-	blk_cleanup_queue(q);
-	return 1;
 }
 
 static int __make_request(request_queue_t *, struct bio *);
@@ -1276,41 +1220,79 @@
 	blk_queue_max_hw_segments(q, MAX_HW_SEGMENTS);
 	blk_queue_max_phys_segments(q, MAX_PHYS_SEGMENTS);
 
-	INIT_LIST_HEAD(&q->plug_list);
-
 	return 0;
 }
 
+static inline void blk_free_request(request_queue_t *q, struct request *rq)
+{
+	elv_put_request(q, rq);
+	mempool_free(rq, q->rq.rq_pool);
+}
+
+static inline struct request *blk_alloc_request(request_queue_t *q,int gfp_mask)
+{
+	struct request *rq = mempool_alloc(q->rq.rq_pool, gfp_mask);
+
+	if (!rq)
+		return NULL;
+
+	if (!elv_set_request(q, rq, gfp_mask))
+		return rq;
+
+	mempool_free(rq, q->rq.rq_pool);
+	return NULL;
+}
+
 #define blkdev_free_rq(list) list_entry((list)->next, struct request, queuelist)
 /*
- * Get a free request. queue lock must be held and interrupts
- * disabled on the way in.
+ * Get a free request, queue_lock must not be held
  */
-static struct request *get_request(request_queue_t *q, int rw)
+static struct request *get_request(request_queue_t *q, int rw, int gfp_mask)
 {
 	struct request *rq = NULL;
-	struct request_list *rl = q->rq + rw;
+	struct request_list *rl = &q->rq;
 
-	if (!list_empty(&rl->free)) {
-		rq = blkdev_free_rq(&rl->free);
-		list_del_init(&rq->queuelist);
-		rq->ref_count = 1;
-		rl->count--;
-		if (rl->count < queue_congestion_on_threshold())
-			set_queue_congested(q, rw);
-		rq->flags = 0;
-		rq->rq_status = RQ_ACTIVE;
-		rq->errors = 0;
-		rq->special = NULL;
-		rq->buffer = NULL;
-		rq->data = NULL;
-		rq->sense = NULL;
-		rq->waiting = NULL;
-		rq->bio = rq->biotail = NULL;
-		rq->q = q;
-		rq->rl = rl;
+	spin_lock_irq(q->queue_lock);
+	if (rl->count[rw] == BLKDEV_MAX_RQ) {
+		spin_unlock_irq(q->queue_lock);
+		goto out;
 	}
+	rl->count[rw]++;
+	if ((BLKDEV_MAX_RQ - rl->count[rw]) < queue_congestion_on_threshold())
+		set_queue_congested(q, rw);
+	spin_unlock_irq(q->queue_lock);
+
+	rq = blk_alloc_request(q, gfp_mask);
+	if (!rq) {
+		spin_lock_irq(q->queue_lock);
+		rl->count[rw]--;
+		if ((BLKDEV_MAX_RQ - rl->count[rw]) >= queue_congestion_off_threshold())
+                        clear_queue_congested(q, rw);
+		spin_unlock_irq(q->queue_lock);
+		goto out;
+	}
+	
+	INIT_LIST_HEAD(&rq->queuelist);
 
+	/*
+	 * first three bits are identical in rq->flags and bio->bi_rw,
+	 * see bio.h and blkdev.h
+	 */
+	rq->flags = rw;
+
+	rq->errors = 0;
+	rq->rq_status = RQ_ACTIVE;
+	rq->bio = rq->biotail = NULL;
+	rq->buffer = NULL;
+	rq->ref_count = 1;
+	rq->q = q;
+	rq->rl = rl;
+	rq->waiting = NULL;
+	rq->special = NULL;
+	rq->data = NULL;
+	rq->sense = NULL;
+
+out:
 	return rq;
 }
 
@@ -1319,31 +1301,16 @@
  */
 static struct request *get_request_wait(request_queue_t *q, int rw)
 {
-	DEFINE_WAIT(wait);
-	struct request_list *rl = &q->rq[rw];
 	struct request *rq;
 
-	spin_lock_prefetch(q->queue_lock);
-
 	generic_unplug_device(q);
 	do {
-		int block = 0;
+		rq = get_request(q, rw, GFP_NOIO);
 
-		prepare_to_wait_exclusive(&rl->wait, &wait,
-					TASK_UNINTERRUPTIBLE);
-		spin_lock_irq(q->queue_lock);
-		if (!rl->count)
-			block = 1;
-		spin_unlock_irq(q->queue_lock);
-
-		if (block)
-			io_schedule();
-		finish_wait(&rl->wait, &wait);
+		if (!rq)
+			blk_congestion_wait(rw, HZ / 50);
+	} while (!rq);
 
-		spin_lock_irq(q->queue_lock);
-		rq = get_request(q, rw);
-		spin_unlock_irq(q->queue_lock);
-	} while (rq == NULL);
 	return rq;
 }
 
@@ -1353,39 +1320,11 @@
 
 	BUG_ON(rw != READ && rw != WRITE);
 
-	spin_lock_irq(q->queue_lock);
-	rq = get_request(q, rw);
-	spin_unlock_irq(q->queue_lock);
+	rq = get_request(q, rw, gfp_mask);
 
 	if (!rq && (gfp_mask & __GFP_WAIT))
 		rq = get_request_wait(q, rw);
 
-	if (rq) {
-		rq->flags = 0;
-		rq->buffer = NULL;
-		rq->bio = rq->biotail = NULL;
-		rq->waiting = NULL;
-	}
-	return rq;
-}
-
-/*
- * Non-locking blk_get_request variant, for special requests from drivers.
- */
-struct request *__blk_get_request(request_queue_t *q, int rw)
-{
-	struct request *rq;
-
-	BUG_ON(rw != READ && rw != WRITE);
-
-	rq = get_request(q, rw);
-
-	if (rq) {
-		rq->flags = 0;
-		rq->buffer = NULL;
-		rq->bio = rq->biotail = NULL;
-		rq->waiting = NULL;
-	}
 	return rq;
 }
 
@@ -1503,14 +1442,17 @@
 	disk->stamp_idle = now;
 }
 
+/*
+ * queue lock must be held
+ */
 void __blk_put_request(request_queue_t *q, struct request *req)
 {
 	struct request_list *rl = req->rl;
 
-	if (unlikely(--req->ref_count))
-		return;
 	if (unlikely(!q))
 		return;
+	if (unlikely(--req->ref_count))
+		return;
 
 	req->rq_status = RQ_INACTIVE;
 	req->q = NULL;
@@ -1521,24 +1463,15 @@
 	 * it didn't come out of our reserved rq pools
 	 */
 	if (rl) {
-		int rw = 0;
+		int rw = rq_data_dir(req);
 
 		BUG_ON(!list_empty(&req->queuelist));
 
-		list_add(&req->queuelist, &rl->free);
+		blk_free_request(q, req);
 
-		if (rl == &q->rq[WRITE])
-			rw = WRITE;
-		else if (rl == &q->rq[READ])
-			rw = READ;
-		else
-			BUG();
-
-		rl->count++;
-		if (rl->count >= queue_congestion_off_threshold())
+		rl->count[rw]--;
+		if ((BLKDEV_MAX_RQ - rl->count[rw]) >= queue_congestion_off_threshold())
 			clear_queue_congested(q, rw);
-		if (rl->count >= batch_requests && waitqueue_active(&rl->wait))
-			wake_up(&rl->wait);
 	}
 }
 
@@ -1605,24 +1538,23 @@
 	 * will have updated segment counts, update sector
 	 * counts here.
 	 */
-	if (q->merge_requests_fn(q, req, next)) {
-		req->biotail->bi_next = next->bio;
-		req->biotail = next->biotail;
+	if (!q->merge_requests_fn(q, req, next))
+		return 0;
 
-		req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors;
+	req->biotail->bi_next = next->bio;
+	req->biotail = next->biotail;
 
-		elv_merge_requests(q, req, next);
+	req->nr_sectors = req->hard_nr_sectors += next->hard_nr_sectors;
 
-		if (req->rq_disk) {
-			disk_round_stats(req->rq_disk);
-			disk_stat_dec(req->rq_disk, in_flight);
-		}
+	elv_merge_requests(q, req, next);
 
-		__blk_put_request(q, next);
-		return 1;
+	if (req->rq_disk) {
+		disk_round_stats(req->rq_disk);
+		disk_stat_dec(req->rq_disk, in_flight);
 	}
 
-	return 0;
+	__blk_put_request(q, next);
+	return 1;
 }
 
 static inline int attempt_back_merge(request_queue_t *q, struct request *rq)
@@ -1684,7 +1616,8 @@
 
 	sector = bio->bi_sector;
 	nr_sectors = bio_sectors(bio);
-	cur_nr_sectors = bio_iovec(bio)->bv_len >> 9;
+	cur_nr_sectors = bio_cur_sectors(bio);
+
 	rw = bio_data_dir(bio);
 
 	/*
@@ -1698,9 +1631,9 @@
 
 	barrier = test_bit(BIO_RW_BARRIER, &bio->bi_rw);
 
-	spin_lock_irq(q->queue_lock);
 again:
 	insert_here = NULL;
+	spin_lock_irq(q->queue_lock);
 
 	if (elv_queue_empty(q)) {
 		blk_plug_device(q);
@@ -1740,7 +1673,10 @@
 			}
 
 			bio->bi_next = req->bio;
-			req->bio = bio;
+			req->cbio = req->bio = bio;
+			req->nr_cbio_segments = bio_segments(bio);
+			req->nr_cbio_sectors = bio_sectors(bio);
+
 			/*
 			 * may not be valid. if the low level driver said
 			 * it didn't need a bounce buffer then it better
@@ -1776,17 +1712,17 @@
 	if (freereq) {
 		req = freereq;
 		freereq = NULL;
-	} else if ((req = get_request(q, rw)) == NULL) {
+	} else {
 		spin_unlock_irq(q->queue_lock);
-
-		/*
-		 * READA bit set
-		 */
-		if (bio_flagged(bio, BIO_RW_AHEAD))
-			goto end_io;
-
-		freereq = get_request_wait(q, rw);
-		spin_lock_irq(q->queue_lock);
+		if ((freereq = get_request(q, rw, GFP_ATOMIC)) == NULL) {
+			/*
+			 * READA bit set
+			 */
+			if (bio_flagged(bio, BIO_RW_AHEAD))
+				goto end_io;
+	
+			freereq = get_request_wait(q, rw);
+		}
 		goto again;
 	}
 
@@ -1808,19 +1744,22 @@
 	req->current_nr_sectors = req->hard_cur_sectors = cur_nr_sectors;
 	req->nr_phys_segments = bio_phys_segments(q, bio);
 	req->nr_hw_segments = bio_hw_segments(q, bio);
+	req->nr_cbio_segments = bio_segments(bio);
+	req->nr_cbio_sectors = bio_sectors(bio);
 	req->buffer = bio_data(bio);	/* see ->buffer comment above */
 	req->waiting = NULL;
-	req->bio = req->biotail = bio;
+	req->cbio = req->bio = req->biotail = bio;
 	req->rq_disk = bio->bi_bdev->bd_disk;
 	req->start_time = jiffies;
+
 	add_request(q, req, insert_here);
 out:
 	if (freereq)
 		__blk_put_request(q, freereq);
 
 	if (blk_queue_plugged(q)) {
-		int nr_queued = (queue_nr_requests - q->rq[0].count) +
-				(queue_nr_requests - q->rq[1].count);
+		int nr_queued = q->rq.count[0] + q->rq.count[1];
+
 		if (nr_queued == q->unplug_thresh)
 			__generic_unplug_device(q);
 	}
@@ -1981,6 +1920,81 @@
 	return 1;
 }
 
+/**
+ * blk_rq_next_segment
+ * @rq:		the request being processed
+ *
+ * Description:
+ *	Points to the next segment in the request if the current segment
+ *	is complete. Leaves things unchanged if this segment is not over
+ *	or if no more segments are left in this request.
+ *
+ *	Meant to be used for bio traversal during I/O submission
+ *	Does not affect any I/O completions or update completion state
+ *	in the request, and does not modify any bio fields.
+ *
+ *	Decrementing rq->nr_sectors, rq->current_nr_sectors and
+ *	rq->nr_cbio_sectors as data is transferred is the caller's
+ *	responsibility and should be done before calling this routine.
+ **/
+void blk_rq_next_segment(struct request *rq)
+{
+	if (rq->current_nr_sectors > 0)
+		return;
+
+	if (rq->nr_cbio_sectors > 0) {
+		--rq->nr_cbio_segments;
+		rq->current_nr_sectors = blk_rq_vec(rq)->bv_len >> 9;
+	} else {
+		if ((rq->cbio = rq->cbio->bi_next)) {
+			rq->nr_cbio_segments = bio_segments(rq->cbio);
+			rq->nr_cbio_sectors = bio_sectors(rq->cbio);
+ 			rq->current_nr_sectors = bio_cur_sectors(rq->cbio);
+		}
+ 	}
+
+	/* remember the size of this segment before we start I/O */
+	rq->hard_cur_sectors = rq->current_nr_sectors;
+}
+
+/**
+ * process_that_request_first	-	process partial request submission
+ * @req:	the request being processed
+ * @nr_sectors:	number of sectors I/O has been submitted on
+ *
+ * Description:
+ *	May be used for processing bio's while submitting I/O without
+ *	signalling completion. Fails if more data is requested than is
+ *	available in the request in which case it doesn't advance any
+ *	pointers.
+ *
+ *	Assumes a request is correctly set up. No sanity checks.
+ *
+ * Return:
+ *	0 - no more data left to submit (not processed)
+ *	1 - data available to submit for this request (processed)
+ **/
+int process_that_request_first(struct request *req, unsigned int nr_sectors)
+{
+	unsigned int nsect;
+
+	if (req->nr_sectors < nr_sectors)
+		return 0;
+
+	req->nr_sectors -= nr_sectors;
+	req->sector += nr_sectors;
+	while (nr_sectors) {
+		nsect = min_t(unsigned, req->current_nr_sectors, nr_sectors);
+		req->current_nr_sectors -= nsect;
+		nr_sectors -= nsect;
+		if (req->cbio) {
+			req->nr_cbio_sectors -= nsect;
+			blk_rq_next_segment(req);
+		}
+	}
+	return 1;
+}
+
 void blk_recalc_rq_segments(struct request *rq)
 {
 	struct bio *bio;
@@ -1989,8 +2003,6 @@
 	if (!rq->bio)
 		return;
 
-	rq->buffer = bio_data(rq->bio);
-
 	nr_phys_segs = nr_hw_segs = 0;
 	rq_for_each_bio(bio, rq) {
 		/* Force bio hw/phys segs to be recalculated. */
@@ -2008,11 +2020,24 @@
 {
 	if (blk_fs_request(rq)) {
 		rq->hard_sector += nsect;
-		rq->nr_sectors = rq->hard_nr_sectors -= nsect;
-		rq->sector = rq->hard_sector;
+		rq->hard_nr_sectors -= nsect;
+
+		/*
+		 * Move the I/O submission pointers ahead if required,
+		 * i.e. for drivers not aware of rq->cbio.
+		 */
+		if ((rq->nr_sectors >= rq->hard_nr_sectors) &&
+		    (rq->sector <= rq->hard_sector)) {
+			rq->sector = rq->hard_sector;
+			rq->nr_sectors = rq->hard_nr_sectors;
+			rq->hard_cur_sectors = bio_cur_sectors(rq->bio);
+			rq->current_nr_sectors = rq->hard_cur_sectors;
+			rq->nr_cbio_segments = bio_segments(rq->bio);
+			rq->nr_cbio_sectors = bio_sectors(rq->bio);
+			rq->buffer = bio_data(rq->bio);
 
-		rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
-		rq->hard_cur_sectors = rq->current_nr_sectors;
+			rq->cbio = rq->bio;
+		}
 
 		/*
 		 * if total number of sectors is less than the first segment
@@ -2206,14 +2231,31 @@
 	rq->current_nr_sectors = bio_cur_sectors(bio);
 	rq->hard_cur_sectors = rq->current_nr_sectors;
 	rq->hard_nr_sectors = rq->nr_sectors = bio_sectors(bio);
+	rq->nr_cbio_segments = bio_segments(bio);
+	rq->nr_cbio_sectors = bio_sectors(bio);
 	rq->buffer = bio_data(bio);
 
-	rq->bio = rq->biotail = bio;
+	rq->cbio = rq->bio = rq->biotail = bio;
+}
+
+void blk_rq_prep_restart(struct request *rq)
+{
+	struct bio *bio;
+
+	bio = rq->cbio = rq->bio;
+	if (bio) {
+		rq->nr_cbio_segments = bio_segments(bio);
+		rq->nr_cbio_sectors = bio_sectors(bio);
+		rq->hard_cur_sectors = bio_cur_sectors(bio);
+		rq->buffer = bio_data(bio);
+	}
+	rq->sector = rq->hard_sector;
+	rq->nr_sectors = rq->hard_nr_sectors;
+	rq->current_nr_sectors = rq->hard_cur_sectors;
 }
 
 int __init blk_dev_init(void)
 {
-	int total_ram = nr_free_pages() << (PAGE_SHIFT - 10);
 	int i;
 
 	request_cachep = kmem_cache_create("blkdev_requests",
@@ -2221,24 +2263,11 @@
 	if (!request_cachep)
 		panic("Can't create request pool slab cache\n");
 
-	/*
-	 * Free request slots per queue.  One per quarter-megabyte.
-	 * We use this many requests for reads, and this many for writes.
-	 */
-	queue_nr_requests = (total_ram >> 9) & ~7;
-	if (queue_nr_requests < 16)
-		queue_nr_requests = 16;
-	if (queue_nr_requests > 128)
-		queue_nr_requests = 128;
-
-	batch_requests = queue_nr_requests / 8;
-	if (batch_requests > 8)
-		batch_requests = 8;
+	queue_nr_requests = BLKDEV_MAX_RQ;
 
 	printk("block request queues:\n");
-	printk(" %d requests per read queue\n", queue_nr_requests);
-	printk(" %d requests per write queue\n", queue_nr_requests);
-	printk(" %d requests per batch\n", batch_requests);
+	printk(" %d/%d requests per read queue\n", BLKDEV_MIN_RQ, queue_nr_requests);
+	printk(" %d/%d requests per write queue\n", BLKDEV_MIN_RQ, queue_nr_requests);
 	printk(" enter congestion at %d\n", queue_congestion_on_threshold());
 	printk(" exit congestion at %d\n", queue_congestion_off_threshold());
 
@@ -2250,6 +2279,7 @@
 	return 0;
 };
 
+EXPORT_SYMBOL(process_that_request_first);
 EXPORT_SYMBOL(end_that_request_first);
 EXPORT_SYMBOL(end_that_request_chunk);
 EXPORT_SYMBOL(end_that_request_last);
@@ -2281,7 +2311,6 @@
 EXPORT_SYMBOL(blk_phys_contig_segment);
 EXPORT_SYMBOL(blk_hw_contig_segment);
 EXPORT_SYMBOL(blk_get_request);
-EXPORT_SYMBOL(__blk_get_request);
 EXPORT_SYMBOL(blk_put_request);
 EXPORT_SYMBOL(blk_insert_request);
 
diff -Nru a/drivers/block/loop.c b/drivers/block/loop.c
--- a/drivers/block/loop.c	Sat Apr 19 14:18:27 2003
+++ b/drivers/block/loop.c	Wed May 14 23:43:53 2003
@@ -651,7 +651,8 @@
 	int		lo_flags = 0;
 	int		error;
 
-	MOD_INC_USE_COUNT;
+	/* This is safe, since we have a reference from open(). */
+	__module_get(THIS_MODULE);
 
 	error = -EBUSY;
 	if (lo->lo_state != Lo_unbound)
@@ -751,7 +752,8 @@
  out_putf:
 	fput(file);
  out:
-	MOD_DEC_USE_COUNT;
+	/* This is safe: open() is still holding a reference. */
+	module_put(THIS_MODULE);
 	return error;
 }
 
@@ -824,7 +826,8 @@
 	filp->f_dentry->d_inode->i_mapping->gfp_mask = gfp;
 	lo->lo_state = Lo_unbound;
 	fput(filp);
-	MOD_DEC_USE_COUNT;
+	/* This is safe: open() is still holding a reference. */
+	module_put(THIS_MODULE);
 	return 0;
 }
 
diff -Nru a/drivers/block/paride/pg.c b/drivers/block/paride/pg.c
--- a/drivers/block/paride/pg.c	Mon Mar 24 20:59:59 2003
+++ b/drivers/block/paride/pg.c	Wed May  7 08:47:29 2003
@@ -652,11 +652,8 @@
 	devfs_mk_dir ("pg");
 	for (unit=0; unit<PG_UNITS; unit++)
 		if (PG.present) {
-			char name[16];
-			sprintf(name, "pg/%u", unit);
-			devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-			       major, unit, S_IFCHR | S_IRUSR | S_IWUSR,
-			       &pg_fops, NULL);
+			devfs_mk_cdev(MKDEV(major, unit),
+				S_IFCHR | S_IRUSR | S_IWUSR, "pg/%u", unit);
 		}
 	return 0;
 }
diff -Nru a/drivers/block/paride/pt.c b/drivers/block/paride/pt.c
--- a/drivers/block/paride/pt.c	Thu Apr 24 03:30:41 2003
+++ b/drivers/block/paride/pt.c	Wed May  7 08:47:29 2003
@@ -914,15 +914,12 @@
 	devfs_mk_dir ("pt");
 	for (unit=0;unit<PT_UNITS;unit++)
 		if (PT.present) {
-			char name[16];
-			sprintf(name, "pt/%d", unit);
-			devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-			       major, unit, S_IFCHR | S_IRUSR | S_IWUSR,
-			       &pt_fops, NULL);
-			sprintf(name, "pt/%dn", unit);
-			devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-			       major, 128 + unit, S_IFCHR | S_IRUSR | S_IWUSR,
-			       &pt_fops, NULL);
+			devfs_mk_cdev(MKDEV(major, unit),
+					S_IFCHR | S_IRUSR | S_IWUSR,
+					"pt/%d", unit);
+			devfs_mk_cdev(MKDEV(major, unit + 128),
+					S_IFCHR | S_IRUSR | S_IWUSR,
+					"pt/%dn", unit);
 		}
 	return 0;
 }
diff -Nru a/drivers/block/scsi_ioctl.c b/drivers/block/scsi_ioctl.c
--- a/drivers/block/scsi_ioctl.c	Thu Apr 24 10:36:15 2003
+++ b/drivers/block/scsi_ioctl.c	Sat May 17 03:05:21 2003
@@ -48,6 +48,7 @@
 static int blk_do_rq(request_queue_t *q, struct block_device *bdev, 
 		     struct request *rq)
 {
+	char sense[SCSI_SENSE_BUFFERSIZE];
 	DECLARE_COMPLETION(wait);
 	int err = 0;
 
@@ -59,6 +60,12 @@
 	 */
 	rq->ref_count++;
 
+	if (!rq->sense) {
+		memset(sense, 0, sizeof(sense));
+		rq->sense = sense;
+		rq->sense_len = 0;
+	}
+
 	rq->flags |= REQ_NOMERGE;
 	rq->waiting = &wait;
         drive_stat_acct(rq, rq->nr_sectors, 1);
@@ -212,7 +219,7 @@
 		}
 	}
 
-	rq = blk_get_request(q, WRITE, __GFP_WAIT);
+	rq = blk_get_request(q, writing ? WRITE : READ, __GFP_WAIT);
 
 	/*
 	 * fill in request structure
@@ -227,8 +234,6 @@
 	rq->sense_len = 0;
 
 	rq->flags |= REQ_BLOCK_PC;
-	if (writing)
-		rq->flags |= REQ_RW;
 
 	rq->hard_nr_sectors = rq->nr_sectors = nr_sectors;
 	rq->hard_cur_sectors = rq->current_nr_sectors = nr_sectors;
@@ -299,13 +304,14 @@
 #define MOVE_MEDIUM_TIMEOUT		(5 * 60 * HZ)
 #define READ_ELEMENT_STATUS_TIMEOUT	(5 * 60 * HZ)
 #define READ_DEFECT_DATA_TIMEOUT	(60 * HZ )
+#define OMAX_SB_LEN 16          /* For backward compatibility */
 
 static int sg_scsi_ioctl(request_queue_t *q, struct block_device *bdev,
 			 Scsi_Ioctl_Command *sic)
 {
 	struct request *rq;
 	int err, in_len, out_len, bytes, opcode, cmdlen;
-	char *buffer = NULL, sense[24];
+	char *buffer = NULL, sense[SCSI_SENSE_BUFFERSIZE];
 
 	/*
 	 * get in an out lengths, verify they don't exceed a page worth of data
@@ -328,7 +334,7 @@
 		memset(buffer, 0, bytes);
 	}
 
-	rq = blk_get_request(q, WRITE, __GFP_WAIT);
+	rq = blk_get_request(q, in_len ? WRITE : READ, __GFP_WAIT);
 
 	cmdlen = COMMAND_SIZE(opcode);
 
@@ -372,15 +378,16 @@
 	rq->data = buffer;
 	rq->data_len = bytes;
 	rq->flags |= REQ_BLOCK_PC;
-	if (in_len)
-		rq->flags |= REQ_RW;
 
 	blk_do_rq(q, bdev, rq);
 	err = rq->errors & 0xff;	/* only 8 bit SCSI status */
 	if (err) {
-		if (rq->sense_len)
-			if (copy_to_user(sic->data, rq->sense, rq->sense_len))
+		if (rq->sense_len && rq->sense) {
+			bytes = (OMAX_SB_LEN > rq->sense_len) ?
+				rq->sense_len : OMAX_SB_LEN;
+			if (copy_to_user(sic->data, rq->sense, bytes))
 				err = -EFAULT;
+		}
 	} else {
 		if (copy_to_user(sic->data, buffer, out_len))
 			err = -EFAULT;
diff -Nru a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c
--- a/drivers/bluetooth/hci_ldisc.c	Mon Apr 21 20:58:40 2003
+++ b/drivers/bluetooth/hci_ldisc.c	Thu May  8 16:38:32 2003
@@ -535,6 +535,7 @@
 	hci_uart_ldisc.receive_room= hci_uart_tty_room;
 	hci_uart_ldisc.receive_buf = hci_uart_tty_receive;
 	hci_uart_ldisc.write_wakeup= hci_uart_tty_wakeup;
+	hci_uart_ldisc.owner       = THIS_MODULE;
 
 	if ((err = tty_register_ldisc(N_HCI, &hci_uart_ldisc))) {
 		BT_ERR("HCI line discipline registration failed. (%d)", err);
diff -Nru a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c
--- a/drivers/bluetooth/hci_usb.c	Sun Apr 27 21:33:36 2003
+++ b/drivers/bluetooth/hci_usb.c	Wed May  7 21:06:25 2003
@@ -64,8 +64,8 @@
 #endif
 
 #ifndef CONFIG_BT_USB_ZERO_PACKET
-#undef  USB_ZERO_PACKET
-#define USB_ZERO_PACKET 0
+#undef  URB_ZERO_PACKET
+#define URB_ZERO_PACKET 0
 #endif
 
 static struct usb_driver hci_usb_driver; 
@@ -458,7 +458,7 @@
 	pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->desc.bEndpointAddress);
 	usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, skb->len, 
 			hci_usb_tx_complete, husb);
-	urb->transfer_flags = USB_ZERO_PACKET;
+	urb->transfer_flags = URB_ZERO_PACKET;
 
 	BT_DBG("%s skb %p len %d", husb->hdev.name, skb, skb->len);
 
diff -Nru a/drivers/char/agp/Kconfig b/drivers/char/agp/Kconfig
--- a/drivers/char/agp/Kconfig	Wed Apr  9 18:37:51 2003
+++ b/drivers/char/agp/Kconfig	Mon May 19 15:31:00 2003
@@ -1,6 +1,6 @@
 config AGP
 	tristate "/dev/agpgart (AGP Support)" if !GART_IOMMU
-	default AGP_GART if GART_IOMMU
+	default y if GART_IOMMU
 	---help---
 	  AGP (Accelerated Graphics Port) is a bus system mainly used to
 	  connect graphics cards to the rest of the system.
@@ -25,113 +25,117 @@
 	  a module, say M here and read <file:Documentation/modules.txt>.  The
 	  module will be called agpgart.
 
-config AGP_GART
-	bool "/dev/agpgart (AGP Support)"
-	depends on GART_IOMMU
-
-config AGP_INTEL
-	tristate "Intel 440LX/BX/GX, I8xx and E7x05 support"
-	depends on AGP && !X86_64
-	help
-	  This option gives you AGP support for the GLX component of the
-	  XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860
-	  E7205 and E7505 chipsets and full support for the 810, 815, 830M, 845G,
-	  852GM, 855GM and 865G integrated graphics chipsets.
-
-	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI, or if you have any Intel integrated graphics
-	  chipsets.  If unsure, say Y.
-
-#config AGP_I810
-#	tristate "Intel I810/I815/I830M (on-board) support"
-#	depends on AGP && !X86_64
-#	help
-#	  This option gives you AGP support for the Xserver on the Intel 810
-#	  815 and 830m chipset boards for their on-board integrated graphics. This
-#	  is required to do any useful video modes with these boards.
+config AGP_ALI
+	tristate "ALI chipset support"
+	depends on AGP && X86 && !X86_64
+	---help---
+	  This option gives you AGP support for the GLX component of
+	  XFree86 4.x on the following ALi chipsets.  The supported chipsets
+	  include M1541, M1621, M1631, M1632, M1641,M1647,and M1651.
+	  For the ALi-chipset question, ALi suggests you refer to
+	  <http://www.ali.com.tw/eng/support/index.shtml>.
 
-config AGP_VIA
-	tristate "VIA chipset support"
-	depends on AGP && !X86_64
-	help
-	  This option gives you AGP support for the GLX component of the
-	  XFree86 4.x on VIA MPV3/Apollo Pro chipsets.
+	  The M1541 chipset can do AGP 1x and 2x, but note that there is an
+	  acknowledged incompatibility with Matrox G200 cards. Due to
+	  timing issues, this chipset cannot do AGP 2x with the G200.
+	  This is a hardware limitation. AGP 1x seems to be fine, though.
 
 	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
 	  use GLX or DRI.  If unsure, say N.
 
 config AGP_AMD
-	tristate "AMD Irongate, 761, and 762 support"
-	depends on AGP && !X86_64
+	tristate "AMD Irongate, 761, and 762 chipset support"
+	depends on AGP && X86 && !X86_64
 	help
-	  This option gives you AGP support for the GLX component of the
+	  This option gives you AGP support for the GLX component of
 	  XFree86 4.x on AMD Irongate, 761, and 762 chipsets.
 
 	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
 	  use GLX or DRI.  If unsure, say N.
 
-config AGP_SIS
-	tristate "Generic SiS support"
-	depends on AGP && !X86_64
+config AGP_AMD_8151
+	tristate "AMD Opteron/Athlon64 on-CPU GART support"
+	depends on AGP && X86
+	default GART_IOMMU
 	help
-	  This option gives you AGP support for the GLX component of the "soon
-	  to be released" XFree86 4.x on Silicon Integrated Systems [SiS]
-	  chipsets.
+	  This option gives you AGP support for the GLX component of
+	  XFree86 4.x using the on-CPU AGP bridge of the AMD Athlon64/Opteron CPUs.
+	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+	  use GLX or DRI.  If unsure, say N
 
-	  Note that 5591/5592 AGP chipsets are NOT supported.
+config AGP_INTEL
+	tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support"
+	depends on AGP && X86 && !X86_64
+	help
+	  This option gives you AGP support for the GLX component of
+	  XFree86 4.x on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860
+	  E7205 and E7505 chipsets and full support for the 810, 815, 830M, 845G,
+	  852GM, 855GM and 865G integrated graphics chipsets.
 
 	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
-	  use GLX or DRI.  If unsure, say N.
+	  use GLX or DRI, or if you have any Intel integrated graphics
+	  chipsets.  If unsure, say Y.
 
-config AGP_ALI
-	tristate "ALI chipset support"
-	depends on AGP && !X86_64
-	---help---
-	  This option gives you AGP support for the GLX component of the
-	  XFree86 4.x on the following ALi chipsets.  The supported chipsets
-	  include M1541, M1621, M1631, M1632, M1641,M1647,and M1651.
-	  For the ALi-chipset question, ALi suggests you refer to
-	  <http://www.ali.com.tw/eng/support/index.shtml>.
+config AGP_NVIDIA
+	tristate "NVIDIA nForce/nForce2 chipset support"
+	depends on AGP && X86 && !X86_64
+	help
+	  This option gives you AGP support for the GLX component of
+	  XFree86 4.x on the following NVIDIA chipsets.  The supported chipsets
+	  include nForce and nForce2
 
-	  The M1541 chipset can do AGP 1x and 2x, but note that there is an
-	  acknowledged incompatibility with Matrox G200 cards. Due to
-	  timing issues, this chipset cannot do AGP 2x with the G200.
-	  This is a hardware limitation. AGP 1x seems to be fine, though.
+config AGP_SIS
+	tristate "SiS chipset support"
+	depends on AGP && X86 && !X86_64
+	help
+	  This option gives you AGP support for the GLX component of
+	  XFree86 4.x on Silicon Integrated Systems [SiS] chipsets.
+
+	  Note that 5591/5592 AGP chipsets are NOT supported.
 
 	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
 	  use GLX or DRI.  If unsure, say N.
 
 config AGP_SWORKS
-	tristate "Serverworks LE/HE support"
-	depends on AGP && !X86_64
+	tristate "Serverworks LE/HE chipset support"
+	depends on AGP && X86 && !X86_64
 	help
 	  Say Y here to support the Serverworks AGP card.  See 
 	  <http://www.serverworks.com/> for product descriptions and images.
 
-config AGP_AMD_8151
-	tristate "AMD 8151 support"
-	depends on AGP
-	default GART_IOMMU
+config AGP_VIA
+	tristate "VIA chipset support"
+	depends on AGP && X86 && !X86_64
 	help
-	  Say Y here to support the AMD 8151 AGP bridge and the builtin
-	  GART on the AMD Athlon64/Opteron ("Hammer") CPUs.
+	  This option gives you AGP support for the GLX component of
+	  XFree86 4.x on VIA MPV3/Apollo Pro chipsets.
+
+	  You should say Y here if you use XFree86 3.3.6 or 4.x and want to
+	  use GLX or DRI.  If unsure, say N.
 
 config AGP_I460
-	tristate "Intel 460GX support"
+	tristate "Intel 460GX chipset support"
 	depends on AGP && IA64
 	help
 	  This option gives you AGP GART support for the Intel 460GX chipset
 	  for IA64 processors.
 
 config AGP_HP_ZX1
-	tristate "HP ZX1 AGP support"
+	tristate "HP ZX1 chipset AGP support"
 	depends on AGP && IA64
 	help
 	  This option gives you AGP GART support for the HP ZX1 chipset
 	  for IA64 processors.
 
 config AGP_ALPHA_CORE
-	tristate
+	tristate "Alpha AGP support"
 	depends on AGP && (ALPHA_GENERIC || ALPHA_TITAN || ALPHA_MARVEL)
 	default AGP
+
+config AGP_UNINORTH
+	tristate "Apple UniNorth AGP support"
+	depends on AGP && ALL_PPC
+	help
+	  This option gives you AGP support for Apple machines with a
+	  UniNorth bridge.
 
diff -Nru a/drivers/char/agp/Makefile b/drivers/char/agp/Makefile
--- a/drivers/char/agp/Makefile	Wed Apr  9 17:15:09 2003
+++ b/drivers/char/agp/Makefile	Wed May 14 05:55:16 2003
@@ -1,21 +1,16 @@
-#
-# Makefile for the agpgart device driver.  This driver adds a user
-# space ioctl interface to use agp memory.  It also adds a kernel interface
-# that other drivers could use to manipulate agp memory.
+agpgart-y := backend.o frontend.o generic.o isoch.o
 
-agpgart-y := backend.o frontend.o generic.o generic-3.0.o
-agpgart-objs := $(agpgart-y)
-obj-$(CONFIG_AGP) += agpgart.o
-
-obj-$(CONFIG_AGP_INTEL)		+= intel-agp.o
-obj-$(CONFIG_AGP_VIA)		+= via-agp.o
-obj-$(CONFIG_AGP_AMD)		+= amd-k7-agp.o
-obj-$(CONFIG_AGP_SIS)		+= sis-agp.o
+obj-$(CONFIG_AGP)		+= agpgart.o
 obj-$(CONFIG_AGP_ALI)		+= ali-agp.o
-obj-$(CONFIG_AGP_SWORKS)	+= sworks-agp.o
-obj-$(CONFIG_AGP_I460)		+= i460-agp.o
-obj-$(CONFIG_AGP_HP_ZX1)	+= hp-agp.o
+obj-$(CONFIG_AGP_AMD)		+= amd-k7-agp.o
 obj-$(CONFIG_AGP_AMD_8151)	+= amd-k8-agp.o
 obj-$(CONFIG_AGP_ALPHA_CORE)	+= alpha-agp.o
-
+obj-$(CONFIG_AGP_HP_ZX1)	+= hp-agp.o
+obj-$(CONFIG_AGP_I460)		+= i460-agp.o
+obj-$(CONFIG_AGP_INTEL)		+= intel-agp.o
+obj-$(CONFIG_AGP_NVIDIA)	+= nvidia-agp.o
+obj-$(CONFIG_AGP_SIS)		+= sis-agp.o
+obj-$(CONFIG_AGP_SWORKS)	+= sworks-agp.o
+obj-$(CONFIG_AGP_UNINORTH)	+= uninorth-agp.o
+obj-$(CONFIG_AGP_VIA)		+= via-agp.o
 
diff -Nru a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
--- a/drivers/char/agp/agp.h	Wed Apr  9 15:56:26 2003
+++ b/drivers/char/agp/agp.h	Mon May 19 16:15:37 2003
@@ -30,27 +30,16 @@
 
 #include <asm/agp.h>	/* for flush_agp_cache() */
 
-extern struct agp_bridge_data *agp_bridge;
-
 #define PFX "agpgart: "
 
-#ifdef CONFIG_SMP
-static void ipi_handler(void *null)
-{
-	flush_agp_cache();
-}
-
-static void __attribute__((unused)) global_cache_flush(void)
-{
-	if (on_each_cpu(ipi_handler, NULL, 1, 1) != 0)
-		panic(PFX "timed out waiting for the other CPUs!\n");
-}
+//#define AGP_DEBUG 1
+#ifdef AGP_DEBUG
+#define DBG(x,y...) printk (KERN_DEBUG PFX "%s: " x "\n", __FUNCTION__ , ## y)
 #else
-static void global_cache_flush(void)
-{
-	flush_agp_cache();
-}
-#endif	/* !CONFIG_SMP */
+#define DBG(x,y...) do { } while (0)
+#endif
+
+extern struct agp_bridge_data *agp_bridge;
 
 enum aper_size_type {
 	U8_APER_SIZE,
@@ -101,14 +90,39 @@
 	int page_order;
 };
 
+struct agp_bridge_driver {
+	struct module *owner;
+	void *aperture_sizes;
+	int num_aperture_sizes;
+	enum aper_size_type size_type;
+	int cant_use_aperture;
+	int needs_scratch_page;
+	struct gatt_mask *masks;
+	int (*fetch_size)(void);
+	int (*configure)(void);
+	void (*agp_enable)(u32);
+	void (*cleanup)(void);
+	void (*tlb_flush)(agp_memory *);
+	unsigned long (*mask_memory)(unsigned long, int);
+	void (*cache_flush)(void);
+	int (*create_gatt_table)(void);
+	int (*free_gatt_table)(void);
+	int (*insert_memory)(agp_memory *, off_t, int);
+	int (*remove_memory)(agp_memory *, off_t, int);
+	agp_memory *(*alloc_by_type) (size_t, int);
+	void (*free_by_type)(agp_memory *);
+	void *(*agp_alloc_page)(void);
+	void (*agp_destroy_page)(void *);
+};
+
 struct agp_bridge_data {
 	struct agp_version *version;
-	void *aperture_sizes;
+	struct agp_bridge_driver *driver;
+	struct vm_operations_struct *vm_ops;
 	void *previous_size;
 	void *current_size;
 	void *dev_private_data;
 	struct pci_dev *dev;
-	struct gatt_mask *masks;
 	u32 *gatt_table;
 	u32 *gatt_table_real;
 	unsigned long scratch_page;
@@ -117,38 +131,14 @@
 	unsigned long gatt_bus_addr;
 	u32 mode;
 	enum chipset_type type;
-	enum aper_size_type size_type;
 	unsigned long *key_list;
 	atomic_t current_memory_agp;
 	atomic_t agp_in_use;
 	int max_memory_agp;	/* in number of pages */
-	int needs_scratch_page;
 	int aperture_size_idx;
-	int num_aperture_sizes;
 	int capndx;
-	int cant_use_aperture;
-	struct vm_operations_struct *vm_ops;
-
-	/* Links to driver specific functions */
-
-	int (*fetch_size) (void);
-	int (*configure) (void);
-	void (*agp_enable) (u32);
-	void (*cleanup) (void);
-	void (*tlb_flush) (agp_memory *);
-	unsigned long (*mask_memory) (unsigned long, int);
-	void (*cache_flush) (void);
-	int (*create_gatt_table) (void);
-	int (*free_gatt_table) (void);
-	int (*insert_memory) (agp_memory *, off_t, int);
-	int (*remove_memory) (agp_memory *, off_t, int);
-	agp_memory *(*alloc_by_type) (size_t, int);
-	void (*free_by_type) (agp_memory *);
-	void *(*agp_alloc_page) (void);
-	void (*agp_destroy_page) (void *);
-	int (*suspend)(void);
-	void (*resume)(void);
-	
+	char major_version;
+	char minor_version;
 };
 
 #define OUTREG64(mmap, addr, val)	__raw_writeq((val), (mmap)+(addr))
@@ -165,20 +155,17 @@
 #define MB(x)	(KB (KB (x)))
 #define GB(x)	(MB (KB (x)))
 
-#define CACHE_FLUSH	agp_bridge->cache_flush
 #define A_SIZE_8(x)	((struct aper_size_info_8 *) x)
 #define A_SIZE_16(x)	((struct aper_size_info_16 *) x)
 #define A_SIZE_32(x)	((struct aper_size_info_32 *) x)
 #define A_SIZE_LVL2(x)	((struct aper_size_info_lvl2 *) x)
 #define A_SIZE_FIX(x)	((struct aper_size_info_fixed *) x)
-#define A_IDX8()	(A_SIZE_8(agp_bridge->aperture_sizes) + i)
-#define A_IDX16()	(A_SIZE_16(agp_bridge->aperture_sizes) + i)
-#define A_IDX32()	(A_SIZE_32(agp_bridge->aperture_sizes) + i)
-#define A_IDXLVL2()	(A_SIZE_LVL2(agp_bridge->aperture_sizes) + i)
-#define A_IDXFIX()	(A_SIZE_FIX(agp_bridge->aperture_sizes) + i)
+#define A_IDX8(bridge)	(A_SIZE_8((bridge)->driver->aperture_sizes) + i)
+#define A_IDX16(bridge)	(A_SIZE_16((bridge)->driver->aperture_sizes) + i)
+#define A_IDX32(bridge)	(A_SIZE_32((bridge)->driver->aperture_sizes) + i)
 #define MAXKEY		(4096 * 32)
 
-#define PGE_EMPTY(p)	(!(p) || (p) == (unsigned long) agp_bridge->scratch_page)
+#define PGE_EMPTY(b, p)	(!(p) || (p) == (unsigned long) (b)->scratch_page)
 
 /* intel register */
 #define INTEL_APBASE	0x10
@@ -374,11 +361,15 @@
 	int (*chipset_setup) (struct pci_dev *pdev);	/* used to override generic */
 };
 
-struct agp_driver {
-	struct module *owner;
-	struct pci_dev *dev;
-};
-
+/* Driver registration */
+struct agp_bridge_data *agp_alloc_bridge(void);
+void agp_put_bridge(struct agp_bridge_data *bridge);
+int agp_add_bridge(struct agp_bridge_data *bridge);
+void agp_remove_bridge(struct agp_bridge_data *bridge);
+
+/* Frontend routines. */
+int agp_frontend_initialize(void);
+void agp_frontend_cleanup(void);
 
 /* Generic routines. */
 void agp_generic_enable(u32 mode);
@@ -391,14 +382,42 @@
 void agp_generic_free_by_type(agp_memory * curr);
 void *agp_generic_alloc_page(void);
 void agp_generic_destroy_page(void *addr);
-int agp_generic_suspend(void);
-void agp_generic_resume(void);
 void agp_free_key(int key);
 int agp_num_entries(void);
-int agp_register_driver (struct agp_driver *drv);
-int agp_unregister_driver(struct agp_driver *drv);
 u32 agp_collect_device_status(u32 mode, u32 command);
 void agp_device_command(u32 command, int agp_v3);
-int agp_3_0_node_enable(u32 mode, u32 minor);
+int agp_3_5_enable(struct agp_bridge_data *bridge);
+void global_cache_flush(void);
+void get_agp_version(struct agp_bridge_data *bridge);
+unsigned long agp_generic_mask_memory(unsigned long addr, int type);
+
+/* Standard agp registers */
+#define AGPSTAT			0x4
+#define AGPCMD			0x8
+#define AGPNISTAT		0xc
+#define AGPNEPG			0x16
+#define AGPNICMD		0x20
+
+#define AGP_MAJOR_VERSION_SHIFT	(20)
+#define AGP_MINOR_VERSION_SHIFT	(16)
+
+#define AGPSTAT_RQ_DEPTH	(0xff000000)
+
+#define AGPSTAT_CAL_MASK	(1<<12|1<<11|1<<10)
+#define AGPSTAT_ARQSZ		(1<<15|1<<14|1<<13)
+#define AGPSTAT_ARQSZ_SHIFT	13
+
+#define AGPSTAT_SBA		(1<<9)
+#define AGPSTAT_AGP_ENABLE	(1<<8)
+#define AGPSTAT_FW		(1<<4)
+#define AGPSTAT_MODE_3_0	(1<<3)
+
+#define AGPSTAT2_1X		(1<<0)
+#define AGPSTAT2_2X		(1<<1)
+#define AGPSTAT2_4X		(1<<2)
+
+#define AGPSTAT3_RSVD		(1<<2)
+#define AGPSTAT3_8X		(1<<1)
+#define AGPSTAT3_4X		(1)
 
 #endif				/* _AGP_BACKEND_PRIV_H */
diff -Nru a/drivers/char/agp/ali-agp.c b/drivers/char/agp/ali-agp.c
--- a/drivers/char/agp/ali-agp.c	Mon Mar 24 12:21:12 2003
+++ b/drivers/char/agp/ali-agp.c	Thu May 15 06:50:47 2003
@@ -19,9 +19,9 @@
 
 	pci_read_config_dword(agp_bridge->dev, ALI_ATTBASE, &temp);
 	temp &= ~(0xfffffff0);
-	values = A_SIZE_32(agp_bridge->aperture_sizes);
+	values = A_SIZE_32(agp_bridge->driver->aperture_sizes);
 
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		if (temp == values[i].size_value) {
 			agp_bridge->previous_size =
 			    agp_bridge->current_size = (void *) (values + i);
@@ -114,51 +114,49 @@
 	return 0;
 }
 
-static unsigned long ali_mask_memory(unsigned long addr, int type)
-{
-	/* Memory type is ignored */
-
-	return addr | agp_bridge->masks[0].mask;
-}
 
-static void ali_cache_flush(void)
+static void m1541_cache_flush(void)
 {
-	global_cache_flush();
+	int i, page_count;
+	u32 temp;
 
-	if (agp_bridge->type == ALI_M1541) {
-		int i, page_count;
-		u32 temp;
+	global_cache_flush();
 
-		page_count = 1 << A_SIZE_32(agp_bridge->current_size)->page_order;
-		for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) {
-			pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
-			pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
-					(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-					  (agp_bridge->gatt_bus_addr + i)) |
-					    ALI_CACHE_FLUSH_EN));
-		}
+	page_count = 1 << A_SIZE_32(agp_bridge->current_size)->page_order;
+	for (i = 0; i < PAGE_SIZE * page_count; i += PAGE_SIZE) {
+		pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
+				&temp);
+		pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
+				(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
+				  (agp_bridge->gatt_bus_addr + i)) |
+				 ALI_CACHE_FLUSH_EN));
 	}
 }
 
-static void *ali_alloc_page(void)
+static void *m1541_alloc_page(void)
 {
-	void *adr = agp_generic_alloc_page();
+	void *addr = agp_generic_alloc_page();
 	u32 temp;
 
-	if (adr == 0)
-		return 0;
+	if (!addr)
+		return NULL;
+	
+	pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
+	pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
+			(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
+			  virt_to_phys(addr)) | ALI_CACHE_FLUSH_EN ));
+	return addr;
+}
 
-	if (agp_bridge->type == ALI_M1541) {
-		pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
-		pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
-				(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-				  virt_to_phys(adr)) |
-				    ALI_CACHE_FLUSH_EN ));
+static void ali_destroy_page(void * addr)
+{
+	if (addr) {
+		global_cache_flush();	/* is this really needed?  --hch */
+		agp_generic_destroy_page(addr);
 	}
-	return adr;
 }
 
-static void ali_destroy_page(void * addr)
+static void m1541_destroy_page(void * addr)
 {
 	u32 temp;
 
@@ -167,22 +165,15 @@
 
 	global_cache_flush();
 
-	if (agp_bridge->type == ALI_M1541) {
-		pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
-		pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
-				(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
-				  virt_to_phys(addr)) |
-				    ALI_CACHE_FLUSH_EN));
-	}
-
+	pci_read_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL, &temp);
+	pci_write_config_dword(agp_bridge->dev, ALI_CACHE_FLUSH_CTRL,
+			(((temp & ALI_CACHE_FLUSH_ADDR_MASK) |
+			  virt_to_phys(addr)) | ALI_CACHE_FLUSH_EN));
 	agp_generic_destroy_page(addr);
 }
 
+
 /* Setup function */
-static struct gatt_mask ali_generic_masks[] =
-{
-	{.mask = 0x00000000, .type = 0}
-};
 
 static struct aper_size_info_32 ali_generic_sizes[7] =
 {
@@ -195,170 +186,181 @@
 	{4, 1024, 0, 3}
 };
 
-static int __init ali_generic_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = ali_generic_masks;
-	agp_bridge->aperture_sizes = (void *) ali_generic_sizes;
-	agp_bridge->size_type = U32_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = ali_configure;
-	agp_bridge->fetch_size = ali_fetch_size;
-	agp_bridge->cleanup = ali_cleanup;
-	agp_bridge->tlb_flush = ali_tlbflush;
-	agp_bridge->mask_memory = ali_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = ali_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = ali_alloc_page;
-	agp_bridge->agp_destroy_page = ali_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
+struct agp_bridge_driver ali_generic_bridge = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= ali_generic_sizes,
+	.size_type		= U32_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= ali_configure,
+	.fetch_size		= ali_fetch_size,
+	.cleanup		= ali_cleanup,
+	.tlb_flush		= ali_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= ali_destroy_page,
+};
+
+struct agp_bridge_driver ali_m1541_bridge = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= ali_generic_sizes,
+	.size_type		= U32_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= ali_configure,
+	.fetch_size		= ali_fetch_size,
+	.cleanup		= ali_cleanup,
+	.tlb_flush		= ali_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= m1541_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= m1541_alloc_page,
+	.agp_destroy_page	= m1541_destroy_page,
+};
+
 
 struct agp_device_ids ali_agp_device_ids[] __initdata =
 {
 	{
 		.device_id	= PCI_DEVICE_ID_AL_M1541,
-		.chipset	= ALI_M1541,
 		.chipset_name	= "M1541",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AL_M1621,
-		.chipset	= ALI_M1621,
 		.chipset_name	= "M1621",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AL_M1631,
-		.chipset	= ALI_M1631,
 		.chipset_name	= "M1631",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AL_M1632,
-		.chipset	= ALI_M1632,
 		.chipset_name	= "M1632",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AL_M1641,
-		.chipset	= ALI_M1641,
 		.chipset_name	= "M1641",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AL_M1644,
-		.chipset	= ALI_M1644,
 		.chipset_name	= "M1644",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AL_M1647,
-		.chipset	= ALI_M1647,
 		.chipset_name	= "M1647",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AL_M1651,
-		.chipset	= ALI_M1651,
 		.chipset_name	= "M1651",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AL_M1671,
-		.chipset	= ALI_M1671,
 		.chipset_name	= "M1671",
 	},
 	{ }, /* dummy final entry, always present */
 };
 
-/* scan table above for supported devices */
-static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
+static int __init agp_ali_probe(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
 {
-	int j=0;
-	struct agp_device_ids *devs;
-	
-	devs = ali_agp_device_ids;
+	struct agp_device_ids *devs = ali_agp_device_ids;
+	struct agp_bridge_data *bridge;
+	u8 hidden_1621_id, cap_ptr;
+	int j;
 
-	while (devs[j].chipset_name != NULL) {
-		if (pdev->device == devs[j].device_id) {
-			if (pdev->device == PCI_DEVICE_ID_AL_M1621) {
-				u8 hidden_1621_id;
-
-				pci_read_config_byte(pdev, 0xFB, &hidden_1621_id);
-				switch (hidden_1621_id) {
-				case 0x31:
-					devs[j].chipset_name="M1631";
-					break;
-				case 0x32:
-					devs[j].chipset_name="M1632";
-					break;
-				case 0x41:
-					devs[j].chipset_name="M1641";
-					break;
-				case 0x43:
-					break;
-				case 0x47:
-					devs[j].chipset_name="M1647";
-					break;
-				case 0x51:
-					devs[j].chipset_name="M1651";
-					break;
-				default:
-					break;
-				}
-			}
-
-			printk (KERN_INFO PFX "Detected ALi %s chipset\n",
-				devs[j].chipset_name);
-			agp_bridge->type = devs[j].chipset;
-
-			if (devs[j].chipset_setup != NULL)
-				return devs[j].chipset_setup(pdev);
-			else
-				return ali_generic_setup(pdev);
-		}
-		j++;
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (!cap_ptr)
+		return -ENODEV;
+
+	/* probe for known chipsets */
+	for (j = 0; devs[j].chipset_name; j++) {
+		if (pdev->device == devs[j].device_id)
+			goto found;
 	}
 
-	/* try init anyway, if user requests it */
-	if (agp_try_unsupported) {
-		printk(KERN_WARNING PFX "Trying generic ALi routines"
-		       " for device id: %04x\n", pdev->device);
-		agp_bridge->type = ALI_GENERIC;
-		return ali_generic_setup(pdev);
+	if (!agp_try_unsupported) {
+		printk(KERN_ERR PFX
+		     "Unsupported ALi chipset (device id: %04x),"
+		     " you might want to try agp_try_unsupported=1.\n",
+		     pdev->device);
+		return -ENODEV;
 	}
 
-	printk(KERN_ERR PFX "Unsupported ALi chipset (device id: %04x),"
-		" you might want to try agp_try_unsupported=1.\n", pdev->device);
-	return -ENODEV;
-}
+	printk(KERN_WARNING PFX "Trying generic ALi routines"
+	       " for device id: %04x\n", pdev->device);
 
-static struct agp_driver ali_agp_driver = {
-	.owner = THIS_MODULE,
-};
+found:
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
+
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_AL_M1541:
+		bridge->driver = &ali_m1541_bridge;
+		break;
+	case PCI_DEVICE_ID_AL_M1621:
+		pci_read_config_byte(pdev, 0xFB, &hidden_1621_id);
+		switch (hidden_1621_id) {
+		case 0x31:
+			devs[j].chipset_name = "M1631";
+			break;
+		case 0x32:
+			devs[j].chipset_name = "M1632";
+			break;
+		case 0x41:
+			devs[j].chipset_name = "M1641";
+			break;
+		case 0x43:
+			break;
+		case 0x47:
+			devs[j].chipset_name = "M1647";
+			break;
+		case 0x51:
+			devs[j].chipset_name = "M1651";
+			break;
+		default:
+			break;
+		}
+		/*FALLTHROUGH*/
+	default:
+		bridge->driver = &ali_generic_bridge;
+	}
 
-static int __init agp_ali_probe (struct pci_dev *dev, const struct pci_device_id *ent)
-{
-	u8 cap_ptr = 0;
+	printk(KERN_INFO PFX "Detected ALi %s chipset\n",
+			devs[j].chipset_name);
 
-	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
-	if (cap_ptr == 0)
-		return -ENODEV;
+	/* Fill in the mode register */
+	pci_read_config_dword(pdev,
+			bridge->capndx+PCI_AGP_STATUS,
+			&bridge->mode);
 
-	/* probe for known chipsets */
-	if (agp_lookup_host_bridge(dev) != -ENODEV) {
-		agp_bridge->dev = dev;
-		agp_bridge->capndx = cap_ptr;
-		/* Fill in the mode register */
-		pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode);
-		ali_agp_driver.dev = dev;
-		agp_register_driver(&ali_agp_driver);
-		return 0;
-	}
-	return -ENODEV;	
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+}
+
+static void __devexit agp_ali_remove(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
 }
 
 static struct pci_device_id agp_ali_pci_table[] __initdata = {
@@ -375,26 +377,20 @@
 
 MODULE_DEVICE_TABLE(pci, agp_ali_pci_table);
 
-static struct __initdata pci_driver agp_ali_pci_driver = {
+static struct pci_driver agp_ali_pci_driver = {
 	.name		= "agpgart-ali",
 	.id_table	= agp_ali_pci_table,
 	.probe		= agp_ali_probe,
+	.remove		= agp_ali_remove,
 };
 
 static int __init agp_ali_init(void)
 {
-	int ret_val;
-
-	ret_val = pci_module_init(&agp_ali_pci_driver);
-	if (ret_val)
-		agp_bridge->type = NOT_SUPPORTED;
-
-	return ret_val;
+	return pci_module_init(&agp_ali_pci_driver);
 }
 
 static void __exit agp_ali_cleanup(void)
 {
-	agp_unregister_driver(&ali_agp_driver);
 	pci_unregister_driver(&agp_ali_pci_driver);
 }
 
diff -Nru a/drivers/char/agp/alpha-agp.c b/drivers/char/agp/alpha-agp.c
--- a/drivers/char/agp/alpha-agp.c	Fri Feb 21 10:13:43 2003
+++ b/drivers/char/agp/alpha-agp.c	Wed May 14 18:05:00 2003
@@ -38,10 +38,6 @@
 	{ 0, 0, 0 }, /* filled in by alpha_core_agp_setup */
 };
 
-static struct gatt_mask alpha_core_agp_masks[] = {
-	{ .mask = 0, .type = 0 },
-};
-
 struct vm_operations_struct alpha_core_agp_vm_ops = {
 	.nopage = alpha_core_agp_vm_nopage,
 };
@@ -78,12 +74,6 @@
 	alpha_mv.mv_pci_tbi(agp->hose, 0, -1);
 }
 
-static unsigned long alpha_core_agp_mask_memory(unsigned long addr, int type)
-{
-	/* Memory type is ignored */
-	return addr | agp_bridge->masks[0].mask;
-}
-
 static void alpha_core_agp_enable(u32 mode)
 {
 	alpha_agp_info *agp = agp_bridge->dev_private_data;
@@ -109,7 +99,7 @@
 
 	status = agp->ops->bind(agp, pg_start, mem);
 	mb();
-	agp_bridge->tlb_flush(mem);
+	alpha_core_agp_tlbflush(mem);
 
 	return status;
 }
@@ -121,29 +111,57 @@
 	int status;
 
 	status = agp->ops->unbind(agp, pg_start, mem);
-	agp_bridge->tlb_flush(mem);
+	alpha_core_agp_tlbflush(mem);
 	return status;
 }
 
-
-static struct agp_driver alpha_core_agp_driver = {
-	.owner = THIS_MODULE,
+struct agp_bridge_driver alpha_core_agp_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= aper_size,
+	.current_size		= aper_size,	/* only one entry */
+	.size_type		= FIXED_APER_SIZE,
+	.num_aperture_sizes	= 1,
+	.configure		= alpha_core_agp_configure,
+	.fetch_size		= alpha_core_agp_fetch_size,
+	.cleanup		= alpha_core_agp_cleanup,
+	.tlb_flush		= alpha_core_agp_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.agp_enable		= alpha_core_agp_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= alpha_core_agp_nop,
+	.free_gatt_table	= alpha_core_agp_nop,
+	.insert_memory		= alpha_core_agp_insert_memory,
+	.remove_memory		= alpha_core_agp_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+	.mode			= agp->capability.lw,
+	.cant_use_aperture	= 1,
+	.vm_ops			= &alpha_core_agp_vm_ops,
 };
 
+struct agp_bridge_data *alpha_bridge;
+
 int __init
 alpha_core_agp_setup(void)
 {
 	alpha_agp_info *agp = alpha_mv.agp_info();
+	struct pci_dev *pdev;	/* faked */
 	struct aper_size_info_fixed *aper_size;
 
-	if (!agp) return -ENODEV;
-	if (agp->ops->setup(agp)) return -ENODEV;
+	if (!agp)
+		return -ENODEV;
+	if (agp->ops->setup(agp))
+		return -ENODEV;
 
 	/*
 	 * Build the aperture size descriptor
 	 */
 	aper_size = alpha_core_agp_sizes;
-	if (!aper_size) return -ENOMEM;
+	if (!aper_size)
+		return -ENOMEM;
 	aper_size->size = agp->aperture.size / (1024 * 1024);
 	aper_size->num_entries = agp->aperture.size / PAGE_SIZE;
 	aper_size->page_order = ffs(aper_size->num_entries / 1024) - 1;
@@ -151,63 +169,40 @@
 	/*
 	 * Build a fake pci_dev struct
 	 */
-	if (!(agp_bridge->dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL))) {
+	pdev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL);
+	if (!pdev)
 		return -ENOMEM;
-	}
-	agp_bridge->dev->vendor = 0xffff;
-	agp_bridge->dev->device = 0xffff;
-	agp_bridge->dev->sysdata = agp->hose;
-
-	/*
-	 * Fill in the rest of the agp_bridge struct
-	 */
-	agp_bridge->masks = alpha_core_agp_masks;
-	agp_bridge->aperture_sizes = aper_size;
-	agp_bridge->current_size = aper_size;	/* only one entry */
-	agp_bridge->size_type = FIXED_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 1;
-	agp_bridge->dev_private_data = agp;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = alpha_core_agp_configure;
-	agp_bridge->fetch_size = alpha_core_agp_fetch_size;
-	agp_bridge->cleanup = alpha_core_agp_cleanup;
-	agp_bridge->tlb_flush = alpha_core_agp_tlbflush;
-	agp_bridge->mask_memory = alpha_core_agp_mask_memory;
-	agp_bridge->agp_enable = alpha_core_agp_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = alpha_core_agp_nop;
-	agp_bridge->free_gatt_table = alpha_core_agp_nop;
-	agp_bridge->insert_memory = alpha_core_agp_insert_memory;
-	agp_bridge->remove_memory = alpha_core_agp_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->mode = agp->capability.lw;
-	agp_bridge->cant_use_aperture = 1;
-	agp_bridge->vm_ops =  &alpha_core_agp_vm_ops;
+	pdev->vendor = 0xffff;
+	pdev->device = 0xffff;
+	pdev->sysdata = agp->hose;
+
+	alpha_bridge = agp_alloc_bridge();
+	if (!alpha_bridge)
+		goto fail;
+
+	alpha_bridge->driver = &alpha_core_agp_driver;
+	alpha_bridge->dev_private_data = agp;
+	alpha_bridge->dev = pdev;
 
-	alpha_core_agp_driver.dev = agp_bridge->dev;
-	agp_register_driver(&alpha_core_agp_driver);
 	printk(KERN_INFO "Detected AGP on hose %d\n", agp->hose->index);
-	return 0;
+	return agp_add_bridge(alpha_bridge);
+
+ fail:
+	kfree(pdev);
+	return -ENOMEM;
 }
 
 static int __init agp_alpha_core_init(void)
 {
-	int ret_val = -ENODEV;
-	if (alpha_mv.agp_info) {
-		agp_bridge->type = ALPHA_CORE_AGP;
-		ret_val = alpha_core_agp_setup();
-	}
-
-	return ret_val;
+	if (alpha_mv.agp_info)
+		return alpha_core_agp_setup();
+	return -ENODEV;
 }
 
 static void __exit agp_alpha_core_cleanup(void)
 {
-	agp_unregister_driver(&alpha_core_agp_driver);
-	/* no pci driver for core */
+	agp_remove_bridge(alpha_bridge);
+	agp_put_bridge(alpha_bridge);
 }
 
 module_init(agp_alpha_core_init);
diff -Nru a/drivers/char/agp/amd-k7-agp.c b/drivers/char/agp/amd-k7-agp.c
--- a/drivers/char/agp/amd-k7-agp.c	Mon Mar 24 12:21:12 2003
+++ b/drivers/char/agp/amd-k7-agp.c	Thu May 15 06:50:47 2003
@@ -29,11 +29,11 @@
 	int i;
 
 	page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
-	if (page_map->real == NULL) {
+	if (page_map->real == NULL)
 		return -ENOMEM;
-	}
+
 	SetPageReserved(virt_to_page(page_map->real));
-	CACHE_FLUSH();
+	global_cache_flush();
 	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
 					    PAGE_SIZE);
 	if (page_map->remapped == NULL) {
@@ -42,11 +42,10 @@
 		page_map->real = NULL;
 		return -ENOMEM;
 	}
-	CACHE_FLUSH();
+	global_cache_flush();
 
-	for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
+	for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++)
 		page_map->remapped[i] = agp_bridge->scratch_page;
-	}
 
 	return 0;
 }
@@ -65,16 +64,16 @@
 	struct amd_page_map *entry;
 
 	tables = amd_irongate_private.gatt_pages;
-	for(i = 0; i < amd_irongate_private.num_tables; i++) {
+	for (i = 0; i < amd_irongate_private.num_tables; i++) {
 		entry = tables[i];
 		if (entry != NULL) {
-			if (entry->real != NULL) {
+			if (entry->real != NULL)
 				amd_free_page_map(entry);
-			}
 			kfree(entry);
 		}
 	}
 	kfree(tables);
+	amd_irongate_private.gatt_pages = NULL;
 }
 
 static int amd_create_gatt_pages(int nr_tables)
@@ -86,25 +85,27 @@
 
 	tables = kmalloc((nr_tables + 1) * sizeof(struct amd_page_map *), 
 			 GFP_KERNEL);
-	if (tables == NULL) {
+	if (tables == NULL)
 		return -ENOMEM;
-	}
-	memset(tables, 0, sizeof(struct amd_page_map *) * (nr_tables + 1));
+
+	memset (tables, 0, sizeof(struct amd_page_map *) * (nr_tables + 1));
 	for (i = 0; i < nr_tables; i++) {
 		entry = kmalloc(sizeof(struct amd_page_map), GFP_KERNEL);
 		if (entry == NULL) {
 			retval = -ENOMEM;
 			break;
 		}
-		memset(entry, 0, sizeof(struct amd_page_map));
+		memset (entry, 0, sizeof(struct amd_page_map));
 		tables[i] = entry;
 		retval = amd_create_page_map(entry);
-		if (retval != 0) break;
+		if (retval != 0)
+			break;
 	}
 	amd_irongate_private.num_tables = nr_tables;
 	amd_irongate_private.gatt_pages = tables;
 
-	if (retval != 0) amd_free_gatt_pages();
+	if (retval != 0)
+		amd_free_gatt_pages();
 
 	return retval;
 }
@@ -131,9 +132,8 @@
 
 	value = A_SIZE_LVL2(agp_bridge->current_size);
 	retval = amd_create_page_map(&page_dir);
-	if (retval != 0) {
+	if (retval != 0)
 		return retval;
-	}
 
 	retval = amd_create_gatt_pages(value->num_entries / 1024);
 	if (retval != 0) {
@@ -155,7 +155,7 @@
 	agp_bridge->gart_bus_addr = addr;
 
 	/* Calculate the agp offset */
-	for(i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
+	for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
 		page_dir.remapped[GET_PAGE_DIR_OFF(addr)] =
 			virt_to_phys(amd_irongate_private.gatt_pages[i]->real);
 		page_dir.remapped[GET_PAGE_DIR_OFF(addr)] |= 0x00000001;
@@ -184,8 +184,8 @@
 
 	pci_read_config_dword(agp_bridge->dev, AMD_APSIZE, &temp);
 	temp = (temp & 0x0000000e);
-	values = A_SIZE_LVL2(agp_bridge->aperture_sizes);
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes);
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		if (temp == values[i].size_value) {
 			agp_bridge->previous_size =
 			    agp_bridge->current_size = (void *) (values + i);
@@ -265,20 +265,12 @@
  * entries.
  */
 
-static void amd_irongate_tlbflush(agp_memory * temp)
+static void amd_irongate_tlbflush(agp_memory *temp)
 {
 	OUTREG32(amd_irongate_private.registers, AMD_TLBFLUSH, 0x00000001);
 }
 
-static unsigned long amd_irongate_mask_memory(unsigned long addr, int type)
-{
-	/* Only type 0 is supported by the irongate */
-
-	return addr | agp_bridge->masks[0].mask;
-}
-
-static int amd_insert_memory(agp_memory * mem,
-			     off_t pg_start, int type)
+static int amd_insert_memory(agp_memory * mem, off_t pg_start, int type)
 {
 	int i, j, num_entries;
 	unsigned long *cur_gatt;
@@ -286,25 +278,23 @@
 
 	num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
 
-	if (type != 0 || mem->type != 0) {
+	if (type != 0 || mem->type != 0)
 		return -EINVAL;
-	}
-	if ((pg_start + mem->page_count) > num_entries) {
+
+	if ((pg_start + mem->page_count) > num_entries)
 		return -EINVAL;
-	}
 
 	j = pg_start;
 	while (j < (pg_start + mem->page_count)) {
 		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 		cur_gatt = GET_GATT(addr);
-		if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) {
+		if (!PGE_EMPTY(agp_bridge, cur_gatt[GET_GATT_OFF(addr)]))
 			return -EBUSY;
-		}
 		j++;
 	}
 
 	if (mem->is_flushed == FALSE) {
-		CACHE_FLUSH();
+		global_cache_flush();
 		mem->is_flushed = TRUE;
 	}
 
@@ -312,22 +302,21 @@
 		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 		cur_gatt = GET_GATT(addr);
 		cur_gatt[GET_GATT_OFF(addr)] =
-			agp_bridge->mask_memory(mem->memory[i], mem->type);
+			agp_generic_mask_memory(mem->memory[i], mem->type);
 	}
-	agp_bridge->tlb_flush(mem);
+	amd_irongate_tlbflush(mem);
 	return 0;
 }
 
-static int amd_remove_memory(agp_memory * mem, off_t pg_start,
-			     int type)
+static int amd_remove_memory(agp_memory *mem, off_t pg_start, int type)
 {
 	int i;
 	unsigned long *cur_gatt;
 	unsigned long addr;
 
-	if (type != 0 || mem->type != 0) {
+	if (type != 0 || mem->type != 0)
 		return -EINVAL;
-	}
+
 	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
 		addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 		cur_gatt = GET_GATT(addr);
@@ -335,7 +324,7 @@
 			(unsigned long) agp_bridge->scratch_page;
 	}
 
-	agp_bridge->tlb_flush(mem);
+	amd_irongate_tlbflush(mem);
 	return 0;
 }
 
@@ -352,118 +341,105 @@
 
 static struct gatt_mask amd_irongate_masks[] =
 {
-	{.mask = 0x00000001, .type = 0}
+	{.mask = 1, .type = 0}
 };
 
-static int __init amd_irongate_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = amd_irongate_masks;
-	agp_bridge->aperture_sizes = (void *) amd_irongate_sizes;
-	agp_bridge->size_type = LVL2_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = (void *) &amd_irongate_private;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = amd_irongate_configure;
-	agp_bridge->fetch_size = amd_irongate_fetch_size;
-	agp_bridge->cleanup = amd_irongate_cleanup;
-	agp_bridge->tlb_flush = amd_irongate_tlbflush;
-	agp_bridge->mask_memory = amd_irongate_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = amd_create_gatt_table;
-	agp_bridge->free_gatt_table = amd_free_gatt_table;
-	agp_bridge->insert_memory = amd_insert_memory;
-	agp_bridge->remove_memory = amd_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
+struct agp_bridge_driver amd_irongate_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= amd_irongate_sizes,
+	.size_type		= LVL2_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= amd_irongate_configure,
+	.fetch_size		= amd_irongate_fetch_size,
+	.cleanup		= amd_irongate_cleanup,
+	.tlb_flush		= amd_irongate_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= amd_irongate_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= amd_create_gatt_table,
+	.free_gatt_table	= amd_free_gatt_table,
+	.insert_memory		= amd_insert_memory,
+	.remove_memory		= amd_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
 struct agp_device_ids amd_agp_device_ids[] __initdata =
 {
 	{
 		.device_id	= PCI_DEVICE_ID_AMD_FE_GATE_7006,
-		.chipset	= AMD_IRONGATE,
 		.chipset_name	= "Irongate",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AMD_FE_GATE_700E,
-		.chipset	= AMD_761,
 		.chipset_name	= "761",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_AMD_FE_GATE_700C,
-		.chipset	= AMD_762,
 		.chipset_name	= "760MP",
 	},
 	{ }, /* dummy final entry, always present */
 };
 
-
-/* scan table above for supported devices */
-static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
+static int __init agp_amdk7_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
 {
-	int j=0;
-	struct agp_device_ids *devs;
-	
-	devs = amd_agp_device_ids;
+	struct agp_device_ids *devs = amd_agp_device_ids;
+	struct agp_bridge_data *bridge;
+	u8 cap_ptr;
+	int j;
 
-	while (devs[j].chipset_name != NULL) {
-		if (pdev->device == devs[j].device_id) {
-			printk (KERN_INFO PFX "Detected AMD %s chipset\n", devs[j].chipset_name);
-			agp_bridge->type = devs[j].chipset;
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (!cap_ptr)
+		return -ENODEV;
 
-			if (devs[j].chipset_setup != NULL)
-				return devs[j].chipset_setup(pdev);
-			else
-				return amd_irongate_setup(pdev);
+	for (j = 0; devs[j].chipset_name; j++) {
+		if (pdev->device == devs[j].device_id) {
+			printk (KERN_INFO PFX "Detected AMD %s chipset\n",
+					devs[j].chipset_name);
+			goto found;
 		}
-		j++;
 	}
 
-	/* try init anyway, if user requests it */
-	if (agp_try_unsupported) {
-		printk(KERN_WARNING PFX "Trying generic AMD routines"
-		       " for device id: %04x\n", pdev->device);
-		agp_bridge->type = AMD_GENERIC;
-		return amd_irongate_setup(pdev);
+	if (!agp_try_unsupported) {
+		printk(KERN_ERR PFX
+		    "Unsupported AMD chipset (device id: %04x),"
+		    " you might want to try agp_try_unsupported=1.\n",
+		    pdev->device);
+		return -ENODEV;
 	}
 
-	printk(KERN_ERR PFX "Unsupported AMD chipset (device id: %04x),"
-		" you might want to try agp_try_unsupported=1.\n", pdev->device);
-	return -ENODEV;
-}
+	printk(KERN_WARNING PFX "Trying generic AMD routines"
+	       " for device id: %04x\n", pdev->device);
 
+found:
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
 
-static struct agp_driver amd_k7_agp_driver = {
-	.owner = THIS_MODULE,
-};
+	bridge->driver = &amd_irongate_driver;
+	bridge->dev_private_data = &amd_irongate_private,
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
 
-/* Supported Device Scanning routine */
+	/* Fill in the mode register */
+	pci_read_config_dword(pdev,
+			bridge->capndx+PCI_AGP_STATUS,
+			&bridge->mode);
 
-static int __init agp_amdk7_probe (struct pci_dev *dev, const struct pci_device_id *ent)
-{
-	u8 cap_ptr = 0;
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+}
 
-	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
-	if (cap_ptr == 0)
-		return -ENODEV;
+static void __devexit agp_amdk7_remove(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 
-	if (agp_lookup_host_bridge(dev) != -ENODEV) {
-		agp_bridge->dev = dev;
-		agp_bridge->capndx = cap_ptr;
-		/* Fill in the mode register */
-		pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode);
-		amd_k7_agp_driver.dev = dev;
-		agp_register_driver(&amd_k7_agp_driver);
-		return 0;
-	}
-	return -ENODEV;
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
 }
 
 static struct pci_device_id agp_amdk7_pci_table[] __initdata = {
@@ -480,26 +456,20 @@
 
 MODULE_DEVICE_TABLE(pci, agp_amdk7_pci_table);
 
-static struct __initdata pci_driver agp_amdk7_pci_driver = {
+static struct pci_driver agp_amdk7_pci_driver = {
 	.name		= "agpgart-amdk7",
 	.id_table	= agp_amdk7_pci_table,
 	.probe		= agp_amdk7_probe,
+	.remove		= agp_amdk7_remove,
 };
 
 static int __init agp_amdk7_init(void)
 {
-	int ret_val;
-
-	ret_val = pci_module_init(&agp_amdk7_pci_driver);
-	if (ret_val)
-		agp_bridge->type = NOT_SUPPORTED;
-
-	return ret_val;
+	return pci_module_init(&agp_amdk7_pci_driver);
 }
 
 static void __exit agp_amdk7_cleanup(void)
 {
-	agp_unregister_driver(&amd_k7_agp_driver);
 	pci_unregister_driver(&agp_amdk7_pci_driver);
 }
 
@@ -508,4 +478,3 @@
 
 MODULE_PARM(agp_try_unsupported, "1i");
 MODULE_LICENSE("GPL and additional rights");
-
diff -Nru a/drivers/char/agp/amd-k8-agp.c b/drivers/char/agp/amd-k8-agp.c
--- a/drivers/char/agp/amd-k8-agp.c	Thu Apr 10 04:29:50 2003
+++ b/drivers/char/agp/amd-k8-agp.c	Mon May 19 15:17:52 2003
@@ -29,6 +29,21 @@
 static int gart_iterator;
 #define for_each_nb() for(gart_iterator=0;gart_iterator<nr_garts;gart_iterator++)
 
+static void flush_x86_64_tlb(struct pci_dev *dev)
+{
+	u32 tmp;
+
+	pci_read_config_dword (dev, AMD_X86_64_GARTCACHECTL, &tmp);
+	tmp |= 1<<0;
+	pci_write_config_dword (dev, AMD_X86_64_GARTCACHECTL, tmp);
+}
+
+static void amd_x86_64_tlbflush(agp_memory *temp)
+{
+	for_each_nb()
+		flush_x86_64_tlb(hammers[gart_iterator]);
+}
+
 static int x86_64_insert_memory(agp_memory * mem, off_t pg_start, int type)
 {
 	int i, j, num_entries;
@@ -50,18 +65,18 @@
 
 	/* gatt table should be empty. */
 	while (j < (pg_start + mem->page_count)) {
-		if (!PGE_EMPTY(agp_bridge->gatt_table[j]))
+		if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j]))
 			return -EBUSY;
 		j++;
 	}
 
 	if (mem->is_flushed == FALSE) {
-		CACHE_FLUSH();
+		global_cache_flush();
 		mem->is_flushed = TRUE;
 	}
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
-		addr = agp_bridge->mask_memory(mem->memory[i], mem->type);
+		addr = agp_bridge->driver->mask_memory(mem->memory[i], mem->type);
 
 		tmp = addr;
 		BUG_ON(tmp & 0xffffff0000000ffc);
@@ -71,7 +86,7 @@
 
 		agp_bridge->gatt_table[j] = pte;
 	}
-	agp_bridge->tlb_flush(mem);
+	amd_x86_64_tlbflush(mem);
 	return 0;
 }
 
@@ -113,7 +128,7 @@
 	temp = (temp & 0xe);
 	values = A_SIZE_32(x86_64_aperture_sizes);
 
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		if (temp == values[i].size_value) {
 			agp_bridge->previous_size =
 			    agp_bridge->current_size = (void *) (values + i);
@@ -125,25 +140,6 @@
 	return 0;
 }
 
-
-static void flush_x86_64_tlb(struct pci_dev *dev)
-{
-	u32 tmp;
-
-	pci_read_config_dword (dev, AMD_X86_64_GARTCACHECTL, &tmp);
-	tmp |= 1<<0;
-	pci_write_config_dword (dev, AMD_X86_64_GARTCACHECTL, tmp);
-}
-
-
-static void amd_x86_64_tlbflush(agp_memory * temp)
-{
-	for_each_nb() {
-		flush_x86_64_tlb (hammers[gart_iterator]);
-	}
-}
-
-
 /*
  * In a multiprocessor x86-64 system, this function gets
  * called once for each CPU.
@@ -216,141 +212,116 @@
 }
 
 
-static unsigned long amd_8151_mask_memory(unsigned long addr, int type)
-{
-	return addr | agp_bridge->masks[0].mask;
-}
-
-
 static struct gatt_mask amd_8151_masks[] =
 {
-	{.mask = 0x00000001, .type = 0}
+	{ .mask = 1, .type = 0 }
 };
 
+struct agp_bridge_driver amd_8151_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= amd_8151_sizes,
+	.size_type		= U32_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= amd_8151_configure,
+	.fetch_size		= amd_x86_64_fetch_size,
+	.cleanup		= amd_8151_cleanup,
+	.tlb_flush		= amd_x86_64_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= amd_8151_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= x86_64_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
-/*
- * Try to configure an AGP v3 capable setup.
- * If we fail (typically because we don't have an AGP v3
- * card in the system) we fall back to the generic AGP v2
- * routines.
- */
-static void agp_x86_64_agp_enable(u32 mode)
+static int __init agp_amdk8_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
 {
-	struct pci_dev *device = NULL;
-	u32 command, scratch; 
+	struct agp_bridge_data *bridge;
+	struct pci_dev *loop_dev;
+	u8 rev_id;
 	u8 cap_ptr;
-	u8 v3_devs=0;
+	int i = 0;
+	char *revstring="  ";
 
-	/* FIXME: If 'mode' is x1/x2/x4 should we call the AGPv2 routines directly ?
-	 * Messy, as some AGPv3 cards can only do x4 as a minimum.
-	 */
-
-	/* PASS1: Count # of devs capable of AGPv3 mode. */
-	pci_for_each_dev(device) {
-		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
-		if (cap_ptr != 0x00) {
-			pci_read_config_dword(device, cap_ptr, &scratch);
-			scratch &= (1<<20|1<<21|1<<22|1<<23);
-			scratch = scratch>>20;
-			/* AGP v3 capable ? */
-			if (scratch>=3) {
-				v3_devs++;
-				printk (KERN_INFO "AGP: Found AGPv3 capable device at %d:%d:%d\n",
-					device->bus->number, PCI_FUNC(device->devfn), PCI_SLOT(device->devfn));
-			} else {
-				printk (KERN_INFO "AGP: Meh. version %x AGP device found.\n", scratch);
-			}
-		}
-	}
-	/* If not enough, go to AGP v2 setup */
-	if (v3_devs<2) {
-		printk (KERN_INFO "AGP: Only %d devices found, not enough, trying AGPv2\n", v3_devs);
-		return agp_generic_enable(mode);
-	} else {
-		printk (KERN_INFO "AGP: Enough AGPv3 devices found, setting up...\n");
-	}
-
-
-	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &command);
-
-	command = agp_collect_device_status(mode, command);
-	command |= 0x100;
-
-	pci_write_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_COMMAND, command);
-
-	agp_device_command(command, 1);
-}
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (!cap_ptr)
+		return -ENODEV;
 
+	printk(KERN_INFO PFX "Detected Opteron/Athlon64 on-CPU GART\n");
 
-static int __init amd_8151_setup (struct pci_dev *pdev)
-{
-	struct pci_dev *dev;
-	int i=0;
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
+
+	if (pdev->vendor == PCI_VENDOR_ID_AMD &&
+	    pdev->device == PCI_DEVICE_ID_AMD_8151_0) {
+
+		pci_read_config_byte(pdev, PCI_REVISION_ID, &rev_id);
+		switch (rev_id) {
+		case 0x01:	revstring="A0";
+				break;
+		case 0x02:	revstring="A1";
+				break;
+		case 0x11:	revstring="B0";
+				break;
+		case 0x12:	revstring="B1";
+				break;
+		case 0x13:	revstring="B2";
+				break;
+		default:	revstring="??";
+				break;
+		}
+		printk ("Detected AMD 8151 AGP Bridge rev %s", revstring);
+		/*
+		 * Work around errata.
+		 * Chips before B2 stepping incorrectly reporting v3.5
+		 */
+		if (rev_id < 0x13) {
+			bridge->major_version = 3;
+			bridge->minor_version = 0;
+		}
+	}
 
-	agp_bridge->masks = amd_8151_masks;
-	agp_bridge->aperture_sizes = (void *) amd_8151_sizes;
-	agp_bridge->size_type = U32_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = amd_8151_configure;
-	agp_bridge->fetch_size = amd_x86_64_fetch_size;
-	agp_bridge->cleanup = amd_8151_cleanup;
-	agp_bridge->tlb_flush = amd_x86_64_tlbflush;
-	agp_bridge->mask_memory = amd_8151_mask_memory;
-	agp_bridge->agp_enable = agp_x86_64_agp_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = x86_64_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
+	bridge->driver = &amd_8151_driver;
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
 
+	/* Fill in the mode register */
+	pci_read_config_dword(pdev, bridge->capndx+PCI_AGP_STATUS, &bridge->mode);
 
 	/* cache pci_devs of northbridges. */
-	pci_for_each_dev(dev) {
-		if (dev->bus->number==0 && PCI_FUNC(dev->devfn)==3 &&
-			(PCI_SLOT(dev->devfn) >=24) && (PCI_SLOT(dev->devfn) <=31)) {
-
-			hammers[i++] = dev;
+	pci_for_each_dev(loop_dev) {
+		if (loop_dev->bus->number == 0 &&
+		    PCI_FUNC(loop_dev->devfn) == 3 &&
+		    PCI_SLOT(loop_dev->devfn) >=24 &&
+		    PCI_SLOT(loop_dev->devfn) <=31) {
+			hammers[i++] = loop_dev;
 			nr_garts = i;
-			if (i==MAX_HAMMER_GARTS)
-				return 0;
+			if (i == MAX_HAMMER_GARTS)
+				goto out_free;
 		}
 	}
 
-	return 0;
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+out_free:
+	agp_put_bridge(bridge);
+	return -ENOMEM;
 }
 
-static struct agp_driver amd_k8_agp_driver = {
-	.owner = THIS_MODULE,
-};
-
-static int __init agp_amdk8_probe (struct pci_dev *dev, const struct pci_device_id *ent)
+static void __devexit agp_amdk8_remove(struct pci_dev *pdev)
 {
-	u8 cap_ptr = 0;
-
-	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
-	if (cap_ptr == 0)
-		return -ENODEV;
-
-	printk (KERN_INFO PFX "Detected Opteron/Athlon64 on-CPU GART\n");
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 
-	agp_bridge->dev = dev;
-	agp_bridge->capndx = cap_ptr;
-
-	/* Fill in the mode register */
-	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode);
-	amd_8151_setup(dev);
-	amd_k8_agp_driver.dev = dev;
-	agp_register_driver(&amd_k8_agp_driver);
-	return 0;
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
 }
 
 static struct pci_device_id agp_amdk8_pci_table[] __initdata = {
@@ -362,34 +333,34 @@
 	.subvendor	= PCI_ANY_ID,
 	.subdevice	= PCI_ANY_ID,
 	},
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_VIA,
+	.device		= PCI_DEVICE_ID_VIA_K8T400M_0,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
 	{ }
 };
 
 MODULE_DEVICE_TABLE(pci, agp_amdk8_pci_table);
 
-static struct __initdata pci_driver agp_amdk8_pci_driver = {
+static struct pci_driver agp_amdk8_pci_driver = {
 	.name		= "agpgart-amd-k8",
 	.id_table	= agp_amdk8_pci_table,
 	.probe		= agp_amdk8_probe,
+	.remove		= agp_amdk8_remove,
 };
 
 /* Not static due to IOMMU code calling it early. */
 int __init agp_amdk8_init(void)
 {
-	int ret_val;
-
-	ret_val = pci_module_init(&agp_amdk8_pci_driver);
-	if (ret_val)
-		agp_bridge->type = NOT_SUPPORTED;
-
-	agp_bridge->type = AMD_8151;
-
-	return ret_val;
+	return pci_module_init(&agp_amdk8_pci_driver);
 }
 
 static void __exit agp_amdk8_cleanup(void)
 {
-	agp_unregister_driver(&amd_k8_agp_driver);
 	pci_unregister_driver(&agp_amdk8_pci_driver);
 }
 
diff -Nru a/drivers/char/agp/backend.c b/drivers/char/agp/backend.c
--- a/drivers/char/agp/backend.c	Mon Mar 24 12:39:10 2003
+++ b/drivers/char/agp/backend.c	Wed May 14 10:34:05 2003
@@ -43,37 +43,54 @@
  * past 0.99 at all due to some boolean logic error. */
 #define AGPGART_VERSION_MAJOR 0
 #define AGPGART_VERSION_MINOR 100
+static struct agp_version agp_current_version =
+{
+	.major = AGPGART_VERSION_MAJOR,
+	.minor = AGPGART_VERSION_MINOR,
+};
+
+static int agp_count=0;
 
 struct agp_bridge_data agp_bridge_dummy = { .type = NOT_SUPPORTED };
 struct agp_bridge_data *agp_bridge = &agp_bridge_dummy;
+EXPORT_SYMBOL(agp_bridge);
+
 
+/**
+ *	agp_backend_acquire  -  attempt to acquire the agp backend.
+ *
+ *	returns -EBUSY if agp is in use,
+ *	returns 0 if the caller owns the agp backend
+ */
 int agp_backend_acquire(void)
 {
 	if (agp_bridge->type == NOT_SUPPORTED)
 		return -EINVAL;
-
-	if (atomic_read(&agp_bridge->agp_in_use) != 0)
+	if (atomic_read(&agp_bridge->agp_in_use))
 		return -EBUSY;
-
 	atomic_inc(&agp_bridge->agp_in_use);
 	return 0;
 }
+EXPORT_SYMBOL(agp_backend_acquire);
+
 
+/**
+ *	agp_backend_release  -  release the lock on the agp backend.
+ *
+ *	The caller must insure that the graphics aperture translation table
+ *	is read for use by another entity.
+ *
+ *	(Ensure that all memory it bound is unbound.)
+ */
 void agp_backend_release(void)
 {
-	if (agp_bridge->type == NOT_SUPPORTED)
-		return;
-
-	atomic_dec(&agp_bridge->agp_in_use);
+	if (agp_bridge->type != NOT_SUPPORTED)
+		atomic_dec(&agp_bridge->agp_in_use);
 }
+EXPORT_SYMBOL(agp_backend_release);
 
-struct agp_max_table {
-	int mem;
-	int agp;
-};
 
-static struct agp_max_table maxes_table[9] =
-{
+struct { int mem, agp; } maxes_table[] = {
 	{0, 0},
 	{32, 4},
 	{64, 28},
@@ -85,7 +102,7 @@
 	{4096, 3932}
 };
 
-static int agp_find_max (void)
+static int agp_find_max(void)
 {
 	long memory, index, result;
 
@@ -105,48 +122,43 @@
 	return result;
 }
 
-static struct agp_version agp_current_version =
-{
-	.major = AGPGART_VERSION_MAJOR,
-	.minor = AGPGART_VERSION_MINOR,
-};
 
-static int agp_backend_initialize(struct pci_dev *dev)
+static int agp_backend_initialize(struct agp_bridge_data *bridge)
 {
 	int size_value, rc, got_gatt=0, got_keylist=0;
 
-	agp_bridge->max_memory_agp = agp_find_max();
-	agp_bridge->version = &agp_current_version;
+	bridge->max_memory_agp = agp_find_max();
+	bridge->version = &agp_current_version;
 
-	if (agp_bridge->needs_scratch_page == TRUE) {
-		void *addr;
-		addr = agp_bridge->agp_alloc_page();
+	if (bridge->driver->needs_scratch_page) {
+		void *addr = bridge->driver->agp_alloc_page();
 
-		if (addr == NULL) {
+		if (!addr) {
 			printk(KERN_ERR PFX "unable to get memory for scratch page.\n");
 			return -ENOMEM;
 		}
-		agp_bridge->scratch_page_real = virt_to_phys(addr);
-		agp_bridge->scratch_page =
-			agp_bridge->mask_memory(agp_bridge->scratch_page_real, 0);
-	}
 
-	size_value = agp_bridge->fetch_size();
+		bridge->scratch_page_real = virt_to_phys(addr);
+		bridge->scratch_page =
+		    bridge->driver->mask_memory(bridge->scratch_page_real, 0);
+	}
 
+	size_value = bridge->driver->fetch_size();
 	if (size_value == 0) {
 		printk(KERN_ERR PFX "unable to determine aperture size.\n");
 		rc = -EINVAL;
 		goto err_out;
 	}
-	if (agp_bridge->create_gatt_table()) {
-		printk(KERN_ERR PFX "unable to get memory for graphics translation table.\n");
+	if (bridge->driver->create_gatt_table()) {
+		printk(KERN_ERR PFX
+		    "unable to get memory for graphics translation table.\n");
 		rc = -ENOMEM;
 		goto err_out;
 	}
 	got_gatt = 1;
 	
-	agp_bridge->key_list = vmalloc(PAGE_SIZE * 4);
-	if (agp_bridge->key_list == NULL) {
+	bridge->key_list = vmalloc(PAGE_SIZE * 4);
+	if (bridge->key_list == NULL) {
 		printk(KERN_ERR PFX "error allocating memory for key lists.\n");
 		rc = -ENOMEM;
 		goto err_out;
@@ -154,61 +166,49 @@
 	got_keylist = 1;
 	
 	/* FIXME vmalloc'd memory not guaranteed contiguous */
-	memset(agp_bridge->key_list, 0, PAGE_SIZE * 4);
+	memset(bridge->key_list, 0, PAGE_SIZE * 4);
 
-	if (agp_bridge->configure()) {
+	if (bridge->driver->configure()) {
 		printk(KERN_ERR PFX "error configuring host chipset.\n");
 		rc = -EINVAL;
 		goto err_out;
 	}
 
 	printk(KERN_INFO PFX "AGP aperture is %dM @ 0x%lx\n",
-	       size_value, agp_bridge->gart_bus_addr);
+	       size_value, bridge->gart_bus_addr);
 
 	return 0;
 
 err_out:
-	if (agp_bridge->needs_scratch_page == TRUE) {
-		agp_bridge->agp_destroy_page(phys_to_virt(agp_bridge->scratch_page_real));
-	}
+	if (bridge->driver->needs_scratch_page)
+		bridge->driver->agp_destroy_page(
+				phys_to_virt(bridge->scratch_page_real));
 	if (got_gatt)
-		agp_bridge->free_gatt_table();
-	if (got_keylist)
-		vfree(agp_bridge->key_list);
+		bridge->driver->free_gatt_table();
+	if (got_keylist) {
+		vfree(bridge->key_list);
+		bridge->key_list = NULL;
+	}
 	return rc;
 }
 
-
 /* cannot be __exit b/c as it could be called from __init code */
-static void agp_backend_cleanup(void)
+static void agp_backend_cleanup(struct agp_bridge_data *bridge)
 {
-	if (agp_bridge->cleanup != NULL)
-		agp_bridge->cleanup();
-	if (agp_bridge->free_gatt_table != NULL)
-		agp_bridge->free_gatt_table();
-	if (agp_bridge->key_list)
-		vfree(agp_bridge->key_list);
-
-	if ((agp_bridge->agp_destroy_page!=NULL) &&
-			(agp_bridge->needs_scratch_page == TRUE))
-		agp_bridge->agp_destroy_page(phys_to_virt(agp_bridge->scratch_page_real));
-}
-
-static int agp_power(struct pm_dev *dev, pm_request_t rq, void *data)
-{
-	switch(rq)
-	{
-		case PM_SUSPEND:
-			return agp_bridge->suspend();
-		case PM_RESUME:
-			agp_bridge->resume();
-			return 0;
-	}		
-	return 0;
-}
+	if (bridge->driver->cleanup)
+		bridge->driver->cleanup();
+	if (bridge->driver->free_gatt_table)
+		bridge->driver->free_gatt_table();
+	if (bridge->key_list) {
+		vfree(bridge->key_list);
+		bridge->key_list = NULL;
+	}
 
-extern int agp_frontend_initialize(void);
-extern void agp_frontend_cleanup(void);
+	if (bridge->driver->agp_destroy_page &&
+	    bridge->driver->needs_scratch_page)
+		bridge->driver->agp_destroy_page(
+				phys_to_virt(bridge->scratch_page_real));
+}
 
 static const drm_agp_t drm_agp = {
 	&agp_free_memory,
@@ -221,78 +221,85 @@
 	&agp_copy_info
 };
 
-static int agp_count=0;
+/* XXX Kludge alert: agpgart isn't ready for multiple bridges yet */
+struct agp_bridge_data *agp_alloc_bridge(void)
+{
+	return agp_bridge;
+}
+EXPORT_SYMBOL(agp_alloc_bridge);
+
+
+void agp_put_bridge(struct agp_bridge_data *bridge)
+{
+}
+EXPORT_SYMBOL(agp_put_bridge);
 
-int agp_register_driver (struct agp_driver *drv)
+ 
+int agp_add_bridge(struct agp_bridge_data *bridge)
 {
-	int ret_val;
+	int error;
 
-	if (drv->dev == NULL) {
+	if (!bridge->dev) {
 		printk (KERN_DEBUG PFX "Erk, registering with no pci_dev!\n");
 		return -EINVAL;
 	}
 
-	if (agp_count==1) {
-		printk (KERN_DEBUG PFX "Only one agpgart device currently supported.\n");
+	if (agp_count) {
+		printk (KERN_INFO PFX
+		       "Only one agpgart device currently supported.\n");
 		return -ENODEV;
 	}
 
 	/* Grab reference on the chipset driver. */
-	if (!try_module_get(drv->owner))
+	if (!try_module_get(bridge->driver->owner)) {
+		printk (KERN_INFO PFX "Couldn't lock chipset driver.\n");
 		return -EINVAL;
+	}
+
+	bridge->type = SUPPORTED;
 
-	ret_val = agp_backend_initialize(drv->dev);
-	if (ret_val)
+	error = agp_backend_initialize(agp_bridge);
+	if (error) {
+		printk (KERN_INFO PFX "agp_backend_initialize() failed.\n");
 		goto err_out;
+	}
 
-	ret_val = agp_frontend_initialize();
-	if (ret_val)
+	error = agp_frontend_initialize();
+	if (error) {
+		printk (KERN_INFO PFX "agp_frontend_initialize() failed.\n");
 		goto frontend_err;
+	}
 
 	/* FIXME: What to do with this? */
 	inter_module_register("drm_agp", THIS_MODULE, &drm_agp);
 
-	pm_register(PM_PCI_DEV, PM_PCI_ID(agp_bridge->dev), agp_power);
 	agp_count++;
 	return 0;
 
 frontend_err:
-	agp_backend_cleanup();
+	agp_backend_cleanup(agp_bridge);
 err_out:
-	agp_bridge->type = NOT_SUPPORTED;
-	module_put(drv->owner);
-	drv->dev = NULL;
-	return ret_val;
+	bridge->type = NOT_SUPPORTED;
+	module_put(bridge->driver->owner);
+	return error;
 }
+EXPORT_SYMBOL_GPL(agp_add_bridge);
 
-int agp_unregister_driver(struct agp_driver *drv)
-{
-	if (drv->dev==NULL)
-		return -ENODEV;
 
-	agp_bridge->type = NOT_SUPPORTED;
-	pm_unregister_all(agp_power);
+void agp_remove_bridge(struct agp_bridge_data *bridge)
+{
+	bridge->type = NOT_SUPPORTED;
 	agp_frontend_cleanup();
-	agp_backend_cleanup();
+	agp_backend_cleanup(bridge);
 	inter_module_unregister("drm_agp");
 	agp_count--;
-	module_put(drv->owner);
-	return 0;
+	module_put(bridge->driver->owner);
 }
+EXPORT_SYMBOL_GPL(agp_remove_bridge);
 
 
-int __init agp_init(void)
+static int __init agp_init(void)
 {
-	static int already_initialised=0;
-
-	if (already_initialised!=0)
-		return 0;
-
-	already_initialised = 1;
-
-	memset(agp_bridge, 0, sizeof(struct agp_bridge_data));
-	agp_bridge->type = NOT_SUPPORTED;
-
 	printk(KERN_INFO "Linux agpgart interface v%d.%d (c) Dave Jones\n",
 	       AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
 	return 0;
@@ -300,19 +307,13 @@
 
 void __exit agp_exit(void)
 {
-	if (agp_count!=0)
-		BUG();
 }
 
-#ifndef CONFIG_GART_IOMMU
-module_init(agp_init);
-module_exit(agp_exit);
-#endif
-
-EXPORT_SYMBOL(agp_backend_acquire);
-EXPORT_SYMBOL(agp_backend_release);
-EXPORT_SYMBOL_GPL(agp_register_driver);
-EXPORT_SYMBOL_GPL(agp_unregister_driver);
 
 MODULE_AUTHOR("Dave Jones <davej@codemonkey.org.uk>");
+MODULE_DESCRIPTION("AGP GART driver");
 MODULE_LICENSE("GPL and additional rights");
+
+module_init(agp_init);
+module_exit(agp_exit);
+
diff -Nru a/drivers/char/agp/frontend.c b/drivers/char/agp/frontend.c
--- a/drivers/char/agp/frontend.c	Sun Apr  6 18:50:35 2003
+++ b/drivers/char/agp/frontend.c	Thu May  1 11:33:19 2003
@@ -53,11 +53,12 @@
 
 	while (curr != NULL) {
 		if (curr->key == key)
-			return curr;
+			break;
 		curr = curr->next;
 	}
 
-	return NULL;
+	DBG("key=%d -> mem=%p", key, curr);
+	return curr;
 }
 
 static void agp_remove_from_pool(agp_memory * temp)
@@ -67,6 +68,7 @@
 
 	/* Check to see if this is even in the memory pool */
 
+	DBG("mem=%p", temp);
 	if (agp_find_mem_by_key(temp->key) != NULL) {
 		next = temp->next;
 		prev = temp->prev;
@@ -92,11 +94,12 @@
  * to each auth'ed client.
  */
 
-static agp_segment_priv *agp_find_seg_in_client(const agp_client * client,
+static struct
+agp_segment_priv *agp_find_seg_in_client(const struct agp_client *client,
 						unsigned long offset,
 					    int size, pgprot_t page_prot)
 {
-	agp_segment_priv *seg;
+	struct agp_segment_priv *seg;
 	int num_segments, i;
 	off_t pg_start;
 	size_t pg_count;
@@ -117,25 +120,32 @@
 	return NULL;
 }
 
-static void agp_remove_seg_from_client(agp_client * client)
+static void agp_remove_seg_from_client(struct agp_client *client)
 {
+	DBG("client=%p", client);
+
 	if (client->segments != NULL) {
-		if (*(client->segments) != NULL)
+		if (*(client->segments) != NULL) {
+			DBG("Freeing %p from client %p", *(client->segments), client);
 			kfree(*(client->segments));
+		}
+		DBG("Freeing %p from client %p", client->segments, client);
 		kfree(client->segments);
+		client->segments = NULL;
 	}
 }
 
-static void agp_add_seg_to_client(agp_client * client,
-			       agp_segment_priv ** seg, int num_segments)
+static void agp_add_seg_to_client(struct agp_client *client,
+			       struct agp_segment_priv ** seg, int num_segments)
 {
-	agp_segment_priv **prev_seg;
+	struct agp_segment_priv **prev_seg;
 
 	prev_seg = client->segments;
 
 	if (prev_seg != NULL)
 		agp_remove_seg_from_client(client);
 
+	DBG("Adding seg %p (%d segments) to client %p", seg, num_segments, client);
 	client->num_segments = num_segments;
 	client->segments = seg;
 }
@@ -171,19 +181,20 @@
 	return temp;
 }
 
-static int agp_create_segment(agp_client * client, agp_region * region)
+static int agp_create_segment(struct agp_client *client, struct agp_region *region)
 {
-	agp_segment_priv **ret_seg;
-	agp_segment_priv *seg;
-	agp_segment *user_seg;
+	struct agp_segment_priv **ret_seg;
+	struct agp_segment_priv *seg;
+	struct agp_segment *user_seg;
 	size_t i;
 
-	seg = kmalloc((sizeof(agp_segment_priv) * region->seg_count), GFP_KERNEL);
+	seg = kmalloc((sizeof(struct agp_segment_priv) * region->seg_count), GFP_KERNEL);
 	if (seg == NULL) {
 		kfree(region->seg_list);
+		region->seg_list = NULL;
 		return -ENOMEM;
 	}
-	memset(seg, 0, (sizeof(agp_segment_priv) * region->seg_count));
+	memset(seg, 0, (sizeof(struct agp_segment_priv) * region->seg_count));
 	user_seg = region->seg_list;
 
 	for (i = 0; i < region->seg_count; i++) {
@@ -191,14 +202,15 @@
 		seg[i].pg_count = user_seg[i].pg_count;
 		seg[i].prot = agp_convert_mmap_flags(user_seg[i].prot);
 	}
+	kfree(region->seg_list);
+	region->seg_list = NULL;
+
 	ret_seg = kmalloc(sizeof(void *), GFP_KERNEL);
 	if (ret_seg == NULL) {
-		kfree(region->seg_list);
 		kfree(seg);
 		return -ENOMEM;
 	}
 	*ret_seg = seg;
-	kfree(region->seg_list);
 	agp_add_seg_to_client(client, ret_seg, region->seg_count);
 	return 0;
 }
@@ -222,9 +234,9 @@
 
 /* File private list routines */
 
-agp_file_private *agp_find_private(pid_t pid)
+struct agp_file_private *agp_find_private(pid_t pid)
 {
-	agp_file_private *curr;
+	struct agp_file_private *curr;
 
 	curr = agp_fe.file_priv_list;
 
@@ -237,9 +249,9 @@
 	return NULL;
 }
 
-void agp_insert_file_private(agp_file_private * priv)
+void agp_insert_file_private(struct agp_file_private * priv)
 {
-	agp_file_private *prev;
+	struct agp_file_private *prev;
 
 	prev = agp_fe.file_priv_list;
 
@@ -249,10 +261,10 @@
 	agp_fe.file_priv_list = priv;
 }
 
-void agp_remove_file_private(agp_file_private * priv)
+void agp_remove_file_private(struct agp_file_private * priv)
 {
-	agp_file_private *next;
-	agp_file_private *prev;
+	struct agp_file_private *next;
+	struct agp_file_private *prev;
 
 	next = priv->next;
 	prev = priv->prev;
@@ -301,9 +313,9 @@
  * controllers
  */
 
-static agp_controller *agp_find_controller_by_pid(pid_t id)
+static struct agp_controller *agp_find_controller_by_pid(pid_t id)
 {
-	agp_controller *controller;
+	struct agp_controller *controller;
 
 	controller = agp_fe.controllers;
 
@@ -316,24 +328,24 @@
 	return NULL;
 }
 
-static agp_controller *agp_create_controller(pid_t id)
+static struct agp_controller *agp_create_controller(pid_t id)
 {
-	agp_controller *controller;
+	struct agp_controller *controller;
 
-	controller = kmalloc(sizeof(agp_controller), GFP_KERNEL);
+	controller = kmalloc(sizeof(struct agp_controller), GFP_KERNEL);
 
 	if (controller == NULL)
 		return NULL;
 
-	memset(controller, 0, sizeof(agp_controller));
+	memset(controller, 0, sizeof(struct agp_controller));
 	controller->pid = id;
 
 	return controller;
 }
 
-static int agp_insert_controller(agp_controller * controller)
+static int agp_insert_controller(struct agp_controller *controller)
 {
-	agp_controller *prev_controller;
+	struct agp_controller *prev_controller;
 
 	prev_controller = agp_fe.controllers;
 	controller->next = prev_controller;
@@ -346,15 +358,15 @@
 	return 0;
 }
 
-static void agp_remove_all_clients(agp_controller * controller)
+static void agp_remove_all_clients(struct agp_controller *controller)
 {
-	agp_client *client;
-	agp_client *temp;
+	struct agp_client *client;
+	struct agp_client *temp;
 
 	client = controller->clients;
 
 	while (client) {
-		agp_file_private *priv;
+		struct agp_file_private *priv;
 
 		temp = client;
 		agp_remove_seg_from_client(temp);
@@ -369,7 +381,7 @@
 	}
 }
 
-static void agp_remove_all_memory(agp_controller * controller)
+static void agp_remove_all_memory(struct agp_controller *controller)
 {
 	agp_memory *memory;
 	agp_memory *temp;
@@ -383,10 +395,10 @@
 	}
 }
 
-static int agp_remove_controller(agp_controller * controller)
+static int agp_remove_controller(struct agp_controller *controller)
 {
-	agp_controller *prev_controller;
-	agp_controller *next_controller;
+	struct agp_controller *prev_controller;
+	struct agp_controller *next_controller;
 
 	prev_controller = controller->prev;
 	next_controller = controller->next;
@@ -415,14 +427,14 @@
 	return 0;
 }
 
-static void agp_controller_make_current(agp_controller * controller)
+static void agp_controller_make_current(struct agp_controller *controller)
 {
-	agp_client *clients;
+	struct agp_client *clients;
 
 	clients = controller->clients;
 
 	while (clients != NULL) {
-		agp_file_private *priv;
+		struct agp_file_private *priv;
 
 		priv = agp_find_private(clients->pid);
 
@@ -436,16 +448,16 @@
 	agp_fe.current_controller = controller;
 }
 
-static void agp_controller_release_current(agp_controller * controller,
-				      agp_file_private * controller_priv)
+static void agp_controller_release_current(struct agp_controller *controller,
+				      struct agp_file_private *controller_priv)
 {
-	agp_client *clients;
+	struct agp_client *clients;
 
 	clear_bit(AGP_FF_IS_VALID, &controller_priv->access_flags);
 	clients = controller->clients;
 
 	while (clients != NULL) {
-		agp_file_private *priv;
+		struct agp_file_private *priv;
 
 		priv = agp_find_private(clients->pid);
 
@@ -465,10 +477,10 @@
  * These routines are for managing the list of auth'ed clients.
  */
 
-static agp_client *agp_find_client_in_controller(agp_controller * controller,
-						 pid_t id)
+static struct agp_client
+*agp_find_client_in_controller(struct agp_controller *controller, pid_t id)
 {
-	agp_client *client;
+	struct agp_client *client;
 
 	if (controller == NULL)
 		return NULL;
@@ -484,9 +496,9 @@
 	return NULL;
 }
 
-static agp_controller *agp_find_controller_for_client(pid_t id)
+static struct agp_controller *agp_find_controller_for_client(pid_t id)
 {
-	agp_controller *controller;
+	struct agp_controller *controller;
 
 	controller = agp_fe.controllers;
 
@@ -499,9 +511,9 @@
 	return NULL;
 }
 
-static agp_client *agp_find_client_by_pid(pid_t id)
+static struct agp_client *agp_find_client_by_pid(pid_t id)
 {
-	agp_client *temp;
+	struct agp_client *temp;
 
 	if (agp_fe.current_controller == NULL)
 		return NULL;
@@ -510,9 +522,9 @@
 	return temp;
 }
 
-static void agp_insert_client(agp_client * client)
+static void agp_insert_client(struct agp_client *client)
 {
-	agp_client *prev_client;
+	struct agp_client *prev_client;
 
 	prev_client = agp_fe.current_controller->clients;
 	client->next = prev_client;
@@ -524,16 +536,16 @@
 	agp_fe.current_controller->num_clients++;
 }
 
-static agp_client *agp_create_client(pid_t id)
+static struct agp_client *agp_create_client(pid_t id)
 {
-	agp_client *new_client;
+	struct agp_client *new_client;
 
-	new_client = kmalloc(sizeof(agp_client), GFP_KERNEL);
+	new_client = kmalloc(sizeof(struct agp_client), GFP_KERNEL);
 
 	if (new_client == NULL)
 		return NULL;
 
-	memset(new_client, 0, sizeof(agp_client));
+	memset(new_client, 0, sizeof(struct agp_client));
 	new_client->pid = id;
 	agp_insert_client(new_client);
 	return new_client;
@@ -541,10 +553,10 @@
 
 static int agp_remove_client(pid_t id)
 {
-	agp_client *client;
-	agp_client *prev_client;
-	agp_client *next_client;
-	agp_controller *controller;
+	struct agp_client *client;
+	struct agp_client *prev_client;
+	struct agp_client *next_client;
+	struct agp_controller *controller;
 
 	controller = agp_find_controller_for_client(id);
 	if (controller == NULL)
@@ -582,11 +594,11 @@
 {
 	unsigned int size, current_size;
 	unsigned long offset;
-	agp_client *client;
-	agp_file_private *priv = (agp_file_private *) file->private_data;
+	struct agp_client *client;
+	struct agp_file_private *priv = file->private_data;
 	agp_kern_info kerninfo;
 
-	AGP_LOCK();
+	down(&(agp_fe.agp_mutex));
 
 	if (agp_fe.backend_acquired != TRUE)
 		goto out_eperm;
@@ -599,6 +611,7 @@
 	current_size = kerninfo.aper_size;
 	current_size = current_size * 0x100000;
 	offset = vma->vm_pgoff << PAGE_SHIFT;
+	DBG("%lx:%lx", offset, offset+size);
 
 	if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) {
 		if ((size + offset) > current_size)
@@ -612,6 +625,7 @@
 		if (!agp_find_seg_in_client(client, offset, size, vma->vm_page_prot))
 			goto out_inval;
 
+		DBG("client vm_ops=%p", kerninfo.vm_ops);
 		if (kerninfo.vm_ops) {
 			vma->vm_ops = kerninfo.vm_ops;
 		} else if (remap_page_range(vma, vma->vm_start, 
@@ -619,7 +633,7 @@
 					    size, vma->vm_page_prot)) {
 			goto out_again;
 		}
-		AGP_UNLOCK();
+		up(&(agp_fe.agp_mutex));
 		return 0;
 	}
 
@@ -627,6 +641,7 @@
 		if (size != current_size)
 			goto out_inval;
 
+		DBG("controller vm_ops=%p", kerninfo.vm_ops);
 		if (kerninfo.vm_ops) {
 			vma->vm_ops = kerninfo.vm_ops;
 		} else if (remap_page_range(vma, vma->vm_start, 
@@ -634,68 +649,71 @@
 					    size, vma->vm_page_prot)) {
 			goto out_again;
 		}
-		AGP_UNLOCK();
+		up(&(agp_fe.agp_mutex));
 		return 0;
 	}
 
 out_eperm:
-	AGP_UNLOCK();
+	up(&(agp_fe.agp_mutex));
 	return -EPERM;
 
 out_inval:
-	AGP_UNLOCK();
+	up(&(agp_fe.agp_mutex));
 	return -EINVAL;
 
 out_again:
-	AGP_UNLOCK();
+	up(&(agp_fe.agp_mutex));
 	return -EAGAIN;
 }
 
 static int agp_release(struct inode *inode, struct file *file)
 {
-	agp_file_private *priv = (agp_file_private *) file->private_data;
+	struct agp_file_private *priv = file->private_data;
 
-	AGP_LOCK();
+	down(&(agp_fe.agp_mutex));
+
+	DBG("priv=%p", priv);
 
 	if (test_bit(AGP_FF_IS_CONTROLLER, &priv->access_flags)) {
-		agp_controller *controller;
+		struct agp_controller *controller;
 
 		controller = agp_find_controller_by_pid(priv->my_pid);
 
 		if (controller != NULL) {
-			if (controller == agp_fe.current_controller) {
-				agp_controller_release_current(controller,
-							       priv);
-			}
+			if (controller == agp_fe.current_controller)
+				agp_controller_release_current(controller, priv);
 			agp_remove_controller(controller);
+			controller = NULL;
 		}
 	}
-	if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags)) {
+
+	if (test_bit(AGP_FF_IS_CLIENT, &priv->access_flags))
 		agp_remove_client(priv->my_pid);
-	}
+
 	agp_remove_file_private(priv);
 	kfree(priv);
-	AGP_UNLOCK();
+	file->private_data = NULL;
+	up(&(agp_fe.agp_mutex));
 	return 0;
 }
 
 static int agp_open(struct inode *inode, struct file *file)
 {
 	int minor = minor(inode->i_rdev);
-	agp_file_private *priv;
-	agp_client *client;
+	struct agp_file_private *priv;
+	struct agp_client *client;
 	int rc = -ENXIO;
 
-	AGP_LOCK();
+	down(&(agp_fe.agp_mutex));
 
 	if (minor != AGPGART_MINOR)
 		goto err_out;
 
-	priv = kmalloc(sizeof(agp_file_private), GFP_KERNEL);
+	priv = kmalloc(sizeof(struct agp_file_private), GFP_KERNEL);
 	if (priv == NULL)
 		goto err_out_nomem;
 
-	memset(priv, 0, sizeof(agp_file_private));
+	memset(priv, 0, sizeof(struct agp_file_private));
 	set_bit(AGP_FF_ALLOW_CLIENT, &priv->access_flags);
 	priv->my_pid = current->pid;
 
@@ -711,13 +729,14 @@
 	}
 	file->private_data = (void *) priv;
 	agp_insert_file_private(priv);
-	AGP_UNLOCK();
+	DBG("private=%p, client=%p", priv, client);
+	up(&(agp_fe.agp_mutex));
 	return 0;
 
 err_out_nomem:
 	rc = -ENOMEM;
 err_out:
-	AGP_UNLOCK();
+	up(&(agp_fe.agp_mutex));
 	return rc;
 }
 
@@ -734,9 +753,9 @@
 	return -EINVAL;
 }
 
-static int agpioc_info_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_info_wrap(struct agp_file_private *priv, unsigned long arg)
 {
-	agp_info userinfo;
+	struct agp_info userinfo;
 	agp_kern_info kerninfo;
 
 	agp_copy_info(&kerninfo);
@@ -751,17 +770,19 @@
 	userinfo.pg_total = userinfo.pg_system = kerninfo.max_memory;
 	userinfo.pg_used = kerninfo.current_memory;
 
-	if (copy_to_user((void *) arg, &userinfo, sizeof(agp_info)))
+	if (copy_to_user((void *) arg, &userinfo, sizeof(struct agp_info)))
 		return -EFAULT;
 
 	return 0;
 }
 
-static int agpioc_acquire_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_acquire_wrap(struct agp_file_private *priv, unsigned long arg)
 {
 	int ret;
+	struct agp_controller *controller;
+
+	DBG("");
 
-	agp_controller *controller;
 	if (!(test_bit(AGP_FF_ALLOW_CONTROLLER, &priv->access_flags)))
 		return -EPERM;
 
@@ -795,33 +816,36 @@
 	return 0;
 }
 
-static int agpioc_release_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_release_wrap(struct agp_file_private *priv, unsigned long arg)
 {
+	DBG("");
 	agp_controller_release_current(agp_fe.current_controller, priv);
 	return 0;
 }
 
-static int agpioc_setup_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_setup_wrap(struct agp_file_private *priv, unsigned long arg)
 {
-	agp_setup mode;
+	struct agp_setup mode;
 
-	if (copy_from_user(&mode, (void *) arg, sizeof(agp_setup))) {
+	DBG("");
+	if (copy_from_user(&mode, (void *) arg, sizeof(struct agp_setup)))
 		return -EFAULT;
-	}
+
 	agp_enable(mode.agp_mode);
 	return 0;
 }
 
-static int agpioc_reserve_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_reserve_wrap(struct agp_file_private *priv, unsigned long arg)
 {
-	agp_region reserve;
-	agp_client *client;
-	agp_file_private *client_priv;
+	struct agp_region reserve;
+	struct agp_client *client;
+	struct agp_file_private *client_priv;
 
-	if (copy_from_user(&reserve, (void *) arg, sizeof(agp_region)))
+	DBG("");
+	if (copy_from_user(&reserve, (void *) arg, sizeof(struct agp_region)))
 		return -EFAULT;
 
-	if ((unsigned) reserve.seg_count >= ~0U/sizeof(agp_segment))
+	if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment))
 		return -EFAULT;
 
 	client = agp_find_client_by_pid(reserve.pid);
@@ -831,10 +855,8 @@
 		client_priv = agp_find_private(reserve.pid);
 
 		if (client_priv != NULL) {
-			set_bit(AGP_FF_IS_CLIENT,
-				&client_priv->access_flags);
-			set_bit(AGP_FF_IS_VALID,
-				&client_priv->access_flags);
+			set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
+			set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
 		}
 		if (client == NULL) {
 			/* client is already removed */
@@ -842,19 +864,19 @@
 		}
 		return agp_remove_client(reserve.pid);
 	} else {
-		agp_segment *segment;
+		struct agp_segment *segment;
 
 		if (reserve.seg_count >= 16384)
 			return -EINVAL;
-			
-		segment = kmalloc((sizeof(agp_segment) * reserve.seg_count),
+
+		segment = kmalloc((sizeof(struct agp_segment) * reserve.seg_count),
 				  GFP_KERNEL);
 
 		if (segment == NULL)
 			return -ENOMEM;
 
 		if (copy_from_user(segment, (void *) reserve.seg_list,
-				   sizeof(agp_segment) * reserve.seg_count)) {
+				   sizeof(struct agp_segment) * reserve.seg_count)) {
 			kfree(segment);
 			return -EFAULT;
 		}
@@ -871,32 +893,30 @@
 			client_priv = agp_find_private(reserve.pid);
 
 			if (client_priv != NULL) {
-				set_bit(AGP_FF_IS_CLIENT,
-					&client_priv->access_flags);
-				set_bit(AGP_FF_IS_VALID,
-					&client_priv->access_flags);
+				set_bit(AGP_FF_IS_CLIENT, &client_priv->access_flags);
+				set_bit(AGP_FF_IS_VALID, &client_priv->access_flags);
 			}
-			return agp_create_segment(client, &reserve);
-		} else {
-			return agp_create_segment(client, &reserve);
 		}
+		return agp_create_segment(client, &reserve);
 	}
 	/* Will never really happen */
 	return -EINVAL;
 }
 
-static int agpioc_protect_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_protect_wrap(struct agp_file_private *priv, unsigned long arg)
 {
+	DBG("");
 	/* This function is not currently implemented */
 	return -EINVAL;
 }
 
-static int agpioc_allocate_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_allocate_wrap(struct agp_file_private *priv, unsigned long arg)
 {
 	agp_memory *memory;
-	agp_allocate alloc;
+	struct agp_allocate alloc;
 
-	if (copy_from_user(&alloc, (void *) arg, sizeof(agp_allocate)))
+	DBG("");
+	if (copy_from_user(&alloc, (void *) arg, sizeof(struct agp_allocate)))
 		return -EFAULT;
 
 	memory = agp_allocate_memory_wrap(alloc.pg_count, alloc.type);
@@ -907,17 +927,18 @@
 	alloc.key = memory->key;
 	alloc.physical = memory->physical;
 
-	if (copy_to_user((void *) arg, &alloc, sizeof(agp_allocate))) {
+	if (copy_to_user((void *) arg, &alloc, sizeof(struct agp_allocate))) {
 		agp_free_memory_wrap(memory);
 		return -EFAULT;
 	}
 	return 0;
 }
 
-static int agpioc_deallocate_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_deallocate_wrap(struct agp_file_private *priv, unsigned long arg)
 {
 	agp_memory *memory;
 
+	DBG("");
 	memory = agp_find_mem_by_key((int) arg);
 
 	if (memory == NULL)
@@ -927,12 +948,13 @@
 	return 0;
 }
 
-static int agpioc_bind_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_bind_wrap(struct agp_file_private *priv, unsigned long arg)
 {
-	agp_bind bind_info;
+	struct agp_bind bind_info;
 	agp_memory *memory;
 
-	if (copy_from_user(&bind_info, (void *) arg, sizeof(agp_bind)))
+	DBG("");
+	if (copy_from_user(&bind_info, (void *) arg, sizeof(struct agp_bind)))
 		return -EFAULT;
 
 	memory = agp_find_mem_by_key(bind_info.key);
@@ -943,12 +965,13 @@
 	return agp_bind_memory(memory, bind_info.pg_start);
 }
 
-static int agpioc_unbind_wrap(agp_file_private * priv, unsigned long arg)
+static int agpioc_unbind_wrap(struct agp_file_private *priv, unsigned long arg)
 {
 	agp_memory *memory;
-	agp_unbind unbind;
+	struct agp_unbind unbind;
 
-	if (copy_from_user(&unbind, (void *) arg, sizeof(agp_unbind)))
+	DBG("");
+	if (copy_from_user(&unbind, (void *) arg, sizeof(struct agp_unbind)))
 		return -EFAULT;
 
 	memory = agp_find_mem_by_key(unbind.key);
@@ -962,10 +985,11 @@
 static int agp_ioctl(struct inode *inode, struct file *file,
 		     unsigned int cmd, unsigned long arg)
 {
-	agp_file_private *curr_priv = (agp_file_private *) file->private_data;
+	struct agp_file_private *curr_priv = file->private_data;
 	int ret_val = -ENOTTY;
 
-	AGP_LOCK();
+	DBG("priv=%p, cmd=%x", curr_priv, cmd);
+	down(&(agp_fe.agp_mutex));
 
 	if ((agp_fe.current_controller == NULL) &&
 	    (cmd != AGPIOC_ACQUIRE)) {
@@ -1034,7 +1058,8 @@
 	}
 
 ioctl_out:
-	AGP_UNLOCK();
+	DBG("ioctl returns %d\n", ret_val);
+	up(&(agp_fe.agp_mutex));
 	return ret_val;
 }
 
@@ -1060,7 +1085,7 @@
 int agp_frontend_initialize(void)
 {
 	memset(&agp_fe, 0, sizeof(struct agp_front_data));
-	AGP_LOCK_INIT();
+	sema_init(&(agp_fe.agp_mutex), 1);
 
 	if (misc_register(&agp_miscdev)) {
 		printk(KERN_ERR PFX "unable to get minor: %d\n", AGPGART_MINOR);
diff -Nru a/drivers/char/agp/generic-3.0.c b/drivers/char/agp/generic-3.0.c
--- a/drivers/char/agp/generic-3.0.c	Sun Apr  6 16:18:32 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,529 +0,0 @@
-/*
- * Generic routines for AGP 3.0 compliant bridges.
- */
-
-#include <linux/list.h>
-#include <linux/pci.h>
-#include <linux/agp_backend.h>
-#include <linux/module.h>
-
-#include "agp.h"
-
-/* Generic AGP 3.0 enabling routines */
-
-struct agp_3_0_dev {
-	struct list_head list;
-	u8 capndx;
-	u32 maxbw;
-	struct pci_dev *dev;
-};
-
-static int agp_3_0_dev_list_insert(struct list_head *head, struct list_head *new)
-{
-	struct agp_3_0_dev *cur, *n = list_entry(new, struct agp_3_0_dev, list);
-	struct list_head *pos;
-
-	list_for_each(pos, head) {
-		cur = list_entry(pos, struct agp_3_0_dev, list);
-		if(cur->maxbw > n->maxbw)
-			break;
-	}
-	list_add_tail(new, pos);
-
-	return 0;
-}
-
-static int agp_3_0_dev_list_sort(struct agp_3_0_dev *list, unsigned int ndevs)
-{
-	struct agp_3_0_dev *cur;
-	struct pci_dev *dev;
-	struct list_head *pos, *tmp, *head = &list->list, *start = head->next;
-	u32 nistat;
-
-	INIT_LIST_HEAD(head);
-
-	for(pos = start; pos != head;) {
-		cur = list_entry(pos, struct agp_3_0_dev, list);
-		dev = cur->dev;
-
-		pci_read_config_dword(dev, cur->capndx + 0x0c, &nistat);
-		cur->maxbw = (nistat >> 16) & 0xff;
-
-		tmp = pos;
-		pos = pos->next;
-		agp_3_0_dev_list_insert(head, tmp);
-	}
-	return 0;
-}
-
-/* 
- * Initialize all isochronous transfer parameters for an AGP 3.0 
- * node (i.e. a host bridge in combination with the adapters 
- * lying behind it...)
- */
-
-static int agp_3_0_isochronous_node_enable(struct agp_3_0_dev *dev_list, unsigned int ndevs)
-{
-	/*
-	 * Convenience structure to make the calculations clearer
-	 * here.  The field names come straight from the AGP 3.0 spec.
-	 */
-	struct isoch_data {
-		u32 maxbw;
-		u32 n;
-		u32 y;
-		u32 l;
-		u32 rq;
-		struct agp_3_0_dev *dev;
-	};
-
-	struct pci_dev *td = agp_bridge->dev, *dev;
-	struct list_head *head = &dev_list->list, *pos;
-	struct agp_3_0_dev *cur;
-	struct isoch_data *master, target;
-	unsigned int cdev = 0;
-	u32 mnistat, tnistat, tstatus, mcmd;
-	u16 tnicmd, mnicmd;
-	u8 mcapndx;
-	u32 tot_bw = 0, tot_n = 0, tot_rq = 0, y_max, rq_isoch, rq_async;
-	u32 step, rem, rem_isoch, rem_async;
-	int ret = 0;
-
-	/*
-	 * We'll work with an array of isoch_data's (one for each
-	 * device in dev_list) throughout this function.
-	 */
-	if((master = kmalloc(ndevs * sizeof(*master), GFP_KERNEL)) == NULL) {
-		ret = -ENOMEM;
-		goto get_out;
-	}
-
-	/*
-	 * Sort the device list by maxbw.  We need to do this because the
-	 * spec suggests that the devices with the smallest requirements
-	 * have their resources allocated first, with all remaining resources
-	 * falling to the device with the largest requirement.
-	 *
-	 * We don't exactly do this, we divide target resources by ndevs
-	 * and split them amongst the AGP 3.0 devices.  The remainder of such
-	 * division operations are dropped on the last device, sort of like
-	 * the spec mentions it should be done.
-	 *
-	 * We can't do this sort when we initially construct the dev_list
-	 * because we don't know until this function whether isochronous
-	 * transfers are enabled and consequently whether maxbw will mean
-	 * anything.
-	 */
-	if((ret = agp_3_0_dev_list_sort(dev_list, ndevs)) != 0)
-		goto free_and_exit;
-
-	pci_read_config_dword(td, agp_bridge->capndx + 0x0c, &tnistat);
-	pci_read_config_dword(td, agp_bridge->capndx + 0x04, &tstatus);
-
-	/* Extract power-on defaults from the target */
-	target.maxbw = (tnistat >> 16) & 0xff;
-	target.n     = (tnistat >> 8)  & 0xff;
-	target.y     = (tnistat >> 6)  & 0x3;
-	target.l     = (tnistat >> 3)  & 0x7;
-	target.rq    = (tstatus >> 24) & 0xff;
-
-	y_max = target.y;
-
-	/*
-	 * Extract power-on defaults for each device in dev_list.  Along
-	 * the way, calculate the total isochronous bandwidth required
-	 * by these devices and the largest requested payload size.
-	 */
-	list_for_each(pos, head) {
-		cur = list_entry(pos, struct agp_3_0_dev, list);
-		dev = cur->dev;
-
-		mcapndx = cur->capndx;
-
-		pci_read_config_dword(dev, cur->capndx + 0x0c, &mnistat);
-
-		master[cdev].maxbw = (mnistat >> 16) & 0xff;
-		master[cdev].n     = (mnistat >> 8)  & 0xff;
-		master[cdev].y     = (mnistat >> 6)  & 0x3;
-		master[cdev].dev   = cur;
-
-		tot_bw += master[cdev].maxbw;
-		y_max = max(y_max, master[cdev].y);
-
-		cdev++;
-	}
-
-	/* Check if this configuration has any chance of working */
-	if(tot_bw > target.maxbw) {
-		printk(KERN_ERR PFX "isochronous bandwidth required "
-			"by AGP 3.0 devices exceeds that which is supported by "
-			"the AGP 3.0 bridge!\n");
-		ret = -ENODEV;
-		goto free_and_exit;
-	}
-
-	target.y = y_max;
-
-	/*
-	 * Write the calculated payload size into the target's NICMD
-	 * register.  Doing this directly effects the ISOCH_N value
-	 * in the target's NISTAT register, so we need to do this now
-	 * to get an accurate value for ISOCH_N later.
-	 */
-	pci_read_config_word(td, agp_bridge->capndx + 0x20, &tnicmd);
-	tnicmd &= ~(0x3 << 6);
-	tnicmd |= target.y << 6;
-	pci_write_config_word(td, agp_bridge->capndx + 0x20, tnicmd);
-
-	/* Reread the target's ISOCH_N */
-	pci_read_config_dword(td, agp_bridge->capndx + 0x0c, &tnistat);
-	target.n = (tnistat >> 8) & 0xff;
-
-	/* Calculate the minimum ISOCH_N needed by each master */
-	for(cdev = 0; cdev < ndevs; cdev++) {
-		master[cdev].y = target.y;
-		master[cdev].n = master[cdev].maxbw / (master[cdev].y + 1);
-
-		tot_n += master[cdev].n;
-	}
-
-	/* Exit if the minimal ISOCH_N allocation among the masters is more
-	 * than the target can handle. */
-	if(tot_n > target.n) {
-		printk(KERN_ERR PFX "number of isochronous "
-			"transactions per period required by AGP 3.0 devices "
-			"exceeds that which is supported by the AGP 3.0 "
-			"bridge!\n");
-		ret = -ENODEV;
-		goto free_and_exit;
-	}
-
-	/* Calculate left over ISOCH_N capability in the target.  We'll give
-	 * this to the hungriest device (as per the spec) */
-	rem  = target.n - tot_n;
-
-	/* 
-	 * Calculate the minimum isochronous RQ depth needed by each master.
-	 * Along the way, distribute the extra ISOCH_N capability calculated
-	 * above.
-	 */
-	for(cdev = 0; cdev < ndevs; cdev++) {
-		/*
-		 * This is a little subtle.  If ISOCH_Y > 64B, then ISOCH_Y
-		 * byte isochronous writes will be broken into 64B pieces.
-		 * This means we need to budget more RQ depth to account for
-		 * these kind of writes (each isochronous write is actually
-		 * many writes on the AGP bus).
-		 */
-		master[cdev].rq = master[cdev].n;
-		if(master[cdev].y > 0x1) {
-			master[cdev].rq *= (1 << (master[cdev].y - 1));
-		}
-
-		tot_rq += master[cdev].rq;
-
-		if(cdev == ndevs - 1)
-			master[cdev].n += rem;
-	}
-
-	/* Figure the number of isochronous and asynchronous RQ slots the
-	 * target is providing. */
-	rq_isoch = (target.y > 0x1) ? target.n * (1 << (target.y - 1)) : target.n;
-	rq_async = target.rq - rq_isoch;
-
-	/* Exit if the minimal RQ needs of the masters exceeds what the target
-	 * can provide. */
-	if(tot_rq > rq_isoch) {
-		printk(KERN_ERR PFX "number of request queue slots "
-			"required by the isochronous bandwidth requested by "
-			"AGP 3.0 devices exceeds the number provided by the "
-			"AGP 3.0 bridge!\n");
-		ret = -ENODEV;
-		goto free_and_exit;
-	}
-
-	/* Calculate asynchronous RQ capability in the target (per master) as
-	 * well as the total number of leftover isochronous RQ slots. */
-	step      = rq_async / ndevs;
-	rem_async = step + (rq_async % ndevs);
-	rem_isoch = rq_isoch - tot_rq;
-
-	/* Distribute the extra RQ slots calculated above and write our
-	 * isochronous settings out to the actual devices. */
-	for(cdev = 0; cdev < ndevs; cdev++) {
-		cur = master[cdev].dev;
-		dev = cur->dev;
-
-		mcapndx = cur->capndx;
-
-		master[cdev].rq += (cdev == ndevs - 1)
-		              ? (rem_async + rem_isoch) : step;
-
-		pci_read_config_word(dev, cur->capndx + 0x20, &mnicmd);
-		pci_read_config_dword(dev, cur->capndx + 0x08, &mcmd);
-
-		mnicmd &= ~(0xff << 8);
-		mnicmd &= ~(0x3  << 6);
-		mcmd   &= ~(0xff << 24);
-
-		mnicmd |= master[cdev].n  << 8;
-		mnicmd |= master[cdev].y  << 6;
-		mcmd   |= master[cdev].rq << 24;
-
-		pci_write_config_dword(dev, cur->capndx + 0x08, mcmd);
-		pci_write_config_word(dev, cur->capndx + 0x20, mnicmd);
-	}
-
-free_and_exit:
-	kfree(master);
-
-get_out:
-	return ret;
-}
-
-/*
- * This function basically allocates request queue slots among the
- * AGP 3.0 systems in nonisochronous nodes.  The algorithm is
- * pretty stupid, divide the total number of RQ slots provided by the
- * target by ndevs.  Distribute this many slots to each AGP 3.0 device,
- * giving any left over slots to the last device in dev_list.
- */
-static int agp_3_0_nonisochronous_node_enable(struct agp_3_0_dev *dev_list, unsigned int ndevs)
-{
-	struct agp_3_0_dev *cur;
-	struct list_head *head = &dev_list->list, *pos;
-	u32 tstatus, mcmd;
-	u32 trq, mrq, rem;
-	unsigned int cdev = 0;
-
-	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + 0x04, &tstatus);
-
-	trq = (tstatus >> 24) & 0xff;
-	mrq = trq / ndevs;
-
-	rem = mrq + (trq % ndevs);
-
-	for(pos = head->next; cdev < ndevs; cdev++, pos = pos->next) {
-		cur = list_entry(pos, struct agp_3_0_dev, list);
-
-		pci_read_config_dword(cur->dev, cur->capndx + 0x08, &mcmd);
-		mcmd &= ~(0xff << 24);
-		mcmd |= ((cdev == ndevs - 1) ? rem : mrq) << 24;
-		pci_write_config_dword(cur->dev, cur->capndx + 0x08, mcmd);
-	}
-
-	return 0;
-}
-
-/*
- * Fully configure and enable an AGP 3.0 host bridge and all the devices
- * lying behind it.
- */
-int agp_3_0_node_enable(u32 mode, u32 minor)
-{
-	struct pci_dev *td = agp_bridge->dev, *dev;
-	u8 mcapndx;
-	u32 isoch, arqsz, cal_cycle, tmp, rate;
-	u32 tstatus, tcmd, mcmd, mstatus, ncapid;
-	u32 mmajor, mminor;
-	u16 mpstat;
-	struct agp_3_0_dev *dev_list, *cur;
-	struct list_head *head, *pos;
-	unsigned int ndevs = 0;
-	int ret = 0;
-
-	/* 
-	 * Allocate a head for our AGP 3.0 device list (multiple AGP 3.0
-	 * devices are allowed behind a single bridge). 
-	 */
-	if((dev_list = kmalloc(sizeof(*dev_list), GFP_KERNEL)) == NULL) {
-		ret = -ENOMEM;
-		goto get_out;
-	}
-	head = &dev_list->list;
-	INIT_LIST_HEAD(head);
-
-	/* Find all AGP devices, and add them to dev_list. */
-	pci_for_each_dev(dev) { 
-		switch ((dev->class >>8) & 0xff00) {
-			case 0x0001:    /* Unclassified device */
-			case 0x0300:    /* Display controller */
-			case 0x0400:    /* Multimedia controller */
-			case 0x0600:    /* Bridge */
-				mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP);
-				if (mcapndx == 0)
-					continue;
-
-				if((cur = kmalloc(sizeof(*cur), GFP_KERNEL)) == NULL) {
-					ret = -ENOMEM;
-					goto free_and_exit;
-				}
-				cur->dev = dev;
-
-				pos = &cur->list;
-				list_add(pos, head);
-				ndevs++;
-				continue;
-
-			default:
-				continue;
-		}
-	}
-
-	/* Extract some power-on defaults from the target */
-	pci_read_config_dword(td, agp_bridge->capndx + 0x04, &tstatus);
-	isoch     = (tstatus >> 17) & 0x1;
-	arqsz     = (tstatus >> 13) & 0x7;
-	cal_cycle = (tstatus >> 10) & 0x7;
-	rate      = tstatus & 0x7;
-
-	/*
-	 * Take an initial pass through the devices lying behind our host
-	 * bridge.  Make sure each one is actually an AGP 3.0 device, otherwise
-	 * exit with an error message.  Along the way store the AGP 3.0
-	 * cap_ptr for each device, the minimum supported cal_cycle, and the
-	 * minimum supported data rate.
-	 */
-	list_for_each(pos, head) {
-		cur = list_entry(pos, struct agp_3_0_dev, list);
-		dev = cur->dev;
-		
-		pci_read_config_word(dev, PCI_STATUS, &mpstat);
-		if((mpstat & PCI_STATUS_CAP_LIST) == 0)
-			continue;
-
-		pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &mcapndx);
-		if (mcapndx != 0x00) {
-			do {
-				pci_read_config_dword(dev, mcapndx, &ncapid);
-				if ((ncapid & 0xff) != 0x02)
-					mcapndx = (ncapid >> 8) & 0xff;
-			}
-			while (((ncapid & 0xff) != 0x02) && (mcapndx != 0x00));
-		}
-
-		if(mcapndx == 0) {
-			printk(KERN_ERR PFX "woah!  Non-AGP device "
-				"found on the secondary bus of an AGP 3.0 bridge!\n");
-			ret = -ENODEV;
-			goto free_and_exit;
-		}
-
-		mmajor = (ncapid >> 20) & 0xf;
-		mminor = (ncapid >> 16) & 0xf;
-
-		if(mmajor < 3) {
-			printk(KERN_ERR PFX "woah!  AGP 2.0 device "
-				"found on the secondary bus of an AGP 3.0 "
-				"bridge operating with AGP 3.0 electricals!\n");
-			ret = -ENODEV;
-			goto free_and_exit;
-		}
-
-		cur->capndx = mcapndx;
-
-		pci_read_config_dword(dev, cur->capndx + 0x04, &mstatus);
-
-		if(((mstatus >> 3) & 0x1) == 0) {
-			printk(KERN_ERR PFX "woah!  AGP 3.0 device "
-				"not operating in AGP 3.0 mode found on the "
-				"secondary bus of an AGP 3.0 bridge operating "
-				"with AGP 3.0 electricals!\n");
-			ret = -ENODEV;
-			goto free_and_exit;
-		}
-
-		tmp = (mstatus >> 10) & 0x7;
-		cal_cycle = min(cal_cycle, tmp);
-
-		/* figure the lesser rate */
-		tmp = mstatus & 0x7;
-		if(tmp < rate) 
-			rate = tmp;
-			
-	}		
-
-	/* Turn rate into something we can actually write out to AGPCMD */
-	switch(rate) {
-	case 0x1:
-	case 0x2:
-		break;
-	case 0x3:
-		rate = 0x2;
-		break;
-	default:
-		printk(KERN_ERR PFX "woah!  Bogus AGP rate (%d) "
-			"value found advertised behind an AGP 3.0 bridge!\n", rate);
-		ret = -ENODEV;
-		goto free_and_exit;
-	}
-
-	/*
-	 * Call functions to divide target resources amongst the AGP 3.0
-	 * masters.  This process is dramatically different depending on
-	 * whether isochronous transfers are supported.
-	 */
-	if(isoch != 0) {
-		if((ret = agp_3_0_isochronous_node_enable(dev_list, ndevs)) != 0)
-			goto free_and_exit;
-	} else {
-		if((ret = agp_3_0_nonisochronous_node_enable(dev_list,ndevs)) != 0)
-			goto free_and_exit;
-	}
-
-	/*
-	 * Set the calculated minimum supported cal_cycle and minimum
-	 * supported transfer rate in the target's AGPCMD register.
-	 * Also set the AGP_ENABLE bit, effectively 'turning on' the
-	 * target (this has to be done _before_ turning on the masters).
-	 */
-	pci_read_config_dword(td, agp_bridge->capndx + 0x08, &tcmd);
-
-	tcmd &= ~(0x7 << 10);
-	tcmd &= ~0x7;
-
-	tcmd |= cal_cycle << 10;
-	tcmd |= 0x1 << 8;
-	tcmd |= rate;
-
-	pci_write_config_dword(td, agp_bridge->capndx + 0x08, tcmd);
-
-	/*
-	 * Set the target's advertised arqsz value, the minimum supported
-	 * transfer rate, and the AGP_ENABLE bit in each master's AGPCMD
-	 * register.
-	 */
-	list_for_each(pos, head) {
-		cur = list_entry(pos, struct agp_3_0_dev, list);
-		dev = cur->dev;
-
-		mcapndx = cur->capndx;
-
-		pci_read_config_dword(dev, cur->capndx + 0x08, &mcmd);
-
-		mcmd &= ~(0x7 << 13);
-		mcmd &= ~0x7;
-
-		mcmd |= arqsz << 13;
-		mcmd |= 0x1 << 8;
-		mcmd |= rate;
-
-		pci_write_config_dword(dev, cur->capndx + 0x08, mcmd);
-	}
-
-free_and_exit:
-	/* Be sure to free the dev_list */
-	for(pos = head->next; pos != head;) {
-		cur = list_entry(pos, struct agp_3_0_dev, list);
-
-		pos = pos->next;
-		kfree(cur);
-	}
-	kfree(dev_list);
-
-get_out:
-	return ret;
-}
-
-EXPORT_SYMBOL_GPL(agp_3_0_node_enable);
-
diff -Nru a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
--- a/drivers/char/agp/generic.c	Wed Apr  9 17:15:09 2003
+++ b/drivers/char/agp/generic.c	Mon May 19 18:22:55 2003
@@ -1,6 +1,6 @@
 /*
  * AGPGART driver.
- * Copyright (C) 2002 Dave Jones.
+ * Copyright (C) 2002-2003 Dave Jones.
  * Copyright (C) 1999 Jeff Hartmann.
  * Copyright (C) 1999 Precision Insight, Inc.
  * Copyright (C) 1999 Xi Graphics, Inc.
@@ -42,19 +42,19 @@
 
 /* 
  * Generic routines for handling agp_memory structures -
- * They use the basic page allocation routines to do the
- * brunt of the work.
+ * They use the basic page allocation routines to do the brunt of the work.
  */
 
 void agp_free_key(int key)
 {
-
 	if (key < 0)
 		return;
 
 	if (key < MAXKEY)
 		clear_bit(key, agp_bridge->key_list);
 }
+EXPORT_SYMBOL(agp_free_key);
+
 
 static int agp_get_key(void)
 {
@@ -68,6 +68,7 @@
 	return -1;
 }
 
+
 agp_memory *agp_create_memory(int scratch_pages)
 {
 	agp_memory *new;
@@ -94,7 +95,16 @@
 	new->num_scratch_pages = scratch_pages;
 	return new;
 }
+EXPORT_SYMBOL(agp_create_memory);
 
+/**
+ *	agp_free_memory - free memory associated with an agp_memory pointer.
+ *
+ *	@curr:		agp_memory pointer to be freed.
+ *
+ *	It is the only function that can be called when the backend is not owned
+ *	by the caller.  (So it can free memory on client death.)
+ */
 void agp_free_memory(agp_memory * curr)
 {
 	size_t i;
@@ -106,21 +116,33 @@
 		agp_unbind_memory(curr);
 
 	if (curr->type != 0) {
-		agp_bridge->free_by_type(curr);
+		agp_bridge->driver->free_by_type(curr);
 		return;
 	}
 	if (curr->page_count != 0) {
 		for (i = 0; i < curr->page_count; i++) {
-			agp_bridge->agp_destroy_page(phys_to_virt(curr->memory[i]));
+			agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[i]));
 		}
 	}
 	agp_free_key(curr->key);
 	vfree(curr->memory);
 	kfree(curr);
 }
+EXPORT_SYMBOL(agp_free_memory);
 
 #define ENTRIES_PER_PAGE		(PAGE_SIZE / sizeof(unsigned long))
 
+/**
+ *	agp_allocate_memory  -  allocate a group of pages of a certain type.
+ *
+ *	@page_count:	size_t argument of the number of pages
+ *	@type:	u32 argument of the type of memory to be allocated.  
+ *
+ *	Every agp bridge device will allow you to allocate AGP_NORMAL_MEMORY which
+ *	maps to physical ram.  Any other type is device dependent.
+ *
+ *	It returns NULL whenever memory is unavailable. 
+ */
 agp_memory *agp_allocate_memory(size_t page_count, u32 type)
 {
 	int scratch_pages;
@@ -134,7 +156,7 @@
 		return NULL;
 
 	if (type != 0) {
-		new = agp_bridge->alloc_by_type(page_count, type);
+		new = agp_bridge->driver->alloc_by_type(page_count, type);
 		return new;
 	}
 
@@ -146,7 +168,7 @@
 		return NULL;
 
 	for (i = 0; i < page_count; i++) {
-		void *addr = agp_bridge->agp_alloc_page();
+		void *addr = agp_bridge->driver->agp_alloc_page();
 
 		if (addr == NULL) {
 			agp_free_memory(new);
@@ -160,9 +182,12 @@
 
 	return new;
 }
+EXPORT_SYMBOL(agp_allocate_memory);
+
 
 /* End - Generic routines for handling agp_memory structures */
 
+
 static int agp_return_size(void)
 {
 	int current_size;
@@ -170,7 +195,7 @@
 
 	temp = agp_bridge->current_size;
 
-	switch (agp_bridge->size_type) {
+	switch (agp_bridge->driver->size_type) {
 	case U8_APER_SIZE:
 		current_size = A_SIZE_8(temp)->size;
 		break;
@@ -197,6 +222,7 @@
 	return current_size;
 }
 
+
 int agp_num_entries(void)
 {
 	int num_entries;
@@ -204,7 +230,7 @@
 
 	temp = agp_bridge->current_size;
 
-	switch (agp_bridge->size_type) {
+	switch (agp_bridge->driver->size_type) {
 	case U8_APER_SIZE:
 		num_entries = A_SIZE_8(temp)->num_entries;
 		break;
@@ -230,39 +256,61 @@
 		num_entries = 0;
 	return num_entries;
 }
+EXPORT_SYMBOL_GPL(agp_num_entries);
 
-/* Routine to copy over information structure */
 
+/**
+ *	agp_copy_info  -  copy bridge state information
+ *
+ *	@info:		agp_kern_info pointer.  The caller should insure that this pointer is valid. 
+ *
+ *	This function copies information about the agp bridge device and the state of
+ *	the agp backend into an agp_kern_info pointer.
+ */
 int agp_copy_info(agp_kern_info * info)
 {
 	memset(info, 0, sizeof(agp_kern_info));
-	if (agp_bridge->type == NOT_SUPPORTED) {
-		info->chipset = agp_bridge->type;
+	if (!agp_bridge || agp_bridge->type == NOT_SUPPORTED ||
+	    !agp_bridge->version) {
+		info->chipset = NOT_SUPPORTED;
 		return -EIO;
 	}
+
 	info->version.major = agp_bridge->version->major;
 	info->version.minor = agp_bridge->version->minor;
-	info->device = agp_bridge->dev;
 	info->chipset = agp_bridge->type;
+	info->device = agp_bridge->dev;
 	info->mode = agp_bridge->mode;
 	info->aper_base = agp_bridge->gart_bus_addr;
 	info->aper_size = agp_return_size();
 	info->max_memory = agp_bridge->max_memory_agp;
 	info->current_memory = atomic_read(&agp_bridge->current_memory_agp);
-	info->cant_use_aperture = agp_bridge->cant_use_aperture;
+	info->cant_use_aperture = agp_bridge->driver->cant_use_aperture;
 	info->vm_ops = agp_bridge->vm_ops;
 	info->page_mask = ~0UL;
 	return 0;
 }
+EXPORT_SYMBOL(agp_copy_info);
+
 
 /* End - Routine to copy over information structure */
 
+
 /*
  * Routines for handling swapping of agp_memory into the GATT -
  * These routines take agp_memory and insert them into the GATT.
  * They call device specific routines to actually write to the GATT.
  */
 
+/**
+ *	agp_bind_memory  -  Bind an agp_memory structure into the GATT.
+ * 
+ *	@curr:		agp_memory pointer
+ *	@pg_start:	an offset into the graphics aperture translation table
+ *
+ *	It returns -EINVAL if the pointer == NULL.
+ *	It returns -EBUSY if the area of the table requested is already in use.
+ */
 int agp_bind_memory(agp_memory * curr, off_t pg_start)
 {
 	int ret_val;
@@ -272,10 +320,10 @@
 		return -EINVAL;
 	}
 	if (curr->is_flushed == FALSE) {
-		CACHE_FLUSH();
+		agp_bridge->driver->cache_flush();
 		curr->is_flushed = TRUE;
 	}
-	ret_val = agp_bridge->insert_memory(curr, pg_start, curr->type);
+	ret_val = agp_bridge->driver->insert_memory(curr, pg_start, curr->type);
 
 	if (ret_val != 0)
 		return ret_val;
@@ -284,7 +332,17 @@
 	curr->pg_start = pg_start;
 	return 0;
 }
+EXPORT_SYMBOL(agp_bind_memory);
 
+
+/**
+ *	agp_unbind_memory  -  Removes an agp_memory structure from the GATT
+ * 
+ * @curr:	agp_memory pointer to be removed from the GATT.
+ * 
+ * It returns -EINVAL if this piece of agp_memory is not currently bound to
+ * the graphics aperture translation table or if the agp_memory pointer == NULL
+ */
 int agp_unbind_memory(agp_memory * curr)
 {
 	int ret_val;
@@ -295,7 +353,7 @@
 	if (curr->is_bound != TRUE)
 		return -EINVAL;
 
-	ret_val = agp_bridge->remove_memory(curr, curr->pg_start, curr->type);
+	ret_val = agp_bridge->driver->remove_memory(curr, curr->pg_start, curr->type);
 
 	if (ret_val != 0)
 		return ret_val;
@@ -304,74 +362,143 @@
 	curr->pg_start = 0;
 	return 0;
 }
+EXPORT_SYMBOL(agp_unbind_memory);
 
 /* End - Routines for handling swapping of agp_memory into the GATT */
 
 
 /* Generic Agp routines - Start */
+static void agp_v2_parse_one(u32 *mode, u32 *cmd, u32 *tmp)
+{
+	/* disable SBA if it's not supported */
+	if (!((*cmd & AGPSTAT_SBA) && (*tmp & AGPSTAT_SBA) && (*mode & AGPSTAT_SBA)))
+		*cmd &= ~AGPSTAT_SBA;
+
+	/* disable FW if it's not supported */
+	if (!((*cmd & AGPSTAT_FW) && (*tmp & AGPSTAT_FW) && (*mode & AGPSTAT_FW)))
+		*cmd &= ~AGPSTAT_FW;
+
+	/* Set speed */
+	if (!((*cmd & AGPSTAT2_4X) && (*tmp & AGPSTAT2_4X) && (*mode & AGPSTAT2_4X)))
+		*cmd &= ~AGPSTAT2_4X;
+
+	if (!((*cmd & AGPSTAT2_2X) && (*tmp & AGPSTAT2_2X) && (*mode & AGPSTAT2_2X)))
+		*cmd &= ~AGPSTAT2_2X;
+
+	if (!((*cmd & AGPSTAT2_1X) && (*tmp & AGPSTAT2_1X) && (*mode & AGPSTAT2_1X)))
+		*cmd &= ~AGPSTAT2_1X;
+
+	/* Now we know what mode it should be, clear out the unwanted bits. */
+	if (*cmd & AGPSTAT2_4X)
+		*cmd &= ~(AGPSTAT2_1X | AGPSTAT2_2X);	/* 4X */
 
-u32 agp_collect_device_status(u32 mode, u32 command)
+	if (*cmd & AGPSTAT2_2X)
+		*cmd &= ~(AGPSTAT2_1X | AGPSTAT2_4X);	/* 2X */
+
+	if (*cmd & AGPSTAT2_1X)
+		*cmd &= ~(AGPSTAT2_2X | AGPSTAT2_4X);	/* 1Xf */
+}
+
+
+static void agp_v3_parse_one(u32 *mode, u32 *cmd, u32 *tmp)
+{
+	/* ARQSZ - Set the value to the maximum one.
+	 * Don't allow the mode register to override values. */
+	*cmd = ((*cmd & ~AGPSTAT_ARQSZ) |
+		max_t(u32,(*cmd & AGPSTAT_ARQSZ),(*tmp & AGPSTAT_ARQSZ)));
+
+	/* Calibration cycle.
+	 * Don't allow the mode register to override values. */
+	*cmd = ((*cmd & ~AGPSTAT_CAL_MASK) |
+		min_t(u32,(*cmd & AGPSTAT_CAL_MASK),(*tmp & AGPSTAT_CAL_MASK)));
+
+	/* SBA *must* be supported for AGP v3 */
+	*cmd |= AGPSTAT_SBA;
+
+	/* disable FW if it's not supported */
+	if (!((*cmd & AGPSTAT_FW) && (*tmp & AGPSTAT_FW) && (*mode & AGPSTAT_FW)))
+		*cmd &= ~AGPSTAT_FW;
+
+	/*
+	 * Set speed.
+	 * Check for invalid speeds. This can happen when applications
+	 * written before the AGP 3.0 standard pass AGP2.x modes to AGP3 hardware
+	 */
+	if (*mode & AGPSTAT_MODE_3_0) {
+		/*
+		 * Caller hasn't a clue what its doing. We are in 3.0 mode,
+		 * have been passed a 3.0 mode, but with 2.x speed bits set.
+		 * AGP2.x 4x -> AGP3.0 4x.
+		 */
+		if (*mode & AGPSTAT2_4X) {
+			printk (KERN_INFO PFX "%s passes broken AGP3 flags (%x). Fixed.\n",
+						current->comm, *mode);
+			*mode &= ~AGPSTAT2_4X;
+			*mode |= AGPSTAT3_4X;
+		}
+	} else {
+		/*
+		 * The caller doesn't know what they are doing. We are in 3.0 mode,
+		 * but have been passed an AGP 2.x mode.
+		 * Convert AGP 1x,2x,4x -> AGP 3.0 4x.
+		 */
+		printk (KERN_INFO PFX "%s passes broken AGP2 flags (%x) in AGP3 mode. Fixed.\n",
+					current->comm, *mode);
+		*mode &= ~(AGPSTAT2_4X | AGPSTAT2_2X | AGPSTAT2_1X);
+		*mode |= AGPSTAT3_4X;
+	}
+
+	if (!((*cmd & AGPSTAT3_8X) && (*tmp & AGPSTAT3_8X) && (*mode & AGPSTAT3_8X)))
+		*cmd &= ~AGPSTAT3_8X;
+
+	if (!((*cmd & AGPSTAT3_4X) && (*tmp & AGPSTAT3_4X) && (*mode & AGPSTAT3_4X)))
+		*cmd &= ~AGPSTAT3_4X;
+
+	/* Clear out unwanted bits. */
+	if (*cmd & AGPSTAT3_8X)
+		*cmd = ~(AGPSTAT3_4X | AGPSTAT3_RSVD);
+	if (*cmd & AGPSTAT3_4X)
+		*cmd = ~(AGPSTAT3_8X | AGPSTAT3_RSVD);
+}
+
+//FIXME: This doesn't smell right.
+//We need a function we pass an agp_device to.
+u32 agp_collect_device_status(u32 mode, u32 cmd)
 {
 	struct pci_dev *device;
-	u8 agp;
-	u32 scratch; 
+	u8 cap_ptr;
+	u32 tmp;
+	u32 agp3;
 
 	pci_for_each_dev(device) {
-		agp = pci_find_capability(device, PCI_CAP_ID_AGP);
-		if (!agp)
+		cap_ptr = pci_find_capability(device, PCI_CAP_ID_AGP);
+		if (!cap_ptr)
 			continue;
 
 		/*
 		 * Ok, here we have a AGP device. Disable impossible 
 		 * settings, and adjust the readqueue to the minimum.
 		 */
-		pci_read_config_dword(device, agp + PCI_AGP_STATUS, &scratch);
+		pci_read_config_dword(device, cap_ptr+PCI_AGP_STATUS, &tmp);
 
 		/* adjust RQ depth */
-		command = ((command & ~0xff000000) |
-		     min_t(u32, (mode & 0xff000000),
-			 min_t(u32, (command & 0xff000000),
-			     (scratch & 0xff000000))));
-
-		/* disable SBA if it's not supported */
-		if (!((command & 0x00000200) &&
-		      (scratch & 0x00000200) &&
-		      (mode & 0x00000200)))
-			command &= ~0x00000200;
-
-		/* disable FW if it's not supported */
-		if (!((command & 0x00000010) &&
-		      (scratch & 0x00000010) &&
-		      (mode & 0x00000010)))
-			command &= ~0x00000010;
-
-		if (!((command & 4) &&
-		      (scratch & 4) &&
-		      (mode & 4)))
-			command &= ~0x00000004;
-
-		if (!((command & 2) &&
-		      (scratch & 2) &&
-		      (mode & 2)))
-			command &= ~0x00000002;
-
-		if (!((command & 1) &&
-		      (scratch & 1) &&
-		      (mode & 1)))
-			command &= ~0x00000001;
-	}
-
-	if (command & 4)
-		command &= ~3;	/* 4X */
-
-	if (command & 2)
-		command &= ~5;	/* 2X (8X for AGP3.0) */
+		cmd = ((cmd & ~AGPSTAT_RQ_DEPTH) |
+		     min_t(u32, (mode & AGPSTAT_RQ_DEPTH),
+			 min_t(u32, (cmd & AGPSTAT_RQ_DEPTH), (tmp & AGPSTAT_RQ_DEPTH))));
+		
+		pci_read_config_dword(device, cap_ptr+AGPSTAT, &agp3);
 
-	if (command & 1)
-		command &= ~6;	/* 1X (4X for AGP3.0) */
-
-	return command;
+		/* Check to see if we are operating in 3.0 mode */
+		if (agp3 & AGPSTAT_MODE_3_0) {
+			agp_v3_parse_one(&mode, &cmd, &tmp);
+		} else {
+			agp_v2_parse_one(&mode, &cmd, &tmp);
+		}
+	}
+	return cmd;
 }
+EXPORT_SYMBOL(agp_collect_device_status);
+
 
 void agp_device_command(u32 command, int agp_v3)
 {
@@ -392,40 +519,68 @@
 		pci_write_config_dword(device, agp + PCI_AGP_COMMAND, command);
 	}
 }
+EXPORT_SYMBOL(agp_device_command);
 
-void agp_generic_enable(u32 mode)
+
+void get_agp_version(struct agp_bridge_data *bridge)
 {
-	u32 command, ncapid, major, minor;
+	u32 ncapid;
+
+	/* Exit early if already set by errata workarounds. */
+	if (agp_bridge->major_version != 0)
+		return;
 
 	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx, &ncapid);
-	major = (ncapid >> 20) & 0xf;
-	minor = (ncapid >> 16) & 0xf;
-	printk(KERN_INFO PFX "Found an AGP %d.%d compliant device.\n",major, minor);
+	agp_bridge->major_version = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf;
+	agp_bridge->minor_version = (ncapid >> AGP_MINOR_VERSION_SHIFT) & 0xf;
+}
+EXPORT_SYMBOL(get_agp_version);
 
-	if(major >= 3) {
-		u32 agp_3_0;
 
-		pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + 0x4, &agp_3_0);
-		/* Check to see if we are operating in 3.0 mode */
-		if((agp_3_0 >> 3) & 0x1) {
-			agp_3_0_node_enable(mode, minor);
-			return;
-		} else {
-			printk (KERN_INFO PFX "not in AGP 3.0 mode, falling back to 2.x\n");
-		}
-	}
+void agp_generic_enable(u32 mode)
+{
+	u32 command;
+	u32 agp3;
+
+	get_agp_version(agp_bridge);
+
+	printk(KERN_INFO PFX "Found an AGP %d.%d compliant device at %s.\n",
+				agp_bridge->major_version,
+				agp_bridge->minor_version,
+				agp_bridge->dev->slot_name);
 
-	/* AGP v<3 */
 	pci_read_config_dword(agp_bridge->dev,
 		      agp_bridge->capndx + PCI_AGP_STATUS, &command);
 
 	command = agp_collect_device_status(mode, command);
-	command |= 0x100;
+	command |= AGPSTAT_AGP_ENABLE;
 
 	pci_write_config_dword(agp_bridge->dev,
 		       agp_bridge->capndx + PCI_AGP_COMMAND, command);
-	agp_device_command(command, 0);
+
+	/* Do AGP version specific frobbing. */
+	if(agp_bridge->major_version >= 3) {
+		pci_read_config_dword(agp_bridge->dev,
+			agp_bridge->capndx+AGPSTAT, &agp3);
+
+		/* Check to see if we are operating in 3.0 mode */
+		if (agp3 & AGPSTAT_MODE_3_0) {
+			/* If we have 3.5, we can do the isoch stuff. */
+			if (agp_bridge->minor_version >= 5)
+				agp_3_5_enable(agp_bridge);
+			agp_device_command(command, TRUE);
+			return;
+		} else {
+			printk (KERN_INFO PFX "Device is in legacy mode,"
+				" falling back to 2.x\n");
+		}
+	}
+
+	/* AGP v<3 */
+	agp_device_command(command, FALSE);
 }
+EXPORT_SYMBOL(agp_generic_enable);
+
 
 int agp_generic_create_gatt_table(void)
 {
@@ -439,7 +594,7 @@
 	struct page *page;
 
 	/* The generic routines can't handle 2 level gatt's */
-	if (agp_bridge->size_type == LVL2_APER_SIZE)
+	if (agp_bridge->driver->size_type == LVL2_APER_SIZE)
 		return -EINVAL;
 
 	table = NULL;
@@ -447,9 +602,9 @@
 	temp = agp_bridge->current_size;
 	size = page_order = num_entries = 0;
 
-	if (agp_bridge->size_type != FIXED_APER_SIZE) {
+	if (agp_bridge->driver->size_type != FIXED_APER_SIZE) {
 		do {
-			switch (agp_bridge->size_type) {
+			switch (agp_bridge->driver->size_type) {
 			case U8_APER_SIZE:
 				size = A_SIZE_8(temp)->size;
 				page_order =
@@ -480,19 +635,17 @@
 
 			if (table == NULL) {
 				i++;
-				switch (agp_bridge->size_type) {
+				switch (agp_bridge->driver->size_type) {
 				case U8_APER_SIZE:
-					agp_bridge->current_size = A_IDX8();
+					agp_bridge->current_size = A_IDX8(agp_bridge);
 					break;
 				case U16_APER_SIZE:
-					agp_bridge->current_size = A_IDX16();
+					agp_bridge->current_size = A_IDX16(agp_bridge);
 					break;
 				case U32_APER_SIZE:
-					agp_bridge->current_size = A_IDX32();
+					agp_bridge->current_size = A_IDX32(agp_bridge);
 					break;
-					/* This case will never really 
-					 * happen. 
-					 */
+					/* This case will never really happen. */
 				case FIXED_APER_SIZE:
 				case LVL2_APER_SIZE:
 				default:
@@ -504,7 +657,7 @@
 			} else {
 				agp_bridge->aperture_size_idx = i;
 			}
-		} while ((table == NULL) && (i < agp_bridge->num_aperture_sizes));
+		} while (!table && (i < agp_bridge->driver->num_aperture_sizes));
 	} else {
 		size = ((struct aper_size_info_fixed *) temp)->size;
 		page_order = ((struct aper_size_info_fixed *) temp)->page_order;
@@ -522,10 +675,11 @@
 
 	agp_bridge->gatt_table_real = (u32 *) table;
 	agp_gatt_table = (void *)table; 
-	CACHE_FLUSH();
+
+	agp_bridge->driver->cache_flush();
 	agp_bridge->gatt_table = ioremap_nocache(virt_to_phys(table),
 					(PAGE_SIZE * (1 << page_order)));
-	CACHE_FLUSH();
+	agp_bridge->driver->cache_flush();
 
 	if (agp_bridge->gatt_table == NULL) {
 		for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
@@ -543,16 +697,7 @@
 
 	return 0;
 }
-
-int agp_generic_suspend(void)
-{
-	return 0;
-}
-
-void agp_generic_resume(void)
-{
-	return;
-}
+EXPORT_SYMBOL(agp_generic_create_gatt_table);
 
 int agp_generic_free_gatt_table(void)
 {
@@ -563,7 +708,7 @@
 
 	temp = agp_bridge->current_size;
 
-	switch (agp_bridge->size_type) {
+	switch (agp_bridge->driver->size_type) {
 	case U8_APER_SIZE:
 		page_order = A_SIZE_8(temp)->page_order;
 		break;
@@ -587,8 +732,7 @@
 
 	/* Do not worry about freeing memory, because if this is
 	 * called, then all agp memory is deallocated and removed
-	 * from the table.
-	 */
+	 * from the table. */
 
 	iounmap(agp_bridge->gatt_table);
 	table = (char *) agp_bridge->gatt_table_real;
@@ -598,8 +742,16 @@
 		ClearPageReserved(page);
 
 	free_pages((unsigned long) agp_bridge->gatt_table_real, page_order);
+
+	agp_gatt_table = NULL;
+	agp_bridge->gatt_table = NULL;
+	agp_bridge->gatt_table_real = NULL;
+	agp_bridge->gatt_bus_addr = 0;
+
 	return 0;
 }
+EXPORT_SYMBOL(agp_generic_free_gatt_table);
+
 
 int agp_generic_insert_memory(agp_memory * mem, off_t pg_start, int type)
 {
@@ -610,7 +762,7 @@
 
 	temp = agp_bridge->current_size;
 
-	switch (agp_bridge->size_type) {
+	switch (agp_bridge->driver->size_type) {
 	case U8_APER_SIZE:
 		num_entries = A_SIZE_8(temp)->num_entries;
 		break;
@@ -647,24 +799,27 @@
 	j = pg_start;
 
 	while (j < (pg_start + mem->page_count)) {
-		if (!PGE_EMPTY(agp_bridge->gatt_table[j])) {
+		if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j])) {
 			return -EBUSY;
 		}
 		j++;
 	}
 
 	if (mem->is_flushed == FALSE) {
-		CACHE_FLUSH();
+		agp_bridge->driver->cache_flush();
 		mem->is_flushed = TRUE;
 	}
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
 		agp_bridge->gatt_table[j] =
-				agp_bridge->mask_memory(mem->memory[i], mem->type);
+				agp_bridge->driver->mask_memory(
+						mem->memory[i], mem->type);
 
-	agp_bridge->tlb_flush(mem);
+	agp_bridge->driver->tlb_flush(mem);
 	return 0;
 }
+EXPORT_SYMBOL(agp_generic_insert_memory);
+
 
 int agp_generic_remove_memory(agp_memory * mem, off_t pg_start, int type)
 {
@@ -681,14 +836,18 @@
 		    (unsigned long) agp_bridge->scratch_page;
 	}
 
-	agp_bridge->tlb_flush(mem);
+	agp_bridge->driver->tlb_flush(mem);
 	return 0;
 }
+EXPORT_SYMBOL(agp_generic_remove_memory);
+
 
 agp_memory *agp_generic_alloc_by_type(size_t page_count, int type)
 {
 	return NULL;
 }
+EXPORT_SYMBOL(agp_generic_alloc_by_type);
+
 
 void agp_generic_free_by_type(agp_memory * curr)
 {
@@ -698,13 +857,13 @@
 	agp_free_key(curr->key);
 	kfree(curr);
 }
+EXPORT_SYMBOL(agp_generic_free_by_type);
+
 
 /* 
  * Basic Page Allocation Routines -
- * These routines handle page allocation
- * and by default they reserve the allocated 
- * memory.  They also handle incrementing the
- * current_memory_agp value, Which is checked
+ * These routines handle page allocation and by default they reserve the allocated 
+ * memory.  They also handle incrementing the current_memory_agp value, Which is checked
  * against a maximum value.
  */
 
@@ -723,6 +882,8 @@
 	atomic_inc(&agp_bridge->current_memory_agp);
 	return page_address(page);
 }
+EXPORT_SYMBOL(agp_generic_alloc_page);
+
 
 void agp_generic_destroy_page(void *addr)
 {
@@ -738,41 +899,50 @@
 	free_page((unsigned long)addr);
 	atomic_dec(&agp_bridge->current_memory_agp);
 }
+EXPORT_SYMBOL(agp_generic_destroy_page);
 
 /* End Basic Page Allocation Routines */
 
+
+/** 
+ * agp_enable  -  initialise the agp point-to-point connection.
+ * 
+ * @mode:	agp mode register value to configure with.
+ */
 void agp_enable(u32 mode)
 {
 	if (agp_bridge->type == NOT_SUPPORTED)
 		return;
-	agp_bridge->agp_enable(mode);
+	agp_bridge->driver->agp_enable(mode);
 }
-
-EXPORT_SYMBOL(agp_free_memory);
-EXPORT_SYMBOL(agp_allocate_memory);
-EXPORT_SYMBOL(agp_copy_info);
-EXPORT_SYMBOL(agp_create_memory);
-EXPORT_SYMBOL(agp_bind_memory);
-EXPORT_SYMBOL(agp_unbind_memory);
-EXPORT_SYMBOL(agp_free_key);
 EXPORT_SYMBOL(agp_enable);
-EXPORT_SYMBOL(agp_bridge);
 
-EXPORT_SYMBOL(agp_generic_alloc_page);
-EXPORT_SYMBOL(agp_generic_destroy_page);
-EXPORT_SYMBOL(agp_generic_suspend);
-EXPORT_SYMBOL(agp_generic_resume);
-EXPORT_SYMBOL(agp_generic_enable);
-EXPORT_SYMBOL(agp_generic_create_gatt_table);
-EXPORT_SYMBOL(agp_generic_free_gatt_table);
-EXPORT_SYMBOL(agp_generic_insert_memory);
-EXPORT_SYMBOL(agp_generic_remove_memory);
-EXPORT_SYMBOL(agp_generic_alloc_by_type);
-EXPORT_SYMBOL(agp_generic_free_by_type);
-EXPORT_SYMBOL(global_cache_flush);
 
-EXPORT_SYMBOL(agp_device_command);
-EXPORT_SYMBOL(agp_collect_device_status);
+#ifdef CONFIG_SMP
+static void ipi_handler(void *null)
+{
+	flush_agp_cache();
+}
+#endif
 
-EXPORT_SYMBOL_GPL(agp_num_entries);
+void global_cache_flush(void)
+{
+#ifdef CONFIG_SMP
+	if (on_each_cpu(ipi_handler, NULL, 1, 1) != 0)
+		panic(PFX "timed out waiting for the other CPUs!\n");
+#else
+	flush_agp_cache();
+#endif
+}
+EXPORT_SYMBOL(global_cache_flush);
+
+unsigned long agp_generic_mask_memory(unsigned long addr, int type)
+{
+	/* memory type is ignored in the generic routine */
+	if (agp_bridge->driver->masks)
+		return addr | agp_bridge->driver->masks[0].mask;
+	else
+		return addr;
+}
+EXPORT_SYMBOL(agp_generic_mask_memory);
 
diff -Nru a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
--- a/drivers/char/agp/hp-agp.c	Wed Apr  9 15:58:29 2003
+++ b/drivers/char/agp/hp-agp.c	Thu May 15 06:50:47 2003
@@ -285,7 +285,7 @@
 	}
 
 	if (mem->is_flushed == FALSE) {
-		CACHE_FLUSH();
+		global_cache_flush();
 		mem->is_flushed = TRUE;
 	}
 
@@ -296,11 +296,11 @@
 		for (k = 0;
 		     k < hp->io_pages_per_kpage;
 		     k++, j++, paddr += hp->io_page_size) {
-			hp->gatt[j] = agp_bridge->mask_memory(paddr, type);
+			hp->gatt[j] = agp_bridge->driver->mask_memory(paddr, type);
 		}
 	}
 
-	agp_bridge->tlb_flush(mem);
+	agp_bridge->driver->tlb_flush(mem);
 	return 0;
 }
 
@@ -319,7 +319,7 @@
 		hp->gatt[i] = agp_bridge->scratch_page;
 	}
 
-	agp_bridge->tlb_flush(mem);
+	agp_bridge->driver->tlb_flush(mem);
 	return 0;
 }
 
@@ -328,58 +328,62 @@
 	return HP_ZX1_PDIR_VALID_BIT | addr;
 }
 
-static int __init hp_zx1_setup (struct pci_dev *pdev __attribute__((unused)))
-{
-	agp_bridge->masks = hp_zx1_masks;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->size_type = FIXED_APER_SIZE;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = hp_zx1_configure;
-	agp_bridge->fetch_size = hp_zx1_fetch_size;
-	agp_bridge->cleanup = hp_zx1_cleanup;
-	agp_bridge->tlb_flush = hp_zx1_tlbflush;
-	agp_bridge->mask_memory = hp_zx1_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = hp_zx1_create_gatt_table;
-	agp_bridge->free_gatt_table = hp_zx1_free_gatt_table;
-	agp_bridge->insert_memory = hp_zx1_insert_memory;
-	agp_bridge->remove_memory = hp_zx1_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->cant_use_aperture = 1;
-	return hp_zx1_ioc_init();
-}
+struct agp_bridge_driver hp_zx1_driver = {
+	.owner			= THIS_MODULE,
+	.size_type		= FIXED_APER_SIZE,
+	.configure		= hp_zx1_configure,
+	.fetch_size		= hp_zx1_fetch_size,
+	.cleanup		= hp_zx1_cleanup,
+	.tlb_flush		= hp_zx1_tlbflush,
+	.mask_memory		= hp_zx1_mask_memory,
+	.masks			= hp_zx1_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= hp_zx1_create_gatt_table,
+	.free_gatt_table	= hp_zx1_free_gatt_table,
+	.insert_memory		= hp_zx1_insert_memory,
+	.remove_memory		= hp_zx1_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+	.cant_use_aperture	= 1,
+};
 
-static int __init agp_find_supported_device(struct pci_dev *dev)
+static int __init agp_hp_probe(struct pci_dev *pdev,
+			       const struct pci_device_id *ent)
 {
-	agp_bridge->dev = dev;
+	struct agp_bridge_data *bridge;
+	int error;
 
 	/* ZX1 LBAs can be either PCI or AGP bridges */
-	if (pci_find_capability(dev, PCI_CAP_ID_AGP)) {
-		printk(KERN_INFO PFX "Detected HP ZX1 AGP chipset at %s\n",
-			dev->slot_name);
-		agp_bridge->type = HP_ZX1;
-		agp_bridge->dev = dev;
-		return hp_zx1_setup(dev);
-	}
-	return -ENODEV;
-}
+	if (!pci_find_capability(pdev, PCI_CAP_ID_AGP))
+		return -ENODEV;
 
-static struct agp_driver hp_agp_driver = {
-	.owner = THIS_MODULE,
-};
+	printk(KERN_INFO PFX "Detected HP ZX1 AGP chipset at %s\n",
+			pdev->slot_name);
+
+	error = hp_zx1_ioc_init();
+	if (error)
+		return error;
+
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
 
-static int __init agp_hp_probe (struct pci_dev *dev, const struct pci_device_id *ent)
+	bridge->driver = &hp_zx1_driver;
+	bridge->dev = pdev;
+
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+}
+
+static void __devexit agp_hp_remove(struct pci_dev *pdev)
 {
-	if (agp_find_supported_device(dev) == 0) {
-		hp_agp_driver.dev = dev;
-		agp_register_driver(&hp_agp_driver);
-		return 0;
-	}
-	return -ENODEV;
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
 }
 
 static struct pci_device_id agp_hp_pci_table[] __initdata = {
@@ -396,26 +400,20 @@
 
 MODULE_DEVICE_TABLE(pci, agp_hp_pci_table);
 
-static struct __initdata pci_driver agp_hp_pci_driver = {
+static struct pci_driver agp_hp_pci_driver = {
 	.name		= "agpgart-hp",
 	.id_table	= agp_hp_pci_table,
 	.probe		= agp_hp_probe,
+	.remove		= agp_hp_remove,
 };
 
 static int __init agp_hp_init(void)
 {
-	int ret_val;
-
-	ret_val = pci_module_init(&agp_hp_pci_driver);
-	if (ret_val)
-		agp_bridge->type = NOT_SUPPORTED;
-
-	return ret_val;
+	return pci_module_init(&agp_hp_pci_driver);
 }
 
 static void __exit agp_hp_cleanup(void)
 {
-	agp_unregister_driver(&hp_agp_driver);
 	pci_unregister_driver(&agp_hp_pci_driver);
 }
 
diff -Nru a/drivers/char/agp/i460-agp.c b/drivers/char/agp/i460-agp.c
--- a/drivers/char/agp/i460-agp.c	Wed Apr  9 15:58:29 2003
+++ b/drivers/char/agp/i460-agp.c	Thu May 15 06:50:47 2003
@@ -69,7 +69,7 @@
 	} *lp_desc;
 } i460;
 
-static const struct aper_size_info_8 i460_sizes[3] =
+static struct aper_size_info_8 i460_sizes[3] =
 {
 	/*
 	 * The 32GB aperture is only available with a 4M GART page size.  Due to the
@@ -107,7 +107,7 @@
 		return 0;
 	}
 
-	values = A_SIZE_8(agp_bridge->aperture_sizes);
+	values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
 
 	pci_read_config_byte(agp_bridge->dev, INTEL_I460_AGPSIZ, &temp);
 
@@ -130,7 +130,7 @@
 	else
 		i460.dynamic_apbase = INTEL_I460_APBASE;
 
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		/*
 		 * Dynamically calculate the proper num_entries and page_order values for
 		 * the define aperture sizes. Take care not to shift off the end of
@@ -140,7 +140,7 @@
 		values[i].page_order = log2((sizeof(u32)*values[i].num_entries) >> PAGE_SHIFT);
 	}
 
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		/* Neglect control bits when matching up size_value */
 		if ((temp & I460_AGPSIZ_MASK) == values[i].size_value) {
 			agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i);
@@ -294,7 +294,7 @@
 
 	j = io_pg_start;
 	while (j < (io_pg_start + I460_IOPAGES_PER_KPAGE * mem->page_count)) {
-		if (!PGE_EMPTY(RD_GATT(j))) {
+		if (!PGE_EMPTY(agp_bridge, RD_GATT(j))) {
 			pr_debug("i460_insert_memory_small_io_page: GATT[%d]=0x%x is busy\n",
 				 j, RD_GATT(j));
 			return -EBUSY;
@@ -306,7 +306,7 @@
 	for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
 		paddr = mem->memory[i];
 		for (k = 0; k < I460_IOPAGES_PER_KPAGE; k++, j++, paddr += io_page_size)
-			WR_GATT(j, agp_bridge->mask_memory(paddr, mem->type));
+			WR_GATT(j, agp_bridge->driver->mask_memory(paddr, mem->type));
 	}
 	WR_FLUSH_GATT(j - 1);
 	return 0;
@@ -417,7 +417,7 @@
 			if (i460_alloc_large_page(lp) < 0)
 				return -ENOMEM;
 			pg = lp - i460.lp_desc;
-			WR_GATT(pg, agp_bridge->mask_memory(lp->paddr, 0));
+			WR_GATT(pg, agp_bridge->driver->mask_memory(lp->paddr, 0));
 			WR_FLUSH_GATT(pg);
 		}
 
@@ -439,7 +439,7 @@
 	struct lp_desc *start, *end, *lp;
 	void *temp;
 
-	temp = agp_bridge->current_size;
+	temp = agp_bridge->driver->current_size;
 	num_entries = A_SIZE_8(temp)->num_entries;
 
 	/* Figure out what pg_start means in terms of our large GART pages */
@@ -519,64 +519,69 @@
 static unsigned long i460_mask_memory (unsigned long addr, int type)
 {
 	/* Make sure the returned address is a valid GATT entry */
-	return (agp_bridge->masks[0].mask
+	return (agp_bridge->driver->masks[0].mask
 		| (((addr & ~((1 << I460_IO_PAGE_SHIFT) - 1)) & 0xffffff000) >> 12));
 }
 
-static int __init intel_i460_setup (struct pci_dev *pdev __attribute__((unused)))
-{
-	agp_bridge->masks = i460_masks;
-	agp_bridge->aperture_sizes = (void *) i460_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 3;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = i460_configure;
-	agp_bridge->fetch_size = i460_fetch_size;
-	agp_bridge->cleanup = i460_cleanup;
-	agp_bridge->tlb_flush = i460_tlb_flush;
-	agp_bridge->mask_memory = i460_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = i460_create_gatt_table;
-	agp_bridge->free_gatt_table = i460_free_gatt_table;
+struct agp_bridge_driver intel_i460_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= i460_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 3,
+	.configure		= i460_configure,
+	.fetch_size		= i460_fetch_size,
+	.cleanup		= i460_cleanup,
+	.tlb_flush		= i460_tlb_flush,
+	.mask_memory		= i460_mask_memory,
+	.masks			= i460_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= i460_create_gatt_table,
+	.free_gatt_table	= i460_free_gatt_table,
 #if I460_LARGE_IO_PAGES
-	agp_bridge->insert_memory = i460_insert_memory;
-	agp_bridge->remove_memory = i460_remove_memory;
-	agp_bridge->agp_alloc_page = i460_alloc_page;
-	agp_bridge->agp_destroy_page = i460_destroy_page;
+	.insert_memory		= i460_insert_memory,
+	.remove_memory		= i460_remove_memory,
+	.agp_alloc_page		= i460_alloc_page,
+	.agp_destroy_page	= i460_destroy_page,
 #else
-	agp_bridge->insert_memory = i460_insert_memory_small_io_page;
-	agp_bridge->remove_memory = i460_remove_memory_small_io_page;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
+	.insert_memory		= i460_insert_memory_small_io_page,
+	.remove_memory		= i460_remove_memory_small_io_page,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
 #endif
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 1;
-	return 0;
-}
-
-static struct agp_driver i460_agp_driver = {
-	.owner = THIS_MODULE,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.cant_use_aperture	= 1,
 };
 
-static int __init agp_intel_i460_probe (struct pci_dev *dev, const struct pci_device_id *ent)
+static int __init agp_intel_i460_probe(struct pci_dev *pdev,
+				       const struct pci_device_id *ent)
 {
-	u8 cap_ptr = 0;
+	struct agp_bridge_data *bridge;
+	u8 cap_ptr;
 
-	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
-	if (cap_ptr == 0)
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (!cap_ptr)
 		return -ENODEV;
 
-	agp_bridge->dev = dev;
-	agp_bridge->capndx = cap_ptr;
-	intel_i460_setup(dev);
-	i460_agp_driver.dev = dev;
-	agp_register_driver(&i460_agp_driver);
-	return 0;
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
+
+	bridge->driver = &intel_i460_driver;
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
+
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+}
+
+static void __devexit agp_intel_i460_remove(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
 }
 
 static struct pci_device_id agp_intel_i460_pci_table[] __initdata = {
@@ -593,26 +598,20 @@
 
 MODULE_DEVICE_TABLE(pci, agp_intel_i460_pci_table);
 
-static struct __initdata pci_driver agp_intel_i460_pci_driver = {
+static struct pci_driver agp_intel_i460_pci_driver = {
 	.name		= "agpgart-intel-i460",
 	.id_table	= agp_intel_i460_pci_table,
 	.probe		= agp_intel_i460_probe,
+	.remove		= agp_intel_i460_remove,
 };
 
 static int __init agp_intel_i460_init(void)
 {
-	int ret_val;
-
-	ret_val = pci_module_init(&agp_intel_i460_pci_driver);
-	if (ret_val)
-		agp_bridge->type = NOT_SUPPORTED;
-
-	return ret_val;
+	return pci_module_init(&agp_intel_i460_pci_driver);
 }
 
 static void __exit agp_intel_i460_cleanup(void)
 {
-	agp_unregister_driver(&i460_agp_driver);
 	pci_unregister_driver(&agp_intel_i460_pci_driver);
 }
 
diff -Nru a/drivers/char/agp/intel-agp.c b/drivers/char/agp/intel-agp.c
--- a/drivers/char/agp/intel-agp.c	Wed Apr  9 15:56:26 2003
+++ b/drivers/char/agp/intel-agp.c	Thu May 15 06:50:47 2003
@@ -45,7 +45,7 @@
 	struct aper_size_info_fixed *values;
 
 	pci_read_config_dword(agp_bridge->dev, I810_SMRAM_MISCC, &smram_miscc);
-	values = A_SIZE_FIX(agp_bridge->aperture_sizes);
+	values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
 
 	if ((smram_miscc & I810_GMS) == I810_GMS_DISABLE) {
 		printk(KERN_WARNING PFX "i810 is disabled\n");
@@ -89,9 +89,9 @@
 	agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
 	OUTREG32(intel_i810_private.registers, I810_PGETBL_CTL,
 		 agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED);
-	CACHE_FLUSH();
+	global_cache_flush();
 
-	if (agp_bridge->needs_scratch_page == TRUE) {
+	if (agp_bridge->driver->needs_scratch_page) {
 		for (i = 0; i < current_size->num_entries; i++) {
 			OUTREG32(intel_i810_private.registers,
 				 I810_PTE_BASE + (i * 4),
@@ -130,23 +130,22 @@
 		return -EINVAL;
 	}
 	for (j = pg_start; j < (pg_start + mem->page_count); j++) {
-		if (!PGE_EMPTY(agp_bridge->gatt_table[j])) {
+		if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j]))
 			return -EBUSY;
-		}
 	}
 
 	if (type != 0 || mem->type != 0) {
 		if ((type == AGP_DCACHE_MEMORY) && (mem->type == AGP_DCACHE_MEMORY)) {
 			/* special insert */
-			CACHE_FLUSH();
+			global_cache_flush();
 			for (i = pg_start; i < (pg_start + mem->page_count); i++) {
 				OUTREG32(intel_i810_private.registers,
 					 I810_PTE_BASE + (i * 4),
 					 (i * 4096) | I810_PTE_LOCAL |
 					 I810_PTE_VALID);
 			}
-			CACHE_FLUSH();
-			agp_bridge->tlb_flush(mem);
+			global_cache_flush();
+			agp_bridge->driver->tlb_flush(mem);
 			return 0;
 		}
 		if((type == AGP_PHYS_MEMORY) && (mem->type == AGP_PHYS_MEMORY))
@@ -155,15 +154,15 @@
 	}
 
 insert:
-	CACHE_FLUSH();
+	global_cache_flush();
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
 		OUTREG32(intel_i810_private.registers,
 			I810_PTE_BASE + (j * 4),
-			agp_bridge->mask_memory(mem->memory[i], mem->type));
+			agp_bridge->driver->mask_memory(mem->memory[i], mem->type));
 	}
-	CACHE_FLUSH();
+	global_cache_flush();
 
-	agp_bridge->tlb_flush(mem);
+	agp_bridge->driver->tlb_flush(mem);
 	return 0;
 }
 
@@ -178,58 +177,61 @@
 			 agp_bridge->scratch_page);
 	}
 
-	CACHE_FLUSH();
-	agp_bridge->tlb_flush(mem);
+	global_cache_flush();
+	agp_bridge->driver->tlb_flush(mem);
 	return 0;
 }
 
+/*
+ * The i810/i830 requires a physical address to program its mouse
+ * pointer into hardware.
+ * However the Xserver still writes to it through the agp aperture.
+ */
+static agp_memory *alloc_agpphysmem_i8xx(size_t pg_count, int type)
+{
+	agp_memory *new;
+	void *addr;
+
+	if (pg_count != 1)
+		return NULL;
+
+	addr = agp_bridge->driver->agp_alloc_page();
+	if (addr == NULL)
+		return NULL;
+
+	new = agp_create_memory(1);
+	if (new == NULL)
+		return NULL;
+
+	new->memory[0] = virt_to_phys(addr);
+	new->page_count = 1;
+	new->num_scratch_pages = 1;
+	new->type = AGP_PHYS_MEMORY;
+	new->physical = new->memory[0];
+	return new;
+}
+
 static agp_memory *intel_i810_alloc_by_type(size_t pg_count, int type)
 {
 	agp_memory *new;
 
 	if (type == AGP_DCACHE_MEMORY) {
-		if (pg_count != intel_i810_private.num_dcache_entries) {
+		if (pg_count != intel_i810_private.num_dcache_entries)
 			return NULL;
-		}
-		new = agp_create_memory(1);
 
-		if (new == NULL) {
+		new = agp_create_memory(1);
+		if (new == NULL)
 			return NULL;
-		}
+
 		new->type = AGP_DCACHE_MEMORY;
 		new->page_count = pg_count;
 		new->num_scratch_pages = 0;
 		vfree(new->memory);
 		return new;
 	}
-	if(type == AGP_PHYS_MEMORY) {
-		void *addr;
-		/* The I810 requires a physical address to program
-		 * it's mouse pointer into hardware.  However the
-		 * Xserver still writes to it through the agp
-		 * aperture
-		 */
-		if (pg_count != 1)
-			return NULL;
-
-		new = agp_create_memory(1);
-		if (new == NULL)
-			return NULL;
-
-		addr = agp_bridge->agp_alloc_page();
+	if (type == AGP_PHYS_MEMORY)
+		return(alloc_agpphysmem_i8xx(pg_count, type));
 
-		if (addr == NULL) {
-			/* Free this structure */
-			agp_free_memory(new);
-			return NULL;
-		}
-		new->memory[0] = virt_to_phys(addr);
-		new->page_count = 1;
-		new->num_scratch_pages = 1;
-		new->type = AGP_PHYS_MEMORY;
-		new->physical = new->memory[0];
-		return new;
-	}
 	return NULL;
 }
 
@@ -237,7 +239,7 @@
 {
 	agp_free_key(curr->key);
 	if(curr->type == AGP_PHYS_MEMORY) {
-		agp_bridge->agp_destroy_page(phys_to_virt(curr->memory[0]));
+		agp_bridge->driver->agp_destroy_page(phys_to_virt(curr->memory[0]));
 		vfree(curr->memory);
 	}
 	kfree(curr);
@@ -246,39 +248,7 @@
 static unsigned long intel_i810_mask_memory(unsigned long addr, int type)
 {
 	/* Type checking must be done elsewhere */
-	return addr | agp_bridge->masks[type].mask;
-}
-
-static int __init intel_i810_setup(struct pci_dev *i810_dev)
-{
-	intel_i810_private.i810_dev = i810_dev;
-
-	agp_bridge->masks = intel_i810_masks;
-	agp_bridge->aperture_sizes = (void *) intel_i810_sizes;
-	agp_bridge->size_type = FIXED_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 2;
-	agp_bridge->dev_private_data = (void *) &intel_i810_private;
-	agp_bridge->needs_scratch_page = TRUE;
-	agp_bridge->configure = intel_i810_configure;
-	agp_bridge->fetch_size = intel_i810_fetch_size;
-	agp_bridge->cleanup = intel_i810_cleanup;
-	agp_bridge->tlb_flush = intel_i810_tlbflush;
-	agp_bridge->mask_memory = intel_i810_mask_memory;
-	agp_bridge->agp_enable = intel_i810_agp_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = intel_i810_insert_entries;
-	agp_bridge->remove_memory = intel_i810_remove_entries;
-	agp_bridge->alloc_by_type = intel_i810_alloc_by_type;
-	agp_bridge->free_by_type = intel_i810_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-
-	return 0;
+	return addr | agp_bridge->driver->masks[type].mask;
 }
 
 static struct aper_size_info_fixed intel_i830_sizes[] =
@@ -379,10 +349,11 @@
 	temp &= 0xfff80000;
 
 	intel_i830_private.registers = (volatile u8 *) ioremap(temp,128 * 4096);
-	if (!intel_i830_private.registers) return (-ENOMEM);
+	if (!intel_i830_private.registers)
+		return (-ENOMEM);
 
 	temp = INREG32(intel_i830_private.registers,I810_PGETBL_CTL) & 0xfffff000;
-	CACHE_FLUSH();
+	global_cache_flush();
 
 	/* we have to call this as early as possible after the MMIO base address is known */
 	intel_i830_init_gtt_entries();
@@ -407,7 +378,7 @@
 	u16 gmch_ctrl;
 	struct aper_size_info_fixed *values;
 
-	values = A_SIZE_FIX(agp_bridge->aperture_sizes);
+	values = A_SIZE_FIX(agp_bridge->driver->aperture_sizes);
 
 	if (agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82830_HB &&
 	    agp_bridge->dev->device != PCI_DEVICE_ID_INTEL_82845G_HB) {
@@ -449,9 +420,9 @@
 	pci_write_config_word(agp_bridge->dev,I830_GMCH_CTRL,gmch_ctrl);
 
 	OUTREG32(intel_i830_private.registers,I810_PGETBL_CTL,agp_bridge->gatt_bus_addr | I810_PGETBL_ENABLED);
-	CACHE_FLUSH();
+	global_cache_flush();
 
-	if (agp_bridge->needs_scratch_page == TRUE)
+	if (agp_bridge->driver->needs_scratch_page)
 		for (i = intel_i830_private.gtt_entries; i < current_size->num_entries; i++)
 			OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page);
 
@@ -490,15 +461,15 @@
 		(mem->type != 0 && mem->type != AGP_PHYS_MEMORY))
 		return (-EINVAL);
 
-	CACHE_FLUSH();
+	global_cache_flush();
 
 	for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
 		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (j * 4),
-			agp_bridge->mask_memory(mem->memory[i], mem->type));
+			agp_bridge->driver->mask_memory(mem->memory[i], mem->type));
 
-	CACHE_FLUSH();
+	global_cache_flush();
 
-	agp_bridge->tlb_flush(mem);
+	agp_bridge->driver->tlb_flush(mem);
 
 	return(0);
 }
@@ -507,7 +478,7 @@
 {
 	int i;
 
-	CACHE_FLUSH ();
+	global_cache_flush();
 
 	if (pg_start < intel_i830_private.gtt_entries) {
 		printk ("Trying to disable local/stolen memory\n");
@@ -517,90 +488,22 @@
 	for (i = pg_start; i < (mem->page_count + pg_start); i++)
 		OUTREG32(intel_i830_private.registers,I810_PTE_BASE + (i * 4),agp_bridge->scratch_page);
 
-	CACHE_FLUSH();
+	global_cache_flush();
 
-	agp_bridge->tlb_flush(mem);
+	agp_bridge->driver->tlb_flush(mem);
 
 	return (0);
 }
 
 static agp_memory *intel_i830_alloc_by_type(size_t pg_count,int type)
 {
-	agp_memory *nw;
-
-	/* always return NULL for now */
-	if (type == AGP_DCACHE_MEMORY) return(NULL);
-
-	if (type == AGP_PHYS_MEMORY) {
-		void *addr;
-
-		/* The i830 requires a physical address to program
-		 * it's mouse pointer into hardware. However the
-		 * Xserver still writes to it through the agp
-		 * aperture
-		 */
-
-		if (pg_count != 1) return(NULL);
-
-		nw = agp_create_memory(1);
-
-		if (nw == NULL) return(NULL);
-
-		addr = agp_bridge->agp_alloc_page();
-		if (addr == NULL) {
-			/* free this structure */
-			agp_free_memory(nw);
-			return(NULL);
-		}
-
-		nw->memory[0] = virt_to_phys(addr);
-		nw->page_count = 1;
-		nw->num_scratch_pages = 1;
-		nw->type = AGP_PHYS_MEMORY;
-		nw->physical = nw->memory[0];
-		return(nw);
-	}
+	if (type == AGP_PHYS_MEMORY)
+		return(alloc_agpphysmem_i8xx(pg_count, type));
 
+	/* always return NULL for other allocation types for now */
 	return(NULL);
 }
 
-static int __init intel_i830_setup(struct pci_dev *i830_dev)
-{
-	intel_i830_private.i830_dev = i830_dev;
-
-	agp_bridge->masks = intel_i810_masks;
-	agp_bridge->aperture_sizes = (void *) intel_i830_sizes;
-	agp_bridge->size_type = FIXED_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 2;
-
-	agp_bridge->dev_private_data = (void *) &intel_i830_private;
-	agp_bridge->needs_scratch_page = TRUE;
-
-	agp_bridge->configure = intel_i830_configure;
-	agp_bridge->fetch_size = intel_i830_fetch_size;
-	agp_bridge->cleanup = intel_i830_cleanup;
-	agp_bridge->tlb_flush = intel_i810_tlbflush;
-	agp_bridge->mask_memory = intel_i810_mask_memory;
-	agp_bridge->agp_enable = intel_i810_agp_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-
-	agp_bridge->create_gatt_table = intel_i830_create_gatt_table;
-	agp_bridge->free_gatt_table = intel_i830_free_gatt_table;
-
-	agp_bridge->insert_memory = intel_i830_insert_entries;
-	agp_bridge->remove_memory = intel_i830_remove_entries;
-	agp_bridge->alloc_by_type = intel_i830_alloc_by_type;
-	agp_bridge->free_by_type = intel_i810_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-
-	return(0);
-}
-
 static int intel_fetch_size(void)
 {
 	int i;
@@ -608,9 +511,9 @@
 	struct aper_size_info_16 *values;
 
 	pci_read_config_word(agp_bridge->dev, INTEL_APSIZE, &temp);
-	values = A_SIZE_16(agp_bridge->aperture_sizes);
+	values = A_SIZE_16(agp_bridge->driver->aperture_sizes);
 
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		if (temp == values[i].size_value) {
 			agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i);
 			agp_bridge->aperture_size_idx = i;
@@ -621,22 +524,14 @@
 	return 0;
 }
 
-static int intel_8xx_fetch_size(void)
+static int __intel_8xx_fetch_size(u8 temp)
 {
 	int i;
-	u8 temp;
 	struct aper_size_info_8 *values;
 
-	pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
-
-	/* Intel 815 chipsets have a _weird_ APSIZE register with only
-	 * one non-reserved bit, so mask the others out ... */
-	if (agp_bridge->type == INTEL_I815)
-		temp &= (1 << 3);
+	values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
 
-	values = A_SIZE_8(agp_bridge->aperture_sizes);
-
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		if (temp == values[i].size_value) {
 			agp_bridge->previous_size =
 				agp_bridge->current_size = (void *) (values + i);
@@ -647,6 +542,25 @@
 	return 0;
 }
 
+static int intel_8xx_fetch_size(void)
+{
+	u8 temp;
+
+	pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
+	return __intel_8xx_fetch_size(temp);
+}
+
+static int intel_815_fetch_size(void)
+{
+	u8 temp;
+
+	/* Intel 815 chipsets have a _weird_ APSIZE register with only
+	 * one non-reserved bit, so mask the others out ... */
+	pci_read_config_byte(agp_bridge->dev, INTEL_APSIZE, &temp);
+	temp &= (1 << 3);
+
+	return __intel_8xx_fetch_size(temp);
+}
 
 static void intel_tlbflush(agp_memory * mem)
 {
@@ -868,11 +782,6 @@
 	return 0;
 }
 
-static void intel_845_resume(void)
-{
-	intel_845_configure();
-}
-
 static int intel_850_configure(void)
 {
 	u32 temp;
@@ -988,17 +897,6 @@
 	return 0;
 }
 
-static unsigned long intel_mask_memory(unsigned long addr, int type)
-{
-	/* Memory type is ignored */
-	return addr | agp_bridge->masks[0].mask;
-}
-
-static void intel_resume(void)
-{
-	intel_configure();
-}
-
 /* Setup function */
 static struct gatt_mask intel_generic_masks[] =
 {
@@ -1041,584 +939,480 @@
 	{32, 8192, 3, 56}
 };
 
-static int __init intel_generic_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = intel_generic_masks;
-	agp_bridge->aperture_sizes = (void *) intel_generic_sizes;
-	agp_bridge->size_type = U16_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = intel_configure;
-	agp_bridge->fetch_size = intel_fetch_size;
-	agp_bridge->cleanup = intel_cleanup;
-	agp_bridge->tlb_flush = intel_tlbflush;
-	agp_bridge->mask_memory = intel_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = intel_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
+struct agp_bridge_driver intel_generic_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_generic_sizes,
+	.size_type		= U16_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= intel_configure,
+	.fetch_size		= intel_fetch_size,
+	.cleanup		= intel_cleanup,
+	.tlb_flush		= intel_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
-static int __init intel_815_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = intel_generic_masks;
-	agp_bridge->aperture_sizes = (void *) intel_815_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 2;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = intel_815_configure;
-	agp_bridge->fetch_size = intel_8xx_fetch_size;
-	agp_bridge->cleanup = intel_8xx_cleanup;
-	agp_bridge->tlb_flush = intel_8xx_tlbflush;
-	agp_bridge->mask_memory = intel_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
+struct agp_bridge_driver intel_810_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_i810_sizes,
+	.size_type		= FIXED_APER_SIZE,
+	.num_aperture_sizes	= 2,
+	.needs_scratch_page	= TRUE,
+	.configure		= intel_i810_configure,
+	.fetch_size		= intel_i810_fetch_size,
+	.cleanup		= intel_i810_cleanup,
+	.tlb_flush		= intel_i810_tlbflush,
+	.mask_memory		= intel_i810_mask_memory,
+	.masks			= intel_i810_masks,
+	.agp_enable		= intel_i810_agp_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= intel_i810_insert_entries,
+	.remove_memory		= intel_i810_remove_entries,
+	.alloc_by_type		= intel_i810_alloc_by_type,
+	.free_by_type		= intel_i810_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
 
-static int __init intel_820_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = intel_generic_masks;
-	agp_bridge->aperture_sizes = (void *) intel_8xx_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = intel_820_configure;
-	agp_bridge->fetch_size = intel_8xx_fetch_size;
-	agp_bridge->cleanup = intel_820_cleanup;
-	agp_bridge->tlb_flush = intel_820_tlbflush;
-	agp_bridge->mask_memory = intel_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
+struct agp_bridge_driver intel_815_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_815_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 2,
+	.configure		= intel_815_configure,
+	.fetch_size		= intel_815_fetch_size,
+	.cleanup		= intel_8xx_cleanup,
+	.tlb_flush		= intel_8xx_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= intel_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
-static int __init intel_830mp_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = intel_generic_masks;
-	agp_bridge->aperture_sizes = (void *) intel_830mp_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 4;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = intel_830mp_configure;
-	agp_bridge->fetch_size = intel_8xx_fetch_size;
-	agp_bridge->cleanup = intel_8xx_cleanup;
-	agp_bridge->tlb_flush = intel_8xx_tlbflush;
-	agp_bridge->mask_memory = intel_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
+struct agp_bridge_driver intel_830_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_i830_sizes,
+	.size_type		= FIXED_APER_SIZE,
+	.num_aperture_sizes 	= 2,
+	.needs_scratch_page	= TRUE,
+	.configure		= intel_i830_configure,
+	.fetch_size		= intel_i830_fetch_size,
+	.cleanup		= intel_i830_cleanup,
+	.tlb_flush		= intel_i810_tlbflush,
+	.mask_memory		= intel_i810_mask_memory,
+	.masks			= intel_i810_masks,
+	.agp_enable		= intel_i810_agp_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= intel_i830_create_gatt_table,
+	.free_gatt_table	= intel_i830_free_gatt_table,
+	.insert_memory		= intel_i830_insert_entries,
+	.remove_memory		= intel_i830_remove_entries,
+	.alloc_by_type		= intel_i830_alloc_by_type,
+	.free_by_type		= intel_i810_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
-static int __init intel_840_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = intel_generic_masks;
-	agp_bridge->aperture_sizes = (void *) intel_8xx_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = intel_840_configure;
-	agp_bridge->fetch_size = intel_8xx_fetch_size;
-	agp_bridge->cleanup = intel_8xx_cleanup;
-	agp_bridge->tlb_flush = intel_8xx_tlbflush;
-	agp_bridge->mask_memory = intel_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
 
-static int __init intel_845_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = intel_generic_masks;
-	agp_bridge->aperture_sizes = (void *) intel_8xx_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = intel_845_configure;
-	agp_bridge->fetch_size = intel_8xx_fetch_size;
-	agp_bridge->cleanup = intel_8xx_cleanup;
-	agp_bridge->tlb_flush = intel_8xx_tlbflush;
-	agp_bridge->mask_memory = intel_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = intel_845_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
+struct agp_bridge_driver intel_820_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_8xx_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= intel_820_configure,
+	.fetch_size		= intel_8xx_fetch_size,
+	.cleanup		= intel_820_cleanup,
+	.tlb_flush		= intel_820_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= intel_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
-static int __init intel_850_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = intel_generic_masks;
-	agp_bridge->aperture_sizes = (void *) intel_8xx_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = intel_850_configure;
-	agp_bridge->fetch_size = intel_8xx_fetch_size;
-	agp_bridge->cleanup = intel_8xx_cleanup;
-	agp_bridge->tlb_flush = intel_8xx_tlbflush;
-	agp_bridge->mask_memory = intel_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
+struct agp_bridge_driver intel_830mp_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_830mp_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 4,
+	.configure		= intel_830mp_configure,
+	.fetch_size		= intel_8xx_fetch_size,
+	.cleanup		= intel_8xx_cleanup,
+	.tlb_flush		= intel_8xx_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= intel_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
-static int __init intel_860_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = intel_generic_masks;
-	agp_bridge->aperture_sizes = (void *) intel_8xx_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = intel_860_configure;
-	agp_bridge->fetch_size = intel_8xx_fetch_size;
-	agp_bridge->cleanup = intel_8xx_cleanup;
-	agp_bridge->tlb_flush = intel_8xx_tlbflush;
-	agp_bridge->mask_memory = intel_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
+struct agp_bridge_driver intel_840_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_8xx_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= intel_840_configure,
+	.fetch_size		= intel_8xx_fetch_size,
+	.cleanup		= intel_8xx_cleanup,
+	.tlb_flush		= intel_8xx_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= intel_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
-static int __init intel_7505_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = intel_generic_masks;
-	agp_bridge->aperture_sizes = (void *) intel_8xx_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = intel_7505_configure;
-	agp_bridge->fetch_size = intel_8xx_fetch_size;
-	agp_bridge->cleanup = intel_8xx_cleanup;
-	agp_bridge->tlb_flush = intel_8xx_tlbflush;
-	agp_bridge->mask_memory = intel_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
-struct agp_device_ids intel_agp_device_ids[] __initdata =
-{
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82443LX_0,
-		.chipset	= INTEL_LX,
-		.chipset_name	= "440LX",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82443BX_0,
-		.chipset	= INTEL_BX,
-		.chipset_name	= "440BX",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82443GX_0,
-		.chipset	= INTEL_GX,
-		.chipset_name	= "440GX",
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82815_MC,
-		.chipset	= INTEL_I815,
-		.chipset_name	= "i815",
-		.chipset_setup	= intel_815_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82820_HB,
-		.chipset	= INTEL_I820,
-		.chipset_name	= "i820",
-		.chipset_setup	= intel_820_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82820_UP_HB,
-		.chipset	= INTEL_I820,
-		.chipset_name	= "i820",
-		.chipset_setup	= intel_820_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82830_HB,
-		.chipset	= INTEL_I830_M,
-		.chipset_name	= "830M",
-		.chipset_setup	= intel_830mp_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82840_HB,
-		.chipset	= INTEL_I840,
-		.chipset_name	= "i840",
-		.chipset_setup	= intel_840_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82845_HB,
-		.chipset	= INTEL_I845,
-		.chipset_name	= "i845",
-		.chipset_setup	= intel_845_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82845G_HB,
-		.chipset	= INTEL_I845_G,
-		.chipset_name	= "845G",
-		.chipset_setup	= intel_845_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82850_HB,
-		.chipset	= INTEL_I850,
-		.chipset_name	= "i850",
-		.chipset_setup	= intel_850_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82855_HB,
-		.chipset	= INTEL_I855_PM,
-		.chipset_name	= "855PM",
-		.chipset_setup	= intel_845_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82860_HB,
-		.chipset	= INTEL_I860,
-		.chipset_name	= "i860",
-		.chipset_setup	= intel_860_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_82865_HB,
-		.chipset	= INTEL_I865_G,
-		.chipset_name	= "865G",
-		.chipset_setup	= intel_845_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_7505_0,
-		.chipset	= INTEL_E7505,
-		.chipset_name	= "E7505",
-		.chipset_setup	= intel_7505_setup
-	},
-	{
-		.device_id	= PCI_DEVICE_ID_INTEL_7205_0,
-		.chipset	= INTEL_E7505,
-		.chipset_name	= "E7205",
-		.chipset_setup	= intel_7505_setup
-	},
-	{ }, /* dummy final entry, always present */
+struct agp_bridge_driver intel_845_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_8xx_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= intel_845_configure,
+	.fetch_size		= intel_8xx_fetch_size,
+	.cleanup		= intel_8xx_cleanup,
+	.tlb_flush		= intel_8xx_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= intel_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
+struct agp_bridge_driver intel_850_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_8xx_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= intel_850_configure,
+	.fetch_size		= intel_8xx_fetch_size,
+	.cleanup		= intel_8xx_cleanup,
+	.tlb_flush		= intel_8xx_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= intel_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
+
+struct agp_bridge_driver intel_860_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_8xx_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= intel_860_configure,
+	.fetch_size		= intel_8xx_fetch_size,
+	.cleanup		= intel_8xx_cleanup,
+	.tlb_flush		= intel_8xx_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= intel_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
+
+struct agp_bridge_driver intel_7505_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= intel_8xx_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= intel_7505_configure,
+	.fetch_size		= intel_8xx_fetch_size,
+	.cleanup		= intel_8xx_cleanup,
+	.tlb_flush		= intel_8xx_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= intel_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
-/* scan table above for supported devices */
-static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
+static int find_i810(u16 device, const char *name)
 {
-	int j=0;
-	struct agp_device_ids *devs;
-	
-	devs = intel_agp_device_ids;
+	struct pci_dev *i810_dev;
 
-	while (devs[j].chipset_name != NULL) {
-		if (pdev->device == devs[j].device_id) {
-			printk (KERN_INFO PFX "Detected Intel %s chipset\n",
-				devs[j].chipset_name);
-			agp_bridge->type = devs[j].chipset;
-
-			if (devs[j].chipset_setup != NULL)
-				return devs[j].chipset_setup(pdev);
-			else
-				return intel_generic_setup(pdev);
-		}
-		j++;
+	i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL);
+	if (!i810_dev) {
+		printk(KERN_ERR PFX "Detected an Intel %s Chipset, "
+				"but could not find the secondary device.\n",
+				name);
+		return 0;
 	}
-	j--;
+	
+	intel_i810_private.i810_dev = i810_dev;
+	return 1;
+}
 
-	/* try init anyway, if user requests it */
-	if (agp_try_unsupported) {
-		printk(KERN_WARNING PFX "Trying generic Intel routines"
-			" for device id: %04x\n", pdev->device);
-		agp_bridge->type = INTEL_GENERIC;
-		return intel_generic_setup(pdev);
-	}
+static int find_i830(u16 device)
+{
+	struct pci_dev *i830_dev;
 
-	printk(KERN_ERR PFX "Unsupported Intel chipset (device id: %04x),"
-		" you might want to try agp_try_unsupported=1.\n", pdev->device);
-	return -ENODEV;
-}
+	i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL, device, NULL);
+	if (i830_dev && PCI_FUNC(i830_dev->devfn) != 0) {
+		i830_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
+				device, i830_dev);
+	}
 
+	if (!i830_dev)
+		return 0;
 
-/* Supported Device Scanning routine */
+	intel_i830_private.i830_dev = i830_dev;
+	return 1;
+}
 
-static int __init agp_find_supported_device(struct pci_dev *dev)
+static int __init agp_intel_probe(struct pci_dev *pdev,
+				  const struct pci_device_id *ent)
 {
-	struct pci_dev *i810_dev;
+	struct agp_bridge_data *bridge;
+	char *name = "(unknown)";
 	u8 cap_ptr = 0;
 
-	agp_bridge->dev = dev;
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
 
-	/* This shit needs moving into tables/init-routines. */
-	switch (dev->device) {
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_INTEL_82443LX_0:
+		bridge->driver = &intel_generic_driver;
+		name = "440LX";
+		break;
+	case PCI_DEVICE_ID_INTEL_82443BX_0:
+		bridge->driver = &intel_generic_driver;
+		name = "440BX";
+		break;
+	case PCI_DEVICE_ID_INTEL_82443GX_0:
+		bridge->driver = &intel_generic_driver;
+		name = "440GX";
+		break;
 	case PCI_DEVICE_ID_INTEL_82810_MC1:
-		i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG1, NULL);
-		if (i810_dev == NULL) {
-			printk(KERN_ERR PFX "Detected an Intel i810,"
-				" but could not find the secondary device.\n");
-			return -ENODEV;
-		}
-		printk(KERN_INFO PFX "Detected an Intel i810 Chipset.\n");
-		agp_bridge->type = INTEL_I810;
-		return intel_i810_setup (i810_dev);
-
+		if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG1, "i810"))
+			goto fail;
+		bridge->driver = &intel_810_driver;
+		name = "i810";
+		break;
 	case PCI_DEVICE_ID_INTEL_82810_MC3:
-		i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810_IG3, NULL);
-		if (i810_dev == NULL) {
-			printk(KERN_ERR PFX "Detected an Intel i810 DC100, but could not find the "
-				"secondary device.\n");
-			return -ENODEV;
-		}
-		printk(KERN_INFO PFX "Detected an Intel i810 DC100 Chipset.\n");
-		agp_bridge->type = INTEL_I810;
-		return intel_i810_setup(i810_dev);
-
+		if (!find_i810(PCI_DEVICE_ID_INTEL_82810_IG3, "i810 DC100"))
+			goto fail;
+		bridge->driver = &intel_810_driver;
+		name = "i810 DC100";
+		break;
 	case PCI_DEVICE_ID_INTEL_82810E_MC:
-		i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82810E_IG, NULL);
-		if (i810_dev == NULL) {
-			printk(KERN_ERR PFX "Detected an Intel i810 E"
-				", but could not find the secondary device.\n");
-			return -ENODEV;
-		}
-		printk(KERN_INFO PFX "Detected an Intel i810 E Chipset.\n");
-		agp_bridge->type = INTEL_I810;
-		return intel_i810_setup(i810_dev);
-
+		if (!find_i810(PCI_DEVICE_ID_INTEL_82810E_IG, "i810 E"))
+			goto fail;
+		bridge->driver = &intel_810_driver;
+		name = "i810 E";
+		break;
 	 case PCI_DEVICE_ID_INTEL_82815_MC:
-		/* The i815 can operate either as an i810 style
+		/*
+		 * The i815 can operate either as an i810 style
 		 * integrated device, or as an AGP4X motherboard.
-		 *
-		 * This only addresses the first mode:
 		 */
-		i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC, NULL);
-		if (i810_dev == NULL) {
-			printk(KERN_ERR PFX "agpgart: Detected an "
-				"Intel i815, but could not find the"
-				" secondary device. Assuming a "
-				"non-integrated video card.\n");
-			break;
+		if (find_i810(PCI_DEVICE_ID_INTEL_82815_CGC, "i815"))
+			bridge->driver = &intel_810_driver;
+		else
+			bridge->driver = &intel_815_driver;
+		name = "i815";
+		break;
+	case PCI_DEVICE_ID_INTEL_82820_HB:
+	case PCI_DEVICE_ID_INTEL_82820_UP_HB:
+		bridge->driver = &intel_820_driver;
+		name = "i820";
+		break;
+	case PCI_DEVICE_ID_INTEL_82830_HB:
+		if (find_i830(PCI_DEVICE_ID_INTEL_82830_CGC)) {
+			bridge->driver = &intel_830_driver;
+		} else {
+			bridge->driver = &intel_830mp_driver;
 		}
-		printk(KERN_INFO PFX "agpgart: Detected an Intel i815 Chipset.\n");
-		agp_bridge->type = INTEL_I810;
-		return intel_i810_setup(i810_dev);
-
+		name = "830M";
+		break;
+	case PCI_DEVICE_ID_INTEL_82840_HB:
+		bridge->driver = &intel_840_driver;
+		name = "i840";
+		break;
+	case PCI_DEVICE_ID_INTEL_82845_HB:
+		bridge->driver = &intel_845_driver;
+		name = "i845";
+		break;
 	case PCI_DEVICE_ID_INTEL_82845G_HB:
-		i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
-				PCI_DEVICE_ID_INTEL_82845G_IG, NULL);
-		if (i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
-			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
-				PCI_DEVICE_ID_INTEL_82845G_IG, i810_dev);
+		if (find_i830(PCI_DEVICE_ID_INTEL_82845G_IG)) {
+			bridge->driver = &intel_830_driver;
+		} else {
+			bridge->driver = &intel_845_driver;
 		}
-
-		if (i810_dev == NULL) {
-			/* 
-			 * We probably have a I845G chipset with an external graphics
-			 * card. It will be initialized later 
-			 */
-			agp_bridge->type = INTEL_I845_G;
-			break;
-		}
-		printk(KERN_INFO PFX "Detected an Intel(R) 845G Chipset.\n");
-		agp_bridge->type = INTEL_I810;
-		return intel_i830_setup(i810_dev);
-
-	case PCI_DEVICE_ID_INTEL_82830_HB:
-		i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82830_CGC, NULL);
-		if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0)
-			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82830_CGC, i810_dev);
-
-		if (i810_dev == NULL) {
-			/* Intel 830MP with external graphic card */
-			/* It will be initialized later */
-			agp_bridge->type = INTEL_I830_M;
-			break;
+		name = "845G";
+		break;
+	case PCI_DEVICE_ID_INTEL_82850_HB:
+		bridge->driver = &intel_850_driver;
+		name = "i850";
+		break;
+	case PCI_DEVICE_ID_INTEL_82855PM_HB:
+		bridge->driver = &intel_845_driver;
+		name = "855PM";
+		break;
+	case PCI_DEVICE_ID_INTEL_82855GM_HB:
+		if (find_i830(PCI_DEVICE_ID_INTEL_82855GM_IG)) {
+			bridge->driver = &intel_830_driver;
+			name = "855";
+		} else {
+			bridge->driver = &intel_845_driver;
+			name = "855GM";
 		}
-		printk(KERN_INFO PFX "Detected an Intel(R) 830M Chipset.\n");
-		agp_bridge->type = INTEL_I810;
-		return intel_i830_setup(i810_dev);
-
-	case PCI_DEVICE_ID_INTEL_82855_HB:
-		i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855_IG, NULL);
-		if(i810_dev && PCI_FUNC(i810_dev->devfn) != 0)
-			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82855_IG, i810_dev);
-
-		if (i810_dev == NULL) {
-			/* Intel 855PM with external graphic card */
-			/* It will be initialized later */
-			agp_bridge->type = INTEL_I855_PM;
-			break;
+		break;
+	case PCI_DEVICE_ID_INTEL_82860_HB:
+		bridge->driver = &intel_860_driver;
+		name = "i860";
+		break;
+	case PCI_DEVICE_ID_INTEL_82865_HB:
+		if (find_i830(PCI_DEVICE_ID_INTEL_82865_IG)) {
+			bridge->driver = &intel_830_driver;
+		} else {
+			bridge->driver = &intel_845_driver;
 		}
-		{
-			u32 capval = 0;
-			const char *name = "855GM/852GM";
-			pci_read_config_dword(dev, I85X_CAPID, &capval);
-			switch ((capval >> I85X_VARIANT_SHIFT) &
-				I85X_VARIANT_MASK) {
-			case I855_GME:
-				name = "855GME";
-				break;
-			case I855_GM:
-				name = "855GM";
-				break;
-			case I852_GME:
-				name = "852GME";
-				break;
-			case I852_GM:
-				name = "852GM";
-				break;
-			}
-			printk(KERN_INFO PFX
-			       "Detected an Intel(R) %s Chipset.\n", name);
+		name = "865";
+		break;
+	case PCI_DEVICE_ID_INTEL_82875_HB:
+		bridge->driver = &intel_845_driver;
+		name = "i875";
+		break;
+	case PCI_DEVICE_ID_INTEL_7505_0:
+		bridge->driver = &intel_7505_driver;
+		name =  "E7505";
+		break;
+	case PCI_DEVICE_ID_INTEL_7205_0:
+		bridge->driver = &intel_7505_driver;
+		name = "E7205";
+		break;
+	default:
+		if (!agp_try_unsupported) {
+			printk(KERN_ERR PFX
+			    "Unsupported Intel chipset (device id: %04x),"
+			    " you might want to try agp_try_unsupported=1.\n",
+			    pdev->device);
+			return -ENODEV;
 		}
-		agp_bridge->type = INTEL_I810;
-		return intel_i830_setup(i810_dev);
+		bridge->driver = &intel_generic_driver;
+		break;
+	};
 
-	case PCI_DEVICE_ID_INTEL_82865_HB:
-		i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
-				PCI_DEVICE_ID_INTEL_82865_IG, NULL);
-		if (i810_dev && PCI_FUNC(i810_dev->devfn) != 0) {
-			i810_dev = pci_find_device(PCI_VENDOR_ID_INTEL,
-				PCI_DEVICE_ID_INTEL_82865_IG, i810_dev);
-		}
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
 
-		if (i810_dev == NULL) {
-			/* 
-			 * We probably have a 865G chipset with an external graphics
-			 * card. It will be initialized later 
-			 */
-			agp_bridge->type = INTEL_I865_G;
-			break;
-		}
-		printk(KERN_INFO PFX "Detected an Intel(R) 865G Chipset.\n");
-		agp_bridge->type = INTEL_I810;
-		return intel_i830_setup(i810_dev);
+	if (bridge->driver == &intel_810_driver)
+		bridge->dev_private_data = &intel_i810_private;
+	else if (bridge->driver == &intel_830_driver)
+		bridge->dev_private_data = &intel_i830_private;
 
-	default:
-		break;
+	printk(KERN_INFO PFX "Detected an Intel %s Chipset.\n", name);
+
+	/* Fill in the mode register */
+	if (cap_ptr) {
+		pci_read_config_dword(pdev,
+				bridge->capndx+PCI_AGP_STATUS,
+				&bridge->mode);
 	}
 
-	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
-	if (cap_ptr == 0)
-		return -ENODEV;
-	agp_bridge->capndx = cap_ptr;
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+ fail:
+	agp_put_bridge(bridge);
+	return -ENODEV;
+}
 
-	/* Fill in the mode register */
-	pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode);
+static void __devexit agp_intel_remove(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
 
-	/* probe for known chipsets */
-	return agp_lookup_host_bridge(dev);
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
 }
 
-static struct agp_driver intel_agp_driver = {
-	.owner = THIS_MODULE,
-};
+static int agp_intel_suspend(struct pci_dev *dev, u32 state)
+{
+	return 0;
+}
 
-static int __init agp_intel_probe (struct pci_dev *dev, const struct pci_device_id *ent)
+static int agp_intel_resume(struct pci_dev *pdev)
 {
-	if (agp_find_supported_device(dev) == 0) {
-		intel_agp_driver.dev = dev;	
-		agp_register_driver(&intel_agp_driver);
-		return 0;
-	}
-	return -ENODEV;	
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	if (bridge->driver == &intel_generic_driver)
+		intel_configure();
+	else if (bridge->driver == &intel_845_driver)
+		intel_845_configure();
+
+	return 0;
 }
 
 static struct pci_device_id agp_intel_pci_table[] __initdata = {
@@ -1635,33 +1429,30 @@
 
 MODULE_DEVICE_TABLE(pci, agp_intel_pci_table);
 
-static struct __initdata pci_driver agp_intel_pci_driver = {
+static struct pci_driver agp_intel_pci_driver = {
 	.name		= "agpgart-intel",
 	.id_table	= agp_intel_pci_table,
 	.probe		= agp_intel_probe,
+	.remove		= agp_intel_remove,
+	.suspend	= agp_intel_suspend,
+	.resume		= agp_intel_resume,
 };
 
 /* intel_agp_init() must not be declared static for explicit
    early initialization to work (ie i810fb) */
 int __init agp_intel_init(void)
 {
-	int ret_val;
 	static int agp_initialised=0;
 
-	if (agp_initialised==1)
+	if (agp_initialised == 1)
 		return 0;
 	agp_initialised=1;
 
-	ret_val = pci_module_init(&agp_intel_pci_driver);
-	if (ret_val)
-		agp_bridge->type = NOT_SUPPORTED;
-
-	return ret_val;
+	return pci_module_init(&agp_intel_pci_driver);
 }
 
 static void __exit agp_intel_cleanup(void)
 {
-	agp_unregister_driver(&intel_agp_driver);
 	pci_unregister_driver(&agp_intel_pci_driver);
 }
 
diff -Nru a/drivers/char/agp/isoch.c b/drivers/char/agp/isoch.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/agp/isoch.c	Mon May 19 18:08:37 2003
@@ -0,0 +1,470 @@
+/*
+ * Setup routines for AGP 3.5 compliant bridges.
+ */
+
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/agp_backend.h>
+#include <linux/module.h>
+
+#include "agp.h"
+
+/* Generic AGP 3.5 enabling routines */
+
+struct agp_3_5_dev {
+	struct list_head list;
+	u8 capndx;
+	u32 maxbw;
+	struct pci_dev *dev;
+};
+
+static void agp_3_5_dev_list_insert(struct list_head *head, struct list_head *new)
+{
+	struct agp_3_5_dev *cur, *n = list_entry(new, struct agp_3_5_dev, list);
+	struct list_head *pos;
+
+	list_for_each(pos, head) {
+		cur = list_entry(pos, struct agp_3_5_dev, list);
+		if(cur->maxbw > n->maxbw)
+			break;
+	}
+	list_add_tail(new, pos);
+}
+
+static void agp_3_5_dev_list_sort(struct agp_3_5_dev *list, unsigned int ndevs)
+{
+	struct agp_3_5_dev *cur;
+	struct pci_dev *dev;
+	struct list_head *pos, *tmp, *head = &list->list, *start = head->next;
+	u32 nistat;
+
+	INIT_LIST_HEAD(head);
+
+	for (pos=start; pos!=head; ) {
+		cur = list_entry(pos, struct agp_3_5_dev, list);
+		dev = cur->dev;
+
+		pci_read_config_dword(dev, cur->capndx+AGPNISTAT, &nistat);
+		cur->maxbw = (nistat >> 16) & 0xff;
+
+		tmp = pos;
+		pos = pos->next;
+		agp_3_5_dev_list_insert(head, tmp);
+	}
+}
+
+/* 
+ * Initialize all isochronous transfer parameters for an AGP 3.0 
+ * node (i.e. a host bridge in combination with the adapters 
+ * lying behind it...)
+ */
+
+static int agp_3_5_isochronous_node_enable(struct agp_bridge_data *bridge,
+		struct agp_3_5_dev *dev_list, unsigned int ndevs)
+{
+	/*
+	 * Convenience structure to make the calculations clearer
+	 * here.  The field names come straight from the AGP 3.0 spec.
+	 */
+	struct isoch_data {
+		u32 maxbw;
+		u32 n;
+		u32 y;
+		u32 l;
+		u32 rq;
+		struct agp_3_5_dev *dev;
+	};
+
+	struct pci_dev *td = bridge->dev, *dev;
+	struct list_head *head = &dev_list->list, *pos;
+	struct agp_3_5_dev *cur;
+	struct isoch_data *master, target;
+	unsigned int cdev = 0;
+	u32 mnistat, tnistat, tstatus, mcmd;
+	u16 tnicmd, mnicmd;
+	u8 mcapndx;
+	u32 tot_bw = 0, tot_n = 0, tot_rq = 0, y_max, rq_isoch, rq_async;
+	u32 step, rem, rem_isoch, rem_async;
+	int ret = 0;
+
+	/*
+	 * We'll work with an array of isoch_data's (one for each
+	 * device in dev_list) throughout this function.
+	 */
+	if ((master = kmalloc(ndevs * sizeof(*master), GFP_KERNEL)) == NULL) {
+		ret = -ENOMEM;
+		goto get_out;
+	}
+
+	/*
+	 * Sort the device list by maxbw.  We need to do this because the
+	 * spec suggests that the devices with the smallest requirements
+	 * have their resources allocated first, with all remaining resources
+	 * falling to the device with the largest requirement.
+	 *
+	 * We don't exactly do this, we divide target resources by ndevs
+	 * and split them amongst the AGP 3.0 devices.  The remainder of such
+	 * division operations are dropped on the last device, sort of like
+	 * the spec mentions it should be done.
+	 *
+	 * We can't do this sort when we initially construct the dev_list
+	 * because we don't know until this function whether isochronous
+	 * transfers are enabled and consequently whether maxbw will mean
+	 * anything.
+	 */
+	agp_3_5_dev_list_sort(dev_list, ndevs);
+
+	pci_read_config_dword(td, bridge->capndx+AGPNISTAT, &tnistat);
+	pci_read_config_dword(td, bridge->capndx+AGPSTAT, &tstatus);
+
+	/* Extract power-on defaults from the target */
+	target.maxbw = (tnistat >> 16) & 0xff;
+	target.n     = (tnistat >> 8)  & 0xff;
+	target.y     = (tnistat >> 6)  & 0x3;
+	target.l     = (tnistat >> 3)  & 0x7;
+	target.rq    = (tstatus >> 24) & 0xff;
+
+	y_max = target.y;
+
+	/*
+	 * Extract power-on defaults for each device in dev_list.  Along
+	 * the way, calculate the total isochronous bandwidth required
+	 * by these devices and the largest requested payload size.
+	 */
+	list_for_each(pos, head) {
+		cur = list_entry(pos, struct agp_3_5_dev, list);
+		dev = cur->dev;
+
+		mcapndx = cur->capndx;
+
+		pci_read_config_dword(dev, cur->capndx+AGPNISTAT, &mnistat);
+
+		master[cdev].maxbw = (mnistat >> 16) & 0xff;
+		master[cdev].n     = (mnistat >> 8)  & 0xff;
+		master[cdev].y     = (mnistat >> 6)  & 0x3;
+		master[cdev].dev   = cur;
+
+		tot_bw += master[cdev].maxbw;
+		y_max = max(y_max, master[cdev].y);
+
+		cdev++;
+	}
+
+	/* Check if this configuration has any chance of working */
+	if (tot_bw > target.maxbw) {
+		printk(KERN_ERR PFX "isochronous bandwidth required "
+			"by AGP 3.0 devices exceeds that which is supported by "
+			"the AGP 3.0 bridge!\n");
+		ret = -ENODEV;
+		goto free_and_exit;
+	}
+
+	target.y = y_max;
+
+	/*
+	 * Write the calculated payload size into the target's NICMD
+	 * register.  Doing this directly effects the ISOCH_N value
+	 * in the target's NISTAT register, so we need to do this now
+	 * to get an accurate value for ISOCH_N later.
+	 */
+	pci_read_config_word(td, bridge->capndx+AGPNICMD, &tnicmd);
+	tnicmd &= ~(0x3 << 6);
+	tnicmd |= target.y << 6;
+	pci_write_config_word(td, bridge->capndx+AGPNICMD, tnicmd);
+
+	/* Reread the target's ISOCH_N */
+	pci_read_config_dword(td, bridge->capndx+AGPNISTAT, &tnistat);
+	target.n = (tnistat >> 8) & 0xff;
+
+	/* Calculate the minimum ISOCH_N needed by each master */
+	for (cdev=0; cdev<ndevs; cdev++) {
+		master[cdev].y = target.y;
+		master[cdev].n = master[cdev].maxbw / (master[cdev].y + 1);
+
+		tot_n += master[cdev].n;
+	}
+
+	/* Exit if the minimal ISOCH_N allocation among the masters is more
+	 * than the target can handle. */
+	if (tot_n > target.n) {
+		printk(KERN_ERR PFX "number of isochronous "
+			"transactions per period required by AGP 3.0 devices "
+			"exceeds that which is supported by the AGP 3.0 "
+			"bridge!\n");
+		ret = -ENODEV;
+		goto free_and_exit;
+	}
+
+	/* Calculate left over ISOCH_N capability in the target.  We'll give
+	 * this to the hungriest device (as per the spec) */
+	rem  = target.n - tot_n;
+
+	/* 
+	 * Calculate the minimum isochronous RQ depth needed by each master.
+	 * Along the way, distribute the extra ISOCH_N capability calculated
+	 * above.
+	 */
+	for (cdev=0; cdev<ndevs; cdev++) {
+		/*
+		 * This is a little subtle.  If ISOCH_Y > 64B, then ISOCH_Y
+		 * byte isochronous writes will be broken into 64B pieces.
+		 * This means we need to budget more RQ depth to account for
+		 * these kind of writes (each isochronous write is actually
+		 * many writes on the AGP bus).
+		 */
+		master[cdev].rq = master[cdev].n;
+		if(master[cdev].y > 0x1)
+			master[cdev].rq *= (1 << (master[cdev].y - 1));
+
+		tot_rq += master[cdev].rq;
+
+		if (cdev == ndevs-1)
+			master[cdev].n += rem;
+	}
+
+	/* Figure the number of isochronous and asynchronous RQ slots the
+	 * target is providing. */
+	rq_isoch = (target.y > 0x1) ? target.n * (1 << (target.y - 1)) : target.n;
+	rq_async = target.rq - rq_isoch;
+
+	/* Exit if the minimal RQ needs of the masters exceeds what the target
+	 * can provide. */
+	if (tot_rq > rq_isoch) {
+		printk(KERN_ERR PFX "number of request queue slots "
+			"required by the isochronous bandwidth requested by "
+			"AGP 3.0 devices exceeds the number provided by the "
+			"AGP 3.0 bridge!\n");
+		ret = -ENODEV;
+		goto free_and_exit;
+	}
+
+	/* Calculate asynchronous RQ capability in the target (per master) as
+	 * well as the total number of leftover isochronous RQ slots. */
+	step      = rq_async / ndevs;
+	rem_async = step + (rq_async % ndevs);
+	rem_isoch = rq_isoch - tot_rq;
+
+	/* Distribute the extra RQ slots calculated above and write our
+	 * isochronous settings out to the actual devices. */
+	for (cdev=0; cdev<ndevs; cdev++) {
+		cur = master[cdev].dev;
+		dev = cur->dev;
+
+		mcapndx = cur->capndx;
+
+		master[cdev].rq += (cdev == ndevs - 1)
+		              ? (rem_async + rem_isoch) : step;
+
+		pci_read_config_word(dev, cur->capndx+AGPNICMD, &mnicmd);
+		pci_read_config_dword(dev, cur->capndx+AGPCMD, &mcmd);
+
+		mnicmd &= ~(0xff << 8);
+		mnicmd &= ~(0x3  << 6);
+		mcmd   &= ~(0xff << 24);
+
+		mnicmd |= master[cdev].n  << 8;
+		mnicmd |= master[cdev].y  << 6;
+		mcmd   |= master[cdev].rq << 24;
+
+		pci_write_config_dword(dev, cur->capndx+AGPCMD, mcmd);
+		pci_write_config_word(dev, cur->capndx+AGPNICMD, mnicmd);
+	}
+
+free_and_exit:
+	kfree(master);
+
+get_out:
+	return ret;
+}
+
+/*
+ * This function basically allocates request queue slots among the
+ * AGP 3.0 systems in nonisochronous nodes.  The algorithm is
+ * pretty stupid, divide the total number of RQ slots provided by the
+ * target by ndevs.  Distribute this many slots to each AGP 3.0 device,
+ * giving any left over slots to the last device in dev_list.
+ */
+static void agp_3_5_nonisochronous_node_enable(struct agp_bridge_data *bridge,
+		struct agp_3_5_dev *dev_list, unsigned int ndevs)
+{
+	struct agp_3_5_dev *cur;
+	struct list_head *head = &dev_list->list, *pos;
+	u32 tstatus, mcmd;
+	u32 trq, mrq, rem;
+	unsigned int cdev = 0;
+
+	pci_read_config_dword(bridge->dev, bridge->capndx+AGPSTAT, &tstatus);
+
+	trq = (tstatus >> 24) & 0xff;
+	mrq = trq / ndevs;
+
+	rem = mrq + (trq % ndevs);
+
+	for (pos=head->next; cdev<ndevs; cdev++, pos=pos->next) {
+		cur = list_entry(pos, struct agp_3_5_dev, list);
+
+		pci_read_config_dword(cur->dev, cur->capndx+AGPCMD, &mcmd);
+		mcmd &= ~(0xff << 24);
+		mcmd |= ((cdev == ndevs - 1) ? rem : mrq) << 24;
+		pci_write_config_dword(cur->dev, cur->capndx+AGPCMD, mcmd);
+	}
+}
+
+/*
+ * Fully configure and enable an AGP 3.0 host bridge and all the devices
+ * lying behind it.
+ */
+int agp_3_5_enable(struct agp_bridge_data *bridge)
+{
+	struct pci_dev *td = bridge->dev, *dev;
+	u8 mcapndx;
+	u32 isoch, arqsz;
+	u32 tstatus, mstatus, ncapid;
+	u32 mmajor;
+	u16 mpstat;
+	struct agp_3_5_dev *dev_list, *cur;
+	struct list_head *head, *pos;
+	unsigned int ndevs = 0;
+	int ret = 0;
+
+	/* Extract some power-on defaults from the target */
+	pci_read_config_dword(td, bridge->capndx+AGPSTAT, &tstatus);
+	isoch     = (tstatus >> 17) & 0x1;
+	if (isoch == 0)	/* isoch xfers not available, bail out. */
+		return -ENODEV;
+
+	arqsz     = (tstatus >> 13) & 0x7;
+
+	/* 
+	 * Allocate a head for our AGP 3.5 device list
+	 * (multiple AGP v3 devices are allowed behind a single bridge). 
+	 */
+	if ((dev_list = kmalloc(sizeof(*dev_list), GFP_KERNEL)) == NULL) {
+		ret = -ENOMEM;
+		goto get_out;
+	}
+	head = &dev_list->list;
+	INIT_LIST_HEAD(head);
+
+	/* Find all AGP devices, and add them to dev_list. */
+	pci_for_each_dev(dev) { 
+		mcapndx = pci_find_capability(dev, PCI_CAP_ID_AGP);
+		if (mcapndx == 0)
+			continue;
+
+		switch ((dev->class >>8) & 0xff00) {
+			case 0x0600:    /* Bridge */
+				/* Skip bridges. We should call this function for each one. */
+				continue;
+
+			case 0x0001:    /* Unclassified device */
+				/* Don't know what this is, but log it for investigation. */
+				if (mcapndx != 0) {
+					printk (KERN_INFO PFX "Wacky, found unclassified AGP device. %x:%x\n",
+						dev->vendor, dev->device);
+				}
+				continue;
+
+			case 0x0300:    /* Display controller */
+			case 0x0400:    /* Multimedia controller */
+				if((cur = kmalloc(sizeof(*cur), GFP_KERNEL)) == NULL) {
+					ret = -ENOMEM;
+					goto free_and_exit;
+				}
+				cur->dev = dev;
+
+				pos = &cur->list;
+				list_add(pos, head);
+				ndevs++;
+				continue;
+
+			default:
+				continue;
+		}
+	}
+
+	/*
+	 * Take an initial pass through the devices lying behind our host
+	 * bridge.  Make sure each one is actually an AGP 3.0 device, otherwise
+	 * exit with an error message.  Along the way store the AGP 3.0
+	 * cap_ptr for each device
+	 */
+	list_for_each(pos, head) {
+		cur = list_entry(pos, struct agp_3_5_dev, list);
+		dev = cur->dev;
+		
+		pci_read_config_word(dev, PCI_STATUS, &mpstat);
+		if ((mpstat & PCI_STATUS_CAP_LIST) == 0)
+			continue;
+
+		pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &mcapndx);
+		if (mcapndx != 0) {
+			do {
+				pci_read_config_dword(dev, mcapndx, &ncapid);
+				if ((ncapid & 0xff) != 2)
+					mcapndx = (ncapid >> 8) & 0xff;
+			}
+			while (((ncapid & 0xff) != 2) && (mcapndx != 0));
+		}
+
+		if (mcapndx == 0) {
+			printk(KERN_ERR PFX "woah!  Non-AGP device "
+				"found on the secondary bus of an AGP 3.5 bridge!\n");
+			ret = -ENODEV;
+			goto free_and_exit;
+		}
+
+		mmajor = (ncapid >> AGP_MAJOR_VERSION_SHIFT) & 0xf;
+		if (mmajor < 3) {
+			printk(KERN_ERR PFX "woah!  AGP 2.0 device "
+				"found on the secondary bus of an AGP 3.5 "
+				"bridge operating with AGP 3.0 electricals!\n");
+			ret = -ENODEV;
+			goto free_and_exit;
+		}
+
+		cur->capndx = mcapndx;
+
+		pci_read_config_dword(dev, cur->capndx+AGPSTAT, &mstatus);
+
+		if (((mstatus >> 3) & 0x1) == 0) {
+			printk(KERN_ERR PFX "woah!  AGP 3.x device "
+				"not operating in AGP 3.x mode found on the "
+				"secondary bus of an AGP 3.5 bridge operating "
+				"with AGP 3.0 electricals!\n");
+			ret = -ENODEV;
+			goto free_and_exit;
+		}
+	}		
+
+	/*
+	 * Call functions to divide target resources amongst the AGP 3.0
+	 * masters.  This process is dramatically different depending on
+	 * whether isochronous transfers are supported.
+	 */
+	if (isoch) {
+		ret = agp_3_5_isochronous_node_enable(bridge, dev_list, ndevs);
+		if (ret) {
+			printk(KERN_INFO PFX "Something bad happened setting "
+			       "up isochronous xfers.  Falling back to "
+			       "non-isochronous xfer mode.\n");
+		} else {
+			goto free_and_exit;
+		}
+	}
+	agp_3_5_nonisochronous_node_enable(bridge, dev_list, ndevs);
+
+free_and_exit:
+	/* Be sure to free the dev_list */
+	for (pos=head->next; pos!=head; ) {
+		cur = list_entry(pos, struct agp_3_5_dev, list);
+
+		pos = pos->next;
+		kfree(cur);
+	}
+	kfree(dev_list);
+
+get_out:
+	return ret;
+}
+
diff -Nru a/drivers/char/agp/nvidia-agp.c b/drivers/char/agp/nvidia-agp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/agp/nvidia-agp.c	Thu May 15 11:27:42 2003
@@ -0,0 +1,377 @@
+/*
+ * Nvidia AGPGART routines.
+ * Based upon a 2.4 agpgart diff by the folks from NVIDIA, and hacked up
+ * to work in 2.5 by Dave Jones <davej@codemonkey.org.uk>
+ */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/agp_backend.h>
+#include <linux/gfp.h>
+#include <linux/page-flags.h>
+#include <linux/mm.h>
+#include "agp.h"
+
+
+/* registers */
+#define NVIDIA_0_APBASE		0x10
+#define NVIDIA_0_APSIZE		0x80
+#define NVIDIA_1_WBC		0xf0
+#define NVIDIA_2_GARTCTRL	0xd0
+#define NVIDIA_2_APBASE		0xd8
+#define NVIDIA_2_APLIMIT	0xdc
+#define NVIDIA_2_ATTBASE(i)	(0xe0 + (i) * 4)
+#define NVIDIA_3_APBASE		0x50
+#define NVIDIA_3_APLIMIT	0x54
+
+
+static int agp_try_unsupported __initdata = 0;
+
+static struct _nvidia_private {
+	struct pci_dev *dev_1;
+	struct pci_dev *dev_2;
+	struct pci_dev *dev_3;
+	volatile u32 *aperture;
+	int num_active_entries;
+	off_t pg_offset;
+	u32 wbc_mask;
+} nvidia_private;
+
+
+static int nvidia_fetch_size(void)
+{
+	int i;
+	u8 size_value;
+	struct aper_size_info_8 *values;
+
+	pci_read_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE, &size_value);
+	size_value &= 0x0f;
+	values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
+
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
+		if (size_value == values[i].size_value) {
+			agp_bridge->previous_size =
+				agp_bridge->current_size = (void *) (values + i);
+			agp_bridge->aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+
+	return 0;
+}
+
+
+static int nvidia_configure(void)
+{
+	int i, num_dirs;
+	u32 apbase, aplimit;
+	struct aper_size_info_8 *current_size;
+	u32 temp;
+
+	current_size = A_SIZE_8(agp_bridge->current_size);
+
+	/* aperture size */
+	pci_write_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE,
+		current_size->size_value);
+
+    /* address to map to */
+	pci_read_config_dword(agp_bridge->dev, NVIDIA_0_APBASE, &apbase);
+	apbase &= PCI_BASE_ADDRESS_MEM_MASK;
+	agp_bridge->gart_bus_addr = apbase;
+	aplimit = apbase + (current_size->size * 1024 * 1024) - 1;
+	pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APBASE, apbase);
+	pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_APLIMIT, aplimit);
+	pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APBASE, apbase);
+	pci_write_config_dword(nvidia_private.dev_3, NVIDIA_3_APLIMIT, aplimit);
+
+	/* directory size is 64k */
+	num_dirs = current_size->size / 64;
+	nvidia_private.num_active_entries = current_size->num_entries;
+	nvidia_private.pg_offset = 0;
+	if (num_dirs == 0) {
+		num_dirs = 1;
+		nvidia_private.num_active_entries /= (64 / current_size->size);
+		nvidia_private.pg_offset = (apbase & (64 * 1024 * 1024 - 1) &
+			~(current_size->size * 1024 * 1024 - 1)) / PAGE_SIZE;
+	}
+
+	/* attbase */
+	for(i = 0; i < 8; i++) {
+		pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_ATTBASE(i),
+			(agp_bridge->gatt_bus_addr + (i % num_dirs) * 64 * 1024) | 1);
+	}
+
+	/* gtlb control */
+	pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp);
+	pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp | 0x11);
+
+	/* gart control */
+	pci_read_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, &temp);
+	pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp | 0x100);
+
+	/* map aperture */
+	nvidia_private.aperture =
+		(volatile u32 *) ioremap(apbase, 33 * PAGE_SIZE);
+
+	return 0;
+}
+
+static void nvidia_cleanup(void)
+{
+	struct aper_size_info_8 *previous_size;
+	u32 temp;
+
+	/* gart control */
+	pci_read_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, &temp);
+	pci_write_config_dword(agp_bridge->dev, NVIDIA_0_APSIZE, temp & ~(0x100));
+
+	/* gtlb control */
+	pci_read_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, &temp);
+	pci_write_config_dword(nvidia_private.dev_2, NVIDIA_2_GARTCTRL, temp & ~(0x11));
+
+	/* unmap aperture */
+	iounmap((void *) nvidia_private.aperture);
+
+	/* restore previous aperture size */
+	previous_size = A_SIZE_8(agp_bridge->previous_size);
+	pci_write_config_byte(agp_bridge->dev, NVIDIA_0_APSIZE,
+		previous_size->size_value);
+}
+
+
+/*
+ * Note we can't use the generic routines, even though they are 99% the same.
+ * Aperture sizes <64M still requires a full 64k GART directory, but
+ * only use the portion of the TLB entries that correspond to the apertures
+ * alignment inside the surrounding 64M block.
+ */
+extern int agp_memory_reserved;
+
+static int nvidia_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	int i, j;
+	
+	if ((type != 0) || (mem->type != 0))
+		return -EINVAL;
+	
+	if ((pg_start + mem->page_count) >
+		(nvidia_private.num_active_entries - agp_memory_reserved/PAGE_SIZE))
+		return -EINVAL;
+	
+	for(j = pg_start; j < (pg_start + mem->page_count); j++) {
+		if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[nvidia_private.pg_offset + j]))
+			return -EBUSY;
+	}
+
+	if (mem->is_flushed == FALSE) {
+		global_cache_flush();
+		mem->is_flushed = TRUE;
+	}
+	for (i = 0, j = pg_start; i < mem->page_count; i++, j++)
+		agp_bridge->gatt_table[nvidia_private.pg_offset + j] = mem->memory[i];
+
+	agp_bridge->driver->tlb_flush(mem);
+	return 0;
+}
+
+
+static int nvidia_remove_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	int i;
+
+	if ((type != 0) || (mem->type != 0))
+		return -EINVAL;
+	
+	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
+		agp_bridge->gatt_table[nvidia_private.pg_offset + i] =
+		    (unsigned long) agp_bridge->scratch_page;
+	}
+
+	agp_bridge->driver->tlb_flush(mem);
+	return 0;
+}
+
+
+static void nvidia_tlbflush(agp_memory * mem)
+{
+	unsigned long end;
+	u32 wbc_reg, temp;
+	int i;
+
+	/* flush chipset */
+	if (nvidia_private.wbc_mask) {
+		pci_read_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, &wbc_reg);
+		wbc_reg |= nvidia_private.wbc_mask;
+		pci_write_config_dword(nvidia_private.dev_1, NVIDIA_1_WBC, wbc_reg);
+
+		end = jiffies + 3*HZ;
+		do {
+			pci_read_config_dword(nvidia_private.dev_1,
+					NVIDIA_1_WBC, &wbc_reg);
+			if ((signed)(end - jiffies) <= 0) {
+				printk(KERN_ERR
+				    "TLB flush took more than 3 seconds.\n");
+			}
+		} while (wbc_reg & nvidia_private.wbc_mask);
+	}
+
+	/* flush TLB entries */
+	for(i = 0; i < 32 + 1; i++)
+		temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)];
+	for(i = 0; i < 32 + 1; i++)
+		temp = nvidia_private.aperture[i * PAGE_SIZE / sizeof(u32)];
+}
+
+
+static struct aper_size_info_8 nvidia_generic_sizes[5] =
+{
+	{512, 131072, 7, 0},
+	{256, 65536, 6, 8},
+	{128, 32768, 5, 12},
+	{64, 16384, 4, 14},
+	/* The 32M mode still requires a 64k gatt */
+	{32, 16384, 4, 15}
+};
+
+
+static struct gatt_mask nvidia_generic_masks[] =
+{
+	{ .mask = 1, .type = 0}
+};
+
+
+struct agp_bridge_driver nvidia_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= nvidia_generic_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 5,
+	.configure		= nvidia_configure,
+	.fetch_size		= nvidia_fetch_size,
+	.cleanup		= nvidia_cleanup,
+	.tlb_flush		= nvidia_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= nvidia_generic_masks,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= nvidia_insert_memory,
+	.remove_memory		= nvidia_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
+
+static int __init agp_nvidia_probe(struct pci_dev *pdev,
+				   const struct pci_device_id *ent)
+{
+	struct agp_bridge_data *bridge;
+	u8 cap_ptr;
+
+	nvidia_private.dev_1 =
+		pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 1));
+	nvidia_private.dev_2 =
+		pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(0, 2));
+	nvidia_private.dev_3 =
+		pci_find_slot((unsigned int)pdev->bus->number, PCI_DEVFN(30, 0));
+	
+	if (!nvidia_private.dev_1 || !nvidia_private.dev_2 || !nvidia_private.dev_3) {
+		printk(KERN_INFO PFX "agpgart: Detected an NVIDIA "
+			"nForce/nForce2 chipset, but could not find "
+			"the secondary devices.\n");
+		return -ENODEV;
+	}
+
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (!cap_ptr)
+		return -ENODEV;
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_NVIDIA_NFORCE:
+		printk(KERN_INFO PFX "Detected NVIDIA nForce chipset\n");
+		nvidia_private.wbc_mask = 0x00010000;
+		break;
+	case PCI_DEVICE_ID_NVIDIA_NFORCE2:
+		printk(KERN_INFO PFX "Detected NVIDIA nForce2 chipset\n");
+		nvidia_private.wbc_mask = 0x80000000;
+		break;
+	default:
+		if (!agp_try_unsupported) {
+			printk(KERN_ERR PFX
+			    "Unsupported NVIDIA chipset (device id: %04x),"
+			    " you might want to try agp_try_unsupported=1.\n",
+			    pdev->device);
+			return -ENODEV;
+		}
+		printk(KERN_WARNING PFX
+		    "Trying generic NVIDIA routines for device id: %04x\n",
+		    pdev->device);
+		break;
+	}
+
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
+
+	bridge->driver = &nvidia_driver;
+	bridge->dev_private_data = &nvidia_private,
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
+
+	/* Fill in the mode register */
+	pci_read_config_dword(pdev,
+			bridge->capndx+PCI_AGP_STATUS,
+			&bridge->mode);
+
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+}
+
+static void __devexit agp_nvidia_remove(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
+}
+
+static struct pci_device_id agp_nvidia_pci_table[] __initdata = {
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_NVIDIA,
+	.device		= PCI_ANY_ID,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, agp_nvidia_pci_table);
+
+static struct pci_driver agp_nvidia_pci_driver = {
+	.name		= "agpgart-nvidia",
+	.id_table	= agp_nvidia_pci_table,
+	.probe		= agp_nvidia_probe,
+	.remove		= agp_nvidia_remove,
+};
+
+static int __init agp_nvidia_init(void)
+{
+	return pci_module_init(&agp_nvidia_pci_driver);
+}
+
+static void __exit agp_nvidia_cleanup(void)
+{
+	pci_unregister_driver(&agp_nvidia_pci_driver);
+}
+
+module_init(agp_nvidia_init);
+module_exit(agp_nvidia_cleanup);
+
+MODULE_PARM(agp_try_unsupported, "1i");
+MODULE_LICENSE("GPL and additional rights");
+MODULE_AUTHOR("NVIDIA Corporation");
+
diff -Nru a/drivers/char/agp/sis-agp.c b/drivers/char/agp/sis-agp.c
--- a/drivers/char/agp/sis-agp.c	Mon Mar 24 12:21:12 2003
+++ b/drivers/char/agp/sis-agp.c	Thu May 15 06:50:47 2003
@@ -17,8 +17,8 @@
 	struct aper_size_info_8 *values;
 
 	pci_read_config_byte(agp_bridge->dev, SIS_APSIZE, &temp_size);
-	values = A_SIZE_8(agp_bridge->aperture_sizes);
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		if ((temp_size == values[i].size_value) ||
 		    ((temp_size & ~(0x03)) ==
 		     (values[i].size_value & ~(0x03)))) {
@@ -63,13 +63,6 @@
 			      (previous_size->size_value & ~(0x03)));
 }
 
-static unsigned long sis_mask_memory(unsigned long addr, int type)
-{
-	/* Memory type is ignored */
-
-	return addr | agp_bridge->masks[0].mask;
-}
-
 static struct aper_size_info_8 sis_generic_sizes[7] =
 {
 	{256, 65536, 6, 99},
@@ -81,169 +74,142 @@
 	{4, 1024, 0, 3}
 };
 
-static struct gatt_mask sis_generic_masks[] =
-{
-	{.mask = 0x00000000, .type = 0}
+struct agp_bridge_driver sis_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes 	= sis_generic_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= sis_configure,
+	.fetch_size		= sis_fetch_size,
+	.cleanup		= sis_cleanup,
+	.tlb_flush		= sis_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
 };
 
-static int __init sis_generic_setup (struct pci_dev *pdev)
-{
-	agp_bridge->masks = sis_generic_masks;
-	agp_bridge->aperture_sizes = (void *) sis_generic_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = sis_configure;
-	agp_bridge->fetch_size = sis_fetch_size;
-	agp_bridge->cleanup = sis_cleanup;
-	agp_bridge->tlb_flush = sis_tlbflush;
-	agp_bridge->mask_memory = sis_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-
-	return 0;
-}
-
 struct agp_device_ids sis_agp_device_ids[] __initdata =
 {
 	{
 		.device_id	= PCI_DEVICE_ID_SI_740,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "740",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_650,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "650",
 	},
 	{
 		.device_id  = PCI_DEVICE_ID_SI_651,
-		.chipset    = SIS_GENERIC,
 		.chipset_name   = "651",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_645,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "645",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_646,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "646",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_735,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "735",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_745,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "745",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_730,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "730",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_630,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "630",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_540,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "540",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_620,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "620",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_530,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "530",
 	},
 	{
 		.device_id	= PCI_DEVICE_ID_SI_550,
-		.chipset	= SIS_GENERIC,
 		.chipset_name	= "550",
 	},
 	{ }, /* dummy final entry, always present */
 };
 
-/* scan table above for supported devices */
-static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
+static int __init agp_sis_probe(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
 {
-	int j=0;
-	struct agp_device_ids *devs;
-	
-	devs = sis_agp_device_ids;
+	struct agp_device_ids *devs = sis_agp_device_ids;
+	struct agp_bridge_data *bridge;
+	u8 cap_ptr;
+	int j;
 
-	while (devs[j].chipset_name != NULL) {
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (!cap_ptr)
+		return -ENODEV;
+
+	/* probe for known chipsets */
+	for (j = 0; devs[j].chipset_name; j++) {
 		if (pdev->device == devs[j].device_id) {
-			printk (KERN_INFO PFX "Detected SiS %s chipset\n",
-				devs[j].chipset_name);
-			agp_bridge->type = devs[j].chipset;
-
-			if (devs[j].chipset_setup != NULL)
-				return devs[j].chipset_setup(pdev);
-			else
-				return sis_generic_setup(pdev);
+			printk(KERN_INFO PFX "Detected SiS %s chipset\n",
+					devs[j].chipset_name);
+			goto found;
 		}
-		j++;
 	}
 
-	/* try init anyway, if user requests it */
-	if (agp_try_unsupported) {
-		printk(KERN_WARNING PFX "Trying generic SiS routines"
-		       " for device id: %04x\n", pdev->device);
-		agp_bridge->type = SIS_GENERIC;
-		return sis_generic_setup(pdev);
+	if (!agp_try_unsupported) {
+		printk(KERN_ERR PFX
+		    "Unsupported SiS chipset (device id: %04x),"
+		    " you might want to try agp_try_unsupported=1.\n",
+		    pdev->device);
+		return -ENODEV;
 	}
 
-	printk(KERN_ERR PFX "Unsupported SiS chipset (device id: %04x),"
-		" you might want to try agp_try_unsupported=1.\n", pdev->device);
-	return -ENODEV;
-}
+	printk(KERN_WARNING PFX "Trying generic SiS routines"
+	       " for device id: %04x\n", pdev->device);
 
-static struct agp_driver sis_agp_driver = {
-	.owner = THIS_MODULE,
-};
+found:
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
 
-static int __init agp_sis_probe (struct pci_dev *dev, const struct pci_device_id *ent)
-{
-	u8 cap_ptr = 0;
+	bridge->driver = &sis_driver;
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
 
-	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
-	if (cap_ptr == 0)
-		return -ENODEV;
+	/* Fill in the mode register */
+	pci_read_config_dword(pdev,
+			bridge->capndx+PCI_AGP_STATUS,
+			&bridge->mode);
 
-	/* probe for known chipsets */
-	if (agp_lookup_host_bridge(dev) != -ENODEV) {
-		agp_bridge->dev = dev;
-		agp_bridge->capndx = cap_ptr;
-		/* Fill in the mode register */
-		pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode);
-		sis_agp_driver.dev = dev;
-		agp_register_driver(&sis_agp_driver);
-		return 0;
-	}
-	return -ENODEV;
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+}
+
+static void __devexit agp_sis_remove(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
 }
 
 static struct pci_device_id agp_sis_pci_table[] __initdata = {
@@ -260,26 +226,20 @@
 
 MODULE_DEVICE_TABLE(pci, agp_sis_pci_table);
 
-static struct __initdata pci_driver agp_sis_pci_driver = {
+static struct pci_driver agp_sis_pci_driver = {
 	.name		= "agpgart-sis",
 	.id_table	= agp_sis_pci_table,
 	.probe		= agp_sis_probe,
+	.remove		= agp_sis_remove,
 };
 
 static int __init agp_sis_init(void)
 {
-	int ret_val;
-
-	ret_val = pci_module_init(&agp_sis_pci_driver);
-	if (ret_val)
-		agp_bridge->type = NOT_SUPPORTED;
-
-	return ret_val;
+	return pci_module_init(&agp_sis_pci_driver);
 }
 
 static void __exit agp_sis_cleanup(void)
 {
-	agp_unregister_driver(&sis_agp_driver);
 	pci_unregister_driver(&agp_sis_pci_driver);
 }
 
diff -Nru a/drivers/char/agp/sworks-agp.c b/drivers/char/agp/sworks-agp.c
--- a/drivers/char/agp/sworks-agp.c	Mon Feb 10 09:53:20 2003
+++ b/drivers/char/agp/sworks-agp.c	Thu May 15 06:50:47 2003
@@ -35,7 +35,7 @@
 		return -ENOMEM;
 	}
 	SetPageReserved(virt_to_page(page_map->real));
-	CACHE_FLUSH();
+	global_cache_flush();
 	page_map->remapped = ioremap_nocache(virt_to_phys(page_map->real), 
 					    PAGE_SIZE);
 	if (page_map->remapped == NULL) {
@@ -44,7 +44,7 @@
 		page_map->real = NULL;
 		return -ENOMEM;
 	}
-	CACHE_FLUSH();
+	global_cache_flush();
 
 	for(i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
 		page_map->remapped[i] = agp_bridge->scratch_page;
@@ -203,7 +203,7 @@
 	u32 temp2;
 	struct aper_size_info_lvl2 *values;
 
-	values = A_SIZE_LVL2(agp_bridge->aperture_sizes);
+	values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes);
 	pci_read_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,&temp);
 	pci_write_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,
 					SVWRKS_SIZE_MASK);
@@ -211,7 +211,7 @@
 	pci_write_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,temp);
 	temp2 &= SVWRKS_SIZE_MASK;
 
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		if (temp2 == values[i].size_value) {
 			agp_bridge->previous_size =
 			    agp_bridge->current_size = (void *) (values + i);
@@ -224,6 +224,37 @@
 	return 0;
 }
 
+/*
+ * This routine could be implemented by taking the addresses
+ * written to the GATT, and flushing them individually.  However
+ * currently it just flushes the whole table.  Which is probably
+ * more efficent, since agp_memory blocks can be a large number of
+ * entries.
+ */
+static void serverworks_tlbflush(agp_memory * temp)
+{
+	unsigned long end;
+
+	OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01);
+	end = jiffies + 3*HZ;
+	while(INREG8(serverworks_private.registers, 
+		     SVWRKS_POSTFLUSH) == 0x01) {
+		if((signed)(end - jiffies) <= 0) {
+			printk(KERN_ERR "Posted write buffer flush took more"
+			       "then 3 seconds\n");
+		}
+	}
+	OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001);
+	end = jiffies + 3*HZ;
+	while(INREG32(serverworks_private.registers, 
+		     SVWRKS_DIRFLUSH) == 0x00000001) {
+		if((signed)(end - jiffies) <= 0) {
+			printk(KERN_ERR "TLB flush took more"
+			       "then 3 seconds\n");
+		}
+	}
+}
+
 static int serverworks_configure(void)
 {
 	struct aper_size_info_lvl2 *current_size;
@@ -253,7 +284,7 @@
 	enable_reg |= 0x1; /* Agp Enable bit */
 	pci_write_config_byte(serverworks_private.svrwrks_dev,
 			      SVWRKS_AGP_ENABLE, enable_reg);
-	agp_bridge->tlb_flush(NULL);
+	serverworks_tlbflush(NULL);
 
 	agp_bridge->capndx = pci_find_capability(serverworks_private.svrwrks_dev, PCI_CAP_ID_AGP);
 
@@ -277,45 +308,6 @@
 	iounmap((void *) serverworks_private.registers);
 }
 
-/*
- * This routine could be implemented by taking the addresses
- * written to the GATT, and flushing them individually.  However
- * currently it just flushes the whole table.  Which is probably
- * more efficent, since agp_memory blocks can be a large number of
- * entries.
- */
-
-static void serverworks_tlbflush(agp_memory * temp)
-{
-	unsigned long end;
-
-	OUTREG8(serverworks_private.registers, SVWRKS_POSTFLUSH, 0x01);
-	end = jiffies + 3*HZ;
-	while(INREG8(serverworks_private.registers, 
-		     SVWRKS_POSTFLUSH) == 0x01) {
-		if((signed)(end - jiffies) <= 0) {
-			printk(KERN_ERR "Posted write buffer flush took more"
-			       "then 3 seconds\n");
-		}
-	}
-	OUTREG32(serverworks_private.registers, SVWRKS_DIRFLUSH, 0x00000001);
-	end = jiffies + 3*HZ;
-	while(INREG32(serverworks_private.registers, 
-		     SVWRKS_DIRFLUSH) == 0x00000001) {
-		if((signed)(end - jiffies) <= 0) {
-			printk(KERN_ERR "TLB flush took more"
-			       "then 3 seconds\n");
-		}
-	}
-}
-
-static unsigned long serverworks_mask_memory(unsigned long addr, int type)
-{
-	/* Only type 0 is supported by the serverworks chipsets */
-
-	return addr | agp_bridge->masks[0].mask;
-}
-
 static int serverworks_insert_memory(agp_memory * mem,
 			     off_t pg_start, int type)
 {
@@ -336,14 +328,14 @@
 	while (j < (pg_start + mem->page_count)) {
 		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 		cur_gatt = SVRWRKS_GET_GATT(addr);
-		if (!PGE_EMPTY(cur_gatt[GET_GATT_OFF(addr)])) {
+		if (!PGE_EMPTY(agp_bridge, cur_gatt[GET_GATT_OFF(addr)])) {
 			return -EBUSY;
 		}
 		j++;
 	}
 
 	if (mem->is_flushed == FALSE) {
-		CACHE_FLUSH();
+		global_cache_flush();
 		mem->is_flushed = TRUE;
 	}
 
@@ -351,9 +343,9 @@
 		addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
 		cur_gatt = SVRWRKS_GET_GATT(addr);
 		cur_gatt[GET_GATT_OFF(addr)] =
-			agp_bridge->mask_memory(mem->memory[i], mem->type);
+			agp_bridge->driver->mask_memory(mem->memory[i], mem->type);
 	}
-	agp_bridge->tlb_flush(mem);
+	serverworks_tlbflush(mem);
 	return 0;
 }
 
@@ -368,8 +360,8 @@
 		return -EINVAL;
 	}
 
-	CACHE_FLUSH();
-	agp_bridge->tlb_flush(mem);
+	global_cache_flush();
+	serverworks_tlbflush(mem);
 
 	for (i = pg_start; i < (mem->page_count + pg_start); i++) {
 		addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
@@ -378,13 +370,13 @@
 			(unsigned long) agp_bridge->scratch_page;
 	}
 
-	agp_bridge->tlb_flush(mem);
+	serverworks_tlbflush(mem);
 	return 0;
 }
 
 static struct gatt_mask serverworks_masks[] =
 {
-	{.mask = 0x00000001, .type = 0}
+	{.mask = 1, .type = 0}
 };
 
 static struct aper_size_info_lvl2 serverworks_sizes[7] =
@@ -420,123 +412,101 @@
 	agp_device_command(command, 0);
 }
 
-static int __init serverworks_setup (struct pci_dev *pdev)
+struct agp_bridge_driver sworks_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= serverworks_sizes,
+	.size_type		= LVL2_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= serverworks_configure,
+	.fetch_size		= serverworks_fetch_size,
+	.cleanup		= serverworks_cleanup,
+	.tlb_flush		= serverworks_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= serverworks_masks,
+	.agp_enable		= serverworks_agp_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= serverworks_create_gatt_table,
+	.free_gatt_table	= serverworks_free_gatt_table,
+	.insert_memory		= serverworks_insert_memory,
+	.remove_memory		= serverworks_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
+
+static int __init agp_serverworks_probe(struct pci_dev *pdev,
+					const struct pci_device_id *ent)
 {
-	u32 temp;
-	u32 temp2;
+	struct agp_bridge_data *bridge;
+	struct pci_dev *bridge_dev;
+	u32 temp, temp2;
 
-	serverworks_private.svrwrks_dev = pdev;
+	/* Everything is on func 1 here so we are hardcoding function one */
+	bridge_dev = pci_find_slot((unsigned int)pdev->bus->number,
+			PCI_DEVFN(0, 1));
+	if (!bridge_dev) {
+		printk(KERN_INFO PFX "agpgart: Detected a Serverworks "
+		       "Chipset, but could not find the secondary "
+		       "device.\n");
+		return -ENODEV;
+	}
 
-	agp_bridge->masks = serverworks_masks;
-	agp_bridge->aperture_sizes = (void *) serverworks_sizes;
-	agp_bridge->size_type = LVL2_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = (void *) &serverworks_private;
-	agp_bridge->needs_scratch_page = TRUE;
-	agp_bridge->configure = serverworks_configure;
-	agp_bridge->fetch_size = serverworks_fetch_size;
-	agp_bridge->cleanup = serverworks_cleanup;
-	agp_bridge->tlb_flush = serverworks_tlbflush;
-	agp_bridge->mask_memory = serverworks_mask_memory;
-	agp_bridge->agp_enable = serverworks_agp_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = serverworks_create_gatt_table;
-	agp_bridge->free_gatt_table = serverworks_free_gatt_table;
-	agp_bridge->insert_memory = serverworks_insert_memory;
-	agp_bridge->remove_memory = serverworks_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-
-	pci_read_config_dword(agp_bridge->dev,
-			      SVWRKS_APSIZE,
-			      &temp);
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_SERVERWORKS_HE:
+	case PCI_DEVICE_ID_SERVERWORKS_LE:
+	case 0x0007:
+		break;
+	default:
+		if (!agp_try_unsupported)
+			return -ENODEV;
+		break;
+	}
 
+	serverworks_private.svrwrks_dev = bridge_dev;
 	serverworks_private.gart_addr_ofs = 0x10;
-
-	if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-		pci_read_config_dword(agp_bridge->dev,
-				      SVWRKS_APSIZE + 4,
-				      &temp2);
-		if(temp2 != 0) {
+	
+	pci_read_config_dword(pdev, SVWRKS_APSIZE, &temp);
+	if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+		pci_read_config_dword(pdev, SVWRKS_APSIZE + 4, &temp2);
+		if (temp2 != 0) {
 			printk("Detected 64 bit aperture address, but top "
 			       "bits are not zero.  Disabling agp\n");
 			return -ENODEV;
 		}
 		serverworks_private.mm_addr_ofs = 0x18;
-	} else {
+	} else
 		serverworks_private.mm_addr_ofs = 0x14;
-	}
 
-	pci_read_config_dword(agp_bridge->dev,
-			      serverworks_private.mm_addr_ofs,
-			      &temp);
-	if(temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
-		pci_read_config_dword(agp_bridge->dev,
-				      serverworks_private.mm_addr_ofs + 4,
-				      &temp2);
-		if(temp2 != 0) {
+	pci_read_config_dword(pdev, serverworks_private.mm_addr_ofs, &temp);
+	if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
+		pci_read_config_dword(pdev,
+				serverworks_private.mm_addr_ofs + 4, &temp2);
+		if (temp2 != 0) {
 			printk("Detected 64 bit MMIO address, but top "
 			       "bits are not zero.  Disabling agp\n");
 			return -ENODEV;
 		}
 	}
 
-	return 0;
-}
-
-
-static int __init agp_find_supported_device(struct pci_dev *dev)
-{
-	struct pci_dev *bridge_dev;
-
-	/* Everything is on func 1 here so we are hardcoding function one */
-	bridge_dev = pci_find_slot ((unsigned int)dev->bus->number, PCI_DEVFN(0, 1));
-	if(bridge_dev == NULL) {
-		printk(KERN_INFO PFX "agpgart: Detected a Serverworks "
-		       "Chipset, but could not find the secondary "
-		       "device.\n");
-		return -ENODEV;
-	}
-
-	agp_bridge->dev = dev;
-
-	switch (dev->device) {
-	case PCI_DEVICE_ID_SERVERWORKS_HE:
-		agp_bridge->type = SVWRKS_HE;
-		return serverworks_setup(bridge_dev);
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
 
-	case PCI_DEVICE_ID_SERVERWORKS_LE:
-	case 0x0007:
-		agp_bridge->type = SVWRKS_LE;
-		return serverworks_setup(bridge_dev);
+	bridge->driver = &sworks_driver;
+	bridge->dev_private_data = &serverworks_private,
+	bridge->dev = pdev;
 
-	default:
-		if(agp_try_unsupported) {
-			agp_bridge->type = SVWRKS_GENERIC;
-			return serverworks_setup(bridge_dev);
-		}
-		break;
-	}
-	return -ENODEV;
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
 }
 
-static struct agp_driver serverworks_agp_driver = {
-	.owner = THIS_MODULE,
-};
-
-static int __init agp_serverworks_probe (struct pci_dev *dev, const struct pci_device_id *ent)
+static void __devexit agp_serverworks_remove(struct pci_dev *pdev)
 {
-	if (agp_find_supported_device(dev) == 0) {
-		serverworks_agp_driver.dev = dev;
-		agp_register_driver(&serverworks_agp_driver);
-		return 0;
-	}
-	return -ENODEV;	
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
 }
 
 static struct pci_device_id agp_serverworks_pci_table[] __initdata = {
@@ -553,26 +523,20 @@
 
 MODULE_DEVICE_TABLE(pci, agp_serverworks_pci_table);
 
-static struct __initdata pci_driver agp_serverworks_pci_driver = {
+static struct pci_driver agp_serverworks_pci_driver = {
 	.name		= "agpgart-serverworks",
 	.id_table	= agp_serverworks_pci_table,
 	.probe		= agp_serverworks_probe,
+	.remove		= agp_serverworks_remove,
 };
 
 static int __init agp_serverworks_init(void)
 {
-	int ret_val;
-
-	ret_val = pci_module_init(&agp_serverworks_pci_driver);
-	if (ret_val)
-		agp_bridge->type = NOT_SUPPORTED;
-
-	return ret_val;
+	return pci_module_init(&agp_serverworks_pci_driver);
 }
 
 static void __exit agp_serverworks_cleanup(void)
 {
-	agp_unregister_driver(&serverworks_agp_driver);
 	pci_unregister_driver(&agp_serverworks_pci_driver);
 }
 
diff -Nru a/drivers/char/agp/uninorth-agp.c b/drivers/char/agp/uninorth-agp.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/char/agp/uninorth-agp.c	Thu May 15 06:50:47 2003
@@ -0,0 +1,398 @@
+/*
+ * UniNorth AGPGART routines.
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/agp_backend.h>
+#include <asm/uninorth.h>
+#include <asm/pci-bridge.h>
+#include "agp.h"
+
+static int agp_try_unsupported __initdata = 0;
+
+static int uninorth_fetch_size(void)
+{
+	int i;
+	u32 temp;
+	struct aper_size_info_32 *values;
+
+	pci_read_config_dword(agp_bridge->dev, UNI_N_CFG_GART_BASE, &temp);
+	temp &= ~(0xfffff000);
+	values = A_SIZE_32(agp_bridge->driver->aperture_sizes);
+
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
+		if (temp == values[i].size_value) {
+			agp_bridge->previous_size =
+			    agp_bridge->current_size = (void *) (values + i);
+			agp_bridge->aperture_size_idx = i;
+			return values[i].size;
+		}
+	}
+
+	agp_bridge->previous_size =
+	    agp_bridge->current_size = (void *) (values + 1);
+	agp_bridge->aperture_size_idx = 1;
+	return values[1].size;
+
+	return 0;
+}
+
+static void uninorth_tlbflush(agp_memory * mem)
+{
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+			UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL);
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+			UNI_N_CFG_GART_ENABLE);
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+			UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_2xRESET);
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+			UNI_N_CFG_GART_ENABLE);
+}
+
+static void uninorth_cleanup(void)
+{
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+			UNI_N_CFG_GART_ENABLE | UNI_N_CFG_GART_INVAL);
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+			0);
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+			UNI_N_CFG_GART_2xRESET);
+	pci_write_config_dword(agp_bridge->dev, UNI_N_CFG_GART_CTRL,
+			0);
+}
+
+static int uninorth_configure(void)
+{
+	struct aper_size_info_32 *current_size;
+	
+	current_size = A_SIZE_32(agp_bridge->current_size);
+
+	printk(KERN_INFO PFX "configuring for size idx: %d\n",
+	       current_size->size_value);
+	
+	/* aperture size and gatt addr */
+	pci_write_config_dword(agp_bridge->dev,
+		UNI_N_CFG_GART_BASE,
+		(agp_bridge->gatt_bus_addr & 0xfffff000)
+			| current_size->size_value);
+
+	/* HACK ALERT
+	 * UniNorth seem to be buggy enough not to handle properly when
+	 * the AGP aperture isn't mapped at bus physical address 0
+	 */
+	agp_bridge->gart_bus_addr = 0;
+	pci_write_config_dword(agp_bridge->dev,
+		UNI_N_CFG_AGP_BASE, agp_bridge->gart_bus_addr);
+	
+	return 0;
+}
+
+static int uninorth_insert_memory(agp_memory * mem, off_t pg_start, int type)
+{
+	int i, j, num_entries;
+	void *temp;
+
+	temp = agp_bridge->current_size;
+	num_entries = A_SIZE_32(temp)->num_entries;
+
+	if (type != 0 || mem->type != 0)
+		/* We know nothing of memory types */
+		return -EINVAL;
+	if ((pg_start + mem->page_count) > num_entries)
+		return -EINVAL;
+
+	j = pg_start;
+
+	while (j < (pg_start + mem->page_count)) {
+		if (!PGE_EMPTY(agp_bridge, agp_bridge->gatt_table[j]))
+			return -EBUSY;
+		j++;
+	}
+
+	for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
+		agp_bridge->gatt_table[j] = cpu_to_le32((mem->memory[i] & 0xfffff000) | 0x00000001UL);
+		flush_dcache_range((unsigned long)__va(mem->memory[i]),
+				   (unsigned long)__va(mem->memory[i])+0x1000);
+	}
+	(void)in_le32((volatile u32*)&agp_bridge->gatt_table[pg_start]);
+	mb();
+	flush_dcache_range((unsigned long)&agp_bridge->gatt_table[pg_start], 
+		(unsigned long)&agp_bridge->gatt_table[pg_start + mem->page_count]);
+
+	uninorth_tlbflush(mem);
+	return 0;
+}
+
+static void uninorth_agp_enable(u32 mode)
+{
+	u32 command, scratch;
+	int timeout;
+
+	pci_read_config_dword(agp_bridge->dev,
+			      agp_bridge->capndx + PCI_AGP_STATUS,
+			      &command);
+
+	command = agp_collect_device_status(mode, command);
+	command |= 0x100;
+
+	uninorth_tlbflush(NULL);
+
+	timeout = 0;
+	do {
+		pci_write_config_dword(agp_bridge->dev,
+				       agp_bridge->capndx + PCI_AGP_COMMAND,
+				       command);
+		pci_read_config_dword(agp_bridge->dev,
+				       agp_bridge->capndx + PCI_AGP_COMMAND,
+				       &scratch);
+	} while ((scratch & 0x100) == 0 && ++timeout < 1000);
+	if ((scratch & 0x100) == 0)
+		printk(KERN_ERR PFX "failed to write UniNorth AGP command reg\n");
+
+	agp_device_command(command, 0);
+
+	uninorth_tlbflush(NULL);
+}
+
+static int uninorth_create_gatt_table(void)
+{
+	char *table;
+	char *table_end;
+	int size;
+	int page_order;
+	int num_entries;
+	int i;
+	void *temp;
+	struct page *page;
+
+	/* We can't handle 2 level gatt's */
+	if (agp_bridge->driver->size_type == LVL2_APER_SIZE)
+		return -EINVAL;
+
+	table = NULL;
+	i = agp_bridge->aperture_size_idx;
+	temp = agp_bridge->current_size;
+	size = page_order = num_entries = 0;
+
+	do {
+		size = A_SIZE_32(temp)->size;
+		page_order = A_SIZE_32(temp)->page_order;
+		num_entries = A_SIZE_32(temp)->num_entries;
+
+		table = (char *) __get_free_pages(GFP_KERNEL, page_order);
+
+		if (table == NULL) {
+			i++;
+			agp_bridge->current_size = A_IDX32(agp_bridge);
+		} else {
+			agp_bridge->aperture_size_idx = i;
+		}
+	} while (!table && (i < agp_bridge->driver->num_aperture_sizes));
+
+	if (table == NULL)
+		return -ENOMEM;
+
+	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
+
+	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
+		SetPageReserved(page);
+
+	agp_bridge->gatt_table_real = (u32 *) table;
+	agp_bridge->gatt_table = (u32 *)table;
+	agp_bridge->gatt_bus_addr = virt_to_phys(table);
+
+	for (i = 0; i < num_entries; i++) {
+		agp_bridge->gatt_table[i] =
+		    (unsigned long) agp_bridge->scratch_page;
+	}
+
+	flush_dcache_range((unsigned long)table, (unsigned long)table_end);
+
+	return 0;
+}
+
+static int uninorth_free_gatt_table(void)
+{
+	int page_order;
+	char *table, *table_end;
+	void *temp;
+	struct page *page;
+
+	temp = agp_bridge->current_size;
+	page_order = A_SIZE_32(temp)->page_order;
+
+	/* Do not worry about freeing memory, because if this is
+	 * called, then all agp memory is deallocated and removed
+	 * from the table.
+	 */
+
+	table = (char *) agp_bridge->gatt_table_real;
+	table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1);
+
+	for (page = virt_to_page(table); page <= virt_to_page(table_end); page++)
+		ClearPageReserved(page);
+
+	free_pages((unsigned long) agp_bridge->gatt_table_real, page_order);
+
+	return 0;
+}
+
+void null_cache_flush(void)
+{
+	mb();
+}
+
+/* Setup function */
+
+static struct aper_size_info_32 uninorth_sizes[7] =
+{
+#if 0 /* Not sure uninorth supports that high aperture sizes */
+	{256, 65536, 6, 64},
+	{128, 32768, 5, 32},
+	{64, 16384, 4, 16},
+#endif	
+	{32, 8192, 3, 8},
+	{16, 4096, 2, 4},
+	{8, 2048, 1, 2},
+	{4, 1024, 0, 1}
+};
+
+struct agp_bridge_driver uninorth_agp_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= (void *)uninorth_sizes,
+	.size_type		= U32_APER_SIZE,
+	.num_aperture_sizes	= 4,
+	.configure		= uninorth_configure,
+	.fetch_size		= uninorth_fetch_size,
+	.cleanup		= uninorth_cleanup,
+	.tlb_flush		= uninorth_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.cache_flush		= null_cache_flush,
+	.agp_enable		= uninorth_agp_enable,
+	.create_gatt_table	= uninorth_create_gatt_table,
+	.free_gatt_table	= uninorth_free_gatt_table,
+	.insert_memory		= uninorth_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+	.suspend		= agp_generic_suspend,
+	.resume			= agp_generic_resume,
+	.cant_use_aperture	= 1,
+};
+
+struct agp_device_ids uninorth_agp_device_ids[] __initdata = {
+	{
+		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP,
+		.chipset_name	= "UniNorth",
+	},
+	{
+		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP_P,
+		.chipset_name	= "UniNorth/Pangea",
+	},
+	{
+		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP15,
+		.chipset_name	= "UniNorth 1.5",
+	},
+	{
+		.device_id	= PCI_DEVICE_ID_APPLE_UNI_N_AGP2,
+		.chipset_name	= "UniNorth 2",
+	},
+};
+
+static int __init agp_uninorth_probe(struct pci_dev *pdev,
+				     const struct pci_device_id *ent)
+{
+	struct agp_device_ids *devs = uninorth_agp_device_ids;
+	struct agp_bridge_data *bridge;
+	u8 cap_ptr;
+	int j;
+
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (cap_ptr == 0)
+		return -ENODEV;
+
+	/* probe for known chipsets */
+	for (j = 0; devs[j].chipset_name != NULL; ++j) {
+		if (pdev->device == devs[j].device_id) {
+			printk(KERN_INFO PFX "Detected Apple %s chipset\n",
+			       devs[j].chipset_name);
+			goto found;
+		}
+	}
+
+	if (!agp_try_unsupported) {
+		printk(KERN_ERR PFX "Unsupported Apple chipset"
+		       " (device id: %04x).\n", pdev->device);
+		printk(KERN_ERR PFX "You might want to try"
+		       " agp_try_unsupported=1\n");
+		return -ENODEV;
+	}
+	printk(KERN_ERR PFX "Trying generic Uninorth routines"
+	       " for device id %04x\n", pdev->device);
+
+ found:
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
+
+	bridge->driver = &uninorth_agp_driver;
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
+
+	/* Fill in the mode register */
+	pci_read_config_dword(pdev, cap_ptr+PCI_AGP_STATUS, &bridge->mode);
+
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
+}
+
+static void __devexit agp_uninorth_remove(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
+}
+
+static struct pci_device_id agp_uninorth_pci_table[] __initdata = {
+	{
+	.class		= (PCI_CLASS_BRIDGE_HOST << 8),
+	.class_mask	= ~0,
+	.vendor		= PCI_VENDOR_ID_APPLE,
+	.device		= PCI_ANY_ID,
+	.subvendor	= PCI_ANY_ID,
+	.subdevice	= PCI_ANY_ID,
+	},
+	{ }
+};
+
+MODULE_DEVICE_TABLE(pci, agp_uninorth_pci_table);
+
+static struct pci_driver agp_uninorth_pci_driver = {
+	.name		= "agpgart-uninorth",
+	.id_table	= agp_uninorth_pci_table,
+	.probe		= agp_uninorth_probe,
+	.remove		= agp_uninorth_remove,
+};
+
+static int __init agp_uninorth_init(void)
+{
+	return pci_module_init(&agp_uninorth_pci_driver);
+}
+
+static void __exit agp_uninorth_cleanup(void)
+{
+	pci_unregister_driver(&agp_uninorth_pci_driver);
+}
+
+module_init(agp_uninorth_init);
+module_exit(agp_uninorth_cleanup);
+
+MODULE_PARM(agp_try_unsupported, "1i");
+MODULE_AUTHOR("Ben Herrenschmidt & Paul Mackerras");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/char/agp/via-agp.c b/drivers/char/agp/via-agp.c
--- a/drivers/char/agp/via-agp.c	Wed Apr  9 17:15:09 2003
+++ b/drivers/char/agp/via-agp.c	Thu May 15 12:04:40 2003
@@ -18,9 +18,9 @@
 	u8 temp;
 	struct aper_size_info_8 *values;
 
-	values = A_SIZE_8(agp_bridge->aperture_sizes);
+	values = A_SIZE_8(agp_bridge->driver->aperture_sizes);
 	pci_read_config_byte(agp_bridge->dev, VIA_APSIZE, &temp);
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		if (temp == values[i].size_value) {
 			agp_bridge->previous_size =
 			    agp_bridge->current_size = (void *) (values + i);
@@ -75,14 +75,6 @@
 }
 
 
-static unsigned long via_mask_memory(unsigned long addr, int type)
-{
-	/* Memory type is ignored */
-
-	return addr | agp_bridge->masks[0].mask;
-}
-
-
 static struct aper_size_info_8 via_generic_sizes[7] =
 {
 	{256, 65536, 6, 0},
@@ -95,23 +87,17 @@
 };
 
 
-static struct gatt_mask via_generic_masks[] =
-{
-	{.mask = 0x00000000, .type = 0}
-};
-
-
 static int via_fetch_size_agp3(void)
 {
 	int i;
 	u16 temp;
 	struct aper_size_info_16 *values;
 
-	values = A_SIZE_16(agp_bridge->aperture_sizes);
+	values = A_SIZE_16(agp_bridge->driver->aperture_sizes);
 	pci_read_config_word(agp_bridge->dev, VIA_AGP3_APSIZE, &temp);
 	temp &= 0xfff;
 
-	for (i = 0; i < agp_bridge->num_aperture_sizes; i++) {
+	for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
 		if (temp == values[i].size_value) {
 			agp_bridge->previous_size =
 				agp_bridge->current_size = (void *) (values + i);
@@ -174,99 +160,51 @@
 	{ 2048, 524288, 9, 1<<11}	/* 2GB <- Max supported */
 };
 
+struct agp_bridge_driver via_agp3_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= via_generic_agp3_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 10,
+	.configure		= via_configure_agp3,
+	.fetch_size		= via_fetch_size_agp3,
+	.cleanup		= via_cleanup_agp3,
+	.tlb_flush		= via_tlbflush_agp3,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
-static int __init via_generic_agp3_setup (struct pci_dev *pdev)
-{
-	agp_bridge->dev = pdev;
-	agp_bridge->type = VIA_GENERIC;
-	agp_bridge->masks = via_generic_masks;
-	agp_bridge->aperture_sizes = (void *) via_generic_agp3_sizes;
-	agp_bridge->size_type = U16_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 10;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->configure = via_configure_agp3;
-	agp_bridge->fetch_size = via_fetch_size_agp3;
-	agp_bridge->cleanup = via_cleanup_agp3;
-	agp_bridge->tlb_flush = via_tlbflush_agp3;
-	agp_bridge->mask_memory = via_mask_memory;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
-
-
-static int __init via_generic_setup (struct pci_dev *pdev)
-{
-	/* Garg, there are KT400s with KT266 IDs. */
-	if (pdev->device == PCI_DEVICE_ID_VIA_8367_0) {
-
-		/* Is there a KT400 subsystem ? */
-		if (pdev->subsystem_device==PCI_DEVICE_ID_VIA_8377_0) {
-			u8 reg;
-
-			printk (KERN_INFO PFX "Found KT400 in disguise as a KT266.\n");
-
-			/* Check AGP compatibility mode. */
-			pci_read_config_byte(pdev, VIA_AGPSEL, &reg);
-			if ((reg & (1<<1))==0)
-				return via_generic_agp3_setup(pdev);
-
-			/* Its in 2.0 mode, drop through. */
-		}
-	}
-
-	agp_bridge->masks = via_generic_masks;
-	agp_bridge->aperture_sizes = (void *) via_generic_sizes;
-	agp_bridge->size_type = U8_APER_SIZE;
-	agp_bridge->num_aperture_sizes = 7;
-	agp_bridge->dev_private_data = NULL;
-	agp_bridge->needs_scratch_page = FALSE;
-	agp_bridge->configure = via_configure;
-	agp_bridge->fetch_size = via_fetch_size;
-	agp_bridge->cleanup = via_cleanup;
-	agp_bridge->tlb_flush = via_tlbflush;
-	agp_bridge->mask_memory = via_mask_memory;
-	agp_bridge->agp_enable = agp_generic_enable;
-	agp_bridge->cache_flush = global_cache_flush;
-	agp_bridge->create_gatt_table = agp_generic_create_gatt_table;
-	agp_bridge->free_gatt_table = agp_generic_free_gatt_table;
-	agp_bridge->insert_memory = agp_generic_insert_memory;
-	agp_bridge->remove_memory = agp_generic_remove_memory;
-	agp_bridge->alloc_by_type = agp_generic_alloc_by_type;
-	agp_bridge->free_by_type = agp_generic_free_by_type;
-	agp_bridge->agp_alloc_page = agp_generic_alloc_page;
-	agp_bridge->agp_destroy_page = agp_generic_destroy_page;
-	agp_bridge->suspend = agp_generic_suspend;
-	agp_bridge->resume = agp_generic_resume;
-	agp_bridge->cant_use_aperture = 0;
-	return 0;
-}
-
-
-/* The KT400 does magick to put the AGP bridge compliant with the same
- * standards version as the graphics card. */
-static int __init via_kt400_setup(struct pci_dev *pdev)
-{
-	u8 reg;
-	pci_read_config_byte(pdev, VIA_AGPSEL, &reg);
-	/* Check AGP 2.0 compatibility mode. */
-	if ((reg & (1<<1))==0)
-		return via_generic_agp3_setup(pdev);
-	return via_generic_setup(pdev);
-}
-
+struct agp_bridge_driver via_driver = {
+	.owner			= THIS_MODULE,
+	.aperture_sizes		= via_generic_sizes,
+	.size_type		= U8_APER_SIZE,
+	.num_aperture_sizes	= 7,
+	.configure		= via_configure,
+	.fetch_size		= via_fetch_size,
+	.cleanup		= via_cleanup,
+	.tlb_flush		= via_tlbflush,
+	.mask_memory		= agp_generic_mask_memory,
+	.masks			= NULL,
+	.agp_enable		= agp_generic_enable,
+	.cache_flush		= global_cache_flush,
+	.create_gatt_table	= agp_generic_create_gatt_table,
+	.free_gatt_table	= agp_generic_free_gatt_table,
+	.insert_memory		= agp_generic_insert_memory,
+	.remove_memory		= agp_generic_remove_memory,
+	.alloc_by_type		= agp_generic_alloc_by_type,
+	.free_by_type		= agp_generic_free_by_type,
+	.agp_alloc_page		= agp_generic_alloc_page,
+	.agp_destroy_page	= agp_generic_destroy_page,
+};
 
 static struct agp_device_ids via_agp_device_ids[] __initdata =
 {
@@ -310,7 +248,7 @@
 
 	/* VT8361 */
 	{
-		.device_id	= PCI_DEVICE_ID_VIA_8361,	// 0x3112
+		.device_id	= PCI_DEVICE_ID_VIA_8361,
 		.chipset_name	= "Apollo KLE133",
 	},
 
@@ -353,7 +291,6 @@
 	{
 		.device_id	= PCI_DEVICE_ID_VIA_8377_0,
 		.chipset_name	= "Apollo Pro KT400",
-		.chipset_setup	= via_kt400_setup,
 	},
 
 	/* VT8604 / VT8605 / VT8603 / TwisterT
@@ -402,74 +339,99 @@
 	/* P4M400 */
 	{
 		.device_id	= PCI_DEVICE_ID_VIA_P4M400,
-		.chipset_name	= "PM400",
+		.chipset_name	= "P4M400",
 	},
 
 	{ }, /* dummy final entry, always present */
 };
 
-
-/* scan table above for supported devices */
-static int __init agp_lookup_host_bridge (struct pci_dev *pdev)
+static int __init agp_via_probe(struct pci_dev *pdev,
+				const struct pci_device_id *ent)
 {
-	int j=0;
-	struct agp_device_ids *devs;
-	
-	devs = via_agp_device_ids;
+	struct agp_device_ids *devs = via_agp_device_ids;
+	struct agp_bridge_data *bridge;
+	int j = 0;
+	u8 cap_ptr, reg;
 
-	while (devs[j].chipset_name != NULL) {
-		if (pdev->device == devs[j].device_id) {
-			printk (KERN_INFO PFX "Detected VIA %s chipset\n", devs[j].chipset_name);
-			agp_bridge->type = VIA_GENERIC;
+	cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
+	if (!cap_ptr)
+		return -ENODEV;
 
-			if (devs[j].chipset_setup != NULL)
-				return devs[j].chipset_setup(pdev);
-			else
-				return via_generic_setup(pdev);
+	/* probe for known chipsets */
+	for (j = 0; devs[j].chipset_name; j++) {
+		if (pdev->device == devs[j].device_id) {
+			printk (KERN_INFO PFX "Detected VIA %s chipset\n",
+					devs[j].chipset_name);
+			goto found;
 		}
-		j++;
 	}
 
-	/* try init anyway, if user requests it */
 	if (agp_try_unsupported) {
-		printk(KERN_WARNING PFX "Trying generic VIA routines"
-		       " for device id: %04x\n", pdev->device);
-		agp_bridge->type = VIA_GENERIC;
-		return via_generic_setup(pdev);
+		printk(KERN_ERR PFX 
+		    "Unsupported VIA chipset (device id: %04x),"
+		    " you might want to try agp_try_unsupported=1.\n",
+		    pdev->device);
+		return -ENODEV;
 	}
 
-	printk(KERN_ERR PFX "Unsupported VIA chipset (device id: %04x),"
-		" you might want to try agp_try_unsupported=1.\n", pdev->device);
-	return -ENODEV;
-}
+	printk(KERN_WARNING PFX "Trying generic VIA routines"
+	       " for device id: %04x\n", pdev->device);
 
-
-static struct agp_driver via_agp_driver = {
-	.owner = THIS_MODULE,
-};
+found:
+	bridge = agp_alloc_bridge();
+	if (!bridge)
+		return -ENOMEM;
+
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
+	bridge->driver = &via_driver;
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_VIA_8367_0:
+		/*
+		 * Garg, there are KT400s with KT266 IDs.
+		 */
+		/* Is there a KT400 subsystem ? */
+		if (pdev->subsystem_device != PCI_DEVICE_ID_VIA_8377_0)
+			break;
+		
+		printk(KERN_INFO PFX "Found KT400 in disguise as a KT266.\n");
+		/*FALLTHROUGH*/
+	case PCI_DEVICE_ID_VIA_8377_0:
+		/*
+		 * The KT400 does magick to put the AGP bridge compliant
+		 * with the same standards version as the graphics card.
+		 */
+		pci_read_config_byte(pdev, VIA_AGPSEL, &reg);
+		/* Check AGP 2.0 compatibility mode. */
+		if ((reg & (1<<1))==0) {
+			bridge->driver = &via_agp3_driver;
+			break;
+		}
+		/*FALLTHROUGH*/
+	default:
+		break;
+	}
 
 
-static int __init agp_via_probe (struct pci_dev *dev, const struct pci_device_id *ent)
-{
-	u8 cap_ptr = 0;
+	bridge->dev = pdev;
+	bridge->capndx = cap_ptr;
 
-	cap_ptr = pci_find_capability(dev, PCI_CAP_ID_AGP);
-	if (cap_ptr == 0)
-		return -ENODEV;
+	/* Fill in the mode register */
+	pci_read_config_dword(pdev,
+			bridge->capndx+PCI_AGP_STATUS, &bridge->mode);
 
-	/* probe for known chipsets */
-	if (agp_lookup_host_bridge (dev) != -ENODEV) {
-		agp_bridge->dev = dev;
-		agp_bridge->capndx = cap_ptr;
-		/* Fill in the mode register */
-		pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode);
-		via_agp_driver.dev = dev;
-		agp_register_driver(&via_agp_driver);
-		return 0;
-	}
-	return -ENODEV;	
+	pci_set_drvdata(pdev, bridge);
+	return agp_add_bridge(bridge);
 }
 
+static void __devexit agp_via_remove(struct pci_dev *pdev)
+{
+	struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
+
+	agp_remove_bridge(bridge);
+	agp_put_bridge(bridge);
+}
 
 static struct pci_device_id agp_via_pci_table[] __initdata = {
 	{
@@ -486,31 +448,23 @@
 MODULE_DEVICE_TABLE(pci, agp_via_pci_table);
 
 
-static struct __initdata pci_driver agp_via_pci_driver = {
+static struct pci_driver agp_via_pci_driver = {
 	.name		= "agpgart-via",
 	.id_table	= agp_via_pci_table,
 	.probe		= agp_via_probe,
+	.remove		= agp_via_remove,
 };
 
 
 static int __init agp_via_init(void)
 {
-	int ret_val;
-
-	ret_val = pci_module_init(&agp_via_pci_driver);
-	if (ret_val)
-		agp_bridge->type = NOT_SUPPORTED;
-
-	return ret_val;
+	return pci_module_init(&agp_via_pci_driver);
 }
 
-
 static void __exit agp_via_cleanup(void)
 {
-	agp_unregister_driver(&via_agp_driver);
 	pci_unregister_driver(&agp_via_pci_driver);
 }
-
 
 module_init(agp_via_init);
 module_exit(agp_via_cleanup);
diff -Nru a/drivers/char/amiserial.c b/drivers/char/amiserial.c
--- a/drivers/char/amiserial.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/char/amiserial.c	Wed May  7 07:11:07 2003
@@ -1528,7 +1528,6 @@
 
 	if (tty_hung_up_p(filp)) {
 		DBG_CNT("before DEC-hung");
-		MOD_DEC_USE_COUNT;
 		local_irq_restore(flags);
 		return;
 	}
@@ -1555,7 +1554,6 @@
 	}
 	if (state->count) {
 		DBG_CNT("before DEC-2");
-		MOD_DEC_USE_COUNT;
 		local_irq_restore(flags);
 		return;
 	}
@@ -1615,7 +1613,6 @@
 	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
 			 ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
-	MOD_DEC_USE_COUNT;
 	local_irq_restore(flags);
 }
 
@@ -1894,15 +1891,12 @@
 	int 			retval, line;
 	unsigned long		page;
 
-	MOD_INC_USE_COUNT;
 	line = tty->index;
 	if ((line < 0) || (line >= NR_PORTS)) {
-		MOD_DEC_USE_COUNT;
 		return -ENODEV;
 	}
 	retval = get_async_struct(line, &info);
 	if (retval) {
-		MOD_DEC_USE_COUNT;
 		return retval;
 	}
 	tty->driver_data = info;
@@ -2116,6 +2110,7 @@
 
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.owner = THIS_MODULE;
 	serial_driver.driver_name = "amiserial";
 	serial_driver.name = "ttyS";
 	serial_driver.major = TTY_MAJOR;
diff -Nru a/drivers/char/cyclades.c b/drivers/char/cyclades.c
--- a/drivers/char/cyclades.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/cyclades.c	Wed May  7 07:11:08 2003
@@ -2579,15 +2579,12 @@
   int retval, line;
   unsigned long page;
 
-    MOD_INC_USE_COUNT;
     line = tty->index;
     if ((line < 0) || (NR_PORTS <= line)){
-	MOD_DEC_USE_COUNT;
         return -ENODEV;
     }
     info = &cy_port[line];
     if (info->line < 0){
-	MOD_DEC_USE_COUNT;
         return -ENODEV;
     }
     
@@ -2607,7 +2604,6 @@
 	    } else {
 		printk("cyc:Cyclades-Z firmware not yet loaded\n");
 	    }
-	    MOD_DEC_USE_COUNT;
 	    return -ENODEV;
 	}
 #ifdef CONFIG_CYZ_INTR
@@ -2803,7 +2799,6 @@
     CY_LOCK(info, flags);
     /* If the TTY is being hung up, nothing to do */
     if (tty_hung_up_p(filp)) {
-	MOD_DEC_USE_COUNT;
 	CY_UNLOCK(info, flags);
         return;
     }
@@ -2834,7 +2829,6 @@
         info->count = 0;
     }
     if (info->count) {
-	MOD_DEC_USE_COUNT;
 	CY_UNLOCK(info, flags);
         return;
     }
@@ -2931,7 +2925,6 @@
     printk(" cyc:cy_close done\n");
 #endif
 
-    MOD_DEC_USE_COUNT;
     CY_UNLOCK(info, flags);
     return;
 } /* cy_close */
@@ -5494,6 +5487,7 @@
     
     memset(&cy_serial_driver, 0, sizeof(struct tty_driver));
     cy_serial_driver.magic = TTY_DRIVER_MAGIC;
+    cy_serial_driver.owner = THIS_MODULE;
     cy_serial_driver.driver_name = "cyclades";
     cy_serial_driver.name = "ttyC";
     cy_serial_driver.major = CYCLADES_MAJOR;
diff -Nru a/drivers/char/drm/Kconfig b/drivers/char/drm/Kconfig
--- a/drivers/char/drm/Kconfig	Fri Apr 25 15:57:57 2003
+++ b/drivers/char/drm/Kconfig	Mon May 12 10:46:27 2003
@@ -49,7 +49,7 @@
 
 config DRM_I810
 	tristate "Intel I810"
-	depends on DRM && AGP
+	depends on DRM && AGP && AGP_INTEL
 	help
 	  Choose this option if you have an Intel I810 graphics card.  If M is
 	  selected, the module will be called i810.  AGP support is required
@@ -57,7 +57,7 @@
 
 config DRM_I830
 	tristate "Intel 830M, 845G, 852GM, 855GM, 865G"
-	depends on DRM && AGP
+	depends on DRM && AGP && AGP_INTEL
 	help
 	  Choose this option if you have a system that has Intel 830M, 845G,
 	  852GM, 855GM or 865G integrated graphics.  If M is selected, the
diff -Nru a/drivers/char/drm/drm_drv.h b/drivers/char/drm/drm_drv.h
--- a/drivers/char/drm/drm_drv.h	Mon Apr 28 19:57:04 2003
+++ b/drivers/char/drm/drm_drv.h	Mon May  5 07:49:08 2003
@@ -334,7 +334,6 @@
 	dev->last_context = 0;
 	dev->last_switch = 0;
 	dev->last_checked = 0;
-	init_timer( &dev->timer );
 	init_waitqueue_head( &dev->context_wait );
 
 	dev->ctx_start = 0;
@@ -590,6 +589,7 @@
 		dev = &(DRM(device)[i]);
 		memset( (void *)dev, 0, sizeof(*dev) );
 		dev->count_lock = SPIN_LOCK_UNLOCKED;
+		init_timer( &dev->timer );
 		sema_init( &dev->struct_sem, 1 );
 
 		if ((DRM(minor)[i] = DRM(stub_register)(DRIVER_NAME, &DRM(fops),dev)) < 0)
diff -Nru a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
--- a/drivers/char/drm/radeon_cp.c	Mon Apr 28 19:59:49 2003
+++ b/drivers/char/drm/radeon_cp.c	Wed May  7 21:17:51 2003
@@ -903,8 +903,8 @@
 
 		RADEON_WRITE( RADEON_CP_RB_RPTR_ADDR,
 			     entry->busaddr[page_ofs]);
-		DRM_DEBUG( "ring rptr: offset=0x%08x handle=0x%08lx\n",
-			   entry->busaddr[page_ofs],
+		DRM_DEBUG( "ring rptr: offset=0x%08lx handle=0x%08lx\n",
+			   (unsigned long) entry->busaddr[page_ofs],
 			   entry->handle + tmp_ofs );
 	}
 
diff -Nru a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
--- a/drivers/char/dsp56k.c	Tue Dec  3 10:07:09 2002
+++ b/drivers/char/dsp56k.c	Wed May  7 08:47:29 2003
@@ -512,10 +512,9 @@
 		printk("DSP56k driver: Unable to register driver\n");
 		return -ENODEV;
 	}
-	devfs_register(NULL, "dsp56k", DEVFS_FL_DEFAULT,
-		      DSP56K_MAJOR, 0,
-		      S_IFCHR | S_IRUSR | S_IWUSR,
-		      &dsp56k_fops, NULL);
+
+	devfs_mk_cdev(MKDEV(DSP56K_MAJOR, 0),
+		      S_IFCHR | S_IRUSR | S_IWUSR, "dsp56k");
 
 	printk(banner);
 	return 0;
diff -Nru a/drivers/char/dtlk.c b/drivers/char/dtlk.c
--- a/drivers/char/dtlk.c	Tue Dec  3 10:08:05 2002
+++ b/drivers/char/dtlk.c	Wed May  7 08:47:29 2003
@@ -345,10 +345,9 @@
 	}
 	if (dtlk_dev_probe() == 0)
 		printk(", MAJOR %d\n", dtlk_major);
-	devfs_register(NULL, "dtlk", DEVFS_FL_DEFAULT,
-		       dtlk_major, DTLK_MINOR,
-		       S_IFCHR | S_IRUSR | S_IWUSR,
-		       &dtlk_fops, NULL);
+
+	devfs_mk_cdev(MKDEV(dtlk_major, DTLK_MINOR),
+		       S_IFCHR | S_IRUSR | S_IWUSR, "dtlk");
 
 	init_timer(&dtlk_timer);
 	dtlk_timer.function = dtlk_timer_tick;
diff -Nru a/drivers/char/dz.c b/drivers/char/dz.c
--- a/drivers/char/dz.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/char/dz.c	Wed May  7 15:51:55 2003
@@ -1332,6 +1332,7 @@
 
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.owner = THIS_MODULE;
 #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
 	serial_driver.name = "ttyS";
 #else
@@ -1425,8 +1426,8 @@
 		printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line,
 		       info->port, SERIAL);
 
-		tty_register_device(&serial_driver, info->line);
-		tty_register_device(&callout_driver, info->line);
+		tty_register_device(&serial_driver, info->line, NULL);
+		tty_register_device(&callout_driver, info->line, NULL);
 	}
 
 	/* Reset the chip */
diff -Nru a/drivers/char/esp.c b/drivers/char/esp.c
--- a/drivers/char/esp.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/esp.c	Wed May  7 07:24:33 2003
@@ -643,9 +643,7 @@
 #ifdef SERIAL_DEBUG_OPEN
 			printk("scheduling hangup...");
 #endif
-			MOD_INC_USE_COUNT;
-			if (schedule_task(&info->tqueue_hangup) == 0)
-				MOD_DEC_USE_COUNT;
+			schedule_task(&info->tqueue_hangup);
 		}
 	}
 }
@@ -811,7 +809,6 @@
 	tty = info->tty;
 	if (tty)
 		tty_hangup(tty);
-	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -2132,7 +2129,7 @@
 	info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
 			 ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
-out:	MOD_DEC_USE_COUNT;
+out:
 	restore_flags(flags);
 }
 
@@ -2375,7 +2372,6 @@
 #ifdef SERIAL_DEBUG_OPEN
 	printk("esp_open %s, count = %d\n", tty->name, info->count);
 #endif
-	MOD_INC_USE_COUNT;
 	info->count++;
 	tty->driver_data = info;
 	info->tty = tty;
@@ -2551,6 +2547,7 @@
 	
 	memset(&esp_driver, 0, sizeof(struct tty_driver));
 	esp_driver.magic = TTY_DRIVER_MAGIC;
+	esp_driver.owner = THIS_MODULE;
 	esp_driver.name = "ttyP";
 	esp_driver.major = ESP_IN_MAJOR;
 	esp_driver.minor_start = 0;
diff -Nru a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
--- a/drivers/char/ftape/zftape/zftape-init.c	Thu Apr 24 03:34:57 2003
+++ b/drivers/char/ftape/zftape/zftape-init.c	Wed May  7 08:47:29 2003
@@ -342,38 +342,24 @@
 	TRACE_CATCH(register_chrdev(QIC117_TAPE_MAJOR, "zft", &zft_cdev),);
 
 	for (i = 0; i < 4; i++) {
-		char devname[9];
-
-		sprintf (devname, "qft%i", i);
-		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
-			        QIC117_TAPE_MAJOR, i,
-				S_IFCHR | S_IRUSR | S_IWUSR,
-				&zft_cdev, NULL);
-		sprintf (devname, "nqft%i", i);
-		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
-				QIC117_TAPE_MAJOR, i + 4,
-				S_IFCHR | S_IRUSR | S_IWUSR,
-				&zft_cdev, NULL);
-		sprintf (devname, "zqft%i", i);
-		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
-				QIC117_TAPE_MAJOR, i + 16,
-				S_IFCHR | S_IRUSR | S_IWUSR,
-				&zft_cdev, NULL);
-		sprintf (devname, "nzqft%i", i);
-		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
-				QIC117_TAPE_MAJOR, i + 20,
-				S_IFCHR | S_IRUSR | S_IWUSR,
-				&zft_cdev, NULL);
-		sprintf (devname, "rawqft%i", i);
-		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
-				QIC117_TAPE_MAJOR, i + 32,
-				S_IFCHR | S_IRUSR | S_IWUSR,
-				&zft_cdev, NULL);
-		sprintf (devname, "nrawqft%i", i);
-		devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
-				QIC117_TAPE_MAJOR, i + 36,
+		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i),
 				S_IFCHR | S_IRUSR | S_IWUSR,
-				&zft_cdev, NULL);
+				"qft%i", i);
+		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 4),
+				S_IFCHR | S_IRUSR | S_IWUSR,
+				"nqft%i", i);
+		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 16),
+				S_IFCHR | S_IRUSR | S_IWUSR,
+				"zqft%i", i);
+		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 20),
+				S_IFCHR | S_IRUSR | S_IWUSR,
+				"nzqft%i", i);
+		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 32),
+				S_IFCHR | S_IRUSR | S_IWUSR,
+				"rawqft%i", i);
+		devfs_mk_cdev(MKDEV(QIC117_TAPE_MAJOR, i + 36),
+				S_IFCHR | S_IRUSR | S_IWUSR,
+				"nrawqft%i", i);
 	}
 
 #ifdef CONFIG_ZFT_COMPRESSOR
diff -Nru a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c
--- a/drivers/char/hvc_console.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/char/hvc_console.c	Wed May  7 15:51:55 2003
@@ -227,7 +227,12 @@
 	spin_unlock_irqrestore(&hp->lock, flags);
 }
 
+#if defined (CONFIG_XMON)
 extern unsigned long cpus_in_xmon;
+#else
+unsigned long cpus_in_xmon=0;
+#endif
+
 
 int khvcd(void *unused)
 {
@@ -252,6 +257,7 @@
 	memset(&hvc_driver, 0, sizeof(struct tty_driver));
 
 	hvc_driver.magic = TTY_DRIVER_MAGIC;
+	hvc_driver.owner = THIS_MODULE;
 	hvc_driver.driver_name = "hvc";
 	hvc_driver.name = "hvc/";
 	hvc_driver.major = HVC_MAJOR;
@@ -277,7 +283,7 @@
 	for (i = 0; i < hvc_driver.num; i++) {
 		hvc_struct[i].lock = SPIN_LOCK_UNLOCKED;
 		hvc_struct[i].index = i;
-		tty_register_device(&hvc_driver, i);
+		tty_register_device(&hvc_driver, i, NULL);
 	}
 
 	if (tty_register_driver(&hvc_driver))
diff -Nru a/drivers/char/ip2main.c b/drivers/char/ip2main.c
--- a/drivers/char/ip2main.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/ip2main.c	Wed May  7 23:16:25 2003
@@ -793,6 +793,7 @@
 
 	/* Initialise the relevant fields. */
 	ip2_tty_driver.magic                = TTY_DRIVER_MAGIC;
+	ip2_tty_driver.owner		    = THIS_MODULE;
 	ip2_tty_driver.name                 = pcTty;
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,0)
 	ip2_tty_driver.driver_name          = pcDriver_name;
@@ -869,29 +870,19 @@
 		 */
 
 		for( i = 0; i < IP2_MAX_BOARDS; ++i ) {
-#ifdef	CONFIG_DEVFS_FS
-			char name[16];
-#endif
-
 			if ( 0 == ip2config.addr[i] ) {
 				continue;
 			}
 
 #ifdef	CONFIG_DEVFS_FS
 			if ( NULL != ( pB = i2BoardPtrTable[i] ) ) {
-				sprintf( name, "ip2/ipl%d", i );
-				devfs_register(NULL, name,
-						DEVFS_FL_DEFAULT,
-						IP2_IPL_MAJOR, 4 * i,
+				devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i),
 						S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
-						&ip2_ipl, NULL);
+						"ip2/ipl%d", i);
 
-				sprintf( name, "ip2/stat%d", i );
-				devfs_register(NULL, name,
-						DEVFS_FL_DEFAULT,
-						IP2_IPL_MAJOR, 4 * i + 1,
+				devfs_mk_cdev(MKDEV(IP2_IPL_MAJOR, 4 * i + 1),
 						S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
-						&ip2_ipl, NULL);
+						"ip2/stat%d", i);
 
 			    for ( box = 0; box < ABS_MAX_BOXES; ++box )
 			    {
@@ -901,10 +892,10 @@
 				    {
 				        tty_register_device(&ip2_tty_driver,
 					    j + ABS_BIGGEST_BOX *
-						    (box+i*ABS_MAX_BOXES));
+						    (box+i*ABS_MAX_BOXES), NULL);
 				            tty_register_device(&ip2_callout_driver,
 					    j + ABS_BIGGEST_BOX *
-						    (box+i*ABS_MAX_BOXES));
+						    (box+i*ABS_MAX_BOXES), NULL);
 			    	    }
 			        }
 			    }
@@ -1577,7 +1568,6 @@
 	/* Setup pointer links in device and tty structures */
 	pCh->pTTY = tty;
 	tty->driver_data = pCh;
-	MOD_INC_USE_COUNT;
 
 #ifdef IP2DEBUG_OPEN
 	printk(KERN_DEBUG \
@@ -1777,14 +1767,12 @@
 #endif
 
 	if ( tty_hung_up_p ( pFile ) ) {
-		MOD_DEC_USE_COUNT;
 
 		ip2trace (CHANN, ITRC_CLOSE, 2, 1, 2 );
 
 		return;
 	}
 	if ( tty->count > 1 ) { /* not the last close */
-		MOD_DEC_USE_COUNT;
 
 		ip2trace (CHANN, ITRC_CLOSE, 2, 1, 3 );
 
@@ -1852,7 +1840,6 @@
 	DBG_CNT("ip2_close: after wakeups--");
 #endif
 
-	MOD_DEC_USE_COUNT;
 
 	ip2trace (CHANN, ITRC_CLOSE, ITRC_RETURN, 1, 1 );
 
diff -Nru a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
--- a/drivers/char/ipmi/ipmi_devintf.c	Fri Apr 18 11:01:14 2003
+++ b/drivers/char/ipmi/ipmi_devintf.c	Wed May  7 08:47:29 2003
@@ -441,24 +441,17 @@
 
 static void ipmi_new_smi(int if_num)
 {
-	char name[10];
-
-	if (if_num > MAX_DEVICES)
-		return;
-
-	snprintf(name, sizeof(name), "ipmidev/%d", if_num);
-
-	devfs_register(NULL, name, 0, ipmi_major, if_num,
-			S_IFCHR | S_IRUSR | S_IWUSR,
-			&ipmi_fops, NULL);
+	if (if_num <= MAX_DEVICES) {
+		devfs_mk_cdev(MKDEV(ipmi_major, if_num),
+				S_IFCHR | S_IRUSR | S_IWUSR,
+				"ipmidev/%d", if_num);
+	}
 }
 
 static void ipmi_smi_gone(int if_num)
 {
-	if (if_num > MAX_DEVICES)
-		return;
-
-	devfs_remove("ipmidev/%d", if_num);
+	if (if_num <= MAX_DEVICES)
+		devfs_remove("ipmidev/%d", if_num);
 }
 
 static struct ipmi_smi_watcher smi_watcher =
diff -Nru a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
--- a/drivers/char/ipmi/ipmi_msghandler.c	Mon Apr  7 16:44:49 2003
+++ b/drivers/char/ipmi/ipmi_msghandler.c	Wed May 14 23:40:16 2003
@@ -174,7 +174,7 @@
 int
 ipmi_register_all_cmd_rcvr(ipmi_user_t user)
 {
-	int flags;
+	unsigned long flags;
 	int rv = -EBUSY;
 
 	write_lock_irqsave(&(user->intf->users_lock), flags);
@@ -193,7 +193,7 @@
 int
 ipmi_unregister_all_cmd_rcvr(ipmi_user_t user)
 {
-	int flags;
+	unsigned long flags;
 	int rv = -EINVAL;
 
 	write_lock_irqsave(&(user->intf->users_lock), flags);
@@ -1023,7 +1023,7 @@
 	int              rv;
 	ipmi_smi_t       new_intf;
 	struct list_head *entry;
-	unsigned int     flags;
+	unsigned long     flags;
 
 
 	/* Make sure the driver is actually initialized, this handles
@@ -1148,7 +1148,7 @@
 	int              rv = -ENODEV;
 	int              i;
 	struct list_head *entry;
-	unsigned int     flags;
+	unsigned long    flags;
 
 	down_write(&interfaces_sem);
 	if (list_empty(&(intf->users)))
diff -Nru a/drivers/char/isicom.c b/drivers/char/isicom.c
--- a/drivers/char/isicom.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/isicom.c	Wed May  7 07:24:28 2003
@@ -590,9 +590,7 @@
 							port->status &= ~ISI_DCD;
 							if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
 								(port->flags & ASYNC_CALLOUT_NOHUP))) {
-								MOD_INC_USE_COUNT;
-								if (schedule_task(&port->hangup_tq) == 0)
-									MOD_DEC_USE_COUNT;
+								schedule_task(&port->hangup_tq);
 							}
 						}
 					}
@@ -846,7 +844,6 @@
 #endif	
 	
 	bp->status |= BOARD_ACTIVE;
-	MOD_INC_USE_COUNT;
 	return;
 }
  
@@ -1104,7 +1101,6 @@
 	for(channel = 0; channel < bp->port_count; channel++, port++) {
 		drop_dtr_rts(port);
 	}	
-	MOD_DEC_USE_COUNT;
 }
 
 static void isicom_shutdown_port(struct isi_port * port)
@@ -1644,7 +1640,6 @@
 	tty = port->tty;
 	if (tty)
 		tty_hangup(tty);	/* FIXME: module removal race here - AKPM */
-	MOD_DEC_USE_COUNT;
 }
 
 static void isicom_hangup(struct tty_struct * tty)
@@ -1715,6 +1710,7 @@
 	/* tty driver structure initialization */
 	memset(&isicom_normal, 0, sizeof(struct tty_driver));
 	isicom_normal.magic	= TTY_DRIVER_MAGIC;
+	isicom_normal.owner	= THIS_MODULE;
 	isicom_normal.name 	= "ttyM";
 	isicom_normal.major	= ISICOM_NMAJOR;
 	isicom_normal.minor_start	= 0;
diff -Nru a/drivers/char/istallion.c b/drivers/char/istallion.c
--- a/drivers/char/istallion.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/char/istallion.c	Wed May  7 23:16:25 2003
@@ -1054,7 +1054,6 @@
 	if (portp->devnr < 1)
 		return(-ENODEV);
 
-	MOD_INC_USE_COUNT;
 
 /*
  *	Check if this port is in the middle of closing. If so then wait
@@ -1170,14 +1169,12 @@
 	save_flags(flags);
 	cli();
 	if (tty_hung_up_p(filp)) {
-		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
 	if ((tty->count == 1) && (portp->refcount != 1))
 		portp->refcount = 1;
 	if (portp->refcount-- > 1) {
-		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
@@ -1232,7 +1229,6 @@
 	portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE |
 		ASYNC_CLOSING);
 	wake_up_interruptible(&portp->close_wait);
-	MOD_DEC_USE_COUNT;
 	restore_flags(flags);
 }
 
@@ -2369,7 +2365,6 @@
 			tty_hangup(portp->tty);
 		}
 	}
-	MOD_DEC_USE_COUNT;
 }
 
 /*****************************************************************************/
@@ -3004,9 +2999,7 @@
 					if (! ((portp->flags & ASYNC_CALLOUT_ACTIVE) &&
 					    (portp->flags & ASYNC_CALLOUT_NOHUP))) {
 						if (tty != (struct tty_struct *) NULL) {
-							MOD_INC_USE_COUNT;
-							if (schedule_task(&portp->tqhangup) == 0)
-								MOD_DEC_USE_COUNT;
+							schedule_task(&portp->tqhangup);
 						}
 					}
 				}
@@ -5336,12 +5329,9 @@
 
 	devfs_mk_dir("staliomem");
 	for (i = 0; i < 4; i++) {
-		char name[16];
-		sprintf(name, "staliomem/%d", i);
-		devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-			       STL_SIOMEMMAJOR, i,
+		devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i),
 			       S_IFCHR | S_IRUSR | S_IWUSR,
-			       &stli_fsiomem, NULL);
+			       "staliomem/%d", i);
 	}
 
 /*
@@ -5350,6 +5340,7 @@
  */
 	memset(&stli_serial, 0, sizeof(struct tty_driver));
 	stli_serial.magic = TTY_DRIVER_MAGIC;
+	stli_serial.owner = THIS_MODULE;
 	stli_serial.driver_name = stli_drvname;
 	stli_serial.name = stli_serialname;
 	stli_serial.major = STL_SERIALMAJOR;
diff -Nru a/drivers/char/keyboard.c b/drivers/char/keyboard.c
--- a/drivers/char/keyboard.c	Mon Apr 21 20:58:40 2003
+++ b/drivers/char/keyboard.c	Sun May  4 14:22:24 2003
@@ -1047,8 +1047,8 @@
 				printk(KERN_WARNING "keyboard.c: can't emulate rawmode for keycode %d\n", keycode);
 
 #ifdef CONFIG_MAGIC_SYSRQ	       /* Handle the SysRq Hack */
-	if (keycode == KEY_SYSRQ && !rep) {
-		sysrq_down = sysrq_alt && down;
+	if (keycode == KEY_SYSRQ && (sysrq_down || (down == 1 && sysrq_alt))) {
+		sysrq_down = down;
 		return;
 	}
 	if (sysrq_down && down && !rep) {
diff -Nru a/drivers/char/lp.c b/drivers/char/lp.c
--- a/drivers/char/lp.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/char/lp.c	Wed May  7 08:47:29 2003
@@ -784,8 +784,6 @@
 
 static int lp_register(int nr, struct parport *port)
 {
-	char name[16];
-
 	lp_table[nr].dev = parport_register_device(port, "lp", 
 						   lp_preempt, NULL, NULL, 0,
 						   (void *) &lp_table[nr]);
@@ -796,11 +794,8 @@
 	if (reset)
 		lp_reset(nr);
 
-	sprintf (name, "printers/%d", nr);
-	devfs_register (NULL, name,
-			DEVFS_FL_DEFAULT, LP_MAJOR, nr,
-			S_IFCHR | S_IRUGO | S_IWUGO,
-			&lp_fops, NULL);
+	devfs_mk_cdev(MKDEV(LP_MAJOR, nr), S_IFCHR | S_IRUGO | S_IWUGO,
+			"printers/%d", nr);
 
 	printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name, 
 	       (port->irq == PARPORT_IRQ_NONE)?"polling":"interrupt-driven");
diff -Nru a/drivers/char/mem.c b/drivers/char/mem.c
--- a/drivers/char/mem.c	Sun Apr 20 16:21:18 2003
+++ b/drivers/char/mem.c	Wed May 14 23:44:05 2003
@@ -522,7 +522,7 @@
  */
 static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
 {
-	int ret;
+	loff_t ret;
 
 	lock_kernel();
 	switch (orig) {
@@ -660,15 +660,16 @@
 	return 0;
 }
 
-void __init memory_devfs_register (void)
-{
-    /*  These are never unregistered  */
-    static const struct {
-	unsigned short minor;
-	char *name;
-	umode_t mode;
-	struct file_operations *fops;
-    } list[] = { /* list of minor devices */
+static struct file_operations memory_fops = {
+	.open		= memory_open,	/* just a selector for the real open */
+};
+
+static const struct {
+	unsigned int		minor;
+	char			*name;
+	umode_t			mode;
+	struct file_operations	*fops;
+} devlist[] = { /* list of minor devices */
 	{1, "mem",     S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
 	{2, "kmem",    S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
 	{3, "null",    S_IRUGO | S_IWUGO,           &null_fops},
@@ -680,25 +681,20 @@
 	{8, "random",  S_IRUGO | S_IWUSR,           &random_fops},
 	{9, "urandom", S_IRUGO | S_IWUSR,           &urandom_fops},
 	{11,"kmsg",    S_IRUGO | S_IWUSR,           &kmsg_fops},
-    };
-    int i;
-
-    for (i=0; i<(sizeof(list)/sizeof(*list)); i++)
-	devfs_register (NULL, list[i].name, DEVFS_FL_NONE,
-			MEM_MAJOR, list[i].minor,
-			list[i].mode | S_IFCHR,
-			list[i].fops, NULL);
-}
-
-static struct file_operations memory_fops = {
-	.open		= memory_open,	/* just a selector for the real open */
 };
 
-int __init chr_dev_init(void)
+static int __init chr_dev_init(void)
 {
+	int i;
+
 	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
-	memory_devfs_register();
+
+	for (i = 0; i < ARRAY_SIZE(devlist); i++) {
+		devfs_mk_cdev(MKDEV(MEM_MAJOR, devlist[i].minor),
+				S_IFCHR | devlist[i].mode, devlist[i].name);
+	}
+	
 	rand_initialize();
 #if defined (CONFIG_FB)
 	fbmem_init();
diff -Nru a/drivers/char/misc.c b/drivers/char/misc.c
--- a/drivers/char/misc.c	Wed Apr 30 11:01:16 2003
+++ b/drivers/char/misc.c	Sat May 17 12:39:13 2003
@@ -114,10 +114,8 @@
 	if (c != &misc_list)
 		new_fops = fops_get(c->fops);
 	if (!new_fops) {
-		char modname[20];
 		up(&misc_sem);
-		sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor);
-		request_module(modname);
+		request_module("char-major-%d-%d", MISC_MAJOR, minor);
 		down(&misc_sem);
 		c = misc_list.next;
 		while ((c != &misc_list) && (c->minor != minor))
@@ -200,8 +198,8 @@
 				"misc/%s", misc->name);
 	}
 
-	devfs_register(NULL, misc->devfs_name, 0, MISC_MAJOR, misc->minor,
-			S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, misc->fops, NULL);
+	devfs_mk_cdev(MKDEV(MISC_MAJOR, misc->minor),
+			S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP, misc->devfs_name);
 
 	/*
 	 * Add it to the front, so that later devices can "override"
diff -Nru a/drivers/char/moxa.c b/drivers/char/moxa.c
--- a/drivers/char/moxa.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/char/moxa.c	Wed May  7 07:24:21 2003
@@ -341,6 +341,7 @@
 	memset(&moxaDriver, 0, sizeof(struct tty_driver));
 	memset(&moxaCallout, 0, sizeof(struct tty_driver));
 	moxaDriver.magic = TTY_DRIVER_MAGIC;
+	moxaDriver.owner = THIS_MODULE;
 	moxaDriver.name = "ttya";
 	moxaDriver.major = ttymajor;
 	moxaDriver.minor_start = 0;
@@ -544,7 +545,6 @@
 			ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);
 		}
 	}
-	MOD_DEC_USE_COUNT;
 }
 
 static int moxa_open(struct tty_struct *tty, struct file *filp)
@@ -556,7 +556,6 @@
 
 	port = PORTNO(tty);
 	if (port == MAX_PORTS) {
-		MOD_INC_USE_COUNT;
 		return (0);
 	}
 	if (!MoxaPortIsValid(port)) {
@@ -579,7 +578,6 @@
 	}
 	up(&moxaBuffSem);
 
-	MOD_INC_USE_COUNT;
 	ch = &moxaChannels[port];
 	ch->count++;
 	tty->driver_data = ch;
@@ -619,7 +617,6 @@
 
 	port = PORTNO(tty);
 	if (port == MAX_PORTS) {
-		MOD_DEC_USE_COUNT;
 		return;
 	}
 	if (!MoxaPortIsValid(port)) {
@@ -633,7 +630,6 @@
 		return;
 	}
 	if (tty_hung_up_p(filp)) {
-		MOD_DEC_USE_COUNT;
 		return;
 	}
 	ch = (struct moxa_str *) tty->driver_data;
@@ -649,7 +645,6 @@
 		ch->count = 0;
 	}
 	if (ch->count) {
-		MOD_DEC_USE_COUNT;
 		return;
 	}
 	ch->asyncflags |= ASYNC_CLOSING;
@@ -688,7 +683,6 @@
 	ch->asyncflags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE |
 			    ASYNC_CLOSING);
 	wake_up_interruptible(&ch->close_wait);
-	MOD_DEC_USE_COUNT;
 }
 
 static int moxa_write(struct tty_struct *tty, int from_user,
@@ -1024,9 +1018,7 @@
 						wake_up_interruptible(&ch->open_wait);
 					else {
 						set_bit(MOXA_EVENT_HANGUP, &ch->event);
-						MOD_DEC_USE_COUNT;
-						if (schedule_work(&ch->tqueue) == 0)
-							MOD_INC_USE_COUNT;
+						schedule_work(&ch->tqueue);
 					}
 				}
 			}
diff -Nru a/drivers/char/mwave/mwavedd.h b/drivers/char/mwave/mwavedd.h
--- a/drivers/char/mwave/mwavedd.h	Mon Apr 28 20:34:29 2003
+++ b/drivers/char/mwave/mwavedd.h	Wed May  7 08:52:04 2003
@@ -50,9 +50,11 @@
 #define _LINUX_MWAVEDD_H
 #include "3780i.h"
 #include "tp3780i.h"
+#include "smapi.h"
 #include "mwavepub.h"
 #include <linux/ioctl.h>
 #include <asm/uaccess.h>
+#include <linux/wait.h>
 
 extern int mwave_debug;
 extern int mwave_3780i_irq;
diff -Nru a/drivers/char/mxser.c b/drivers/char/mxser.c
--- a/drivers/char/mxser.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/mxser.c	Wed May  7 07:24:11 2003
@@ -501,6 +501,7 @@
 
 	memset(&mxvar_sdriver, 0, sizeof(struct tty_driver));
 	mxvar_sdriver.magic = TTY_DRIVER_MAGIC;
+	mxvar_sdriver.owner = THIS_MODULE;
 	mxvar_sdriver.name = "ttyM";
 	mxvar_sdriver.major = ttymajor;
 	mxvar_sdriver.minor_start = 0;
@@ -708,7 +709,6 @@
 			tty_hangup(tty);	/* FIXME: module removal race here - AKPM */
 		}
 	}
-	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -767,8 +767,6 @@
 	info->session = current->session;
 	info->pgrp = current->pgrp;
 
-	MOD_INC_USE_COUNT;
-
 	return (0);
 }
 
@@ -795,7 +793,6 @@
 
 	if (tty_hung_up_p(filp)) {
 		restore_flags(flags);
-		MOD_DEC_USE_COUNT;
 		return;
 	}
 	if ((tty->count == 1) && (info->count != 1)) {
@@ -817,7 +814,6 @@
 	}
 	if (info->count) {
 		restore_flags(flags);
-		MOD_DEC_USE_COUNT;
 		return;
 	}
 	info->flags |= ASYNC_CLOSING;
@@ -881,7 +877,6 @@
 	wake_up_interruptible(&info->close_wait);
 	restore_flags(flags);
 
-	MOD_DEC_USE_COUNT;
 }
 
 static int mxser_write(struct tty_struct *tty, int from_user,
@@ -1492,9 +1487,7 @@
 
 	if (info->xmit_cnt < WAKEUP_CHARS) {
 		set_bit(MXSER_EVENT_TXLOW, &info->event);
-		MOD_INC_USE_COUNT;
-		if (schedule_work(&info->tqueue) == 0)
-		    MOD_DEC_USE_COUNT;
+		schedule_work(&info->tqueue);
 	}
 	if (info->xmit_cnt <= 0) {
 		info->IER &= ~UART_IER_THRI;
@@ -1523,9 +1516,7 @@
 		else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
 			   (info->flags & ASYNC_CALLOUT_NOHUP)))
 			set_bit(MXSER_EVENT_HANGUP, &info->event);
-		MOD_INC_USE_COUNT;
-		if (schedule_work(&info->tqueue) == 0)
-		    MOD_DEC_USE_COUNT;
+		schedule_work(&info->tqueue);
 	}
 	if (info->flags & ASYNC_CTS_FLOW) {
 		if (info->tty->hw_stopped) {
@@ -1535,9 +1526,7 @@
 				outb(info->IER, info->base + UART_IER);
 
 				set_bit(MXSER_EVENT_TXLOW, &info->event);
-				MOD_INC_USE_COUNT;
-				if (schedule_work(&info->tqueue) == 0)
-					MOD_DEC_USE_COUNT;
+				schedule_work(&info->tqueue);
 			}
 		} else {
 			if (!(status & UART_MSR_CTS)) {
diff -Nru a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c
--- a/drivers/char/n_hdlc.c	Mon Apr 21 20:58:41 2003
+++ b/drivers/char/n_hdlc.c	Tue May  6 14:29:59 2003
@@ -9,7 +9,7 @@
  *	Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
  *
  * Original release 01/11/99
- * $Id: n_hdlc.c,v 4.6 2003/04/21 19:14:07 paulkf Exp $
+ * $Id: n_hdlc.c,v 4.8 2003/05/06 21:18:51 paulkf Exp $
  *
  * This code is released under the GNU General Public License (GPL)
  *
@@ -78,7 +78,7 @@
  */
 
 #define HDLC_MAGIC 0x239e
-#define HDLC_VERSION "$Revision: 4.6 $"
+#define HDLC_VERSION "$Revision: 4.8 $"
 
 #include <linux/version.h>
 #include <linux/config.h>
@@ -215,6 +215,21 @@
 /* Define this string only once for all macro invocations */
 static char szVersion[] = HDLC_VERSION;
 
+static struct tty_ldisc n_hdlc_ldisc = {
+	.owner		= THIS_MODULE,
+	.magic		= TTY_LDISC_MAGIC,
+	.name		= "hdlc",
+	.open		= n_hdlc_tty_open,
+	.close		= n_hdlc_tty_close,
+	.read		= n_hdlc_tty_read,
+	.write		= n_hdlc_tty_write,
+	.ioctl		= n_hdlc_tty_ioctl,
+	.poll		= n_hdlc_tty_poll,
+	.receive_buf	= n_hdlc_tty_receive,
+	.receive_room	= n_hdlc_tty_room,
+	.write_wakeup	= n_hdlc_tty_wakeup,
+};
+
 /* n_hdlc_release()
  *
  *	release an n_hdlc per device line discipline info structure
@@ -968,25 +983,6 @@
 
 static int __init n_hdlc_init(void)
 {
-	static struct tty_ldisc	n_hdlc_ldisc = {
-		TTY_LDISC_MAGIC,    /* magic */
-		"hdlc",             /* name */
-		0,                  /* num */
-		0,                  /* flags */
-		n_hdlc_tty_open,    /* open */
-		n_hdlc_tty_close,   /* close */
-		0,                  /* flush_buffer */
-		0,                  /* chars_in_buffer */
-		n_hdlc_tty_read,    /* read */
-		n_hdlc_tty_write,   /* write */
-		n_hdlc_tty_ioctl,   /* ioctl */
-		0,                  /* set_termios */
-		n_hdlc_tty_poll,    /* poll */
-		n_hdlc_tty_receive, /* receive_buf */
-		n_hdlc_tty_room,    /* receive_room */
-		n_hdlc_tty_wakeup,  /* write_wakeup */
-		THIS_MODULE         /* owner */
-	};
 	int    status;
 
 	/* range check maxframe arg */
diff -Nru a/drivers/char/nwbutton.c b/drivers/char/nwbutton.c
--- a/drivers/char/nwbutton.c	Tue Nov  5 07:39:53 2002
+++ b/drivers/char/nwbutton.c	Mon May 12 16:21:23 2003
@@ -146,7 +146,7 @@
  *  increments the counter.
  */ 
 
-static void button_handler (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t button_handler (int irq, void *dev_id, struct pt_regs *regs)
 {
 	if (button_press_count) {
 		del_timer (&button_timer);
@@ -156,6 +156,8 @@
 	button_timer.function = button_sequence_finished;
 	button_timer.expires = (jiffies + bdelay);
 	add_timer (&button_timer);
+
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/drivers/char/nwbutton.h b/drivers/char/nwbutton.h
--- a/drivers/char/nwbutton.h	Tue Feb  5 09:40:07 2002
+++ b/drivers/char/nwbutton.h	Sat May 17 07:28:42 2003
@@ -25,7 +25,7 @@
 /* Function prototypes: */
 
 static void button_sequence_finished (unsigned long parameters);
-static void button_handler (int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t button_handler (int irq, void *dev_id, struct pt_regs *regs);
 static int button_read (struct file *filp, char *buffer,
 			size_t count, loff_t *ppos);
 int button_init (void);
diff -Nru a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c
--- a/drivers/char/pcmcia/synclink_cs.c	Sat Apr 26 09:16:19 2003
+++ b/drivers/char/pcmcia/synclink_cs.c	Wed May 14 23:44:02 2003
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/pcmcia/synclink_cs.c
  *
- * $Id: synclink_cs.c,v 4.6 2003/04/21 17:46:55 paulkf Exp $
+ * $Id: synclink_cs.c,v 4.10 2003/05/13 16:06:03 paulkf Exp $
  *
  * Device driver for Microgate SyncLink PC Card
  * multiprotocol serial adapter.
@@ -430,7 +430,7 @@
 static int  rx_alloc_buffers(MGSLPC_INFO *info);
 static void rx_free_buffers(MGSLPC_INFO *info);
 
-static void mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs);
 
 /*
  * Bottom half interrupt handlers
@@ -476,6 +476,7 @@
 
 static int debug_level = 0;
 static int maxframe[MAX_DEVICE_COUNT] = {0,};
+static int dosyncppp[MAX_DEVICE_COUNT] = {1,1,1,1};
 
 /* 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 */
@@ -492,11 +493,12 @@
 MODULE_PARM(cuamajor,"i");
 MODULE_PARM(debug_level,"i");
 MODULE_PARM(maxframe,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i");
+MODULE_PARM(dosyncppp,"1-" __MODULE_STRING(MAX_DEVICE_COUNT) "i");
 
 MODULE_LICENSE("GPL");
 
 static char *driver_name = "SyncLink PC Card driver";
-static char *driver_version = "$Revision: 4.6 $";
+static char *driver_version = "$Revision: 4.10 $";
 
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
@@ -574,9 +576,6 @@
     link->priv = info;
     
     /* Initialize the dev_link_t structure */
-    init_timer(&link->release);
-    link->release.function = &mgslpc_release;
-    link->release.data = (u_long)link;
 
     /* Interrupt setup */
     link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
@@ -813,7 +812,7 @@
 	    link->state &= ~DEV_PRESENT;
 	    if (link->state & DEV_CONFIG) {
 		    ((MGSLPC_INFO *)link->priv)->stop = 1;
-		    mod_timer(&link->release, jiffies + HZ/20);
+		    mgslpc_release((u_long)link);
 	    }
 	    break;
     case CS_EVENT_CARD_INSERTION:
@@ -1356,7 +1355,7 @@
  * dev_id  device ID supplied during interrupt registration
  * regs    interrupted processor context
  */
-static void mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t mgslpc_isr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	MGSLPC_INFO * info = (MGSLPC_INFO *)dev_id;
 	unsigned short isr;
@@ -1366,10 +1365,10 @@
 	if (debug_level >= DEBUG_LEVEL_ISR)	
 		printk("mgslpc_isr(%d) entry.\n", irq);
 	if (!info)
-		return;
+		return IRQ_NONE;
 		
 	if (!(info->link.state & DEV_CONFIG))
-		return;
+		return IRQ_HANDLED;
 
 	spin_lock(&info->lock);
 
@@ -1459,6 +1458,8 @@
 	if (debug_level >= DEBUG_LEVEL_ISR)	
 		printk("%s(%d):mgslpc_isr(%d)exit.\n",
 		       __FILE__,__LINE__,irq);
+
+	return IRQ_HANDLED;
 }
 
 /* Initialize and start device.
@@ -3113,8 +3114,7 @@
 	if (info->line < MAX_DEVICE_COUNT) {
 		if (maxframe[info->line])
 			info->max_frame_size = maxframe[info->line];
-//		info->dosyncppp = dosyncppp[info->line];
-		info->dosyncppp = 1;
+		info->dosyncppp = dosyncppp[info->line];
 	}
 
 	mgslpc_device_count++;
@@ -3276,7 +3276,6 @@
 
 	unregister_pccard_driver(&dev_info);
 	while (dev_list != NULL) {
-		del_timer(&dev_list->release);
 		if (dev_list->state & DEV_CONFIG)
 			mgslpc_release((u_long)dev_list);
 		mgslpc_detach(dev_list);
diff -Nru a/drivers/char/pcxx.c b/drivers/char/pcxx.c
--- a/drivers/char/pcxx.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/char/pcxx.c	Wed May  7 07:24:09 2003
@@ -431,8 +431,6 @@
 		return(-ENODEV);
 	}
 
-	/* flag the kernel that there is somebody using this guy */
-	MOD_INC_USE_COUNT;
 	/*
 	 * If the device is in the middle of being closed, then block
 	 * until it's done, and then try again.
@@ -576,7 +574,6 @@
 
 		if(tty_hung_up_p(filp)) {
 			/* flag that somebody is done with this module */
-			MOD_DEC_USE_COUNT;
 			restore_flags(flags);
 			return;
 		}
@@ -594,7 +591,6 @@
 		}
 		if (info->count-- > 1) {
 			restore_flags(flags);
-			MOD_DEC_USE_COUNT;
 			return;
 		}
 		if (info->count < 0) {
@@ -651,7 +647,6 @@
 		info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|
 							  ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING);
 		wake_up_interruptible(&info->close_wait);
-		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 	}
 }
@@ -1228,6 +1223,7 @@
 
 	memset(&pcxe_driver, 0, sizeof(struct tty_driver));
 	pcxe_driver.magic = TTY_DRIVER_MAGIC;
+	pcxe_driver.owner = THIS_MODULE;
 	pcxe_driver.name = "ttyD";
 	pcxe_driver.major = DIGI_MAJOR; 
 	pcxe_driver.minor_start = 0;
diff -Nru a/drivers/char/ppdev.c b/drivers/char/ppdev.c
--- a/drivers/char/ppdev.c	Sat Mar 22 07:38:05 2003
+++ b/drivers/char/ppdev.c	Wed May  7 08:47:29 2003
@@ -760,10 +760,8 @@
 	}
 	devfs_mk_dir("parports");
 	for (i = 0; i < PARPORT_MAX; i++) {
-		char name[16];
-		sprintf(name, "parports/%d", i);
-		devfs_register(NULL, name, DEVFS_FL_DEFAULT, PP_MAJOR, i,
-			       S_IFCHR | S_IRUGO | S_IWUGO, &pp_fops, NULL);
+		devfs_mk_cdev(MKDEV(PP_MAJOR, i),
+				S_IFCHR | S_IRUGO | S_IWUGO, "parports/%d", i);
 	}
 
 	printk (KERN_INFO PP_VERSION "\n");
diff -Nru a/drivers/char/random.c b/drivers/char/random.c
--- a/drivers/char/random.c	Mon Mar  3 04:08:26 2003
+++ b/drivers/char/random.c	Sun May  4 22:49:54 2003
@@ -1527,7 +1527,7 @@
 	 * If we gave the user some bytes, update the access time.
 	 */
 	if (count != 0) {
-		UPDATE_ATIME(file->f_dentry->d_inode);
+		update_atime(file->f_dentry->d_inode);
 	}
 	
 	return (count ? count : retval);
diff -Nru a/drivers/char/raw.c b/drivers/char/raw.c
--- a/drivers/char/raw.c	Thu Mar 20 03:11:46 2003
+++ b/drivers/char/raw.c	Wed May  7 21:17:51 2003
@@ -181,7 +181,7 @@
 			}
 			if (rawdev->binding) {
 				bdput(rawdev->binding);
-				MOD_DEC_USE_COUNT;
+				module_put(THIS_MODULE);
 			}
 			if (rq.block_major == 0 && rq.block_minor == 0) {
 				/* unbind */
@@ -191,7 +191,7 @@
 				if (rawdev->binding == NULL)
 					err = -ENOMEM;
 				else
-					try_module_get(THIS_MODULE);
+					__module_get(THIS_MODULE);
 			}
 			up(&raw_mutex);
 		} else {
diff -Nru a/drivers/char/rio/rio_linux.c b/drivers/char/rio/rio_linux.c
--- a/drivers/char/rio/rio_linux.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/rio/rio_linux.c	Wed May  7 07:23:59 2003
@@ -389,29 +389,6 @@
   udelay (usecs);
 }
 
-
-void rio_inc_mod_count (void)
-{
-#ifdef MODULE
-  func_enter ();
-  rio_dprintk (RIO_DEBUG_MOD_COUNT, "rio_inc_mod_count\n");
-  MOD_INC_USE_COUNT; 
-  func_exit ();
-#endif
-}
-
-
-void rio_dec_mod_count (void)
-{
-#ifdef MODULE
-  func_enter ();
-  rio_dprintk (RIO_DEBUG_MOD_COUNT, "rio_dec_mod_count\n");
-  MOD_DEC_USE_COUNT; 
-  func_exit ();
-#endif
-}
-
-
 static int rio_set_real_termios (void *ptr)
 {
   int rv, modem;
@@ -660,7 +637,6 @@
   
   PortP = (struct Port *)ptr;
   PortP->gs.tty = NULL;
-  rio_dec_mod_count (); 
 
   func_exit ();
 }
@@ -686,7 +662,6 @@
   }                
 
   PortP->gs.tty = NULL;
-  rio_dec_mod_count ();
   func_exit ();
 }
 
@@ -908,6 +883,7 @@
 
   memset(&rio_driver, 0, sizeof(rio_driver));
   rio_driver.magic = TTY_DRIVER_MAGIC;
+  rio_driver.owner = THIS_MODULE;
   rio_driver.driver_name = "specialix_rio";
   rio_driver.name = "ttySR";
   rio_driver.major = RIO_NORMAL_MAJOR0;
diff -Nru a/drivers/char/rio/rio_linux.h b/drivers/char/rio/rio_linux.h
--- a/drivers/char/rio/rio_linux.h	Tue Feb  5 07:23:17 2002
+++ b/drivers/char/rio/rio_linux.h	Wed May  7 07:23:59 2003
@@ -87,9 +87,6 @@
 #endif
 
 
-void rio_dec_mod_count (void);
-void rio_inc_mod_count (void);
-
 /* Allow us to debug "in the field" without requiring clients to
    recompile.... */
 #if 1
diff -Nru a/drivers/char/rio/riotty.c b/drivers/char/rio/riotty.c
--- a/drivers/char/rio/riotty.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/char/rio/riotty.c	Wed May  7 07:23:59 2003
@@ -139,7 +139,6 @@
 
 
 extern struct rio_info *p;
-extern void rio_inc_mod_count (void);
 
 
 int
@@ -205,8 +204,6 @@
 	tty->driver_data = PortP;
 
 	PortP->gs.tty = tty;
-	if (!PortP->gs.count)
-		rio_inc_mod_count ();
 	PortP->gs.count++;
 
 	rio_dprintk (RIO_DEBUG_TTY, "%d bytes in tx buffer\n",
@@ -215,8 +212,6 @@
 	retval = gs_init_port (&PortP->gs);
 	if (retval) {
 		PortP->gs.count--;
-		if (PortP->gs.count)
-			rio_dec_mod_count ();
 		return -ENXIO;
 	}
 	/*
diff -Nru a/drivers/char/riscom8.c b/drivers/char/riscom8.c
--- a/drivers/char/riscom8.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/riscom8.c	Wed May  7 07:24:02 2003
@@ -552,9 +552,7 @@
 			wake_up_interruptible(&port->open_wait);
 		else if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&
 			   (port->flags & ASYNC_CALLOUT_NOHUP))) {
-			MOD_INC_USE_COUNT;
-			if (schedule_task(&port->tqueue_hangup) == 0)
-				MOD_DEC_USE_COUNT;
+			schedule_task(&port->tqueue_hangup);
 		}
 	}
 	
@@ -676,7 +674,6 @@
 	IRQ_to_board[bp->irq] = bp;
 	bp->flags |= RC_BOARD_ACTIVE;
 	
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -694,7 +691,6 @@
 	bp->DTR = ~0;
 	rc_out(bp, RC_DTR, bp->DTR);	       /* Drop DTR on all ports */
 	
-	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -1678,7 +1674,6 @@
 	tty = port->tty;
 	if (tty)
 		tty_hangup(tty);	/* FIXME: module removal race still here */
-	MOD_DEC_USE_COUNT;
 }
 
 static void rc_hangup(struct tty_struct * tty)
@@ -1757,6 +1752,7 @@
 	memset(IRQ_to_board, 0, sizeof(IRQ_to_board));
 	memset(&riscom_driver, 0, sizeof(riscom_driver));
 	riscom_driver.magic = TTY_DRIVER_MAGIC;
+	riscom_driver.owner = THIS_MODULE;
 	riscom_driver.name = "ttyL";
 	riscom_driver.major = RISCOM8_NORMAL_MAJOR;
 	riscom_driver.num = RC_NBOARD * RC_NPORT;
diff -Nru a/drivers/char/rocket.c b/drivers/char/rocket.c
--- a/drivers/char/rocket.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/char/rocket.c	Wed May  7 07:23:51 2003
@@ -874,9 +874,6 @@
 	}
 
 	if (info->count++ == 0) {
-#ifdef MODULE
-		MOD_INC_USE_COUNT;
-#endif
 		rp_num_ports_open++;
 #ifdef ROCKET_DEBUG_OPEN
 		printk("rocket mod++ = %d...", rp_num_ports_open);
@@ -1071,9 +1068,6 @@
 	tty->closing = 0;
 	wake_up_interruptible(&info->close_wait);
 	
-#ifdef MODULE
-	MOD_DEC_USE_COUNT;
-#endif
 	rp_num_ports_open--;
 #ifdef ROCKET_DEBUG_OPEN
 	printk("rocket mod-- = %d...", rp_num_ports_open);
@@ -1504,9 +1498,6 @@
 		return;
 	}
 	if (info->count) {
-#ifdef MODULE
-		MOD_DEC_USE_COUNT;
-#endif
 		rp_num_ports_open--;
 	}
 	
@@ -2012,6 +2003,7 @@
 	 */
 	memset(&rocket_driver, 0, sizeof(struct tty_driver));
 	rocket_driver.magic = TTY_DRIVER_MAGIC;
+	rocket_driver.owner = THIS_MODULE;
 #ifdef CONFIG_DEVFS_FS
 	rocket_driver.name = "tts/R";
 #else
diff -Nru a/drivers/char/ser_a2232.c b/drivers/char/ser_a2232.c
--- a/drivers/char/ser_a2232.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/char/ser_a2232.c	Wed May  7 07:23:45 2003
@@ -272,7 +272,6 @@
 		not in "a2232_close()". See the comment in "sx.c", too.
 		If you run into problems, compile this driver into the
 		kernel instead of compiling it as a module. */
-	MOD_DEC_USE_COUNT;
 }
 
 static int  a2232_set_real_termios(void *ptr)
@@ -414,7 +413,6 @@
 	a2232_disable_tx_interrupts(ptr);
 	a2232_disable_rx_interrupts(ptr);
 	/* see the comment in a2232_shutdown_port above. */
-	/* MOD_DEC_USE_COUNT; */
 }
 
 static void a2232_hungup(void *ptr)
@@ -468,13 +466,9 @@
 		return retval;
 	}
 	port->gs.flags |= GS_ACTIVE;
-	if (port->gs.count == 1) {
-		MOD_INC_USE_COUNT;
-	}
 	retval = gs_block_til_ready(port, filp);
 
 	if (retval) {
-		MOD_DEC_USE_COUNT;
 		port->gs.count--;
 		return retval;
 	}
@@ -711,6 +705,7 @@
 
 	memset(&a2232_driver, 0, sizeof(a2232_driver));
 	a2232_driver.magic = TTY_DRIVER_MAGIC;
+	a2232_driver.owner = THIS_MODULE;
 	a2232_driver.driver_name = "commodore_a2232";
 	a2232_driver.name = "ttyY";
 	a2232_driver.major = A2232_NORMAL_MAJOR;
diff -Nru a/drivers/char/serial167.c b/drivers/char/serial167.c
--- a/drivers/char/serial167.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/char/serial167.c	Wed May  7 07:23:48 2003
@@ -2395,6 +2395,7 @@
     
     memset(&cy_serial_driver, 0, sizeof(struct tty_driver));
     cy_serial_driver.magic = TTY_DRIVER_MAGIC;
+    cy_serial_driver.owner = THIS_MODULE;
 #ifdef CONFIG_DEVFS_FS
     cy_serial_driver.name = "tts/";
 #else
diff -Nru a/drivers/char/serial_tx3912.c b/drivers/char/serial_tx3912.c
--- a/drivers/char/serial_tx3912.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/char/serial_tx3912.c	Wed May  7 07:23:38 2003
@@ -41,8 +41,6 @@
 static void rs_shutdown_port (void * ptr); 
 static int rs_set_real_termios (void *ptr);
 static int rs_chars_in_buffer (void * ptr); 
-static void rs_hungup (void *ptr);
-static void rs_close (void *ptr);
 
 /*
  * Used by generic serial driver to access hardware
@@ -56,8 +54,6 @@
 	.shutdown_port         = rs_shutdown_port,  
 	.set_real_termios      = rs_set_real_termios,  
 	.chars_in_buffer       = rs_chars_in_buffer, 
-	.close                 = rs_close, 
-	.hungup                = rs_hungup,
 }; 
 
 /*
@@ -579,9 +575,6 @@
 
 	rs_dprintk (TX3912_UART_DEBUG_OPEN, "before inc_use_count (count=%d.\n", 
 	            port->gs.count);
-	if (port->gs.count == 1) {
-		MOD_INC_USE_COUNT;
-	}
 	rs_dprintk (TX3912_UART_DEBUG_OPEN, "after inc_use_count\n");
 
 	/* Jim: Initialize port hardware here */
@@ -595,7 +588,6 @@
 	            retval, port->gs.count);
 
 	if (retval) {
-		MOD_DEC_USE_COUNT;
 		port->gs.count--;
 		return retval;
 	}
@@ -621,32 +613,6 @@
 }
 
 
-
-static void rs_close (void *ptr)
-{
-	func_enter ();
-
-	/* Anything to do here? */
-
-	MOD_DEC_USE_COUNT;
-	func_exit ();
-}
-
-
-/* I haven't the foggiest why the decrement use count has to happen
-   here. The whole linux serial drivers stuff needs to be redesigned.
-   My guess is that this is a hack to minimize the impact of a bug
-   elsewhere. Thinking about it some more. (try it sometime) Try
-   running minicom on a serial port that is driven by a modularized
-   driver. Have the modem hangup. Then remove the driver module. Then
-   exit minicom.  I expect an "oops".  -- REW */
-static void rs_hungup (void *ptr)
-{
-	func_enter ();
-	MOD_DEC_USE_COUNT;
-	func_exit ();
-}
-
 static int rs_ioctl (struct tty_struct * tty, struct file * filp, 
                      unsigned int cmd, unsigned long arg)
 {
@@ -839,6 +805,7 @@
 
 	memset(&rs_driver, 0, sizeof(rs_driver));
 	rs_driver.magic = TTY_DRIVER_MAGIC;
+	rs_driver.owner = THIS_MODULE;
 	rs_driver.driver_name = "serial";
 	rs_driver.name = "ttyS";
 	rs_driver.major = TTY_MAJOR;
diff -Nru a/drivers/char/sh-sci.c b/drivers/char/sh-sci.c
--- a/drivers/char/sh-sci.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/char/sh-sci.c	Wed May  7 07:23:41 2003
@@ -71,8 +71,6 @@
 static int  sci_get_CD(void *ptr);
 static void sci_shutdown_port(void *ptr);
 static int sci_set_real_termios(void *ptr);
-static void sci_hungup(void *ptr);
-static void sci_close(void *ptr);
 static int sci_chars_in_buffer(void *ptr);
 static int sci_request_irq(struct sci_port *port);
 static void sci_free_irq(struct sci_port *port);
@@ -216,8 +214,6 @@
 	sci_shutdown_port,
 	sci_set_real_termios,
 	sci_chars_in_buffer,
-	sci_close,
-	sci_hungup,
 	NULL
 };
 
@@ -838,12 +834,7 @@
 	sci_setsignals(port, 1,1);
 
 	if (port->gs.count == 1) {
-		MOD_INC_USE_COUNT;
-
 		retval = sci_request_irq(port);
-		if (retval) {
-			goto failed_2;
-		}
 	}
 
 	retval = gs_block_til_ready(port, filp);
@@ -878,23 +869,11 @@
 
 failed_3:
 	sci_free_irq(port);
-failed_2:
-	MOD_DEC_USE_COUNT;
 failed_1:
 	port->gs.count--;
 	return retval;
 }
 
-static void sci_hungup(void *ptr)
-{
-	MOD_DEC_USE_COUNT;
-}
-
-static void sci_close(void *ptr)
-{
-	MOD_DEC_USE_COUNT;
-}
-
 static int sci_ioctl(struct tty_struct * tty, struct file * filp, 
                      unsigned int cmd, unsigned long arg)
 {
@@ -1019,6 +998,7 @@
 
 	memset(&sci_driver, 0, sizeof(sci_driver));
 	sci_driver.magic = TTY_DRIVER_MAGIC;
+	sci_driver.owner = THIS_MODULE;
 	sci_driver.driver_name = "sci";
 #ifdef CONFIG_DEVFS_FS
 	sci_driver.name = "ttsc/";
diff -Nru a/drivers/char/specialix.c b/drivers/char/specialix.c
--- a/drivers/char/specialix.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/specialix.c	Wed May  7 07:23:29 2003
@@ -833,9 +833,7 @@
 #ifdef SPECIALIX_DEBUG
 			printk ( "Sending HUP.\n");
 #endif
-			MOD_INC_USE_COUNT;
-			if (schedule_task(&port->tqueue_hangup) == 0)
-				MOD_DEC_USE_COUNT;
+			schedule_task(&port->tqueue_hangup);
 		} else {
 #ifdef SPECIALIX_DEBUG
 			printk ( "Don't need to send HUP.\n");
@@ -980,7 +978,6 @@
 	turn_ints_on (bp);
 	bp->flags |= SX_BOARD_ACTIVE;
 
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -1000,7 +997,6 @@
 
 	turn_ints_off (bp);
 
-	MOD_DEC_USE_COUNT;
 }
 
 
@@ -2150,7 +2146,6 @@
 	tty = port->tty;
 	if (tty)
 		tty_hangup(tty);	/* FIXME: module removal race here */
-	MOD_DEC_USE_COUNT;
 }
 
 
@@ -2233,6 +2228,7 @@
 	init_bh(SPECIALIX_BH, do_specialix_bh);
 	memset(&specialix_driver, 0, sizeof(specialix_driver));
 	specialix_driver.magic = TTY_DRIVER_MAGIC;
+	specialix_driver.owner = THIS_MODULE;
 	specialix_driver.name = "ttyW";
 	specialix_driver.major = SPECIALIX_NORMAL_MAJOR;
 	specialix_driver.num = SX_NBOARD * SX_NPORT;
diff -Nru a/drivers/char/stallion.c b/drivers/char/stallion.c
--- a/drivers/char/stallion.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/stallion.c	Wed May  7 23:16:25 2003
@@ -1044,8 +1044,6 @@
 	if (portp == (stlport_t *) NULL)
 		return(-ENODEV);
 
-	MOD_INC_USE_COUNT;
-
 /*
  *	On the first open of the device setup the port hardware, and
  *	initialize the per port data structure.
@@ -1207,14 +1205,12 @@
 	save_flags(flags);
 	cli();
 	if (tty_hung_up_p(filp)) {
-		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
 	if ((tty->count == 1) && (portp->refcount != 1))
 		portp->refcount = 1;
 	if (portp->refcount-- > 1) {
-		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
 	}
@@ -1267,7 +1263,6 @@
 	portp->flags &= ~(ASYNC_CALLOUT_ACTIVE | ASYNC_NORMAL_ACTIVE |
 		ASYNC_CLOSING);
 	wake_up_interruptible(&portp->close_wait);
-	MOD_DEC_USE_COUNT;
 	restore_flags(flags);
 }
 
@@ -2241,11 +2236,11 @@
 #endif
 
 	if (portp == (stlport_t *) NULL)
-		goto out;
+		return;
 
 	tty = portp->tty;
 	if (tty == (struct tty_struct *) NULL)
-		goto out;
+		return;
 
 	lock_kernel();
 	if (test_bit(ASYI_TXLOW, &portp->istate)) {
@@ -2270,8 +2265,6 @@
 		}
 	}
 	unlock_kernel();
-out:
-	MOD_DEC_USE_COUNT;
 }
 
 /*****************************************************************************/
@@ -3216,13 +3209,11 @@
 	if (register_chrdev(STL_SIOMEMMAJOR, "staliomem", &stl_fsiomem))
 		printk("STALLION: failed to register serial board device\n");
 	devfs_mk_dir("staliomem");
+
 	for (i = 0; i < 4; i++) {
-		char name[16];
-		sprintf(name, "staliomem/%d", i);
-		devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-			       STL_SIOMEMMAJOR, i,
-			       S_IFCHR | S_IRUSR | S_IWUSR,
-			       &stl_fsiomem, NULL);
+		devfs_mk_cdev(MKDEV(STL_SIOMEMMAJOR, i),
+				S_IFCHR|S_IRUSR|S_IWUSR,
+				&stl_fsiomem, NULL, "staliomem/%d", i);
 	}
 
 /*
@@ -3231,6 +3222,7 @@
  */
 	memset(&stl_serial, 0, sizeof(struct tty_driver));
 	stl_serial.magic = TTY_DRIVER_MAGIC;
+	stl_serial.owner = THIS_MODULE;
 	stl_serial.driver_name = stl_drvname;
 	stl_serial.name = stl_serialname;
 	stl_serial.major = STL_SERIALMAJOR;
@@ -4136,9 +4128,7 @@
 	if ((len == 0) || ((len < STL_TXBUFLOW) &&
 	    (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
 		set_bit(ASYI_TXLOW, &portp->istate);
-		MOD_INC_USE_COUNT;
-		if (schedule_work(&portp->tqueue) == 0)
-			MOD_DEC_USE_COUNT;
+		schedule_work(&portp->tqueue);
 	}
 
 	if (len == 0) {
@@ -4318,9 +4308,7 @@
 	misr = inb(ioaddr + EREG_DATA);
 	if (misr & MISR_DCD) {
 		set_bit(ASYI_DCDCHANGE, &portp->istate);
-		MOD_INC_USE_COUNT;
-		if (schedule_task(&portp->tqueue) == 0)
-			MOD_DEC_USE_COUNT;
+		schedule_task(&portp->tqueue);
 		portp->stats.modem++;
 	}
 
@@ -5117,9 +5105,7 @@
 	if ((len == 0) || ((len < STL_TXBUFLOW) &&
 	    (test_bit(ASYI_TXLOW, &portp->istate) == 0))) {
 		set_bit(ASYI_TXLOW, &portp->istate);
-		MOD_INC_USE_COUNT;
-		if (schedule_task(&portp->tqueue) == 0)
-			MOD_DEC_USE_COUNT;
+		schedule_task(&portp->tqueue); 
 	}
 
 	if (len == 0) {
@@ -5336,9 +5322,7 @@
 		ipr = stl_sc26198getreg(portp, IPR);
 		if (ipr & IPR_DCDCHANGE) {
 			set_bit(ASYI_DCDCHANGE, &portp->istate);
-			MOD_INC_USE_COUNT;
-			if (schedule_task(&portp->tqueue) == 0)
-				MOD_DEC_USE_COUNT;
+			schedule_task(&portp->tqueue); 
 			portp->stats.modem++;
 		}
 		break;
diff -Nru a/drivers/char/sx.c b/drivers/char/sx.c
--- a/drivers/char/sx.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/sx.c	Sat Apr 26 07:08:04 2003
@@ -1739,8 +1739,10 @@
 				if (copy_from_user(tmp, (char *)data + i, 
 						   (i + SX_CHUNK_SIZE >
 						    nbytes) ? nbytes - i :
-						   	      SX_CHUNK_SIZE))
+						   	      SX_CHUNK_SIZE)) {
+					kfree (tmp);
 					return -EFAULT;
+				}
 				memcpy_toio    ((char *) (board->base2 + offset + i), tmp, 
 				                (i+SX_CHUNK_SIZE>nbytes)?nbytes-i:SX_CHUNK_SIZE);
 			}
diff -Nru a/drivers/char/synclink.c b/drivers/char/synclink.c
--- a/drivers/char/synclink.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/char/synclink.c	Tue May  6 14:29:47 2003
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/char/synclink.c
  *
- * $Id: synclink.c,v 4.6 2003/04/21 17:46:54 paulkf Exp $
+ * $Id: synclink.c,v 4.9 2003/05/06 21:18:51 paulkf Exp $
  *
  * Device driver for Microgate SyncLink ISA and PCI
  * high speed multiprotocol serial adapters.
@@ -193,6 +193,7 @@
 	int			flags;
 	int			count;		/* count of opens */
 	int			line;
+	int                     hw_version;
 	unsigned short		close_delay;
 	unsigned short		closing_wait;	/* time to wait before closing */
 	
@@ -917,7 +918,7 @@
 MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
 
 static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "$Revision: 4.6 $";
+static char *driver_version = "$Revision: 4.9 $";
 
 static int synclink_init_one (struct pci_dev *dev,
 				     const struct pci_device_id *ent);
@@ -925,6 +926,7 @@
 
 static struct pci_device_id synclink_pci_tbl[] __devinitdata = {
 	{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, },
+	{ PCI_VENDOR_ID_MICROGATE, 0x0210, PCI_ANY_ID, PCI_ANY_ID, },
 	{ 0, }, /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, synclink_pci_tbl);
@@ -4216,9 +4218,7 @@
 				info->get_tx_holding_index=0;
 
 			/* restart transmit timer */
-			del_timer(&info->tx_timer);
-			info->tx_timer.expires = jiffies + jiffies_from_ms(5000);
-			add_timer(&info->tx_timer);
+			mod_timer(&info->tx_timer, jiffies + jiffies_from_ms(5000));
 
 			ret = 1;
 		}
@@ -4436,12 +4436,12 @@
 		info->max_frame_size = 65535;
 	
 	if ( info->bus_type == MGSL_BUS_TYPE_PCI ) {
-		printk( "SyncLink device %s added:PCI bus IO=%04X IRQ=%d Mem=%08X LCR=%08X MaxFrameSize=%u\n",
-			info->device_name, info->io_base, info->irq_level,
+		printk( "SyncLink PCI v%d %s: IO=%04X IRQ=%d Mem=%08X,%08X MaxFrameSize=%u\n",
+			info->hw_version + 1, info->device_name, info->io_base, info->irq_level,
 			info->phys_memory_base, info->phys_lcr_base,
 		     	info->max_frame_size );
 	} else {
-		printk( "SyncLink device %s added:ISA bus IO=%04X IRQ=%d DMA=%d MaxFrameSize=%u\n",
+		printk( "SyncLink ISA %s: IO=%04X IRQ=%d DMA=%d MaxFrameSize=%u\n",
 			info->device_name, info->io_base, info->irq_level, info->dma_level,
 		     	info->max_frame_size );
 	}
@@ -5296,10 +5296,11 @@
 	info->mbre_bit = BIT8;
 	outw( BIT8, info->io_base );			/* set Master Bus Enable (DCAR) */
 
-	/* Enable DMAEN (Port 7, Bit 14) */
-	/* This connects the DMA request signal to the ISA bus */
-	/* on the ISA adapter. This has no effect for the PCI adapter */
-	usc_OutReg( info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) & ~BIT14) );
+	if (info->bus_type == MGSL_BUS_TYPE_ISA) {
+		/* Enable DMAEN (Port 7, Bit 14) */
+		/* This connects the DMA request signal to the ISA bus */
+		usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT15) & ~BIT14));
+	}
 
 	/* DMA Control Register (DCR)
 	 *
@@ -6276,10 +6277,11 @@
 
 	usc_EnableMasterIrqBit( info );
 
-	/* Enable INTEN (Port 6, Bit12) */
-	/* This connects the IRQ request signal to the ISA bus */
-	/* on the ISA adapter. This has no effect for the PCI adapter */
-	usc_OutReg( info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12) );
+	if (info->bus_type == MGSL_BUS_TYPE_ISA) {
+		/* Enable INTEN (Port 6, Bit12) */
+		/* This connects the IRQ request signal to the ISA bus */
+		usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12));
+	}
 
 }	/* end of usc_set_async_mode() */
 
@@ -6370,10 +6372,11 @@
 	usc_loopback_frame( info );
 	usc_set_sdlc_mode( info );
 
-	/* Enable INTEN (Port 6, Bit12) */
-	/* This connects the IRQ request signal to the ISA bus */
-	/* on the ISA adapter. This has no effect for the PCI adapter */
-	usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12));
+	if (info->bus_type == MGSL_BUS_TYPE_ISA) {
+		/* Enable INTEN (Port 6, Bit12) */
+		/* This connects the IRQ request signal to the ISA bus */
+		usc_OutReg(info, PCR, (u16)((usc_InReg(info, PCR) | BIT13) & ~BIT12));
+	}
 
 	usc_enable_aux_clock(info, info->params.clock_speed);
 
@@ -8115,17 +8118,20 @@
 	info->bus_type = MGSL_BUS_TYPE_PCI;
 	info->io_addr_size = 8;
 	info->irq_flags = SA_SHIRQ;
-		
-	/* Store the PCI9050 misc control register value because a flaw
-	 * in the PCI9050 prevents LCR registers from being read if 
-	 * BIOS assigns an LCR base address with bit 7 set.
-	 *  
-	 * Only the misc control register is accessed for which only 
-	 * write access is needed, so set an initial value and change 
-	 * bits to the device instance data as we write the value
-	 * to the actual misc control register.
-	 */
-	info->misc_ctrl_value = 0x087e4546;
+
+	if (dev->device == 0x0210) {
+		/* Version 1 PCI9030 based universal PCI adapter */
+		info->misc_ctrl_value = 0x007c4080;
+		info->hw_version = 1;
+	} else {
+		/* Version 0 PCI9050 based 5V PCI adapter
+		 * A PCI9050 bug prevents reading LCR registers if 
+		 * LCR base address bit 7 is set. Maintain shadow
+		 * value so we can write to LCR misc control reg.
+		 */
+		info->misc_ctrl_value = 0x087e4546;
+		info->hw_version = 0;
+	}
 				
 	mgsl_add_device(info);
 
diff -Nru a/drivers/char/sysrq.c b/drivers/char/sysrq.c
--- a/drivers/char/sysrq.c	Fri Feb 21 07:36:41 2003
+++ b/drivers/char/sysrq.c	Wed May  7 21:18:01 2003
@@ -101,131 +101,19 @@
 {
 	machine_restart(NULL);
 }
+
 static struct sysrq_key_op sysrq_reboot_op = {
 	.handler	= sysrq_handle_reboot,
 	.help_msg	= "reBoot",
 	.action_msg	= "Resetting",
 };
 
-
-
-/* SYNC SYSRQ HANDLERS BLOCK */
-
-/* do_emergency_sync helper function */
-/* Guesses if the device is a local hard drive */
-static int is_local_disk(struct block_device *bdev)
-{
-	switch (MAJOR(bdev->bd_dev)) {
-	case IDE0_MAJOR:
-	case IDE1_MAJOR:
-	case IDE2_MAJOR:
-	case IDE3_MAJOR:
-	case IDE4_MAJOR:
-	case IDE5_MAJOR:
-	case IDE6_MAJOR:
-	case IDE7_MAJOR:
-	case IDE8_MAJOR:
-	case IDE9_MAJOR:
-	case SCSI_DISK0_MAJOR:
-	case SCSI_DISK1_MAJOR:
-	case SCSI_DISK2_MAJOR:
-	case SCSI_DISK3_MAJOR:
-	case SCSI_DISK4_MAJOR:
-	case SCSI_DISK5_MAJOR:
-	case SCSI_DISK6_MAJOR:
-	case SCSI_DISK7_MAJOR:
-	case XT_DISK_MAJOR:
-		return 1;
-	default:
-		return 0;
-	}
-}
-
-/* do_emergency_sync helper function */
-static void go_sync(struct super_block *sb, int remount_flag)
-{
-	int orig_loglevel;
-	orig_loglevel = console_loglevel;
-	console_loglevel = 7;
-	printk(KERN_INFO "%sing device %s ... ",
-	       remount_flag ? "Remount" : "Sync",
-	       sb->s_id);
-
-	if (remount_flag) { /* Remount R/O */
-		int ret, flags;
-		struct file *file;
-
-		if (sb->s_flags & MS_RDONLY) {
-			printk("R/O\n");
-			return;
-		}
-
-		file_list_lock();
-		list_for_each_entry(file, &sb->s_files, f_list) {
-			if (file->f_dentry && file_count(file)
-				&& S_ISREG(file->f_dentry->d_inode->i_mode))
-				file->f_mode &= ~2;
-		}
-		file_list_unlock();
-		DQUOT_OFF(sb);
-		fsync_bdev(sb->s_bdev);
-		flags = MS_RDONLY;
-		if (sb->s_op && sb->s_op->remount_fs) {
-			ret = sb->s_op->remount_fs(sb, &flags, NULL);
-			if (ret)
-				printk("error %d\n", ret);
-			else {
-				sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
-				printk("OK\n");
-			}
-		} else
-			printk("nothing to do\n");
-	} else { /* Sync only */
-		fsync_bdev(sb->s_bdev);
-		printk("OK\n");
-	}
-	console_loglevel = orig_loglevel;
-}
-/*
- * Emergency Sync or Unmount. We cannot do it directly, so we set a special
- * flag and wake up the bdflush kernel thread which immediately calls this function.
- * We process all mounted hard drives first to recover from crashed experimental
- * block devices and malfunctional network filesystems.
- */
-
-int emergency_sync_scheduled;
-
-void do_emergency_sync(void) {
-	struct super_block *sb;
-	int remount_flag;
-	int orig_loglevel;
-
-	lock_kernel();
-	remount_flag = (emergency_sync_scheduled == EMERG_REMOUNT);
-	emergency_sync_scheduled = 0;
-
-	list_for_each_entry(sb, &super_blocks, s_list)
-		if (sb->s_bdev && is_local_disk(sb->s_bdev))
-			go_sync(sb, remount_flag);
-
-	list_for_each_entry(sb, &super_blocks, s_list)
-		if (sb->s_bdev && !is_local_disk(sb->s_bdev))
-			go_sync(sb, remount_flag);
-
-	unlock_kernel();
-
-	orig_loglevel = console_loglevel;
-	console_loglevel = 7;
-	printk(KERN_INFO "Done.\n");
-	console_loglevel = orig_loglevel;
-}
-
 static void sysrq_handle_sync(int key, struct pt_regs *pt_regs,
 			      struct tty_struct *tty) 
 {
-	emergency_sync_scheduled = EMERG_SYNC;
-	wakeup_bdflush(0);
+	emergency_sync();
 }
+
 static struct sysrq_key_op sysrq_sync_op = {
 	.handler	= sysrq_handle_sync,
 	.help_msg	= "Sync",
@@ -235,9 +123,9 @@
 static void sysrq_handle_mountro(int key, struct pt_regs *pt_regs,
 				 struct tty_struct *tty) 
 {
-	emergency_sync_scheduled = EMERG_REMOUNT;
-	wakeup_bdflush(0);
+	emergency_remount();
 }
+
 static struct sysrq_key_op sysrq_mountro_op = {
 	.handler	= sysrq_handle_mountro,
 	.help_msg	= "Unmount",
diff -Nru a/drivers/char/tipar.c b/drivers/char/tipar.c
--- a/drivers/char/tipar.c	Sat Mar 22 07:38:05 2003
+++ b/drivers/char/tipar.c	Wed May  7 08:47:30 2003
@@ -421,8 +421,6 @@
 static int
 tipar_register(int nr, struct parport *port)
 {
-	char name[32];
-
 	/* Register our module into parport */
 	table[nr].dev = parport_register_device(port, "tipar",
 						NULL, NULL, NULL, 0,
@@ -432,13 +430,9 @@
 		return 1;
 
 	/* Use devfs, tree: /dev/ticables/par/[0..2] */
-	sprintf(name, "ticables/par/%d", nr);
-	printk
-	    ("tipar: registering to devfs : major = %d, minor = %d, node = %s\n",
-	     TISER_MAJOR, (TIPAR_MINOR + nr), name);
-	devfs_register(NULL, name, DEVFS_FL_DEFAULT, TIPAR_MAJOR,
-		       TIPAR_MINOR + nr, S_IFCHR | S_IRUGO | S_IWUGO,
-		       &tipar_fops, NULL);
+	devfs_mk_cdev(MKDEV(TIPAR_MAJOR, TIPAR_MINOR + nr),
+			S_IFCHR | S_IRUGO | S_IWUGO,
+			"ticables/par/%d", nr);
 
 	/* Display informations */
 	printk(KERN_INFO "tipar%d: using %s (%s).\n", nr, port->name,
diff -Nru a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
--- a/drivers/char/tpqic02.c	Thu Apr 24 05:25:35 2003
+++ b/drivers/char/tpqic02.c	Wed May  7 08:47:30 2003
@@ -2694,38 +2694,27 @@
 #endif
 		return -ENODEV;
 	}
-	devfs_register(NULL, "ntpqic11", DEVFS_FL_DEFAULT,
-		       QIC02_TAPE_MAJOR, 2,
-		       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-		       &qic02_tape_fops, NULL);
-	devfs_register(NULL, "tpqic11", DEVFS_FL_DEFAULT,
-		       QIC02_TAPE_MAJOR, 3,
-		       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-		       &qic02_tape_fops, NULL);
-	devfs_register(NULL, "ntpqic24", DEVFS_FL_DEFAULT,
-		       QIC02_TAPE_MAJOR, 4,
-		       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-		       &qic02_tape_fops, NULL);
-	devfs_register(NULL, "tpqic24", DEVFS_FL_DEFAULT,
-		       QIC02_TAPE_MAJOR, 5,
-		       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-		       &qic02_tape_fops, NULL);
-	devfs_register(NULL, "ntpqic120", DEVFS_FL_DEFAULT,
-		       QIC02_TAPE_MAJOR, 6,
-		       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-		       &qic02_tape_fops, NULL);
-	devfs_register(NULL, "tpqic120", DEVFS_FL_DEFAULT,
-		       QIC02_TAPE_MAJOR, 7,
-		       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-		       &qic02_tape_fops, NULL);
-	devfs_register(NULL, "ntpqic150", DEVFS_FL_DEFAULT,
-		       QIC02_TAPE_MAJOR, 8,
-		       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-		       &qic02_tape_fops, NULL);
-	devfs_register(NULL, "tpqic150", DEVFS_FL_DEFAULT,
-		       QIC02_TAPE_MAJOR, 9,
-		       S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-		       &qic02_tape_fops, NULL);
+
+	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 2),
+		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic11");
+	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 3),
+		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic11");
+
+	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 4),
+		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic24");
+	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 5),
+		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic24");
+
+	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 6),
+		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic120");
+	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 7),
+		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic120");
+
+	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 8),
+		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "ntpqic150");
+	devfs_mk_cdev(MKDEV(QIC02_TAPE_MAJOR, 9),
+		       S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP, "tpqic150");
+
 	init_waitqueue_head(&qic02_tape_transfer);
 	/* prepare timer */
 	TIMEROFF;
diff -Nru a/drivers/char/tty_io.c b/drivers/char/tty_io.c
--- a/drivers/char/tty_io.c	Mon Apr 28 23:51:37 2003
+++ b/drivers/char/tty_io.c	Sat May 17 12:39:13 2003
@@ -260,9 +260,7 @@
 	/* Eduardo Blanco <ejbs@cs.cs.com.uy> */
 	/* Cyrus Durgin <cider@speakeasy.org> */
 	if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) {
-		char modname [20];
-		sprintf(modname, "tty-ldisc-%d", ldisc);
-		request_module (modname);
+		request_module("tty-ldisc-%d", ldisc);
 	}
 	if (!(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED))
 		return -EINVAL;
@@ -2088,22 +2086,6 @@
 }
 
 #ifdef CONFIG_DEVFS_FS
-static void tty_register_devfs(struct tty_driver *driver, unsigned index)
-{
-	dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
-	char buf[32];
-
-	if (index >= driver->num) {
-		printk(KERN_ERR "Attempt to register invalid tty line number "
-		       "with devfs (%d).\n", index);
-		return;
-	}
-
-	tty_line_name(driver, index, buf);
-	devfs_register(NULL, buf, 0, MAJOR(dev), MINOR(dev),
-		S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL);
-}
-
 static void tty_unregister_devfs(struct tty_driver *driver, int index)
 {
 	char path[64];
@@ -2111,21 +2093,137 @@
 	devfs_remove(path);
 }
 #else
-# define tty_register_devfs(driver, index)	do { } while (0)
 # define tty_unregister_devfs(driver, index)	do { } while (0)
 #endif /* CONFIG_DEVFS_FS */
 
-/*
- * Register a tty device described by <driver>, with minor number <minor>.
- */
-void tty_register_device(struct tty_driver *driver, unsigned index)
+static struct class tty_class = {
+	.name	= "tty",
+};
+
+struct tty_dev {
+	struct list_head node;
+	dev_t dev;
+	struct class_device class_dev;
+};
+#define to_tty_dev(d) container_of(d, struct tty_dev, class_dev)
+
+static LIST_HEAD(tty_dev_list);
+static spinlock_t tty_dev_list_lock = SPIN_LOCK_UNLOCKED;
+
+static ssize_t show_dev(struct class_device *class_dev, char *buf)
 {
-	tty_register_devfs(driver, index);
+	struct tty_dev *tty_dev = to_tty_dev(class_dev);
+	return sprintf(buf, "%04x\n", tty_dev->dev);
 }
+static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
+
+static void tty_add_class_device(char *name, dev_t dev, struct device *device)
+{
+	struct tty_dev *tty_dev = NULL;
+	char *temp;
+	int retval;
+
+	tty_dev = kmalloc(sizeof(*tty_dev), GFP_KERNEL);
+	if (!tty_dev)
+		return;
+	memset(tty_dev, 0x00, sizeof(*tty_dev));
 
+	/* stupid '/' in tty name strings... */
+	temp = strrchr(name, '/');
+	if (temp && (temp[1] != 0x00))
+		++temp;
+	else
+		temp = name;
+
+	tty_dev->class_dev.dev = device;
+	tty_dev->class_dev.class = &tty_class;
+	snprintf(tty_dev->class_dev.class_id, BUS_ID_SIZE, "%s", temp);
+	retval = class_device_register(&tty_dev->class_dev);
+	if (retval)
+		goto error;
+	class_device_create_file (&tty_dev->class_dev, &class_device_attr_dev);
+	tty_dev->dev = dev;
+	spin_lock(&tty_dev_list_lock);
+	list_add(&tty_dev->node, &tty_dev_list);
+	spin_unlock(&tty_dev_list_lock);
+	return;
+error:
+	kfree(tty_dev);
+}
+
+void tty_remove_class_device(dev_t dev)
+{
+	struct tty_dev *tty_dev = NULL;
+	struct list_head *tmp;
+	int found = 0;
+
+	spin_lock(&tty_dev_list_lock);
+	list_for_each (tmp, &tty_dev_list) {
+		tty_dev = list_entry(tmp, struct tty_dev, node);
+		if ((MAJOR(tty_dev->dev) == MAJOR(dev)) &&
+		    (MINOR(tty_dev->dev) == MINOR(dev))) {
+			found = 1;
+			break;
+		}
+	}
+	if (found) {
+		list_del(&tty_dev->node);
+		spin_unlock(&tty_dev_list_lock);
+		class_device_unregister(&tty_dev->class_dev);
+		kfree(tty_dev);
+	} else {
+		spin_unlock(&tty_dev_list_lock);
+	}
+}
+
+/**
+ * tty_register_device - register a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
+ * @device: a struct device that is associated with this tty device.
+ *	This field is optional, if there is no known struct device for this
+ *	tty device it can be set to NULL safely.
+ *
+ * This call is required to be made to register an individual tty device if
+ * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set.  If that
+ * bit is not set, this function should not be called.
+ */
+void tty_register_device(struct tty_driver *driver, unsigned index,
+			 struct device *device)
+{
+	dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
+	char name[64];
+
+	if (index >= driver->num) {
+		printk(KERN_ERR "Attempt to register invalid tty line number "
+		       " (%d).\n", index);
+		return;
+	}
+
+	tty_line_name(driver, index, name);
+	devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR, name);
+
+	/* stupid console driver devfs names... change vc/X into ttyX */
+	if (driver->type == TTY_DRIVER_TYPE_CONSOLE)
+		sprintf(name, "tty%d", MINOR(dev));
+
+	/* we don't care about the ptys */
+	if (driver->type != TTY_DRIVER_TYPE_PTY)
+		tty_add_class_device (name, dev, device);
+}
+
+/**
+ * tty_unregister_device - unregister a tty device
+ * @driver: the tty driver that describes the tty device
+ * @index: the index in the tty driver for this tty device
+ *
+ * If a tty device is registered with a call to tty_register_device() then
+ * this function must be made when the tty device is gone.
+ */
 void tty_unregister_device(struct tty_driver *driver, unsigned index)
 {
 	tty_unregister_devfs(driver, index);
+	tty_remove_class_device(MKDEV(driver->major, driver->minor_start) + index);
 }
 
 EXPORT_SYMBOL(tty_register_device);
@@ -2207,7 +2305,7 @@
 	
 	if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
 		for(i = 0; i < driver->num; i++)
-		    tty_register_device(driver, i);
+		    tty_register_device(driver, i, NULL);
 	}
 	proc_tty_register_driver(driver);
 	return error;
@@ -2288,10 +2386,6 @@
 extern int vty_init(void);
 #endif
 
-static struct class tty_class = {
-	.name	= "tty",
-};
-
 static int __init tty_class_init(void)
 {
 	return class_register(&tty_class);
@@ -2308,33 +2402,29 @@
 	if (register_chrdev_region(TTYAUX_MAJOR, 0, 1,
 				   "/dev/tty", &tty_fops) < 0)
 		panic("Couldn't register /dev/tty driver\n");
-
-	devfs_register (NULL, "tty", 0, TTYAUX_MAJOR, 0,
-			S_IFCHR | S_IRUGO | S_IWUGO, &tty_fops, NULL);
+	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty");
+	tty_add_class_device ("tty", MKDEV(TTYAUX_MAJOR, 0), NULL);
 
 	if (register_chrdev_region(TTYAUX_MAJOR, 1, 1,
 				   "/dev/console", &tty_fops) < 0)
 		panic("Couldn't register /dev/console driver\n");
-
-	devfs_register (NULL, "console", 0, TTYAUX_MAJOR, 1,
-			S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL);
+	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console");
+	tty_add_class_device ("console", MKDEV(TTYAUX_MAJOR, 1), NULL);
 
 #ifdef CONFIG_UNIX98_PTYS
 	if (register_chrdev_region(TTYAUX_MAJOR, 2, 1,
 				   "/dev/ptmx", &tty_fops) < 0)
 		panic("Couldn't register /dev/ptmx driver\n");
-
-	devfs_register (NULL, "ptmx", 0, TTYAUX_MAJOR, 2,
-			S_IFCHR | S_IRUGO | S_IWUGO, &tty_fops, NULL);
+	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx");
+	tty_add_class_device ("ptmx", MKDEV(TTYAUX_MAJOR, 2), NULL);
 #endif
 	
 #ifdef CONFIG_VT
 	if (register_chrdev_region(TTY_MAJOR, 0, 1,
 				   "/dev/vc/0", &tty_fops) < 0)
 		panic("Couldn't register /dev/tty0 driver\n");
-
-	devfs_register (NULL, "vc/0", 0, TTY_MAJOR, 0,
-			S_IFCHR | S_IRUSR | S_IWUSR, &tty_fops, NULL);
+	devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0");
+	tty_add_class_device ("tty0", MKDEV(TTY_MAJOR, 0), NULL);
 
 	vty_init();
 #endif
diff -Nru a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
--- a/drivers/char/tty_ioctl.c	Mon Apr 21 20:58:40 2003
+++ b/drivers/char/tty_ioctl.c	Wed Apr 23 19:53:14 2003
@@ -394,7 +394,7 @@
 				return -EFAULT;
 			return 0;
 		case TCSETSF:
-			return set_termios(real_tty, arg,  TERMIOS_FLUSH);
+			return set_termios(real_tty, arg,  TERMIOS_FLUSH | TERMIOS_WAIT);
 		case TCSETSW:
 			return set_termios(real_tty, arg, TERMIOS_WAIT);
 		case TCSETS:
@@ -402,7 +402,7 @@
 		case TCGETA:
 			return get_termio(real_tty,(struct termio *) arg);
 		case TCSETAF:
-			return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_TERMIO);
+			return set_termios(real_tty, arg, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
 		case TCSETAW:
 			return set_termios(real_tty, arg, TERMIOS_WAIT | TERMIOS_TERMIO);
 		case TCSETA:
diff -Nru a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
--- a/drivers/char/vc_screen.c	Mon Nov 18 10:27:30 2002
+++ b/drivers/char/vc_screen.c	Wed May  7 08:47:30 2003
@@ -469,40 +469,27 @@
 	.open		= vcs_open,
 };
 
-void vcs_make_devfs (unsigned int index, int unregister)
+void vcs_make_devfs(struct tty_struct *tty)
 {
-#ifdef CONFIG_DEVFS_FS
-
-	if (unregister) {
-		devfs_remove("vcc/%u", index + 1);
-		devfs_remove("vcc/a%u", index + 1);
-	} else {
-		char name[16];
-		sprintf(name, "vcc/%u", index + 1);
-		devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-				VCS_MAJOR, index + 1,
-				S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
-		sprintf(name, "vcc/a%u", index + 1);
-		devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-				VCS_MAJOR, index + 129,
-				S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
-	}
-#endif /* CONFIG_DEVFS_FS */
+	devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 1),
+			S_IFCHR|S_IRUSR|S_IWUSR,
+			"vcc/%u", tty->index + 1);
+	devfs_mk_cdev(MKDEV(VCS_MAJOR, tty->index + 129),
+			S_IFCHR|S_IRUSR|S_IWUSR,
+			"vcc/a%u", tty->index + 1);
+}
+void vcs_remove_devfs(struct tty_struct *tty)
+{
+	devfs_remove("vcc/%u", tty->index + 1);
+	devfs_remove("vcc/a%u", tty->index + 1);
 }
 
 int __init vcs_init(void)
 {
-	int error;
-
-	error = register_chrdev(VCS_MAJOR, "vcs", &vcs_fops);
-
-	if (error)
-		printk("unable to get major %d for vcs device", VCS_MAJOR);
-
-	devfs_register(NULL, "vcc/0", DEVFS_FL_DEFAULT, VCS_MAJOR, 0,
-			S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
-	devfs_register(NULL, "vcc/a", DEVFS_FL_DEFAULT, VCS_MAJOR, 128,
-			S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
+	if (register_chrdev(VCS_MAJOR, "vcs", &vcs_fops))
+		panic("unable to get major %d for vcs device", VCS_MAJOR);
 
-	return error;
+	devfs_mk_cdev(MKDEV(VCS_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/0");
+	devfs_mk_cdev(MKDEV(VCS_MAJOR, 128), S_IFCHR|S_IRUSR|S_IWUSR, "vcc/a0");
+	return 0;
 }
diff -Nru a/drivers/char/vme_scc.c b/drivers/char/vme_scc.c
--- a/drivers/char/vme_scc.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/char/vme_scc.c	Wed May  7 07:23:12 2003
@@ -129,6 +129,7 @@
 
 	memset(&scc_driver, 0, sizeof(scc_driver));
 	scc_driver.magic = TTY_DRIVER_MAGIC;
+	scc_driver.owner = THIS_MODULE;
 	scc_driver.driver_name = "scc";
 #ifdef CONFIG_DEVFS_FS
 	scc_driver.name = "tts/";
@@ -795,7 +796,6 @@
 {
 	scc_disable_tx_interrupts(ptr);
 	scc_disable_rx_interrupts(ptr);
-	MOD_DEC_USE_COUNT;
 }
 
 
@@ -803,7 +803,6 @@
 {
 	scc_disable_tx_interrupts(ptr);
 	scc_disable_rx_interrupts(ptr);
-	MOD_DEC_USE_COUNT;
 }
 
 
@@ -938,13 +937,9 @@
 		return retval;
 	}
 	port->gs.flags |= GS_ACTIVE;
-	if (port->gs.count == 1) {
-		MOD_INC_USE_COUNT;
-	}
 	retval = gs_block_til_ready(port, filp);
 
 	if (retval) {
-		MOD_DEC_USE_COUNT;
 		port->gs.count--;
 		return retval;
 	}
diff -Nru a/drivers/char/vt.c b/drivers/char/vt.c
--- a/drivers/char/vt.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/char/vt.c	Wed May  7 23:26:53 2003
@@ -124,7 +124,9 @@
 #define DEFAULT_BELL_PITCH	750
 #define DEFAULT_BELL_DURATION	(HZ/8)
 
-extern void vcs_make_devfs (unsigned int index, int unregister);
+extern void vcs_make_devfs(struct tty_struct *tty);
+extern void vcs_remove_devfs(struct tty_struct *tty);
+
 extern void console_map_init(void);
 #ifdef CONFIG_PROM_CONSOLE
 extern void prom_con_init(void);
@@ -158,7 +160,6 @@
 static void hide_cursor(int currcons);
 static void unblank_screen_t(unsigned long dummy);
 static void console_callback(void *ignored);
-static void __init con_init_devfs (void);
 
 static int printable;		/* Is console ready for printing? */
 
@@ -2410,7 +2411,7 @@
 		tty->winsize.ws_col = video_num_columns;
 	}
 	if (tty->count == 1)
-		vcs_make_devfs (currcons, 0);
+		vcs_make_devfs(tty);
 	return 0;
 }
 
@@ -2418,10 +2419,10 @@
 {
 	struct vt_struct *vt;
 	
-	if (!tty)
+	if (!tty || tty->count != 1)
 		return;
-	if (tty->count != 1) return;
-	vcs_make_devfs (tty->index, 1);
+
+	vcs_remove_devfs(tty);
 	vt = (struct vt_struct*)tty->driver_data;
 	if (vt)
 		vc_cons[vt->vc_num].d->vc_tty = NULL;
@@ -2525,11 +2526,6 @@
 	console_driver.type = TTY_DRIVER_TYPE_CONSOLE;
 	console_driver.init_termios = tty_std_termios;
 	console_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
-	/* Tell tty_register_driver() to skip consoles because they are
-	 * registered before kmalloc() is ready. We'll patch them in later. 
-	 * See comments at console_init(); see also con_init_devfs(). 
-	 */
-	console_driver.flags |= TTY_DRIVER_NO_DEVFS;
 	console_driver.refcount = &console_refcount;
 	console_driver.table = console_table;
 	console_driver.termios = console_termios;
@@ -2562,7 +2558,6 @@
 #ifdef CONFIG_FRAMEBUFFER_CONSOLE
 	fb_console_init();
 #endif	
-	con_init_devfs();
 	vcs_init();
 	return 0;
 }
@@ -2655,18 +2650,6 @@
     unsigned int mode;
     get_user(mode, argp);
     vesa_blank_mode = (mode < 4) ? mode : 0;
-}
-
-/* We can't register the console with devfs during con_init(), because it
- * is called before kmalloc() works.  This function is called later to
- * do the registration.
- */
-static void __init con_init_devfs (void)
-{
-	int i;
-
-	for (i = 0; i < console_driver.num; i++)
-		tty_register_device (&console_driver, i);
 }
 
 /*
diff -Nru a/drivers/char/vt_ioctl.c b/drivers/char/vt_ioctl.c
--- a/drivers/char/vt_ioctl.c	Thu Mar 20 06:36:40 2003
+++ b/drivers/char/vt_ioctl.c	Mon May 12 07:12:47 2003
@@ -869,13 +869,13 @@
 		if (clin > 32)
 			return -EINVAL;
 		    
-		if (vlin)
-			vc->vc_scan_lines = vlin;
-		if (clin)
-			vc->vc_font.height = clin;
-	
-		for (i = 0; i < MAX_NR_CONSOLES; i++)
+		for (i = 0; i < MAX_NR_CONSOLES; i++) {
+			if (vlin)
+				vc_cons[i].d->vc_scan_lines = vlin;
+			if (clin)
+				vc_cons[i].d->vc_font.height = clin;
 			vc_resize(i, cc, ll);
+		}
   		return 0;
 	}
 
diff -Nru a/drivers/char/watchdog/pcwd.c b/drivers/char/watchdog/pcwd.c
--- a/drivers/char/watchdog/pcwd.c	Thu Apr 24 05:36:57 2003
+++ b/drivers/char/watchdog/pcwd.c	Sat Apr 26 07:08:04 2003
@@ -594,6 +594,7 @@
  
 static int __init pcwatchdog_init(void)
 {
+	char *firmware;
 	int i, found = 0;
 	pcwd_validate_timeout();
 	spin_lock_init(&io_lock);
@@ -633,10 +634,12 @@
 
 	if (revision == PCWD_REVISION_A)
 		printk(KERN_INFO "pcwd: PC Watchdog (REV.A) detected at port 0x%03x\n", current_readport);
-	else if (revision == PCWD_REVISION_C)
+	else if (revision == PCWD_REVISION_C) {
+		firmware = get_firmware();
 		printk(KERN_INFO "pcwd: PC Watchdog (REV.C) detected at port 0x%03x (Firmware version: %s)\n",
-			current_readport, get_firmware());
-	else {
+			current_readport, firmware);
+		kfree(firmware);
+	} else {
 		/* Should NEVER happen, unless get_revision() fails. */
 		printk("pcwd: Unable to get revision.\n");
 		return -1;
diff -Nru a/drivers/cpufreq/proc_intf.c b/drivers/cpufreq/proc_intf.c
--- a/drivers/cpufreq/proc_intf.c	Sat Feb 15 01:34:08 2003
+++ b/drivers/cpufreq/proc_intf.c	Mon May 12 21:23:15 2003
@@ -209,6 +209,9 @@
 {
 	struct proc_dir_entry *entry = NULL;
 
+	if (!cpufreq_driver)
+		return -ENODEV;
+
         /* are these acceptable values? */
 	entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR, 
 				  &proc_root);
diff -Nru a/drivers/hotplug/Kconfig b/drivers/hotplug/Kconfig
--- a/drivers/hotplug/Kconfig	Sun Feb  9 17:29:49 2003
+++ b/drivers/hotplug/Kconfig	Tue May  6 08:42:55 2003
@@ -61,7 +61,7 @@
 
 config HOTPLUG_PCI_ACPI
 	tristate "ACPI PCI Hotplug driver"
-	depends on ACPI && HOTPLUG_PCI
+	depends on ACPI_BUS && HOTPLUG_PCI
 	help
 	  Say Y here if you have a system that supports PCI Hotplug using
 	  ACPI.
diff -Nru a/drivers/hotplug/acpiphp_glue.c b/drivers/hotplug/acpiphp_glue.c
--- a/drivers/hotplug/acpiphp_glue.c	Mon Feb 24 03:28:46 2003
+++ b/drivers/hotplug/acpiphp_glue.c	Wed May 14 23:43:59 2003
@@ -203,6 +203,7 @@
 
 	if (ACPI_FAILURE(status)) {
 		err("failed to register interrupt notify handler\n");
+		kfree(newfunc);
 		return status;
 	}
 
@@ -806,6 +807,7 @@
 	struct list_head *l;
 	struct acpiphp_func *func;
 	int retval = 0;
+	int num;
 
 	if (slot->flags & SLOT_ENABLED)
 		goto err_exit;
@@ -825,7 +827,10 @@
 		goto err_exit;
 
 	/* returned `dev' is the *first function* only! */
-	dev = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));
+	num = pci_scan_slot(slot->bridge->pci_bus, PCI_DEVFN(slot->device, 0));
+	if (num)
+		pci_bus_add_devices(slot->bridge->pci_bus);
+	dev = pci_find_slot(slot->bridge->bus, PCI_DEVFN(slot->device, 0));
 
 	if (!dev) {
 		err("No new device found\n");
diff -Nru a/drivers/hotplug/cpqphp.h b/drivers/hotplug/cpqphp.h
--- a/drivers/hotplug/cpqphp.h	Mon Apr 21 02:40:59 2003
+++ b/drivers/hotplug/cpqphp.h	Fri May  2 14:02:11 2003
@@ -31,7 +31,7 @@
 #include "pci_hotplug.h"
 #include <linux/interrupt.h>
 #include <asm/io.h>		/* for read? and write? functions */
-
+#include <linux/delay.h>	/* for delays */
 
 #if !defined(CONFIG_HOTPLUG_PCI_COMPAQ_MODULE)
 	#define MY_NAME	"cpqphp.o"
@@ -146,6 +146,10 @@
 	u8	reserved11;		/* 0x2b */
 	u8	slot_SERR;		/* 0x2c */
 	u8	slot_power;		/* 0x2d */
+	u8	reserved12;		/* 0x2e */
+	u8	reserved13;		/* 0x2f */
+	u8	next_curr_freq;		/* 0x30 */
+	u8	reset_freq_mode;	/* 0x31 */
 } __attribute__ ((packed));
 
 /* offsets to the controller registers based on the above structure layout */
@@ -173,6 +177,8 @@
 	CTRL_RESERVED11 =	offsetof(struct ctrl_reg, reserved11),
 	SLOT_SERR =		offsetof(struct ctrl_reg, slot_SERR),
 	SLOT_POWER =		offsetof(struct ctrl_reg, slot_power),
+	NEXT_CURR_FREQ =	offsetof(struct ctrl_reg, next_curr_freq),
+	RESET_FREQ_MODE =	offsetof(struct ctrl_reg, reset_freq_mode),
 };
 
 struct hrt {
@@ -294,12 +300,11 @@
 	struct pci_resource *bus_head;
 	struct pci_dev *pci_dev;
 	struct pci_bus *pci_bus;
-	struct proc_dir_entry* proc_entry;
-	struct proc_dir_entry* proc_entry2;
 	struct event_info event_queue[10];
 	struct slot *slot;
 	u8 next_event;
 	u8 interrupt;
+	u8 cfgspc_irq;
 	u8 bus;				/* bus number for the pci hotplug controller */
 	u8 rev;
 	u8 slot_device_offset;
@@ -316,8 +321,6 @@
 	u8 pcix_speed_capability;	/* PCI-X */
 	u8 pcix_support;		/* PCI-X */
 	u16 vendor_id;
-	char proc_name[20];
-	char proc_name2[20];
 	struct work_struct int_task_event;
 	wait_queue_head_t queue;	/* sleep & wake process */
 };
@@ -344,6 +347,7 @@
 #define PCI_SUB_HPC_ID2			0xA2F8
 #define PCI_SUB_HPC_ID3			0xA2F9
 #define PCI_SUB_HPC_ID_INTC		0xA2FA
+#define PCI_SUB_HPC_ID4			0xA2FD
 
 #define INT_BUTTON_IGNORE		0
 #define INT_PRESENCE_ON			1
@@ -436,7 +440,7 @@
 extern void	cpqhp_destroy_resource_list	(struct resource_lists * resources);
 extern int	cpqhp_configure_device		(struct controller* ctrl, struct pci_func* func);
 extern int	cpqhp_unconfigure_device	(struct pci_func* func);
-
+extern struct slot *cpqhp_find_slot		(struct controller *ctrl, u8 device);
 
 /* Global variables */
 extern int cpqhp_debug;
@@ -564,6 +568,7 @@
 	u32 led_control;
 	
 	led_control = readl(ctrl->hpc_reg + LED_CONTROL);
+	led_control &= ~(0x0101L << slot);
 	led_control |= (0x0001L << slot);
 	writel(led_control, ctrl->hpc_reg + LED_CONTROL);
 }
@@ -605,14 +610,63 @@
 }
 
 
+/*
+ * get_controller_speed - find the current frequency/mode of controller.
+ *
+ * @ctrl: controller to get frequency/mode for.
+ *
+ * Returns controller speed.
+ *
+ */
 static inline u8 get_controller_speed (struct controller *ctrl)
 {
-	u16 misc;
-	
-	misc = readw(ctrl->hpc_reg + MISC);
-	return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
+	u8 curr_freq;
+ 	u16 misc;
+ 	
+	if (ctrl->pcix_support) {
+		curr_freq = readb(ctrl->hpc_reg + NEXT_CURR_FREQ);
+		if ((curr_freq & 0xB0) == 0xB0) 
+			return PCI_SPEED_133MHz_PCIX;
+		if ((curr_freq & 0xA0) == 0xA0)
+			return PCI_SPEED_100MHz_PCIX;
+		if ((curr_freq & 0x90) == 0x90)
+			return PCI_SPEED_66MHz_PCIX;
+		if (curr_freq & 0x10)
+			return PCI_SPEED_66MHz;
+
+		return PCI_SPEED_33MHz;
+	}
+
+ 	misc = readw(ctrl->hpc_reg + MISC);
+ 	return (misc & 0x0800) ? PCI_SPEED_66MHz : PCI_SPEED_33MHz;
 }
+ 
+
+/*
+ * get_adapter_speed - find the max supported frequency/mode of adapter.
+ *
+ * @ctrl: hotplug controller.
+ * @hp_slot: hotplug slot where adapter is installed.
+ *
+ * Returns adapter speed.
+ *
+ */
+static inline u8 get_adapter_speed (struct controller *ctrl, u8 hp_slot)
+{
+	u32 temp_dword = readl(ctrl->hpc_reg + NON_INT_INPUT);
+	dbg("slot: %d, PCIXCAP: %8x\n", hp_slot, temp_dword);
+	if (ctrl->pcix_support) {
+		if (temp_dword & (0x10000 << hp_slot))
+			return PCI_SPEED_133MHz_PCIX;
+		if (temp_dword & (0x100 << hp_slot))
+			return PCI_SPEED_66MHz_PCIX;
+	}
 
+	if (temp_dword & (0x01 << hp_slot))
+		return PCI_SPEED_66MHz;
+
+	return PCI_SPEED_33MHz;
+}
 
 static inline void enable_slot_power (struct controller *ctrl, u8 slot)
 {
@@ -719,6 +773,139 @@
 
 	dbg("%s - end\n", __FUNCTION__);
 	return retval;
+}
+
+
+/**
+ * set_controller_speed - set the frequency and/or mode of a specific
+ * controller segment.
+ *
+ * @ctrl: controller to change frequency/mode for.
+ * @adapter_speed: the speed of the adapter we want to match.
+ * @hp_slot: the slot number where the adapter is installed.
+ *
+ * Returns 0 if we successfully change frequency and/or mode to match the
+ * adapter speed.
+ * 
+ */
+static inline u8 set_controller_speed(struct controller *ctrl, u8 adapter_speed, u8 hp_slot)
+{
+	struct slot *slot;
+	u8 reg;
+	u8 slot_power = readb(ctrl->hpc_reg + SLOT_POWER);
+	u16 reg16;
+	u32 leds = readl(ctrl->hpc_reg + LED_CONTROL);
+	
+	if (ctrl->speed == adapter_speed)
+		return 0;
+	
+	/* We don't allow freq/mode changes if we find another adapter running
+	 * in another slot on this controller */
+	for(slot = ctrl->slot; slot; slot = slot->next) {
+		if (slot->device == (hp_slot + ctrl->slot_device_offset)) 
+			continue;
+		if (!slot->hotplug_slot && !slot->hotplug_slot->info) 
+			continue;
+		if (slot->hotplug_slot->info->adapter_status == 0) 
+			continue;
+		/* If another adapter is running on the same segment but at a
+		 * lower speed/mode, we allow the new adapter to function at
+		 * this rate if supported */
+		if (ctrl->speed < adapter_speed) 
+			return 0;
+
+		return 1;
+	}
+	
+	/* If the controller doesn't support freq/mode changes and the
+	 * controller is running at a higher mode, we bail */
+	if ((ctrl->speed > adapter_speed) && (!ctrl->pcix_speed_capability))
+		return 1;
+	
+	/* But we allow the adapter to run at a lower rate if possible */
+	if ((ctrl->speed < adapter_speed) && (!ctrl->pcix_speed_capability))
+		return 0;
+
+	/* We try to set the max speed supported by both the adapter and
+	 * controller */
+	if (ctrl->speed_capability < adapter_speed) {
+		if (ctrl->speed == ctrl->speed_capability)
+			return 0;
+		adapter_speed = ctrl->speed_capability;
+	}
+
+	writel(0x0L, ctrl->hpc_reg + LED_CONTROL);
+	writeb(0x00, ctrl->hpc_reg + SLOT_ENABLE);
+	
+	set_SOGO(ctrl); 
+	wait_for_ctrl_irq(ctrl);
+	
+	if (adapter_speed != PCI_SPEED_133MHz_PCIX)
+		reg = 0xF5;
+	else
+		reg = 0xF4;	
+	pci_write_config_byte(ctrl->pci_dev, 0x41, reg);
+	
+	reg16 = readw(ctrl->hpc_reg + NEXT_CURR_FREQ);
+	reg16 &= ~0x000F;
+	switch(adapter_speed) {
+		case(PCI_SPEED_133MHz_PCIX): 
+			reg = 0x75;
+			reg16 |= 0xB; 
+			break;
+		case(PCI_SPEED_100MHz_PCIX):
+			reg = 0x74;
+			reg16 |= 0xA;
+			break;
+		case(PCI_SPEED_66MHz_PCIX):
+			reg = 0x73;
+			reg16 |= 0x9;
+			break;
+		case(PCI_SPEED_66MHz):
+			reg = 0x73;
+			reg16 |= 0x1;
+			break;
+		default: /* 33MHz PCI 2.2 */
+			reg = 0x71;
+			break;
+			
+	}
+	reg16 |= 0xB << 12;
+	writew(reg16, ctrl->hpc_reg + NEXT_CURR_FREQ);
+	
+	mdelay(5); 
+	
+	/* Reenable interrupts */
+	writel(0, ctrl->hpc_reg + INT_MASK);
+
+	pci_write_config_byte(ctrl->pci_dev, 0x41, reg); 
+	
+	/* Restart state machine */
+	reg = ~0xF;
+	pci_read_config_byte(ctrl->pci_dev, 0x43, &reg);
+	pci_write_config_byte(ctrl->pci_dev, 0x43, reg);
+	
+	/* Only if mode change...*/
+	if (((ctrl->speed == PCI_SPEED_66MHz) && (adapter_speed == PCI_SPEED_66MHz_PCIX)) ||
+		((ctrl->speed == PCI_SPEED_66MHz_PCIX) && (adapter_speed == PCI_SPEED_66MHz))) 
+			set_SOGO(ctrl);
+	
+	wait_for_ctrl_irq(ctrl);
+	mdelay(1100);
+	
+	/* Restore LED/Slot state */
+	writel(leds, ctrl->hpc_reg + LED_CONTROL);
+	writeb(slot_power, ctrl->hpc_reg + SLOT_ENABLE);
+	
+	set_SOGO(ctrl);
+	wait_for_ctrl_irq(ctrl);
+
+	ctrl->speed = adapter_speed;
+	slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+
+	info("Successfully changed frequency/mode for adapter in slot %d\n", 
+			slot->number);
+	return 0;
 }
 
 #endif
diff -Nru a/drivers/hotplug/cpqphp_core.c b/drivers/hotplug/cpqphp_core.c
--- a/drivers/hotplug/cpqphp_core.c	Mon Apr 21 02:40:59 2003
+++ b/drivers/hotplug/cpqphp_core.c	Fri May  2 14:02:11 2003
@@ -24,6 +24,9 @@
  *
  * Send feedback to <greg@kroah.com>
  *
+ * Jan 12, 2003 -	Added 66/100/133MHz PCI-X support,
+ * 			Torben Mathiasen <torben.mathiasen@hp.com>
+ *
  */
 
 #include <linux/config.h>
@@ -57,7 +60,7 @@
 static u8 power_mode;
 static int debug;
 
-#define DRIVER_VERSION	"0.9.6"
+#define DRIVER_VERSION	"0.9.7"
 #define DRIVER_AUTHOR	"Dan Zink <dan.zink@compaq.com>, Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC	"Compaq Hot Plug PCI Controller Driver"
 
@@ -835,6 +838,7 @@
 	u8 hp_slot = 0;
 	u8 device;
 	u8 rev;
+	u8 bus_cap;
 	u16 temp_word;
 	u16 vendor_id;
 	u16 subsystem_vid;
@@ -896,6 +900,39 @@
 
 		switch (subsystem_vid) {
 			case PCI_VENDOR_ID_COMPAQ:
+				if (rev >= 0x13) { /* CIOBX */
+					ctrl->push_flag = 1;
+					ctrl->slot_switch_type = 1;		// Switch is present
+					ctrl->push_button = 1;			// Pushbutton is present
+					ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
+					ctrl->defeature_PHP = 1;		// PHP is supported
+					ctrl->pcix_support = 1;			// PCI-X supported
+					ctrl->pcix_speed_capability = 1;
+					pci_read_config_byte(pdev, 0x41, &bus_cap);
+					if (bus_cap & 0x80) {
+						dbg("bus max supports 133MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_133MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 0x40) {
+						dbg("bus max supports 100MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 20) {
+						dbg("bus max supports 66MHz PCI-X\n");
+						ctrl->speed_capability = PCI_SPEED_66MHz_PCIX;
+						break;
+					}
+					if (bus_cap & 10) {
+						dbg("bus max supports 66MHz PCI\n");
+						ctrl->speed_capability = PCI_SPEED_66MHz;
+						break;
+					}
+
+					break;
+				}
+
 				switch (subsystem_deviceid) {
 					case PCI_SUB_HPC_ID:
 						/* Original 6500/7000 implementation */
@@ -939,8 +976,18 @@
 						ctrl->pcix_support = 0;			// PCI-X not supported
 						ctrl->pcix_speed_capability = 0;	// N/A since PCI-X not supported
 						break;
+					case PCI_SUB_HPC_ID4:
+						/* First PCI-X implementation, 100MHz */
+						ctrl->push_flag = 1;
+						ctrl->slot_switch_type = 1;		// Switch is present
+						ctrl->speed_capability = PCI_SPEED_100MHz_PCIX;
+						ctrl->push_button = 1;			// Pushbutton is present
+						ctrl->pci_config_space = 1;		// Index/data access to working registers 0 = not supported, 1 = supported
+						ctrl->defeature_PHP = 1;		// PHP is supported
+						ctrl->pcix_support = 1;			// PCI-X supported
+						ctrl->pcix_speed_capability = 0;	
+						break;
 					default:
-						// TODO: Add SSIDs for CPQ systems that support PCI-X
 						err(msg_HPC_not_supported);
 						rc = -ENODEV;
 						goto err_free_ctrl;
@@ -1029,7 +1076,7 @@
 	info("Initializing the PCI hot plug controller residing on PCI bus %d\n", pdev->bus->number);
 
 	dbg ("Hotplug controller capabilities:\n");
-	dbg ("    speed_capability       %s\n", ctrl->speed_capability == PCI_SPEED_33MHz ? "33MHz" : "66Mhz");
+	dbg ("    speed_capability       %d\n", ctrl->speed_capability);
 	dbg ("    slot_switch_type       %s\n", ctrl->slot_switch_type == 0 ? "no switch" : "switch present");
 	dbg ("    defeature_PHP          %s\n", ctrl->defeature_PHP == 0 ? "PHP not supported" : "PHP supported");
 	dbg ("    alternate_base_address %s\n", ctrl->alternate_base_address == 0 ? "not supported" : "supported");
@@ -1082,7 +1129,6 @@
 	}
 
 	// Check for 66Mhz operation
-	// TODO: Add PCI-X support
 	ctrl->speed = get_controller_speed(ctrl);
 
 
@@ -1118,6 +1164,9 @@
 	 */
 	// The next line is required for cpqhp_find_available_resources
 	ctrl->interrupt = pdev->irq;
+
+	ctrl->cfgspc_irq = 0;
+	pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &ctrl->cfgspc_irq);
 
 	rc = cpqhp_find_available_resources(ctrl, cpqhp_rom_start);
 	ctrl->add_support = !rc;
diff -Nru a/drivers/hotplug/cpqphp_ctrl.c b/drivers/hotplug/cpqphp_ctrl.c
--- a/drivers/hotplug/cpqphp_ctrl.c	Mon Apr 21 02:40:59 2003
+++ b/drivers/hotplug/cpqphp_ctrl.c	Fri May  2 14:02:11 2003
@@ -136,9 +136,9 @@
 
 
 /*
- * find_slot
+ * cpqhp_find_slot
  */
-static inline struct slot *find_slot (struct controller * ctrl, u8 device)
+struct slot *cpqhp_find_slot (struct controller * ctrl, u8 device)
 {
 	struct slot *slot;
 
@@ -187,7 +187,7 @@
 
 			rc++;
 
-			p_slot = find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4));
+			p_slot = cpqhp_find_slot(ctrl, hp_slot + (readb(ctrl->hpc_reg + SLOT_MASK) >> 4));
 			if (!p_slot)
 				return 0;
 
@@ -920,6 +920,7 @@
 {
 	struct controller *ctrl = data;
 	u8 schedule_flag = 0;
+	u8 reset;
 	u16 misc;
 	u32 Diff;
 	u32 temp_dword;
@@ -971,6 +972,15 @@
 		schedule_flag += handle_power_fault((u8)((Diff & 0xFF00L) >> 8), ctrl);
 	}
 
+	reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE);
+	if (reset & 0x40) {
+		/* Bus reset has completed */
+		reset &= 0xCF;
+		writeb(reset, ctrl->hpc_reg + RESET_FREQ_MODE);
+		reset = readb(ctrl->hpc_reg + RESET_FREQ_MODE);
+		wake_up_interruptible(&ctrl->queue);
+	}
+
 	if (schedule_flag) {
 		up(&event_semaphore);
 		dbg("Signal event_semaphore\n");
@@ -1172,6 +1182,7 @@
 {
 	u8 hp_slot;
 	u8 temp_byte;
+	u8 adapter_speed;
 	u32 index;
 	u32 rc = 0;
 	u32 src = 8;
@@ -1189,46 +1200,46 @@
 		//*********************************
 		rc = CARD_FUNCTIONING;
 	} else {
-		if (ctrl->speed == PCI_SPEED_66MHz) {
-			// Wait for exclusive access to hardware
-			down(&ctrl->crit_sect);
-
-			// turn on board without attaching to the bus
-			enable_slot_power (ctrl, hp_slot);
+		// Wait for exclusive access to hardware
+		down(&ctrl->crit_sect);
 
-			set_SOGO(ctrl);
+		// turn on board without attaching to the bus
+		enable_slot_power (ctrl, hp_slot);
 
-			// Wait for SOBS to be unset
-			wait_for_ctrl_irq (ctrl);
+		set_SOGO(ctrl);
 
-			// Change bits in slot power register to force another shift out
-			// NOTE: this is to work around the timer bug
-			temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
-			writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
-			writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq (ctrl);
 
-			set_SOGO(ctrl);
+		// Change bits in slot power register to force another shift out
+		// NOTE: this is to work around the timer bug
+		temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
+		writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
+		writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
 
-			// Wait for SOBS to be unset
-			wait_for_ctrl_irq (ctrl);
+		set_SOGO(ctrl);
 
-			if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) {
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq (ctrl);
+		
+		adapter_speed = get_adapter_speed(ctrl, hp_slot);
+		if (ctrl->speed != adapter_speed)
+			if (set_controller_speed(ctrl, adapter_speed, hp_slot))
 				rc = WRONG_BUS_FREQUENCY;
-			}
-			// turn off board without attaching to the bus
-			disable_slot_power (ctrl, hp_slot);
 
-			set_SOGO(ctrl);
+		// turn off board without attaching to the bus
+		disable_slot_power (ctrl, hp_slot);
 
-			// Wait for SOBS to be unset
-			wait_for_ctrl_irq (ctrl);
+		set_SOGO(ctrl);
 
-			// Done with exclusive hardware access
-			up(&ctrl->crit_sect);
+		// Wait for SOBS to be unset
+		wait_for_ctrl_irq (ctrl);
 
-			if (rc)
-				return(rc);
-		}
+		// Done with exclusive hardware access
+		up(&ctrl->crit_sect);
+
+		if (rc)
+			return(rc);
 
 		// Wait for exclusive access to hardware
 		down(&ctrl->crit_sect);
@@ -1376,6 +1387,7 @@
 {
 	u8 hp_slot;
 	u8 temp_byte;
+	u8 adapter_speed;
 	int index;
 	u32 temp_register = 0xFFFFFFFF;
 	u32 rc = 0;
@@ -1387,47 +1399,48 @@
 	dbg("%s: func->device, slot_offset, hp_slot = %d, %d ,%d\n",
 	    __FUNCTION__, func->device, ctrl->slot_device_offset, hp_slot);
 
-	if (ctrl->speed == PCI_SPEED_66MHz) {
-		// Wait for exclusive access to hardware
-		down(&ctrl->crit_sect);
-
-		// turn on board without attaching to the bus
-		enable_slot_power (ctrl, hp_slot);
+	// Wait for exclusive access to hardware
+	down(&ctrl->crit_sect);
 
-		set_SOGO(ctrl);
+	// turn on board without attaching to the bus
+	enable_slot_power (ctrl, hp_slot);
 
-		// Wait for SOBS to be unset
-		wait_for_ctrl_irq (ctrl);
+	set_SOGO(ctrl);
 
-		// Change bits in slot power register to force another shift out
-		// NOTE: this is to work around the timer bug
-		temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
-		writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
-		writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
 
-		set_SOGO(ctrl);
+	// Change bits in slot power register to force another shift out
+	// NOTE: this is to work around the timer bug
+	temp_byte = readb(ctrl->hpc_reg + SLOT_POWER);
+	writeb(0x00, ctrl->hpc_reg + SLOT_POWER);
+	writeb(temp_byte, ctrl->hpc_reg + SLOT_POWER);
 
-		// Wait for SOBS to be unset
-		wait_for_ctrl_irq (ctrl);
+	set_SOGO(ctrl);
 
-		if (!(readl(ctrl->hpc_reg + NON_INT_INPUT) & (0x01 << hp_slot))) {
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
+	
+	adapter_speed = get_adapter_speed(ctrl, hp_slot);
+	if (ctrl->speed != adapter_speed)
+		if (set_controller_speed(ctrl, adapter_speed, hp_slot))
 			rc = WRONG_BUS_FREQUENCY;
-		}
-		// turn off board without attaching to the bus
-		disable_slot_power (ctrl, hp_slot);
+	
+	// turn off board without attaching to the bus
+	disable_slot_power (ctrl, hp_slot);
 
-		set_SOGO(ctrl);
+	set_SOGO(ctrl);
 
-		// Wait for SOBS to be unset
-		wait_for_ctrl_irq (ctrl);
+	// Wait for SOBS to be unset
+	wait_for_ctrl_irq (ctrl);
 
-		// Done with exclusive hardware access
-		up(&ctrl->crit_sect);
+	// Done with exclusive hardware access
+	up(&ctrl->crit_sect);
 
-		if (rc)
-			return(rc);
-	}
-	p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+	if (rc)
+		return(rc);
+	
+	p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 
 	// turn on board and blink green LED
 
@@ -1800,7 +1813,7 @@
 				if (!func)
 					return;
 
-				p_slot = find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
+				p_slot = cpqhp_find_slot(ctrl, hp_slot + ctrl->slot_device_offset);
 				if (!p_slot)
 					return;
 
@@ -1860,11 +1873,12 @@
 					}
 					// Wait for exclusive access to hardware
 					down(&ctrl->crit_sect);
-
+					
 					dbg("blink green LED and turn off amber\n");
+					
 					amber_LED_off (ctrl, hp_slot);
 					green_LED_blink (ctrl, hp_slot);
-
+					
 					set_SOGO(ctrl);
 
 					// Wait for SOBS to be unset
@@ -1992,7 +2006,7 @@
 
 	device = func->device;
 	hp_slot = device - ctrl->slot_device_offset;
-	p_slot = find_slot(ctrl, device);
+	p_slot = cpqhp_find_slot(ctrl, device);
 	if (p_slot) {
 		physical_slot = p_slot->number;
 	}
@@ -2091,7 +2105,7 @@
 
 	device = func->device; 
 	func = cpqhp_slot_find(ctrl->bus, device, index++);
-	p_slot = find_slot(ctrl, device);
+	p_slot = cpqhp_find_slot(ctrl, device);
 	if (p_slot) {
 		physical_slot = p_slot->number;
 	}
diff -Nru a/drivers/hotplug/cpqphp_pci.c b/drivers/hotplug/cpqphp_pci.c
--- a/drivers/hotplug/cpqphp_pci.c	Mon Feb 24 03:31:07 2003
+++ b/drivers/hotplug/cpqphp_pci.c	Tue May  6 08:31:37 2003
@@ -85,18 +85,20 @@
 {
 	unsigned char bus;
 	struct pci_bus *child;
-	int rc = 0;
+	int num;
 
 	if (func->pci_dev == NULL)
-		func->pci_dev = pci_find_slot(func->bus, (func->device << 3) | (func->function & 0x7));
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
 
-	//Still NULL ? Well then scan for it !
+	/* No pci device, we need to create it then */
 	if (func->pci_dev == NULL) {
 		dbg("INFO: pci_dev still null\n");
 
-		//this will generate pci_dev structures for all functions, but we will only call this case when lookup fails
-		func->pci_dev = pci_scan_slot(ctrl->pci_dev->bus,
-				 (func->device << 3) + (func->function & 0x7));
+		num = pci_scan_slot(ctrl->pci_dev->bus, PCI_DEVFN(func->device, func->function));
+		if (num)
+			pci_bus_add_devices(ctrl->pci_dev->bus);
+
+		func->pci_dev = pci_find_slot(func->bus, PCI_DEVFN(func->device, func->function));
 		if (func->pci_dev == NULL) {
 			dbg("ERROR: pci_dev still null\n");
 			return 0;
@@ -107,10 +109,9 @@
 		pci_read_config_byte(func->pci_dev, PCI_SECONDARY_BUS, &bus);
 		child = (struct pci_bus*) pci_add_new_bus(func->pci_dev->bus, (func->pci_dev), bus);
 		pci_do_scan_bus(child);
-
 	}
 
-	return rc;
+	return 0;
 }
 
 
@@ -1209,11 +1210,11 @@
 	temp = 0;
 
 	if (!cpqhp_nic_irq) {
-		cpqhp_nic_irq = ctrl->interrupt;
+		cpqhp_nic_irq = ctrl->cfgspc_irq;
 	}
 
 	if (!cpqhp_disk_irq) {
-		cpqhp_disk_irq = ctrl->interrupt;
+		cpqhp_disk_irq = ctrl->cfgspc_irq;
 	}
 
 	dbg("cpqhp_disk_irq, cpqhp_nic_irq= %d, %d\n", cpqhp_disk_irq, cpqhp_nic_irq);
diff -Nru a/drivers/hotplug/ibmphp_core.c b/drivers/hotplug/ibmphp_core.c
--- a/drivers/hotplug/ibmphp_core.c	Mon Feb 24 03:32:11 2003
+++ b/drivers/hotplug/ibmphp_core.c	Tue May  6 08:31:43 2003
@@ -846,22 +846,24 @@
 {
 	unsigned char bus;
 	struct pci_bus *child;
-	int rc = 0;
+	int num;
 	int flag = 0;	/* this is to make sure we don't double scan the bus, for bridged devices primarily */
 
 	if (!(bus_structure_fixup (func->busno)))
 		flag = 1;
 	if (func->dev == NULL)
-		func->dev = pci_find_slot (func->busno, (func->device << 3) | (func->function & 0x7));
+		func->dev = pci_find_slot (func->busno, PCI_DEVFN(func->device, func->function));
 
 	if (func->dev == NULL) {
 		struct pci_bus *bus = ibmphp_find_bus (func->busno);
 		if (!bus)
 			return 0;
 
-		func->dev = pci_scan_slot(bus,
-				 (func->device << 3) + (func->function & 0x7));
+		num = pci_scan_slot(bus, PCI_DEVFN(func->device, func->function));
+		if (num)
+			pci_bus_add_devices(bus);
 
+		func->dev = pci_find_slot(func->busno, PCI_DEVFN(func->device, func->function));
 		if (func->dev == NULL) {
 			err ("ERROR... : pci_dev still NULL \n");
 			return 0;
@@ -873,7 +875,7 @@
 		pci_do_scan_bus (child);
 	}
 
-	return rc;
+	return 0;
 }
 
 /*******************************************************
@@ -1415,7 +1417,7 @@
 
 	/* lock ourselves into memory with a module 
 	 * count of -1 so that no one can unload us. */
-	MOD_DEC_USE_COUNT;
+	module_put(THIS_MODULE);
 
 exit:
 	return rc;
diff -Nru a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
--- a/drivers/i2c/busses/Kconfig	Thu Apr 10 13:46:39 2003
+++ b/drivers/i2c/busses/Kconfig	Sun May 11 15:50:47 2003
@@ -117,6 +117,31 @@
 	  http://www.lm-sensors.nu
 
 
+config I2C_SIS96X
+	tristate "  SiS 96x"
+	depends on I2C && PCI && EXPERIMENTAL
+	help
+	  If you say yes to this option, support will be included for the SiS
+	  96x SMBus (a subset of I2C) interfaces.  Specifically, the following
+	  chipsets are supported:
+	    645/961
+	    645DX/961
+	    645DX/962
+	    648/961
+	    650/961
+	    735
+
+	  This can also be built as a module which can be inserted and removed 
+	  while the kernel is running.  If you want to compile it as a module,
+	  say M here and read <file:Documentation/modules.txt>.
+
+	  The module will be called i2c-sis96x.
+
+	  You will also need the latest user-space utilties: you can find them
+	  in the lm_sensors package, which you can download at 
+	  http://www.lm-sensors.nu
+
+
 config I2C_VIAPRO
 	tristate "  VIA 82C596/82C686/823x"
 	depends on I2C && PCI && EXPERIMENTAL
diff -Nru a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
--- a/drivers/i2c/busses/Makefile	Thu Apr 10 13:37:38 2003
+++ b/drivers/i2c/busses/Makefile	Sun May 11 15:50:47 2003
@@ -8,4 +8,5 @@
 obj-$(CONFIG_I2C_I801)		+= i2c-i801.o
 obj-$(CONFIG_I2C_ISA)		+= i2c-isa.o
 obj-$(CONFIG_I2C_PIIX4)		+= i2c-piix4.o
+obj-$(CONFIG_I2C_SIS96X)	+= i2c-sis96x.o
 obj-$(CONFIG_I2C_VIAPRO)	+= i2c-viapro.o
diff -Nru a/drivers/i2c/busses/i2c-ali15x3.c b/drivers/i2c/busses/i2c-ali15x3.c
--- a/drivers/i2c/busses/i2c-ali15x3.c	Fri Mar 21 12:45:15 2003
+++ b/drivers/i2c/busses/i2c-ali15x3.c	Tue May  6 07:26:13 2003
@@ -475,6 +475,7 @@
 static struct i2c_adapter ali15x3_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_ALI15X3,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
diff -Nru a/drivers/i2c/busses/i2c-amd756.c b/drivers/i2c/busses/i2c-amd756.c
--- a/drivers/i2c/busses/i2c-amd756.c	Fri Mar 21 12:45:15 2003
+++ b/drivers/i2c/busses/i2c-amd756.c	Tue May  6 07:26:20 2003
@@ -313,6 +313,7 @@
 static struct i2c_adapter amd756_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD756,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
diff -Nru a/drivers/i2c/busses/i2c-amd8111.c b/drivers/i2c/busses/i2c-amd8111.c
--- a/drivers/i2c/busses/i2c-amd8111.c	Fri Mar 21 12:45:15 2003
+++ b/drivers/i2c/busses/i2c-amd8111.c	Tue May  6 07:26:28 2003
@@ -360,6 +360,7 @@
 	snprintf(smbus->adapter.dev.name, DEVICE_NAME_SIZE,
 		"SMBus2 AMD8111 adapter at %04x", smbus->base);
 	smbus->adapter.id = I2C_ALGO_SMBUS | I2C_HW_SMBUS_AMD8111;
+	smbus->adapter.class = I2C_ADAP_CLASS_SMBUS;
 	smbus->adapter.algo = &smbus_algorithm;
 	smbus->adapter.algo_data = smbus;
 
diff -Nru a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c
--- a/drivers/i2c/busses/i2c-i801.c	Fri Mar 21 12:45:15 2003
+++ b/drivers/i2c/busses/i2c-i801.c	Tue May  6 07:16:02 2003
@@ -547,6 +547,7 @@
 static struct i2c_adapter i801_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_I801,
+	.class		= I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
diff -Nru a/drivers/i2c/busses/i2c-isa.c b/drivers/i2c/busses/i2c-isa.c
--- a/drivers/i2c/busses/i2c-isa.c	Fri Mar 21 12:45:15 2003
+++ b/drivers/i2c/busses/i2c-isa.c	Tue May  6 07:16:32 2003
@@ -40,6 +40,7 @@
 static struct i2c_adapter isa_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_ISA | I2C_HW_ISA,
+	.class          = I2C_ADAP_CLASS_SMBUS,
 	.algo		= &isa_algorithm,
 	.dev		= {
 		.name	= "ISA main adapter",
diff -Nru a/drivers/i2c/busses/i2c-piix4.c b/drivers/i2c/busses/i2c-piix4.c
--- a/drivers/i2c/busses/i2c-piix4.c	Fri Mar 21 12:45:15 2003
+++ b/drivers/i2c/busses/i2c-piix4.c	Tue May 13 05:33:02 2003
@@ -269,7 +269,7 @@
 
 	if (temp & 0x04) {
 		result = -1;
-		dev_err(&piix4_adapter.dev, "Error: no response!\n");
+		dev_dbg(&piix4_adapter.dev, "Error: no response!\n");
 	}
 
 	if (inb_p(SMBHSTSTS) != 0x00)
@@ -395,6 +395,7 @@
 static struct i2c_adapter piix4_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_PIIX4,
+	.class		= I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
@@ -466,7 +467,7 @@
 
 
 static struct pci_driver piix4_driver = {
-	.name		= "piix4 smbus",
+	.name		= "piix4-smbus",
 	.id_table	= piix4_ids,
 	.probe		= piix4_probe,
 	.remove		= __devexit_p(piix4_remove),
diff -Nru a/drivers/i2c/busses/i2c-sis96x.c b/drivers/i2c/busses/i2c-sis96x.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/i2c/busses/i2c-sis96x.c	Sun May 11 17:33:20 2003
@@ -0,0 +1,376 @@
+/*
+    sis96x.c - Part of lm_sensors, Linux kernel modules for hardware
+              monitoring
+
+    Copyright (c) 2003 Mark M. Hoffman <mhoffman@lightlink.com>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/*
+    This module must be considered BETA unless and until
+    the chipset manufacturer releases a datasheet.
+    The register definitions are based on the SiS630.
+
+    This module relies on quirk_sis_96x_smbus (drivers/pci/quirks.c)
+    for just about every machine for which users have reported.
+    If this module isn't detecting your 96x south bridge, have a 
+    look there.
+
+    We assume there can only be one SiS96x with one SMBus interface.
+*/
+
+/* #define DEBUG */
+
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <asm/io.h>
+
+/*
+	HISTORY:
+	2003-05-11	1.0.0 	Updated from lm_sensors project for kernel 2.5
+				(was i2c-sis645.c from lm_sensors 2.7.0)
+*/
+#define SIS96x_VERSION "1.0.0"
+
+/* SiS96x SMBus PCI device ID */
+#define PCI_DEVICE_ID_SI_SMBUS 0x16
+
+/* base address register in PCI config space */
+#define SIS96x_BAR 0x04
+
+/* SiS96x SMBus registers */
+#define SMB_STS      0x00
+#define SMB_EN       0x01
+#define SMB_CNT      0x02
+#define SMB_HOST_CNT 0x03
+#define SMB_ADDR     0x04
+#define SMB_CMD      0x05
+#define SMB_PCOUNT   0x06
+#define SMB_COUNT    0x07
+#define SMB_BYTE     0x08
+#define SMB_DEV_ADDR 0x10
+#define SMB_DB0      0x11
+#define SMB_DB1      0x12
+#define SMB_SAA      0x13
+
+/* register count for request_region */
+#define SMB_IOSIZE 0x20
+
+/* Other settings */
+#define MAX_TIMEOUT 500
+
+/* SiS96x SMBus constants */
+#define SIS96x_QUICK      0x00
+#define SIS96x_BYTE       0x01
+#define SIS96x_BYTE_DATA  0x02
+#define SIS96x_WORD_DATA  0x03
+#define SIS96x_PROC_CALL  0x04
+#define SIS96x_BLOCK_DATA 0x05
+
+static struct i2c_adapter sis96x_adapter;
+static u16 sis96x_smbus_base = 0;
+
+static inline u8 sis96x_read(u8 reg)
+{
+	return inb(sis96x_smbus_base + reg) ;
+}
+
+static inline void sis96x_write(u8 reg, u8 data)
+{
+	outb(data, sis96x_smbus_base + reg) ;
+}
+
+/* Internally used pause function */
+static void sis96x_do_pause(unsigned int amount)
+{
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(amount);
+}
+
+/* Execute a SMBus transaction.
+   int size is from SIS96x_QUICK to SIS96x_BLOCK_DATA
+ */
+static int sis96x_transaction(int size)
+{
+	int temp;
+	int result = 0;
+	int timeout = 0;
+
+	dev_dbg(&sis96x_adapter.dev, "SMBus transaction %d\n", size);
+
+	/* Make sure the SMBus host is ready to start transmitting */
+	if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
+
+		dev_dbg(&sis96x_adapter.dev, "SMBus busy (0x%02x). "
+			"Resetting...\n", temp);
+
+		/* kill the transaction */
+		sis96x_write(SMB_HOST_CNT, 0x20);
+
+		/* check it again */
+		if (((temp = sis96x_read(SMB_CNT)) & 0x03) != 0x00) {
+			dev_dbg(&sis96x_adapter.dev, "Failed (0x%02x)\n", temp);
+			return -1;
+		} else {
+			dev_dbg(&sis96x_adapter.dev, "Successful\n");
+		}
+	}
+
+	/* Turn off timeout interrupts, set fast host clock */
+	sis96x_write(SMB_CNT, 0x20);
+
+	/* clear all (sticky) status flags */
+	temp = sis96x_read(SMB_STS);
+	sis96x_write(SMB_STS, temp & 0x1e);
+
+	/* start the transaction by setting bit 4 and size bits */
+	sis96x_write(SMB_HOST_CNT, 0x10 | (size & 0x07));
+
+	/* We will always wait for a fraction of a second! */
+	do {
+		sis96x_do_pause(1);
+		temp = sis96x_read(SMB_STS);
+	} while (!(temp & 0x0e) && (timeout++ < MAX_TIMEOUT));
+
+	/* If the SMBus is still busy, we give up */
+	if (timeout >= MAX_TIMEOUT) {
+		dev_dbg(&sis96x_adapter.dev, "SMBus Timeout! (0x%02x)\n", temp);
+		result = -1;
+	}
+
+	/* device error - probably missing ACK */
+	if (temp & 0x02) {
+		dev_dbg(&sis96x_adapter.dev, "Failed bus transaction!\n");
+		result = -1;
+	}
+
+	/* bus collision */
+	if (temp & 0x04) {
+		dev_dbg(&sis96x_adapter.dev, "Bus collision!\n");
+		result = -1;
+	}
+
+	/* Finish up by resetting the bus */
+	sis96x_write(SMB_STS, temp);
+	if ((temp = sis96x_read(SMB_STS))) {
+		dev_dbg(&sis96x_adapter.dev, "Failed reset at "
+			"end of transaction! (0x%02x)\n", temp);
+	}
+
+	return result;
+}
+
+/* Return -1 on error. */
+static s32 sis96x_access(struct i2c_adapter * adap, u16 addr,
+			 unsigned short flags, char read_write,
+			 u8 command, int size, union i2c_smbus_data * data)
+{
+
+	switch (size) {
+	case I2C_SMBUS_QUICK:
+		sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		size = SIS96x_QUICK;
+		break;
+
+	case I2C_SMBUS_BYTE:
+		sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		if (read_write == I2C_SMBUS_WRITE)
+			sis96x_write(SMB_CMD, command);
+		size = SIS96x_BYTE;
+		break;
+
+	case I2C_SMBUS_BYTE_DATA:
+		sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		sis96x_write(SMB_CMD, command);
+		if (read_write == I2C_SMBUS_WRITE)
+			sis96x_write(SMB_BYTE, data->byte);
+		size = SIS96x_BYTE_DATA;
+		break;
+
+	case I2C_SMBUS_PROC_CALL:
+	case I2C_SMBUS_WORD_DATA:
+		sis96x_write(SMB_ADDR, ((addr & 0x7f) << 1) | (read_write & 0x01));
+		sis96x_write(SMB_CMD, command);
+		if (read_write == I2C_SMBUS_WRITE) {
+			sis96x_write(SMB_BYTE, data->word & 0xff);
+			sis96x_write(SMB_BYTE + 1, (data->word & 0xff00) >> 8);
+		}
+		size = (size == I2C_SMBUS_PROC_CALL ? 
+			SIS96x_PROC_CALL : SIS96x_WORD_DATA);
+		break;
+
+	case I2C_SMBUS_BLOCK_DATA:
+		/* TO DO: */
+		dev_info(&adap->dev, "SMBus block not implemented!\n");
+		return -1;
+		break;
+
+	default:
+		dev_info(&adap->dev, "Unsupported I2C size\n");
+		return -1;
+		break;
+	}
+
+	if (sis96x_transaction(size))
+		return -1;
+
+	if ((size != SIS96x_PROC_CALL) &&
+		((read_write == I2C_SMBUS_WRITE) || (size == SIS96x_QUICK)))
+		return 0;
+
+	switch (size) {
+	case SIS96x_BYTE:
+	case SIS96x_BYTE_DATA:
+		data->byte = sis96x_read(SMB_BYTE);
+		break;
+
+	case SIS96x_WORD_DATA:
+	case SIS96x_PROC_CALL:
+		data->word = sis96x_read(SMB_BYTE) +
+				(sis96x_read(SMB_BYTE + 1) << 8);
+		break;
+	}
+	return 0;
+}
+
+static u32 sis96x_func(struct i2c_adapter *adapter)
+{
+	return I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_BYTE |
+	    I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA |
+	    I2C_FUNC_SMBUS_PROC_CALL;
+}
+
+static struct i2c_algorithm smbus_algorithm = {
+	.name		= "Non-I2C SMBus adapter",
+	.id		= I2C_ALGO_SMBUS,
+	.smbus_xfer	= sis96x_access,
+	.functionality	= sis96x_func,
+};
+
+static struct i2c_adapter sis96x_adapter = {
+	.owner		= THIS_MODULE,
+	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_SIS96X,
+	.class		= I2C_ADAP_CLASS_SMBUS,
+	.algo		= &smbus_algorithm,
+	.dev		= {
+		.name	="unset",
+	},
+};
+
+static struct pci_device_id sis96x_ids[] __devinitdata = {
+
+	{
+		.vendor	=	PCI_VENDOR_ID_SI,
+		.device =	PCI_DEVICE_ID_SI_SMBUS,
+		.subvendor =	PCI_ANY_ID,
+		.subdevice =	PCI_ANY_ID,
+	},
+
+	{ 0, }
+};
+
+static int __devinit sis96x_probe(struct pci_dev *dev,
+				const struct pci_device_id *id)
+{
+	u16 ww = 0;
+	int retval;
+
+	if (sis96x_smbus_base) {
+		dev_err(&dev->dev, "Only one device supported.\n");
+		return -EBUSY;
+	}
+
+	pci_read_config_word(dev, PCI_CLASS_DEVICE, &ww);
+	if (PCI_CLASS_SERIAL_SMBUS != ww) {
+		dev_err(&dev->dev, "Unsupported device class 0x%04x!\n", ww);
+		return -ENODEV;
+	}
+
+	sis96x_smbus_base = pci_resource_start(dev, SIS96x_BAR);
+	if (!sis96x_smbus_base) {
+		dev_err(&dev->dev, "SiS96x SMBus base address "
+			"not initialized!\n");
+		return -EINVAL;
+	}
+	dev_info(&dev->dev, "SiS96x SMBus base address: 0x%04x\n",
+			sis96x_smbus_base);
+
+	/* Everything is happy, let's grab the memory and set things up. */
+	if (!request_region(sis96x_smbus_base, SMB_IOSIZE, "sis96x-smbus")) {
+		dev_err(&dev->dev, "SMBus registers 0x%04x-0x%04x "
+			"already in use!\n", sis96x_smbus_base,
+			sis96x_smbus_base + SMB_IOSIZE - 1);
+
+		sis96x_smbus_base = 0;
+		return -EINVAL;
+	}
+
+	/* set up the driverfs linkage to our parent device */
+	sis96x_adapter.dev.parent = &dev->dev;
+
+	snprintf(sis96x_adapter.dev.name, DEVICE_NAME_SIZE,
+		"SiS96x SMBus adapter at 0x%04x", sis96x_smbus_base);
+
+	if ((retval = i2c_add_adapter(&sis96x_adapter))) {
+		dev_err(&dev->dev, "Couldn't register adapter!\n");
+		release_region(sis96x_smbus_base, SMB_IOSIZE);
+		sis96x_smbus_base = 0;
+	}
+
+	return retval;
+}
+
+static void __devexit sis96x_remove(struct pci_dev *dev)
+{
+	if (sis96x_smbus_base) {
+		i2c_del_adapter(&sis96x_adapter);
+		release_region(sis96x_smbus_base, SMB_IOSIZE);
+		sis96x_smbus_base = 0;
+	}
+}
+
+static struct pci_driver sis96x_driver = {
+	.name		= "sis96x smbus",
+	.id_table	= sis96x_ids,
+	.probe		= sis96x_probe,
+	.remove		= __devexit_p(sis96x_remove),
+};
+
+static int __init i2c_sis96x_init(void)
+{
+	printk(KERN_INFO "i2c-sis96x version %s\n", SIS96x_VERSION);
+	return pci_module_init(&sis96x_driver);
+}
+
+static void __exit i2c_sis96x_exit(void)
+{
+	pci_unregister_driver(&sis96x_driver);
+}
+
+MODULE_AUTHOR("Mark M. Hoffman <mhoffman@lightlink.com>");
+MODULE_DESCRIPTION("SiS96x SMBus driver");
+MODULE_LICENSE("GPL");
+
+/* Register initialization functions using helper macros */
+module_init(i2c_sis96x_init);
+module_exit(i2c_sis96x_exit);
+
diff -Nru a/drivers/i2c/busses/i2c-viapro.c b/drivers/i2c/busses/i2c-viapro.c
--- a/drivers/i2c/busses/i2c-viapro.c	Mon Apr 21 15:30:48 2003
+++ b/drivers/i2c/busses/i2c-viapro.c	Tue May  6 07:17:50 2003
@@ -295,6 +295,7 @@
 static struct i2c_adapter vt596_adapter = {
 	.owner		= THIS_MODULE,
 	.id		= I2C_ALGO_SMBUS | I2C_HW_SMBUS_VIA2,
+	.class		= I2C_ADAP_CLASS_SMBUS,
 	.algo		= &smbus_algorithm,
 	.dev		= {
 		.name	= "unset",
diff -Nru a/drivers/i2c/chips/adm1021.c b/drivers/i2c/chips/adm1021.c
--- a/drivers/i2c/chips/adm1021.c	Thu Apr 24 06:36:20 2003
+++ b/drivers/i2c/chips/adm1021.c	Tue May  6 07:19:02 2003
@@ -203,6 +203,8 @@
 
 static int adm1021_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, adm1021_detect);
 }
 
diff -Nru a/drivers/i2c/chips/it87.c b/drivers/i2c/chips/it87.c
--- a/drivers/i2c/chips/it87.c	Thu Apr 24 06:36:20 2003
+++ b/drivers/i2c/chips/it87.c	Sat May 17 00:37:28 2003
@@ -3,7 +3,7 @@
              monitoring.
 
     Supports: IT8705F  Super I/O chip w/LPC interface
-              IT8712F  Super I/O chup w/LPC interface & SMbus
+              IT8712F  Super I/O chip w/LPC interface & SMbus
               Sis950   A clone of the IT8705F
 
     Copyright (c) 2001 Chris Gauthron <chrisg@0-in.com> 
@@ -80,17 +80,17 @@
 
 /* Monitors: 9 voltage (0 to 7, battery), 3 temp (1 to 3), 3 fan (1 to 3) */
 
-#define IT87_REG_FAN(nr)       (0x0c + (nr))
-#define IT87_REG_FAN_MIN(nr)   (0x0f + (nr))
+#define IT87_REG_FAN(nr)       (0x0d + (nr))
+#define IT87_REG_FAN_MIN(nr)   (0x10 + (nr))
 #define IT87_REG_FAN_CTRL      0x13
 
 #define IT87_REG_VIN(nr)       (0x20 + (nr))
-#define IT87_REG_TEMP(nr)      (0x28 + (nr))
+#define IT87_REG_TEMP(nr)      (0x29 + (nr))
 
 #define IT87_REG_VIN_MAX(nr)   (0x30 + (nr) * 2)
 #define IT87_REG_VIN_MIN(nr)   (0x31 + (nr) * 2)
-#define IT87_REG_TEMP_HIGH(nr) (0x3e + (nr) * 2)
-#define IT87_REG_TEMP_LOW(nr)  (0x3f + (nr) * 2)
+#define IT87_REG_TEMP_HIGH(nr) (0x40 + ((nr) * 2))
+#define IT87_REG_TEMP_LOW(nr)  (0x41 + ((nr) * 2))
 
 #define IT87_REG_I2C_ADDR      0x48
 
@@ -99,46 +99,8 @@
 
 #define IT87_REG_CHIPID        0x58
 
-static inline u8 IN_TO_REG(long val, int inNum)
-{
-	/* to avoid floating point, we multiply everything by 100.
-	 val is guaranteed to be positive, so we can achieve the effect of 
-	 rounding by (...*10+5)/10.  Note that the *10 is hidden in the 
-	 /250 (which should really be /2500).
-	 At the end, we need to /100 because we *100 everything and we need
-	 to /10 because of the rounding thing, so we /1000.   */
-	if (inNum <= 1)
-		return (u8)
-		    SENSORS_LIMIT(((val * 210240 - 13300) / 250 + 5) / 1000, 
-				  0, 255);
-	else if (inNum == 2)
-		return (u8)
-		    SENSORS_LIMIT(((val * 157370 - 13300) / 250 + 5) / 1000, 
-				  0, 255);
-	else if (inNum == 3)
-		return (u8)
-		    SENSORS_LIMIT(((val * 101080 - 13300) / 250 + 5) / 1000, 
-				  0, 255);
-	else
-		return (u8) SENSORS_LIMIT(((val * 41714 - 13300) / 250 + 5)
-					  / 1000, 0, 255);
-}
-
-static inline long IN_FROM_REG(u8 val, int inNum)
-{
-	/* to avoid floating point, we multiply everything by 100.
-	 val is guaranteed to be positive, so we can achieve the effect of
-	 rounding by adding 0.5.  Or, to avoid fp math, we do (...*10+5)/10.
-	 We need to scale with *100 anyway, so no need to /100 at the end. */
-	if (inNum <= 1)
-		return (long) (((250000 * val + 13300) / 210240 * 10 + 5) /10);
-	else if (inNum == 2)
-		return (long) (((250000 * val + 13300) / 157370 * 10 + 5) /10);
-	else if (inNum == 3)
-		return (long) (((250000 * val + 13300) / 101080 * 10 + 5) /10);
-	else
-		return (long) (((250000 * val + 13300) / 41714 * 10 + 5) /10);
-}
+#define IN_TO_REG(val)  (SENSORS_LIMIT((((val) * 10 + 8)/16),0,255))
+#define IN_FROM_REG(val) (((val) *  16) / 10)
 
 static inline u8 FAN_TO_REG(long rpm, int div)
 {
@@ -159,7 +121,14 @@
 				205-(val)*5)
 #define ALARMS_FROM_REG(val) (val)
 
-#define DIV_TO_REG(val) ((val)==8?3:(val)==4?2:(val)==1?0:1)
+static int log2(int val)
+{
+	int answer = 0;
+	while ((val >>= 1))
+		answer++;
+	return answer;
+}
+#define DIV_TO_REG(val) log2(val)
 #define DIV_FROM_REG(val) (1 << (val))
 
 /* Initial limits. Use the config file to set better limits. */
@@ -238,6 +207,7 @@
 	u8 temp[3];		/* Register value */
 	u8 temp_high[3];	/* Register value */
 	u8 temp_low[3];		/* Register value */
+	u8 sensor;		/* Register value */
 	u8 fan_div[3];		/* Register encoding, shifted right */
 	u8 vid;			/* Register encoding, combined */
 	u32 alarms;		/* Register encoding, combined */
@@ -252,7 +222,7 @@
 static int it87_write_value(struct i2c_client *client, u8 register,
 			u8 value);
 static void it87_update_client(struct i2c_client *client);
-static void it87_init_client(struct i2c_client *client);
+static void it87_init_client(struct i2c_client *client, struct it87_data *data);
 
 
 static struct i2c_driver it87_driver = {
@@ -271,7 +241,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	it87_update_client(client);
-	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in[nr], nr)*10 );
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in[nr])*10 );
 }
 
 static ssize_t show_in_min(struct device *dev, char *buf, int nr)
@@ -279,7 +249,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	it87_update_client(client);
-	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_min[nr], nr)*10 );
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_min[nr])*10 );
 }
 
 static ssize_t show_in_max(struct device *dev, char *buf, int nr)
@@ -287,7 +257,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	it87_update_client(client);
-	return sprintf(buf, "%ld\n", IN_FROM_REG(data->in_max[nr], nr)*10 );
+	return sprintf(buf, "%d\n", IN_FROM_REG(data->in_max[nr])*10 );
 }
 
 static ssize_t set_in_min(struct device *dev, const char *buf, 
@@ -296,7 +266,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10)/10;
-	data->in_min[nr] = IN_TO_REG(val,nr);
+	data->in_min[nr] = IN_TO_REG(val);
 	it87_write_value(client, IT87_REG_VIN_MIN(nr), 
 			data->in_min[nr]);
 	return count;
@@ -307,7 +277,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	unsigned long val = simple_strtoul(buf, NULL, 10)/10;
-	data->in_max[nr] = IN_TO_REG(val,nr);
+	data->in_max[nr] = IN_TO_REG(val);
 	it87_write_value(client, IT87_REG_VIN_MAX(nr), 
 			data->in_max[nr]);
 	return count;
@@ -319,6 +289,9 @@
 {								\
 	return show_in(dev, buf, 0x##offset);			\
 }								\
+static DEVICE_ATTR(in_input##offset, S_IRUGO, show_in##offset, NULL)
+
+#define limit_in_offset(offset)					\
 static ssize_t							\
 	show_in##offset##_min (struct device *dev, char *buf)	\
 {								\
@@ -339,17 +312,28 @@
 {								\
 	return set_in_max(dev, buf, count, 0x##offset);		\
 }								\
-static DEVICE_ATTR(in_input##offset, S_IRUGO, show_in##offset, NULL) 	\
 static DEVICE_ATTR(in_min##offset, S_IRUGO | S_IWUSR, 		\
 		show_in##offset##_min, set_in##offset##_min)	\
 static DEVICE_ATTR(in_max##offset, S_IRUGO | S_IWUSR, 		\
 		show_in##offset##_max, set_in##offset##_max)
 
 show_in_offset(0);
+limit_in_offset(0);
 show_in_offset(1);
+limit_in_offset(1);
 show_in_offset(2);
+limit_in_offset(2);
 show_in_offset(3);
+limit_in_offset(3);
 show_in_offset(4);
+limit_in_offset(4);
+show_in_offset(5);
+limit_in_offset(5);
+show_in_offset(6);
+limit_in_offset(6);
+show_in_offset(7);
+limit_in_offset(7);
+show_in_offset(8);
 
 /* 3 temperatures */
 static ssize_t show_temp(struct device *dev, char *buf, int nr)
@@ -357,7 +341,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	it87_update_client(client);
-	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])*10 );
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp[nr])*100 );
 }
 /* more like overshoot temperature */
 static ssize_t show_temp_max(struct device *dev, char *buf, int nr)
@@ -365,7 +349,7 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	it87_update_client(client);
-	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])*10);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_high[nr])*100);
 }
 /* more like hysteresis temperature */
 static ssize_t show_temp_min(struct device *dev, char *buf, int nr)
@@ -373,14 +357,14 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	it87_update_client(client);
-	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])*10);
+	return sprintf(buf, "%d\n", TEMP_FROM_REG(data->temp_low[nr])*100);
 }
 static ssize_t set_temp_max(struct device *dev, const char *buf, 
 		size_t count, int nr)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
-	int val = simple_strtol(buf, NULL, 10)/10;
+	int val = simple_strtol(buf, NULL, 10)/100;
 	data->temp_high[nr] = TEMP_TO_REG(val);
 	it87_write_value(client, IT87_REG_TEMP_HIGH(nr), data->temp_high[nr]);
 	return count;
@@ -390,7 +374,7 @@
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
-	int val = simple_strtol(buf, NULL, 10)/10;
+	int val = simple_strtol(buf, NULL, 10)/100;
 	data->temp_low[nr] = TEMP_TO_REG(val);
 	it87_write_value(client, IT87_REG_TEMP_LOW(nr), data->temp_low[nr]);
 	return count;
@@ -430,7 +414,52 @@
 show_temp_offset(2);
 show_temp_offset(3);
 
-/* 2 Fans */
+/* more like overshoot temperature */
+static ssize_t show_sensor(struct device *dev, char *buf, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct it87_data *data = i2c_get_clientdata(client);
+	it87_update_client(client);
+	if (data->sensor & (1 << nr))
+	    return sprintf(buf, "1\n");
+	if (data->sensor & (8 << nr))
+	    return sprintf(buf, "2\n");
+	return sprintf(buf, "0\n");
+}
+static ssize_t set_sensor(struct device *dev, const char *buf, 
+		size_t count, int nr)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct it87_data *data = i2c_get_clientdata(client);
+	int val = simple_strtol(buf, NULL, 10);
+
+	data->sensor &= ~(1 << nr);
+	data->sensor &= ~(8 << nr);
+	if (val == 1)
+	    data->sensor |= 1 << nr;
+	else if (val == 2)
+	    data->sensor |= 8 << nr;
+	it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
+	return count;
+}
+#define show_sensor_offset(offset)					\
+static ssize_t show_sensor_##offset (struct device *dev, char *buf)	\
+{									\
+	return show_sensor(dev, buf, 0x##offset - 1);			\
+}									\
+static ssize_t set_sensor_##offset (struct device *dev, 		\
+		const char *buf, size_t count) 				\
+{									\
+	return set_sensor(dev, buf, count, 0x##offset - 1);		\
+}									\
+static DEVICE_ATTR(sensor##offset, S_IRUGO | S_IWUSR,	 		\
+		show_sensor_##offset, set_sensor_##offset)
+
+show_sensor_offset(1);
+show_sensor_offset(2);
+show_sensor_offset(3);
+
+/* 3 Fans */
 static ssize_t show_fan(struct device *dev, char *buf, int nr)
 {
 	struct i2c_client *client = to_i2c_client(dev);
@@ -461,7 +490,7 @@
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
 	data->fan_min[nr] = FAN_TO_REG(val, DIV_FROM_REG(data->fan_div[nr]));
-	it87_write_value(client, IT87_REG_FAN_MIN(nr+1), data->fan_min[nr]);
+	it87_write_value(client, IT87_REG_FAN_MIN(nr), data->fan_min[nr]);
 	return count;
 }
 static ssize_t set_fan_div(struct device *dev, const char *buf, 
@@ -470,10 +499,34 @@
 	struct i2c_client *client = to_i2c_client(dev);
 	struct it87_data *data = i2c_get_clientdata(client);
 	int val = simple_strtol(buf, NULL, 10);
-	int old = it87_read_value(client, IT87_REG_FAN_DIV);
-	data->fan_div[nr] = DIV_TO_REG(val);
-	old = (old & 0x0f) | (data->fan_div[1] << 6) | (data->fan_div[0] << 4);
-	it87_write_value(client, IT87_REG_FAN_DIV, old);
+	int i, min[3];
+	u8 old = it87_read_value(client, IT87_REG_FAN_DIV);
+
+	for (i = 0; i < 3; i++)
+		min[i] = FAN_FROM_REG(data->fan_min[i], DIV_FROM_REG(data->fan_div[i]));
+
+	switch (nr) {
+	case 0:
+	case 1:
+		data->fan_div[nr] = DIV_TO_REG(val);
+		break;
+	case 2:
+		if (val < 8)
+			data->fan_div[nr] = 1;
+		else
+			data->fan_div[nr] = 3;
+	}
+	val = old & 0x100;
+	val |= (data->fan_div[0] & 0x07);
+	val |= (data->fan_div[1] & 0x07) << 3;
+	if (data->fan_div[2] == 3)
+		val |= 0x1 << 6;
+	it87_write_value(client, IT87_REG_FAN_DIV, val);
+
+	for (i = 0; i < 3; i++) {
+		data->fan_min[i]=FAN_TO_REG(min[i], DIV_FROM_REG(data->fan_div[i]));
+		it87_write_value(client, IT87_REG_FAN_MIN(i), data->fan_min[i]);
+	}
 	return count;
 }
 
@@ -508,6 +561,7 @@
 
 show_fan_offset(1);
 show_fan_offset(2);
+show_fan_offset(3);
 
 /* Alarm */
 static ssize_t show_alarm(struct device *dev, char *buf)
@@ -525,6 +579,8 @@
      * when a new adapter is inserted (and it87_driver is still present) */
 static int it87_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, it87_detect);
 }
 
@@ -585,6 +641,8 @@
 		err = -ENOMEM;
 		goto ERROR1;
 	}
+	memset(new_client, 0x00, sizeof(struct i2c_client) +
+				 sizeof(struct it87_data));
 
 	data = (struct it87_data *) (new_client + 1);
 	if (is_isa)
@@ -652,16 +710,26 @@
 	device_create_file(&new_client->dev, &dev_attr_in_input2);
 	device_create_file(&new_client->dev, &dev_attr_in_input3);
 	device_create_file(&new_client->dev, &dev_attr_in_input4);
+	device_create_file(&new_client->dev, &dev_attr_in_input5);
+	device_create_file(&new_client->dev, &dev_attr_in_input6);
+	device_create_file(&new_client->dev, &dev_attr_in_input7);
+	device_create_file(&new_client->dev, &dev_attr_in_input8);
 	device_create_file(&new_client->dev, &dev_attr_in_min0);
 	device_create_file(&new_client->dev, &dev_attr_in_min1);
 	device_create_file(&new_client->dev, &dev_attr_in_min2);
 	device_create_file(&new_client->dev, &dev_attr_in_min3);
 	device_create_file(&new_client->dev, &dev_attr_in_min4);
+	device_create_file(&new_client->dev, &dev_attr_in_min5);
+	device_create_file(&new_client->dev, &dev_attr_in_min6);
+	device_create_file(&new_client->dev, &dev_attr_in_min7);
 	device_create_file(&new_client->dev, &dev_attr_in_max0);
 	device_create_file(&new_client->dev, &dev_attr_in_max1);
 	device_create_file(&new_client->dev, &dev_attr_in_max2);
 	device_create_file(&new_client->dev, &dev_attr_in_max3);
 	device_create_file(&new_client->dev, &dev_attr_in_max4);
+	device_create_file(&new_client->dev, &dev_attr_in_max5);
+	device_create_file(&new_client->dev, &dev_attr_in_max6);
+	device_create_file(&new_client->dev, &dev_attr_in_max7);
 	device_create_file(&new_client->dev, &dev_attr_temp_input1);
 	device_create_file(&new_client->dev, &dev_attr_temp_input2);
 	device_create_file(&new_client->dev, &dev_attr_temp_input3);
@@ -671,16 +739,22 @@
 	device_create_file(&new_client->dev, &dev_attr_temp_min1);
 	device_create_file(&new_client->dev, &dev_attr_temp_min2);
 	device_create_file(&new_client->dev, &dev_attr_temp_min3);
+	device_create_file(&new_client->dev, &dev_attr_sensor1);
+	device_create_file(&new_client->dev, &dev_attr_sensor2);
+	device_create_file(&new_client->dev, &dev_attr_sensor3);
 	device_create_file(&new_client->dev, &dev_attr_fan_input1);
 	device_create_file(&new_client->dev, &dev_attr_fan_input2);
+	device_create_file(&new_client->dev, &dev_attr_fan_input3);
 	device_create_file(&new_client->dev, &dev_attr_fan_min1);
 	device_create_file(&new_client->dev, &dev_attr_fan_min2);
+	device_create_file(&new_client->dev, &dev_attr_fan_min3);
 	device_create_file(&new_client->dev, &dev_attr_fan_div1);
 	device_create_file(&new_client->dev, &dev_attr_fan_div2);
+	device_create_file(&new_client->dev, &dev_attr_fan_div3);
 	device_create_file(&new_client->dev, &dev_attr_alarm);
 
 	/* Initialize the IT87 chip */
-	it87_init_client(new_client);
+	it87_init_client(new_client, data);
 	return 0;
 
 ERROR1:
@@ -753,70 +827,70 @@
 }
 
 /* Called when we have found a new IT87. It should set limits, etc. */
-static void it87_init_client(struct i2c_client *client)
+static void it87_init_client(struct i2c_client *client, struct it87_data *data)
 {
 	/* Reset all except Watchdog values and last conversion values
 	   This sets fan-divs to 2, among others */
 	it87_write_value(client, IT87_REG_CONFIG, 0x80);
 	it87_write_value(client, IT87_REG_VIN_MIN(0),
-			 IN_TO_REG(IT87_INIT_IN_MIN_0, 0));
+			 IN_TO_REG(IT87_INIT_IN_MIN_0));
 	it87_write_value(client, IT87_REG_VIN_MAX(0),
-			 IN_TO_REG(IT87_INIT_IN_MAX_0, 0));
+			 IN_TO_REG(IT87_INIT_IN_MAX_0));
 	it87_write_value(client, IT87_REG_VIN_MIN(1),
-			 IN_TO_REG(IT87_INIT_IN_MIN_1, 1));
+			 IN_TO_REG(IT87_INIT_IN_MIN_1));
 	it87_write_value(client, IT87_REG_VIN_MAX(1),
-			 IN_TO_REG(IT87_INIT_IN_MAX_1, 1));
+			 IN_TO_REG(IT87_INIT_IN_MAX_1));
 	it87_write_value(client, IT87_REG_VIN_MIN(2),
-			 IN_TO_REG(IT87_INIT_IN_MIN_2, 2));
+			 IN_TO_REG(IT87_INIT_IN_MIN_2));
 	it87_write_value(client, IT87_REG_VIN_MAX(2),
-			 IN_TO_REG(IT87_INIT_IN_MAX_2, 2));
+			 IN_TO_REG(IT87_INIT_IN_MAX_2));
 	it87_write_value(client, IT87_REG_VIN_MIN(3),
-			 IN_TO_REG(IT87_INIT_IN_MIN_3, 3));
+			 IN_TO_REG(IT87_INIT_IN_MIN_3));
 	it87_write_value(client, IT87_REG_VIN_MAX(3),
-			 IN_TO_REG(IT87_INIT_IN_MAX_3, 3));
+			 IN_TO_REG(IT87_INIT_IN_MAX_3));
 	it87_write_value(client, IT87_REG_VIN_MIN(4),
-			 IN_TO_REG(IT87_INIT_IN_MIN_4, 4));
+			 IN_TO_REG(IT87_INIT_IN_MIN_4));
 	it87_write_value(client, IT87_REG_VIN_MAX(4),
-			 IN_TO_REG(IT87_INIT_IN_MAX_4, 4));
+			 IN_TO_REG(IT87_INIT_IN_MAX_4));
 	it87_write_value(client, IT87_REG_VIN_MIN(5),
-			 IN_TO_REG(IT87_INIT_IN_MIN_5, 5));
+			 IN_TO_REG(IT87_INIT_IN_MIN_5));
 	it87_write_value(client, IT87_REG_VIN_MAX(5),
-			 IN_TO_REG(IT87_INIT_IN_MAX_5, 5));
+			 IN_TO_REG(IT87_INIT_IN_MAX_5));
 	it87_write_value(client, IT87_REG_VIN_MIN(6),
-			 IN_TO_REG(IT87_INIT_IN_MIN_6, 6));
+			 IN_TO_REG(IT87_INIT_IN_MIN_6));
 	it87_write_value(client, IT87_REG_VIN_MAX(6),
-			 IN_TO_REG(IT87_INIT_IN_MAX_6, 6));
+			 IN_TO_REG(IT87_INIT_IN_MAX_6));
 	it87_write_value(client, IT87_REG_VIN_MIN(7),
-			 IN_TO_REG(IT87_INIT_IN_MIN_7, 7));
+			 IN_TO_REG(IT87_INIT_IN_MIN_7));
 	it87_write_value(client, IT87_REG_VIN_MAX(7),
-			 IN_TO_REG(IT87_INIT_IN_MAX_7, 7));
+			 IN_TO_REG(IT87_INIT_IN_MAX_7));
 	/* Note: Battery voltage does not have limit registers */
-	it87_write_value(client, IT87_REG_FAN_MIN(1),
+	it87_write_value(client, IT87_REG_FAN_MIN(0),
 			 FAN_TO_REG(IT87_INIT_FAN_MIN_1, 2));
-	it87_write_value(client, IT87_REG_FAN_MIN(2),
+	it87_write_value(client, IT87_REG_FAN_MIN(1),
 			 FAN_TO_REG(IT87_INIT_FAN_MIN_2, 2));
-	it87_write_value(client, IT87_REG_FAN_MIN(3),
+	it87_write_value(client, IT87_REG_FAN_MIN(2),
 			 FAN_TO_REG(IT87_INIT_FAN_MIN_3, 2));
-	it87_write_value(client, IT87_REG_TEMP_HIGH(1),
+	it87_write_value(client, IT87_REG_TEMP_HIGH(0),
 			 TEMP_TO_REG(IT87_INIT_TEMP_HIGH_1));
-	it87_write_value(client, IT87_REG_TEMP_LOW(1),
+	it87_write_value(client, IT87_REG_TEMP_LOW(0),
 			 TEMP_TO_REG(IT87_INIT_TEMP_LOW_1));
-	it87_write_value(client, IT87_REG_TEMP_HIGH(2),
+	it87_write_value(client, IT87_REG_TEMP_HIGH(1),
 			 TEMP_TO_REG(IT87_INIT_TEMP_HIGH_2));
-	it87_write_value(client, IT87_REG_TEMP_LOW(2),
+	it87_write_value(client, IT87_REG_TEMP_LOW(1),
 			 TEMP_TO_REG(IT87_INIT_TEMP_LOW_2));
-	it87_write_value(client, IT87_REG_TEMP_HIGH(3),
+	it87_write_value(client, IT87_REG_TEMP_HIGH(2),
 			 TEMP_TO_REG(IT87_INIT_TEMP_HIGH_3));
-	it87_write_value(client, IT87_REG_TEMP_LOW(3),
+	it87_write_value(client, IT87_REG_TEMP_LOW(2),
 			 TEMP_TO_REG(IT87_INIT_TEMP_LOW_3));
 
 	/* Enable voltage monitors */
 	it87_write_value(client, IT87_REG_VIN_ENABLE, 0xff);
 
 	/* Enable Temp1-Temp3 */
-	it87_write_value(client, IT87_REG_TEMP_ENABLE,
-			(it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0)
-			| (temp_type & 0x3f));
+	data->sensor = (it87_read_value(client, IT87_REG_TEMP_ENABLE) & 0xc0);
+	data->sensor |= temp_type & 0x3f;
+	it87_write_value(client, IT87_REG_TEMP_ENABLE, data->sensor);
 
 	/* Enable fans */
 	it87_write_value(client, IT87_REG_FAN_CTRL,
@@ -860,18 +934,18 @@
 		data->in_min[8] = 0;
 		data->in_max[8] = 255;
 
-		for (i = 1; i <= 3; i++) {
-			data->fan[i - 1] =
+		for (i = 0; i < 3; i++) {
+			data->fan[i] =
 			    it87_read_value(client, IT87_REG_FAN(i));
-			data->fan_min[i - 1] =
+			data->fan_min[i] =
 			    it87_read_value(client, IT87_REG_FAN_MIN(i));
 		}
-		for (i = 1; i <= 3; i++) {
-			data->temp[i - 1] =
+		for (i = 0; i < 3; i++) {
+			data->temp[i] =
 			    it87_read_value(client, IT87_REG_TEMP(i));
-			data->temp_high[i - 1] =
+			data->temp_high[i] =
 			    it87_read_value(client, IT87_REG_TEMP_HIGH(i));
-			data->temp_low[i - 1] =
+			data->temp_low[i] =
 			    it87_read_value(client, IT87_REG_TEMP_LOW(i));
 		}
 
@@ -887,7 +961,7 @@
 		i = it87_read_value(client, IT87_REG_FAN_DIV);
 		data->fan_div[0] = i & 0x07;
 		data->fan_div[1] = (i >> 3) & 0x07;
-		data->fan_div[2] = 1;
+		data->fan_div[2] = (i & 0x40) ? 3 : 1;
 
 		data->alarms =
 			it87_read_value(client, IT87_REG_ALARM1) |
diff -Nru a/drivers/i2c/chips/lm75.c b/drivers/i2c/chips/lm75.c
--- a/drivers/i2c/chips/lm75.c	Thu Apr 24 06:36:20 2003
+++ b/drivers/i2c/chips/lm75.c	Tue May  6 07:19:29 2003
@@ -121,6 +121,8 @@
 
 static int lm75_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, lm75_detect);
 }
 
diff -Nru a/drivers/i2c/chips/via686a.c b/drivers/i2c/chips/via686a.c
--- a/drivers/i2c/chips/via686a.c	Thu Apr 24 06:36:20 2003
+++ b/drivers/i2c/chips/via686a.c	Tue May  6 07:19:37 2003
@@ -661,6 +661,8 @@
 /* This is called when the module is loaded */
 static int via686a_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, via686a_detect);
 }
 
diff -Nru a/drivers/i2c/chips/w83781d.c b/drivers/i2c/chips/w83781d.c
--- a/drivers/i2c/chips/w83781d.c	Thu Apr 24 06:36:20 2003
+++ b/drivers/i2c/chips/w83781d.c	Tue May  6 07:19:48 2003
@@ -1026,6 +1026,8 @@
 static int
 w83781d_attach_adapter(struct i2c_adapter *adapter)
 {
+	if (!(adapter->class & I2C_ADAP_CLASS_SMBUS))
+		return 0;
 	return i2c_detect(adapter, &addr_data, w83781d_detect);
 }
 
diff -Nru a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
--- a/drivers/i2c/i2c-core.c	Thu Apr 24 04:11:42 2003
+++ b/drivers/i2c/i2c-core.c	Fri May  9 09:12:22 2003
@@ -38,8 +38,8 @@
 #define DEB(x) if (i2c_debug>=1) x;
 #define DEB2(x) if (i2c_debug>=2) x;
 
-static struct i2c_adapter *adapters[I2C_ADAP_MAX];
-static struct i2c_driver *drivers[I2C_DRIVER_MAX];
+static LIST_HEAD(adapters);
+static LIST_HEAD(drivers);
 static DECLARE_MUTEX(core_lists);
 
 /**** debug level */
@@ -55,13 +55,17 @@
 	return 0;
 }
 
-static struct device_driver i2c_generic_driver = {
-	.name =	"i2c",
+static struct device_driver i2c_adapter_driver = {
+	.name =	"i2c_adapter",
 	.bus = &i2c_bus_type,
 	.probe = i2c_device_probe,
 	.remove = i2c_device_remove,
 };
 
+static struct class i2c_adapter_class = {
+	.name =		"i2c-adapter"
+};
+
 
 /* ---------------------------------------------------
  * registering functions 
@@ -75,23 +79,17 @@
  */
 int i2c_add_adapter(struct i2c_adapter *adap)
 {
-	int res = 0, i, j;
+	static int nr = 0;
+	struct list_head   *item;
+	struct i2c_driver  *driver;
 
 	down(&core_lists);
-	for (i = 0; i < I2C_ADAP_MAX; i++)
-		if (NULL == adapters[i])
-			break;
-	if (I2C_ADAP_MAX == i) {
-		dev_warn(&adap->dev,
-			"register_adapter - enlarge I2C_ADAP_MAX.\n");
-		res = -ENOMEM;
-		goto out_unlock;
-	}
-
-	adapters[i] = adap;
 
-	init_MUTEX(&adap->bus);
-	init_MUTEX(&adap->list);
+	adap->nr = nr++;
+	init_MUTEX(&adap->bus_lock);
+	init_MUTEX(&adap->clist_lock);
+	list_add_tail(&adap->list,&adapters);
+	INIT_LIST_HEAD(&adap->clients);
 
 	/* Add the adapter to the driver core.
 	 * If the parent pointer is not set up,
@@ -99,77 +97,73 @@
 	 */
 	if (adap->dev.parent == NULL)
 		adap->dev.parent = &legacy_bus;
-	sprintf(adap->dev.bus_id, "i2c-%d", i);
-	adap->dev.driver = &i2c_generic_driver;
+	sprintf(adap->dev.bus_id, "i2c-%d", adap->nr);
+	adap->dev.driver = &i2c_adapter_driver;
 	device_register(&adap->dev);
 
+	/* Add this adapter to the i2c_adapter class */
+	memset(&adap->class_dev, 0x00, sizeof(struct class_device));
+	adap->class_dev.dev = &adap->dev;
+	adap->class_dev.class = &i2c_adapter_class;
+	strncpy(adap->class_dev.class_id, adap->dev.bus_id, BUS_ID_SIZE);
+	class_device_register(&adap->class_dev);
+
 	/* inform drivers of new adapters */
-	for (j=0;j<I2C_DRIVER_MAX;j++)
-		if (drivers[j]!=NULL && 
-		    (drivers[j]->flags&(I2C_DF_NOTIFY|I2C_DF_DUMMY)))
+	list_for_each(item,&drivers) {
+		driver = list_entry(item, struct i2c_driver, list);
+		if (driver->flags & I2C_DF_NOTIFY)
 			/* We ignore the return code; if it fails, too bad */
-			drivers[j]->attach_adapter(adap);
+			driver->attach_adapter(adap);
+	}
 	up(&core_lists);
-	
-	DEB(dev_dbg(&adap->dev, "registered as adapter %d.\n", i));
 
- out_unlock:
-	up(&core_lists);
-	return res;;
+	DEB(dev_dbg(&adap->dev, "registered as adapter #%d\n", adap->nr));
+	return 0;
 }
 
 
 int i2c_del_adapter(struct i2c_adapter *adap)
 {
-	int res = 0, i, j;
+	struct list_head  *item;
+	struct i2c_driver *driver;
+	struct i2c_client *client;
+	int res = 0;
 
 	down(&core_lists);
-	for (i = 0; i < I2C_ADAP_MAX; i++)
-		if (adap == adapters[i])
-			break;
-	if (I2C_ADAP_MAX == i) {
-		dev_warn(&adap->dev, "unregister_adapter adap not found.\n");
-		res = -ENODEV;
-		goto out_unlock;
-	}
 
-	/* DUMMY drivers do not register their clients, so we have to
-	 * use a trick here: we call driver->attach_adapter to
-	 * *detach* it! Of course, each dummy driver should know about
-	 * this or hell will break loose...
-	 */
-	for (j = 0; j < I2C_DRIVER_MAX; j++) 
-		if (drivers[j] && (drivers[j]->flags & I2C_DF_DUMMY))
-			if ((res = drivers[j]->attach_adapter(adap))) {
+	list_for_each(item,&drivers) {
+		driver = list_entry(item, struct i2c_driver, list);
+		if (driver->detach_adapter)
+			if ((res = driver->detach_adapter(adap))) {
 				dev_warn(&adap->dev, "can't detach adapter"
-				       "while detaching driver %s: driver not "
-				       "detached!", drivers[j]->name);
+					 "while detaching driver %s: driver not "
+					 "detached!", driver->name);
 				goto out_unlock;
 			}
+	}
 
 	/* detach any active clients. This must be done first, because
 	 * it can fail; in which case we give upp. */
-	for (j=0;j<I2C_CLIENT_MAX;j++) {
-		struct i2c_client *client = adap->clients[j];
-		if (client!=NULL) {
-		    /* detaching devices is unconditional of the set notify
-		     * flag, as _all_ clients that reside on the adapter
-		     * must be deleted, as this would cause invalid states.
-		     */
-			if ((res=client->driver->detach_client(client))) {
-				dev_err(&adap->dev, "adapter not "
-					"unregistered, because client at "
-					"address %02x can't be detached. ",
-					client->addr);
-				goto out_unlock;
-			}
+	list_for_each(item,&adap->clients) {
+		client = list_entry(item, struct i2c_client, list);
+
+		/* detaching devices is unconditional of the set notify
+		 * flag, as _all_ clients that reside on the adapter
+		 * must be deleted, as this would cause invalid states.
+		 */
+		if ((res=client->driver->detach_client(client))) {
+			dev_err(&adap->dev, "adapter not "
+				"unregistered, because client at "
+				"address %02x can't be detached. ",
+				client->addr);
+			goto out_unlock;
 		}
 	}
 
 	/* clean up the sysfs representation */
+	class_device_unregister(&adap->class_dev);
 	device_unregister(&adap->dev);
-
-	adapters[i] = NULL;
+	list_del(&adap->list);
 
 	DEB(dev_dbg(&adap->dev, "adapter unregistered\n"));
 
@@ -187,24 +181,11 @@
 
 int i2c_add_driver(struct i2c_driver *driver)
 {
-	int res = 0, i;
+	struct list_head   *item;
+	struct i2c_adapter *adapter;
+	int res = 0;
 
 	down(&core_lists);
-	for (i = 0; i < I2C_DRIVER_MAX; i++)
-		if (NULL == drivers[i])
-			break;
-	if (I2C_DRIVER_MAX == i) {
-		printk(KERN_WARNING 
-		       " i2c-core.o: register_driver(%s) "
-		       "- enlarge I2C_DRIVER_MAX.\n",
-			driver->name);
-		res = -ENOMEM;
-		goto out_unlock;
-	}
-
-	drivers[i] = driver;
-	
-	DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
 
 	/* add the driver to the list of i2c drivers in the driver core */
 	driver->driver.name = driver->name;
@@ -216,13 +197,14 @@
 	if (res)
 		goto out_unlock;
 	
-	/* now look for instances of driver on our adapters
-	 */
-	if (driver->flags& (I2C_DF_NOTIFY|I2C_DF_DUMMY)) {
-		for (i=0;i<I2C_ADAP_MAX;i++) {
-			if (adapters[i]!=NULL)
-				/* Ignore errors */
-				driver->attach_adapter(adapters[i]);
+	list_add_tail(&driver->list,&drivers);
+	DEB(printk(KERN_DEBUG "i2c-core.o: driver %s registered.\n",driver->name));
+
+	/* now look for instances of driver on our adapters */
+	if (driver->flags & I2C_DF_NOTIFY) {
+		list_for_each(item,&adapters) {
+			adapter = list_entry(item, struct i2c_adapter, list);
+			driver->attach_adapter(adapter);
 		}
 	}
 
@@ -233,44 +215,29 @@
 
 int i2c_del_driver(struct i2c_driver *driver)
 {
-	int res = 0, i, j, k;
+	struct list_head   *item1;
+	struct list_head   *item2;
+	struct i2c_client  *client;
+	struct i2c_adapter *adap;
+	
+	int res = 0;
 
 	down(&core_lists);
-	for (i = 0; i < I2C_DRIVER_MAX; i++)
-		if (driver == drivers[i])
-			break;
-	if (I2C_DRIVER_MAX == i) {
-		printk(KERN_WARNING " i2c-core.o: unregister_driver: "
-				    "[%s] not found\n",
-			driver->name);
-		res = -ENODEV;
-		goto out_unlock;
-	}
-
-	driver_unregister(&driver->driver);
 
 	/* Have a look at each adapter, if clients of this driver are still
 	 * attached. If so, detach them to be able to kill the driver 
 	 * afterwards.
 	 */
 	DEB2(printk(KERN_DEBUG "i2c-core.o: unregister_driver - looking for clients.\n"));
-
 	/* removing clients does not depend on the notify flag, else 
 	 * invalid operation might (will!) result, when using stale client
 	 * pointers.
 	 */
-	for (k=0;k<I2C_ADAP_MAX;k++) {
-		struct i2c_adapter *adap = adapters[k];
-		if (adap == NULL) /* skip empty entries. */
-			continue;
+	list_for_each(item1,&adapters) {
+		adap = list_entry(item1, struct i2c_adapter, list);
 		DEB2(dev_dbg(&adap->dev, "examining adapter\n"));
-		if (driver->flags & I2C_DF_DUMMY) {
-		/* DUMMY drivers do not register their clients, so we have to
-		 * use a trick here: we call driver->attach_adapter to
-		 * *detach* it! Of course, each dummy driver should know about
-		 * this or hell will break loose...  
-		 */
-			if ((res = driver->attach_adapter(adap))) {
+		if (driver->detach_adapter) {
+			if ((res = driver->detach_adapter(adap))) {
 				dev_warn(&adap->dev, "while unregistering "
 				       "dummy driver %s, adapter could "
 				       "not be detached properly; driver "
@@ -278,31 +245,31 @@
 				goto out_unlock;
 			}
 		} else {
-			for (j=0;j<I2C_CLIENT_MAX;j++) { 
-				struct i2c_client *client = adap->clients[j];
-				if (client != NULL && 
-				    client->driver == driver) {
-					DEB2(printk(KERN_DEBUG "i2c-core.o: "
-						    "detaching client %s:\n",
-					            client->dev.name));
-					if ((res = driver->detach_client(client))) {
-						dev_err(&adap->dev, "while "
-						       "unregistering driver "
-						       "`%s', the client at "
-						       "address %02x of "
-						       "adapter could not "
-						       "be detached; driver "
-						       "not unloaded!",
-						       driver->name,
-						       client->addr);
-						goto out_unlock;
-					}
+			list_for_each(item2,&adap->clients) {
+				client = list_entry(item2, struct i2c_client, list);
+				if (client->driver != driver)
+					continue;
+				DEB2(printk(KERN_DEBUG "i2c-core.o: "
+					    "detaching client %s:\n",
+					    client->dev.name));
+				if ((res = driver->detach_client(client))) {
+					dev_err(&adap->dev, "while "
+						"unregistering driver "
+						"`%s', the client at "
+						"address %02x of "
+						"adapter could not "
+						"be detached; driver "
+						"not unloaded!",
+						driver->name,
+						client->addr);
+					goto out_unlock;
 				}
 			}
 		}
 	}
-	drivers[i] = NULL;
-	
+
+	driver_unregister(&driver->driver);
+	list_del(&driver->list);
 	DEB(printk(KERN_DEBUG "i2c-core.o: driver unregistered: %s\n",driver->name));
 
  out_unlock:
@@ -310,14 +277,16 @@
 	return 0;
 }
 
-static int __i2c_check_addr(struct i2c_adapter *adapter, int addr)
+static int __i2c_check_addr(struct i2c_adapter *adapter, unsigned int addr)
 {
-	int i;
+	struct list_head   *item;
+	struct i2c_client  *client;
 
-	for (i = 0; i < I2C_CLIENT_MAX ; i++)
-		if (adapter->clients[i] && (adapter->clients[i]->addr == addr))
+	list_for_each(item,&adapter->clients) {
+		client = list_entry(item, struct i2c_client, list);
+		if (client->addr == addr)
 			return -EBUSY;
-
+	}
 	return 0;
 }
 
@@ -325,9 +294,9 @@
 {
 	int rval;
 
-	down(&adapter->list);
+	down(&adapter->clist_lock);
 	rval = __i2c_check_addr(adapter, addr);
-	up(&adapter->list);
+	up(&adapter->clist_lock);
 
 	return rval;
 }
@@ -335,28 +304,14 @@
 int i2c_attach_client(struct i2c_client *client)
 {
 	struct i2c_adapter *adapter = client->adapter;
-	int i;
-
-	down(&adapter->list);
-	if (__i2c_check_addr(client->adapter, client->addr))
-		goto out_unlock_list;
 
-	for (i = 0; i < I2C_CLIENT_MAX; i++) {
-		if (!adapter->clients[i])
-			goto free_slot;
+	down(&adapter->clist_lock);
+	if (__i2c_check_addr(client->adapter, client->addr)) {
+		up(&adapter->clist_lock);
+		return -EBUSY;
 	}
-
-	printk(KERN_WARNING 
-	       " i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.\n",
-	       client->dev.name);
-
- out_unlock_list:
-	up(&adapter->list);
-	return -EBUSY;
-
- free_slot:
-	adapter->clients[i] = client;
-	up(&adapter->list);
+	list_add_tail(&client->list,&adapter->clients);
+	up(&adapter->clist_lock);
 	
 	if (adapter->client_register)  {
 		if (adapter->client_register(client))  {
@@ -366,8 +321,8 @@
 		}
 	}
 
-	DEB(dev_dbg(&adapter->dev, "client [%s] registered to adapter "
-			"(pos. %d).\n", client->dev.name, i));
+	DEB(dev_dbg(&adapter->dev, "client [%s] registered to adapter\n",
+			client->dev.name));
 
 	if (client->flags & I2C_CLIENT_ALLOW_USE)
 		client->usage_count = 0;
@@ -388,7 +343,7 @@
 int i2c_detach_client(struct i2c_client *client)
 {
 	struct i2c_adapter *adapter = client->adapter;
-	int res = 0, i;
+	int res = 0;
 	
 	if ((client->flags & I2C_CLIENT_ALLOW_USE) && (client->usage_count > 0))
 		return -EBUSY;
@@ -403,22 +358,11 @@
 		}
 	}
 
-	down(&adapter->list);
-	for (i = 0; i < I2C_CLIENT_MAX; i++) {
-		if (client == adapter->clients[i]) {
-			adapter->clients[i] = NULL;
-			goto out_unlock;
-		}
-	}
-
-	printk(KERN_WARNING
-	       " i2c-core.o: unregister_client [%s] not found\n",
-	       client->dev.name);
-	res = -ENODEV;
-
- out_unlock:
+	down(&adapter->clist_lock);
+	list_del(&client->list);
 	device_unregister(&client->dev);
-	up(&adapter->list);
+	up(&adapter->clist_lock);
+
  out:
 	return res;
 }
@@ -479,6 +423,27 @@
 	return 0;
 }
 
+void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
+{
+	struct list_head  *item;
+	struct i2c_client *client;
+
+	down(&adap->clist_lock);
+	list_for_each(item,&adap->clients) {
+		client = list_entry(item, struct i2c_client, list);
+		if (!try_module_get(client->driver->owner))
+			continue;
+		if (NULL != client->driver->command) {
+			up(&adap->clist_lock);
+			client->driver->command(client,cmd,arg);
+			down(&adap->clist_lock);
+		}
+		module_put(client->driver->owner);
+       }
+       up(&adap->clist_lock);
+}
+
+
 /* match always succeeds, as we want the probe() to tell if we really accept this match */
 static int i2c_device_match(struct device *dev, struct device_driver *drv)
 {
@@ -490,14 +455,23 @@
 	.match =	i2c_device_match,
 };
 
-
 static int __init i2c_init(void)
 {
-	return bus_register(&i2c_bus_type);
+	int retval;
+
+	retval = bus_register(&i2c_bus_type);
+	if (retval)
+		return retval;
+	retval = driver_register(&i2c_adapter_driver);
+	if (retval)
+		return retval;
+	return class_register(&i2c_adapter_class);
 }
 
 static void __exit i2c_exit(void)
 {
+	class_unregister(&i2c_adapter_class);
+	driver_unregister(&i2c_adapter_driver);
 	bus_unregister(&i2c_bus_type);
 }
 
@@ -516,13 +490,13 @@
 	if (adap->algo->master_xfer) {
  	 	DEB2(dev_dbg(&adap->dev, "master_xfer: with %d msgs.\n", num));
 
-		down(&adap->bus);
+		down(&adap->bus_lock);
 		ret = adap->algo->master_xfer(adap,msgs,num);
-		up(&adap->bus);
+		up(&adap->bus_lock);
 
 		return ret;
 	} else {
-		dev_err(&adap->dev, "I2C level transfers not supported\n");
+		DEB2(dev_dbg(&adap->dev, "I2C level transfers not supported\n"));
 		return -ENOSYS;
 	}
 }
@@ -542,9 +516,9 @@
 		DEB2(dev_dbg(&client->adapter->dev, "master_send: writing %d bytes.\n",
 				count));
 	
-		down(&adap->bus);
+		down(&adap->bus_lock);
 		ret = adap->algo->master_xfer(adap,&msg,1);
-		up(&adap->bus);
+		up(&adap->bus_lock);
 
 		/* if everything went ok (i.e. 1 msg transmitted), return #bytes
 		 * transmitted, else error code.
@@ -572,9 +546,9 @@
 		DEB2(dev_dbg(&client->adapter->dev, "master_recv: reading %d bytes.\n",
 				count));
 	
-		down(&adap->bus);
+		down(&adap->bus_lock);
 		ret = adap->algo->master_xfer(adap,&msg,1);
-		up(&adap->bus);
+		up(&adap->bus_lock);
 	
 		DEB2(printk(KERN_DEBUG "i2c-core.o: master_recv: return:%d (count:%d, addr:0x%02x)\n",
 			ret, count, client->addr));
@@ -743,11 +717,30 @@
  */
 int i2c_adapter_id(struct i2c_adapter *adap)
 {
-	int i;
-	for (i = 0; i < I2C_ADAP_MAX; i++)
-		if (adap == adapters[i])
-			return i;
-	return -1;
+	return adap->nr;
+}
+
+struct i2c_adapter* i2c_get_adapter(int id)
+{
+	struct list_head   *item;
+	struct i2c_adapter *adapter;
+	
+	down(&core_lists);
+	list_for_each(item,&adapters) {
+		adapter = list_entry(item, struct i2c_adapter, list);
+		if (id == adapter->nr &&
+		    try_module_get(adapter->owner)) {
+			up(&core_lists);
+			return adapter;
+		}
+	}
+	up(&core_lists);
+	return NULL;
+}
+
+void i2c_put_adapter(struct i2c_adapter *adap)
+{
+	module_put(adap->owner);
 }
 
 /* The SMBus parts */
@@ -1189,10 +1182,10 @@
 	}
 
 	if (adapter->algo->smbus_xfer) {
-		down(&adapter->bus);
+		down(&adapter->bus_lock);
 		res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
 		                                command,size,data);
-		up(&adapter->bus);
+		up(&adapter->bus_lock);
 	} else
 		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
 	                                      command,size,data);
@@ -1232,6 +1225,7 @@
 EXPORT_SYMBOL(i2c_detach_client);
 EXPORT_SYMBOL(i2c_use_client);
 EXPORT_SYMBOL(i2c_release_client);
+EXPORT_SYMBOL(i2c_clients_command);
 EXPORT_SYMBOL(i2c_check_addr);
 
 EXPORT_SYMBOL(i2c_master_send);
@@ -1239,6 +1233,8 @@
 EXPORT_SYMBOL(i2c_control);
 EXPORT_SYMBOL(i2c_transfer);
 EXPORT_SYMBOL(i2c_adapter_id);
+EXPORT_SYMBOL(i2c_get_adapter);
+EXPORT_SYMBOL(i2c_put_adapter);
 EXPORT_SYMBOL(i2c_probe);
 
 EXPORT_SYMBOL(i2c_smbus_xfer);
diff -Nru a/drivers/i2c/i2c-dev.c b/drivers/i2c/i2c-dev.c
--- a/drivers/i2c/i2c-dev.c	Wed Apr  9 14:36:09 2003
+++ b/drivers/i2c/i2c-dev.c	Mon May 19 15:32:51 2003
@@ -3,6 +3,7 @@
 
     Copyright (C) 1995-97 Simon G. Vogl
     Copyright (C) 1998-99 Frodo Looijaard <frodol@dds.nl>
+    Copyright (C) 2003 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
@@ -28,8 +29,6 @@
 /* The devfs code is contributed by Philipp Matthias Hahn 
    <pmhahn@titan.lahn.de> */
 
-/* $Id: i2c-dev.c,v 1.53 2003/01/21 08:08:16 kmalkki Exp $ */
-
 /* If you want debugging uncomment: */
 /* #define DEBUG 1 */
 
@@ -44,55 +43,84 @@
 #include <linux/i2c-dev.h>
 #include <asm/uaccess.h>
 
-/* struct file_operations changed too often in the 2.1 series for nice code */
+static struct i2c_client i2cdev_client_template;
 
-static ssize_t i2cdev_read (struct file *file, char *buf, size_t count, 
-                            loff_t *offset);
-static ssize_t i2cdev_write (struct file *file, const char *buf, size_t count, 
-                             loff_t *offset);
+struct i2c_dev {
+	int minor;
+	struct i2c_adapter *adap;
+	struct class_device class_dev;
+};
+#define to_i2c_dev(d) container_of(d, struct i2c_dev, class_dev)
 
-static int i2cdev_ioctl (struct inode *inode, struct file *file, 
-                         unsigned int cmd, unsigned long arg);
-static int i2cdev_open (struct inode *inode, struct file *file);
+#define I2C_MINORS	256
+static struct i2c_dev *i2c_dev_array[I2C_MINORS];
+static spinlock_t i2c_dev_array_lock = SPIN_LOCK_UNLOCKED;
 
-static int i2cdev_release (struct inode *inode, struct file *file);
+struct i2c_dev *i2c_dev_get_by_minor(unsigned index)
+{
+	struct i2c_dev *i2c_dev;
 
-static int i2cdev_attach_adapter(struct i2c_adapter *adap);
-static int i2cdev_detach_client(struct i2c_client *client);
-static int i2cdev_command(struct i2c_client *client, unsigned int cmd,
-                           void *arg);
+	spin_lock(&i2c_dev_array_lock);
+	i2c_dev = i2c_dev_array[index];
+	spin_unlock(&i2c_dev_array_lock);
+	return i2c_dev;
+}
 
-static struct file_operations i2cdev_fops = {
-	.owner		= THIS_MODULE,
-	.llseek		= no_llseek,
-	.read		= i2cdev_read,
-	.write		= i2cdev_write,
-	.ioctl		= i2cdev_ioctl,
-	.open		= i2cdev_open,
-	.release	= i2cdev_release,
-};
+struct i2c_dev *i2c_dev_get_by_adapter(struct i2c_adapter *adap)
+{
+	struct i2c_dev *i2c_dev = NULL;
+	int i;
 
-#define I2CDEV_ADAPS_MAX I2C_ADAP_MAX
-static struct i2c_adapter *i2cdev_adaps[I2CDEV_ADAPS_MAX];
+	spin_lock(&i2c_dev_array_lock);
+	for (i = 0; i < I2C_MINORS; ++i) {
+		if ((i2c_dev_array[i]) &&
+		    (i2c_dev_array[i]->adap == adap)) {
+			i2c_dev = i2c_dev_array[i];
+			break;
+		}
+	}
+	spin_unlock(&i2c_dev_array_lock);
+	return i2c_dev;
+}
 
-static struct i2c_driver i2cdev_driver = {
-	.owner		= THIS_MODULE,
-	.name		= "dev driver",
-	.id		= I2C_DRIVERID_I2CDEV,
-	.flags		= I2C_DF_DUMMY,
-	.attach_adapter	= i2cdev_attach_adapter,
-	.detach_client	= i2cdev_detach_client,
-	.command	= i2cdev_command,
-};
+static struct i2c_dev *get_free_i2c_dev(void)
+{
+	struct i2c_dev *i2c_dev;
+	unsigned int i;
 
-static struct i2c_client i2cdev_client_template = {
-	.dev		= {
-		.name	= "I2C /dev entry",
-	},
-	.id		= 1,
-	.addr		= -1,
-	.driver		= &i2cdev_driver,
-};
+	i2c_dev = kmalloc(sizeof(*i2c_dev), GFP_KERNEL);
+	if (!i2c_dev)
+		return ERR_PTR(-ENOMEM);
+	memset(i2c_dev, 0x00, sizeof(*i2c_dev));
+
+	spin_lock(&i2c_dev_array_lock);
+	for (i = 0; i < I2C_MINORS; ++i) {
+		if (i2c_dev_array[i])
+			continue;
+		i2c_dev->minor = i;
+		i2c_dev_array[i] = i2c_dev;
+		spin_unlock(&i2c_dev_array_lock);
+		return i2c_dev;
+	}
+	spin_unlock(&i2c_dev_array_lock);
+	kfree(i2c_dev);
+	return ERR_PTR(-ENODEV);
+}
+
+static void return_i2c_dev(struct i2c_dev *i2c_dev)
+{
+	spin_lock(&i2c_dev_array_lock);
+	i2c_dev_array[i2c_dev->minor] = NULL;
+	spin_unlock(&i2c_dev_array_lock);
+	kfree(i2c_dev);
+}
+
+static ssize_t show_dev(struct class_device *class_dev, char *buf)
+{
+	struct i2c_dev *i2c_dev = to_i2c_dev(class_dev);
+	return sprintf(buf, "%04x\n", MKDEV(I2C_MAJOR, i2c_dev->minor));
+}
+static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
 
 static ssize_t i2cdev_read (struct file *file, char *buf, size_t count,
                             loff_t *offset)
@@ -105,7 +133,6 @@
 	if (count > 8192)
 		count = 8192;
 
-	/* copy user space data to kernel space. */
 	tmp = kmalloc(count,GFP_KERNEL);
 	if (tmp==NULL)
 		return -ENOMEM;
@@ -130,7 +157,6 @@
 	if (count > 8192)
 		count = 8192;
 
-	/* copy user space data to kernel space. */
 	tmp = kmalloc(count,GFP_KERNEL);
 	if (tmp==NULL)
 		return -ENOMEM;
@@ -158,7 +184,7 @@
 	int i,datasize,res;
 	unsigned long funcs;
 
-	pr_debug("i2c-dev.o: i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
+	dev_dbg(&client->dev, "i2c-%d ioctl, cmd: 0x%x, arg: %lx.\n",
 		minor(inode->i_rdev),cmd, arg);
 
 	switch ( cmd ) {
@@ -243,13 +269,11 @@
 				rdwr_arg.nmsgs);
 		}
 		while(i-- > 0) {
-			if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD))
-			{
+			if( res>=0 && (rdwr_pa[i].flags & I2C_M_RD)) {
 				if(copy_to_user(
 					rdwr_arg.msgs[i].buf,
 					rdwr_pa[i].buf,
-					rdwr_pa[i].len))
-				{
+					rdwr_pa[i].len)) {
 					res = -EFAULT;
 				}
 			}
@@ -340,74 +364,104 @@
 {
 	unsigned int minor = minor(inode->i_rdev);
 	struct i2c_client *client;
+	struct i2c_adapter *adap;
+	struct i2c_dev *i2c_dev;
+
+	i2c_dev = i2c_dev_get_by_minor(minor);
+	if (!i2c_dev)
+		return -ENODEV;
 
-	if ((minor >= I2CDEV_ADAPS_MAX) || !(i2cdev_adaps[minor]))
+	adap = i2c_get_adapter(i2c_dev->adap->nr);
+	if (!adap)
 		return -ENODEV;
 
 	client = kmalloc(sizeof(*client), GFP_KERNEL);
-	if (!client)
+	if (!client) {
+		i2c_put_adapter(adap);
 		return -ENOMEM;
+	}
 	memcpy(client, &i2cdev_client_template, sizeof(*client));
 
 	/* registered with adapter, passed as client to user */
-	client->adapter = i2cdev_adaps[minor];
+	client->adapter = adap;
 	file->private_data = client;
 
-	/* use adapter module, i2c-dev handled with fops */
-	if (!try_module_get(client->adapter->owner))
-		goto out_kfree;
-
 	return 0;
-
-out_kfree:
-	kfree(client);
-	return -ENODEV;
 }
 
 static int i2cdev_release(struct inode *inode, struct file *file)
 {
 	struct i2c_client *client = file->private_data;
 
-	module_put(client->adapter->owner);
+	i2c_put_adapter(client->adapter);
 	kfree(client);
 	file->private_data = NULL;
 
 	return 0;
 }
 
-int i2cdev_attach_adapter(struct i2c_adapter *adap)
+static struct file_operations i2cdev_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= i2cdev_read,
+	.write		= i2cdev_write,
+	.ioctl		= i2cdev_ioctl,
+	.open		= i2cdev_open,
+	.release	= i2cdev_release,
+};
+
+static struct class i2c_dev_class = {
+	.name	= "i2c-dev",
+};
+
+static int i2cdev_attach_adapter(struct i2c_adapter *adap)
 {
-	int i;
-	char name[12];
+	struct i2c_dev *i2c_dev;
+	int retval;
 
-	if ((i = i2c_adapter_id(adap)) < 0) {
-		dev_dbg(&adap->dev, "Unknown adapter ?!?\n");
-		return -ENODEV;
-	}
-	if (i >= I2CDEV_ADAPS_MAX) {
-		dev_dbg(&adap->dev, "Adapter number too large?!? (%d)\n",i);
+	i2c_dev = get_free_i2c_dev();
+	if (IS_ERR(i2c_dev))
+		return PTR_ERR(i2c_dev);
+
+	devfs_mk_cdev(MKDEV(I2C_MAJOR, i2c_dev->minor),
+			S_IFCHR|S_IRUSR|S_IWUSR, "i2c/%d", i2c_dev->minor);
+	dev_dbg(&adap->dev, "Registered as minor %d\n", i2c_dev->minor);
+
+	/* register this i2c device with the driver core */
+	i2c_dev->adap = adap;
+	if (adap->dev.parent == &legacy_bus)
+		i2c_dev->class_dev.dev = &adap->dev;
+	else
+		i2c_dev->class_dev.dev = adap->dev.parent;
+	i2c_dev->class_dev.class = &i2c_dev_class;
+	snprintf(i2c_dev->class_dev.class_id, BUS_ID_SIZE, "i2c-%d", i2c_dev->minor);
+	retval = class_device_register(&i2c_dev->class_dev);
+	if (retval)
+		goto error;
+	class_device_create_file(&i2c_dev->class_dev, &class_device_attr_dev);
+	return 0;
+error:
+	return_i2c_dev(i2c_dev);
+	return retval;
+}
+
+static int i2cdev_detach_adapter(struct i2c_adapter *adap)
+{
+	struct i2c_dev *i2c_dev;
+
+	i2c_dev = i2c_dev_get_by_adapter(adap);
+	if (!i2c_dev)
 		return -ENODEV;
-	}
 
-	sprintf (name, "i2c/%d", i);
-	if (! i2cdev_adaps[i]) {
-		i2cdev_adaps[i] = adap;
-		devfs_register (NULL, name,
-			DEVFS_FL_DEFAULT, I2C_MAJOR, i,
-			S_IFCHR | S_IRUSR | S_IWUSR,
-			&i2cdev_fops, NULL);
-		dev_dbg(&adap->dev, "Registered as minor %d\n", i);
-	} else {
-		/* This is actually a detach_adapter call! */
-		devfs_remove("i2c/%d", i);
-		i2cdev_adaps[i] = NULL;
-		dev_dbg(&adap->dev, "Adapter unregistered\n");
-	}
+	class_device_unregister(&i2c_dev->class_dev);
+	devfs_remove("i2c/%d", i2c_dev->minor);
+	return_i2c_dev(i2c_dev);
 
+	dev_dbg(&adap->dev, "Adapter unregistered\n");
 	return 0;
 }
 
-int i2cdev_detach_client(struct i2c_client *client)
+static int i2cdev_detach_client(struct i2c_client *client)
 {
 	return 0;
 }
@@ -418,7 +472,27 @@
 	return -1;
 }
 
-int __init i2c_dev_init(void)
+static struct i2c_driver i2cdev_driver = {
+	.owner		= THIS_MODULE,
+	.name		= "dev driver",
+	.id		= I2C_DRIVERID_I2CDEV,
+	.flags		= I2C_DF_NOTIFY,
+	.attach_adapter	= i2cdev_attach_adapter,
+	.detach_adapter	= i2cdev_detach_adapter,
+	.detach_client	= i2cdev_detach_client,
+	.command	= i2cdev_command,
+};
+
+static struct i2c_client i2cdev_client_template = {
+	.dev		= {
+		.name	= "I2C /dev entry",
+	},
+	.id		= 1,
+	.addr		= -1,
+	.driver		= &i2cdev_driver,
+};
+
+static int __init i2c_dev_init(void)
 {
 	int res;
 
@@ -431,6 +505,7 @@
 		return -EIO;
 	}
 	devfs_mk_dir("i2c");
+	class_register(&i2c_dev_class);
 	if ((res = i2c_add_driver(&i2cdev_driver))) {
 		printk(KERN_ERR "i2c-dev.o: Driver registration failed, module not inserted.\n");
 		devfs_remove("i2c");
@@ -443,11 +518,13 @@
 static void __exit i2c_dev_exit(void)
 {
 	i2c_del_driver(&i2cdev_driver);
+	class_unregister(&i2c_dev_class);
 	devfs_remove("i2c");
 	unregister_chrdev(I2C_MAJOR,"i2c");
 }
 
-MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and Simon G. Vogl <simon@tk.uni-linz.ac.at>");
+MODULE_AUTHOR("Frodo Looijaard <frodol@dds.nl> and "
+		"Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C /dev entries driver");
 MODULE_LICENSE("GPL");
 
diff -Nru a/drivers/i2c/i2c-keywest.c b/drivers/i2c/i2c-keywest.c
--- a/drivers/i2c/i2c-keywest.c	Wed Apr  2 13:22:49 2003
+++ b/drivers/i2c/i2c-keywest.c	Wed Apr 23 04:32:32 2003
@@ -212,7 +212,7 @@
 #ifndef POLLED_MODE
 
 /* Interrupt handler */
-static void
+static irqreturn_t
 keywest_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct keywest_iface *iface = (struct keywest_iface *)dev_id;
@@ -225,6 +225,7 @@
 		add_timer(&iface->timeout_timer);
 	}
 	spin_unlock(&iface->lock);
+	return IRQ_HANDLED;
 }
 
 static void
diff -Nru a/drivers/ide/arm/icside.c b/drivers/ide/arm/icside.c
--- a/drivers/ide/arm/icside.c	Mon Feb 24 10:14:34 2003
+++ b/drivers/ide/arm/icside.c	Sat May 17 08:48:35 2003
@@ -19,7 +19,7 @@
 #include <linux/errno.h>
 #include <linux/hdreg.h>
 #include <linux/ide.h>
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
 #include <linux/device.h>
 #include <linux/init.h>
 
@@ -27,12 +27,7 @@
 #include <asm/ecard.h>
 #include <asm/io.h>
 
-/*
- * Maximum number of interfaces per card
- */
-#define MAX_IFS	2
-
-#define ICS_IDENT_OFFSET		0x8a0
+#define ICS_IDENT_OFFSET		0x2280
 
 #define ICS_ARCIN_V5_INTRSTAT		0x000
 #define ICS_ARCIN_V5_INTROFFSET		0x001
@@ -77,14 +72,19 @@
 struct icside_state {
 	unsigned int channel;
 	unsigned int enabled;
-	unsigned int irq_port;
+	unsigned long irq_port;
+	unsigned long slot_port;
+	unsigned int type;
+	/* parent device... until the IDE core gets one of its own */
+	struct device *dev;
+	ide_hwif_t *hwif[2];
 };
 
-typedef enum {
-	ics_if_unknown,
-	ics_if_arcin_v5,
-	ics_if_arcin_v6
-} iftype_t;
+#define ICS_TYPE_A3IN	0
+#define ICS_TYPE_A3USER	1
+#define ICS_TYPE_V6	3
+#define ICS_TYPE_V5	15
+#define ICS_TYPE_NOTYPE	((unsigned int)-1)
 
 /* ---------------- Version 5 PCB Support Functions --------------------- */
 /* Prototype: icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
@@ -92,8 +92,10 @@
  */
 static void icside_irqenable_arcin_v5 (struct expansion_card *ec, int irqnr)
 {
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	outb(0, memc_port + ICS_ARCIN_V5_INTROFFSET);
+	struct icside_state *state = ec->irq_data;
+	unsigned int base = state->irq_port;
+
+	outb(0, base + ICS_ARCIN_V5_INTROFFSET);
 }
 
 /* Prototype: icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
@@ -101,17 +103,15 @@
  */
 static void icside_irqdisable_arcin_v5 (struct expansion_card *ec, int irqnr)
 {
-	unsigned int memc_port = (unsigned int)ec->irq_data;
-	inb(memc_port + ICS_ARCIN_V5_INTROFFSET);
+	struct icside_state *state = ec->irq_data;
+	unsigned int base = state->irq_port;
+
+	inb(base + ICS_ARCIN_V5_INTROFFSET);
 }
 
 static const expansioncard_ops_t icside_ops_arcin_v5 = {
-	icside_irqenable_arcin_v5,
-	icside_irqdisable_arcin_v5,
-	NULL,
-	NULL,
-	NULL,
-	NULL
+	.irqenable	= icside_irqenable_arcin_v5,
+	.irqdisable	= icside_irqdisable_arcin_v5,
 };
 
 
@@ -163,65 +163,11 @@
 }
 
 static const expansioncard_ops_t icside_ops_arcin_v6 = {
-	icside_irqenable_arcin_v6,
-	icside_irqdisable_arcin_v6,
-	icside_irqpending_arcin_v6,
-	NULL,
-	NULL,
-	NULL
+	.irqenable	= icside_irqenable_arcin_v6,
+	.irqdisable	= icside_irqdisable_arcin_v6,
+	.irqpending	= icside_irqpending_arcin_v6,
 };
 
-/* Prototype: icside_identifyif (struct expansion_card *ec)
- * Purpose  : identify IDE interface type
- * Notes    : checks the description string
- */
-static iftype_t __init icside_identifyif (struct expansion_card *ec)
-{
-	unsigned int addr;
-	iftype_t iftype;
-	int id = 0;
-
-	iftype = ics_if_unknown;
-
-	addr = ecard_address (ec, ECARD_IOC, ECARD_FAST) + ICS_IDENT_OFFSET;
-
-	id = inb(addr) & 1;
-	id |= (inb(addr + 1) & 1) << 1;
-	id |= (inb(addr + 2) & 1) << 2;
-	id |= (inb(addr + 3) & 1) << 3;
-
-	switch (id) {
-	case 0: /* A3IN */
-		printk("icside: A3IN unsupported\n");
-		break;
-
-	case 1: /* A3USER */
-		printk("icside: A3USER unsupported\n");
-		break;
-
-	case 3:	/* ARCIN V6 */
-		printk(KERN_DEBUG "icside: detected ARCIN V6 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v6;
-		break;
-
-	case 15:/* ARCIN V5 (no id) */
-		printk(KERN_DEBUG "icside: detected ARCIN V5 in slot %d\n", ec->slot_no);
-		iftype = ics_if_arcin_v5;
-		break;
-
-	default:/* we don't know - complain very loudly */
-		printk("icside: ***********************************\n");
-		printk("icside: *** UNKNOWN ICS INTERFACE id=%d ***\n", id);
-		printk("icside: ***********************************\n");
-		printk("icside: please report this to linux@arm.linux.org.uk\n");
-		printk("icside: defaulting to ARCIN V5\n");
-		iftype = ics_if_arcin_v5;
-		break;
-	}
-
-	return iftype;
-}
-
 /*
  * Handle routing of interrupts.  This is called before
  * we write the command to the drive.
@@ -229,7 +175,7 @@
 static void icside_maskproc(ide_drive_t *drive, int mask)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	struct icside_state *state = hwif->hw.priv;
+	struct icside_state *state = hwif->hwif_data;
 	unsigned long flags;
 
 	local_irq_save(flags);
@@ -271,6 +217,7 @@
 static void ide_build_sglist(ide_drive_t *drive, struct request *rq)
 {
 	ide_hwif_t *hwif = drive->hwif;
+	struct icside_state *state = hwif->hwif_data;
 	struct scatterlist *sg = hwif->sg_table;
 	int nents;
 
@@ -280,9 +227,9 @@
 		ide_task_t *args = rq->special;
 
 		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)
-			hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+			hwif->sg_dma_direction = DMA_TO_DEVICE;
 		else
-			hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+			hwif->sg_dma_direction = DMA_FROM_DEVICE;
 
 		memset(sg, 0, sizeof(*sg));
 		sg->page   = virt_to_page(rq->buffer);
@@ -293,12 +240,12 @@
 		nents = blk_rq_map_sg(&drive->queue, rq, sg);
 
 		if (rq_data_dir(rq) == READ)
-			hwif->sg_dma_direction = PCI_DMA_FROMDEVICE;
+			hwif->sg_dma_direction = DMA_FROM_DEVICE;
 		else
-			hwif->sg_dma_direction = PCI_DMA_TODEVICE;
+			hwif->sg_dma_direction = DMA_TO_DEVICE;
 	}
 
-	nents = pci_map_sg(NULL, sg, nents, hwif->sg_dma_direction);
+	nents = dma_map_sg(state->dev, sg, nents, hwif->sg_dma_direction);
 
 	hwif->sg_nents = nents;
 }
@@ -484,7 +431,7 @@
 	int xfer_mode = XFER_PIO_2;
 	int on;
 
-	if (!id || !(id->capability & 1) || !hwif->autodma)
+	if (!(id->capability & 1) || !hwif->autodma)
 		goto out;
 
 	/*
@@ -500,13 +447,7 @@
 	 * Enable DMA on any drive that has multiword DMA
 	 */
 	if (id->field_valid & 2) {
-		if (id->dma_mword & 4) {
-			xfer_mode = XFER_MW_DMA_2;
-		} else if (id->dma_mword & 2) {
-			xfer_mode = XFER_MW_DMA_1;
-		} else if (id->dma_mword & 1) {
-			xfer_mode = XFER_MW_DMA_0;
-		}
+		xfer_mode = ide_dma_speed(drive, 0);
 		goto out;
 	}
 
@@ -531,13 +472,14 @@
 static int icside_dma_end(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
+	struct icside_state *state = hwif->hwif_data;
 
 	drive->waiting_for_dma = 0;
 
 	disable_dma(hwif->hw.dma);
 
 	/* Teardown mappings after DMA has completed. */
-	pci_unmap_sg(NULL, hwif->sg_table, hwif->sg_nents,
+	dma_unmap_sg(state->dev, hwif->sg_table, hwif->sg_nents,
 		     hwif->sg_dma_direction);
 
 	hwif->sg_dma_active = 0;
@@ -713,7 +655,7 @@
 static int icside_dma_test_irq(ide_drive_t *drive)
 {
 	ide_hwif_t *hwif = HWIF(drive);
-	struct icside_state *state = hwif->hw.priv;
+	struct icside_state *state = hwif->hwif_data;
 
 	return inb(state->irq_port +
 		   (hwif->channel ?
@@ -748,7 +690,7 @@
 	return 1;
 }
 
-static int icside_setup_dma(ide_hwif_t *hwif)
+static int icside_dma_init(ide_hwif_t *hwif)
 {
 	int autodma = 0;
 
@@ -763,6 +705,10 @@
 	if (!hwif->sg_table)
 		goto failed;
 
+	hwif->atapi_dma		= 1;
+	hwif->mwdma_mask	= 7; /* MW0..2 */
+	hwif->swdma_mask	= 7; /* SW0..2 */
+
 	hwif->dmatable_cpu	= NULL;
 	hwif->dmatable_dma	= 0;
 	hwif->speedproc		= icside_set_speed;
@@ -784,10 +730,10 @@
 	hwif->ide_dma_timeout	= icside_dma_timeout;
 	hwif->ide_dma_lostirq	= icside_dma_lostirq;
 
-	hwif->drives[0].autodma = autodma;
-	hwif->drives[1].autodma = autodma;
+	hwif->drives[0].autodma = hwif->autodma;
+	hwif->drives[1].autodma = hwif->autodma;
 
-	printk(" capable%s\n", autodma ? ", auto-enable" : "");
+	printk(" capable%s\n", hwif->autodma ? ", auto-enable" : "");
 
 	return 1;
 
@@ -796,14 +742,16 @@
 	return 0;
 }
 
-int ide_release_dma(ide_hwif_t *hwif)
+static void icside_dma_exit(ide_hwif_t *hwif)
 {
 	if (hwif->sg_table) {
 		kfree(hwif->sg_table);
 		hwif->sg_table = NULL;
 	}
-	return 1;
 }
+#else
+#define icside_dma_init(hwif)	(0)
+#define icside_dma_exit(hwif)	do { } while (0)
 #endif
 
 static ide_hwif_t *icside_find_hwif(unsigned long dataport)
@@ -829,7 +777,7 @@
 }
 
 static ide_hwif_t *
-icside_setup(unsigned long base, struct cardinfo *info, int irq)
+icside_setup(unsigned long base, struct cardinfo *info, struct expansion_card *ec)
 {
 	unsigned long port = base + info->dataoffset;
 	ide_hwif_t *hwif;
@@ -847,42 +795,47 @@
 		}
 		hwif->hw.io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
 		hwif->io_ports[IDE_CONTROL_OFFSET] = base + info->ctrloffset;
-		hwif->hw.irq  = irq;
-		hwif->irq     = irq;
-		hwif->hw.dma  = NO_DMA;
+		hwif->hw.irq  = ec->irq;
+		hwif->irq     = ec->irq;
 		hwif->noprobe = 0;
 		hwif->chipset = ide_acorn;
+		hwif->gendev.parent = &ec->dev;
 	}
 
 	return hwif;
 }
 
-static int __init icside_register_v5(struct expansion_card *ec)
+static int __init
+icside_register_v5(struct icside_state *state, struct expansion_card *ec)
 {
 	unsigned long slot_port;
 	ide_hwif_t *hwif;
 
 	slot_port = ecard_address(ec, ECARD_MEMC, 0);
 
+	state->irq_port = slot_port;
+
 	ec->irqaddr  = (unsigned char *)ioaddr(slot_port + ICS_ARCIN_V5_INTRSTAT);
 	ec->irqmask  = 1;
-	ec->irq_data = (void *)slot_port;
-	ec->ops      = (expansioncard_ops_t *)&icside_ops_arcin_v5;
+	ec->irq_data = state;
+	ec->ops      = &icside_ops_arcin_v5;
 
 	/*
 	 * Be on the safe side - disable interrupts
 	 */
 	inb(slot_port + ICS_ARCIN_V5_INTROFFSET);
 
-	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec->irq);
+	hwif = icside_setup(slot_port, &icside_cardinfo_v5, ec);
+
+	state->hwif[0] = hwif;
 
 	return hwif ? 0 : -ENODEV;
 }
 
-static int __init icside_register_v6(struct expansion_card *ec)
+static int __init
+icside_register_v6(struct icside_state *state, struct expansion_card *ec)
 {
 	unsigned long slot_port, port;
-	struct icside_state *state;
 	ide_hwif_t *hwif, *mate;
 	unsigned int sel = 0;
 
@@ -905,89 +858,173 @@
 	/*
 	 * Find and register the interfaces.
 	 */
-	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec->irq);
-	mate = icside_setup(port, &icside_cardinfo_v6_2, ec->irq);
+	hwif = icside_setup(port, &icside_cardinfo_v6_1, ec);
+	mate = icside_setup(port, &icside_cardinfo_v6_2, ec);
 
 	if (!hwif || !mate)
 		return -ENODEV;
 
-	state = kmalloc(sizeof(struct icside_state), GFP_KERNEL);
-	if (!state)
-		return -ENOMEM;
-
-	state->channel    = 0;
-	state->enabled    = 0;
 	state->irq_port   = port;
+	state->slot_port  = slot_port;
+	state->hwif[0]    = hwif;
+	state->hwif[1]    = mate;
 
-	ec->irq_data      = state;
-	ec->ops           = (expansioncard_ops_t *)&icside_ops_arcin_v6;
+	ec->irq_data	  = state;
+	ec->ops           = &icside_ops_arcin_v6;
 
 	hwif->maskproc    = icside_maskproc;
 	hwif->channel     = 0;
-	hwif->hw.priv     = state;
+	hwif->hwif_data   = state;
 	hwif->mate        = mate;
 	hwif->serialized  = 1;
 	hwif->config_data = slot_port;
 	hwif->select_data = sel;
-	hwif->hw.dma      = ec->dma;
+	hwif->hw.dma	  = ec->dma;
 
 	mate->maskproc    = icside_maskproc;
 	mate->channel     = 1;
-	mate->hw.priv     = state;
+	mate->hwif_data   = state;
 	mate->mate        = hwif;
 	mate->serialized  = 1;
 	mate->config_data = slot_port;
 	mate->select_data = sel | 1;
-	mate->hw.dma      = ec->dma;
+	mate->hw.dma	  = ec->dma;
 
-#ifdef CONFIG_BLK_DEV_IDEDMA_ICS
 	if (ec->dma != NO_DMA && !request_dma(ec->dma, hwif->name)) {
-		icside_setup_dma(hwif);
-		icside_setup_dma(mate);
+		icside_dma_init(hwif);
+		icside_dma_init(mate);
 	}
-#endif
+
 	return 0;
 }
 
 static int __devinit
 icside_probe(struct expansion_card *ec, const struct ecard_id *id)
 {
-	int result;
+	struct icside_state *state;
+	void *idmem;
+	int ret;
 
-	ecard_claim(ec);
+	state = kmalloc(sizeof(struct icside_state), GFP_KERNEL);
+	if (!state) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(state, 0, sizeof(state));
+	state->type	= ICS_TYPE_NOTYPE;
+	state->dev	= &ec->dev;
+
+	idmem = ioremap(ecard_resource_start(ec, ECARD_RES_IOCFAST),
+			ecard_resource_len(ec, ECARD_RES_IOCFAST));
+	if (idmem) {
+		unsigned int type;
+
+		type = readb(idmem + ICS_IDENT_OFFSET) & 1;
+		type |= (readb(idmem + ICS_IDENT_OFFSET + 4) & 1) << 1;
+		type |= (readb(idmem + ICS_IDENT_OFFSET + 8) & 1) << 2;
+		type |= (readb(idmem + ICS_IDENT_OFFSET + 12) & 1) << 3;
+		iounmap(idmem);
 
-	switch (icside_identifyif(ec)) {
-	case ics_if_arcin_v5:
-		result = icside_register_v5(ec);
+		state->type = type;
+	}
+
+	switch (state->type) {
+	case ICS_TYPE_A3IN:
+		printk(KERN_WARNING "icside: A3IN unsupported\n");
+		ret = -ENODEV;
 		break;
 
-	case ics_if_arcin_v6:
-		result = icside_register_v6(ec);
+	case ICS_TYPE_A3USER:
+		printk(KERN_WARNING "icside: A3USER unsupported\n");
+		ret = -ENODEV;
+		break;
+
+	case ICS_TYPE_V5:
+		ret = icside_register_v5(state, ec);
+		break;
+
+	case ICS_TYPE_V6:
+		ret = icside_register_v6(state, ec);
 		break;
 
 	default:
-		result = -ENODEV;
+		printk(KERN_WARNING "icside: unknown interface type\n");
+		ret = -ENODEV;
 		break;
 	}
 
-	if (result)
-		ecard_release(ec);
-	/*
-	 * this locks the driver in-core - remove this
-	 * comment and the two lines below when we can
-	 * safely remove interfaces.
-	 */
-	else
+	if (ret == 0) {
+		ecard_set_drvdata(ec, state);
+
+		/*
+		 * this locks the driver in-core - remove this
+		 * comment and the line below when we can
+		 * safely remove interfaces.
+		 */
 		MOD_INC_USE_COUNT;
+	} else {
+		kfree(state);
+	}
+ out:
+	return ret;
+}
+
+static void __devexit icside_remove(struct expansion_card *ec)
+{
+	struct icside_state *state = ecard_get_drvdata(ec);
 
-	return result;
+	switch (state->type) {
+	case ICS_TYPE_V5:
+		/* FIXME: tell IDE to stop using the interface */
+
+		/* Disable interrupts */
+		inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET);
+		break;
+
+	case ICS_TYPE_V6:
+		/* FIXME: tell IDE to stop using the interface */
+		icside_dma_exit(state->hwif[1]);
+		icside_dma_exit(state->hwif[0]);
+
+		if (ec->dma != NO_DMA)
+			free_dma(ec->dma);
+
+		/* Disable interrupts */
+		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+
+		/* Reset the ROM pointer/EASI selection */
+		outb(0, state->slot_port);
+		break;
+	}
+
+	ecard_set_drvdata(ec, NULL);
+	ec->ops = NULL;
+	ec->irq_data = NULL;
+
+	kfree(state);
 }
 
-static void __devexit
-icside_remove(struct expansion_card *ec)
+static void icside_shutdown(struct expansion_card *ec)
 {
-	/* need to do more */
-	ecard_release(ec);
+	struct icside_state *state = ecard_get_drvdata(ec);
+
+	switch (state->type) {
+	case ICS_TYPE_V5:
+		/* Disable interrupts */
+		inb(state->slot_port + ICS_ARCIN_V5_INTROFFSET);
+		break;
+
+	case ICS_TYPE_V6:
+		/* Disable interrupts */
+		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_1);
+		inb(state->irq_port + ICS_ARCIN_V6_INTROFFSET_2);
+
+		/* Reset the ROM pointer/EASI selection */
+		outb(0, state->slot_port);
+		break;
+	}
 }
 
 static const struct ecard_id icside_ids[] = {
@@ -999,6 +1036,7 @@
 static struct ecard_driver icside_driver = {
 	.probe		= icside_probe,
 	.remove		= __devexit_p(icside_remove),
+	.shutdown	= icside_shutdown,
 	.id_table	= icside_ids,
 	.drv = {
 		.name	= "icside",
diff -Nru a/drivers/ide/arm/rapide.c b/drivers/ide/arm/rapide.c
--- a/drivers/ide/arm/rapide.c	Tue Feb 18 10:06:19 2003
+++ b/drivers/ide/arm/rapide.c	Sat May 17 07:40:49 2003
@@ -20,8 +20,6 @@
 	hw_regs_t hw;
 	int i, ret;
 
-	ecard_claim(ec);
-
 	memset(&hw, 0, sizeof(hw));
 
 	for (i = IDE_DATA_OFFSET; i <= IDE_STATUS_OFFSET; i++) {
@@ -49,7 +47,6 @@
 static void __devexit rapide_remove(struct expansion_card *ec)
 {
 	/* need to do more */
-	ecard_release(ec);
 }
 
 static struct ecard_id rapide_ids[] = {
diff -Nru a/drivers/ide/ide-cd.c b/drivers/ide/ide-cd.c
--- a/drivers/ide/ide-cd.c	Sat Apr 19 14:18:27 2003
+++ b/drivers/ide/ide-cd.c	Wed May 14 03:16:09 2003
@@ -2070,6 +2070,7 @@
 
 	req.sense = sense;
 	req.cmd[0] = GPCMD_TEST_UNIT_READY;
+	req.flags |= REQ_QUIET;
 
 #if ! STANDARD_ATAPI
         /* the Sanyo 3 CD changer uses byte 7 of TEST_UNIT_READY to 
@@ -2871,6 +2872,11 @@
 	struct atapi_capabilities_page cap;
 	int nslots = 1;
 
+	if (drive->media == ide_optical) {
+		printk("%s: ATAPI magneto-optical drive\n", drive->name);
+		return nslots;
+	}
+
 	if (CDROM_CONFIG_FLAGS(drive)->nec260) {
 		CDROM_CONFIG_FLAGS(drive)->no_eject = 0;                       
 		CDROM_CONFIG_FLAGS(drive)->audio_play = 1;       
@@ -3337,7 +3343,7 @@
 		goto failed;
 	if (!drive->present)
 		goto failed;
-	if (drive->media != ide_cdrom)
+	if (drive->media != ide_cdrom && drive->media != ide_optical)
 		goto failed;
 	/* skip drives that we were told to ignore */
 	if (ignore != NULL) {
diff -Nru a/drivers/ide/ide-disk.c b/drivers/ide/ide-disk.c
--- a/drivers/ide/ide-disk.c	Tue Apr 29 17:55:10 2003
+++ b/drivers/ide/ide-disk.c	Thu May  8 07:32:59 2003
@@ -1479,7 +1479,7 @@
 
 static int set_lba_addressing (ide_drive_t *drive, int arg)
 {
-	return (probe_lba_addressing(drive, arg));
+	return probe_lba_addressing(drive, arg);
 }
 
 static void idedisk_add_settings(ide_drive_t *drive)
@@ -1565,6 +1565,18 @@
 	}
 
 	(void) probe_lba_addressing(drive, 1);
+
+	if (drive->addressing == 1) {
+		ide_hwif_t *hwif = HWIF(drive);
+		int max_s = 2048;
+
+		if (max_s > hwif->rqsize)
+			max_s = hwif->rqsize;
+
+		blk_queue_max_sectors(&drive->queue, max_s);
+	}
+
+	printk("%s: max request size: %dKiB\n", drive->name, drive->queue.max_sectors / 2);
 
 	/* Extract geometry if we did not already have one for the drive */
 	if (!drive->cyl || !drive->head || !drive->sect) {
diff -Nru a/drivers/ide/ide-io.c b/drivers/ide/ide-io.c
--- a/drivers/ide/ide-io.c	Sun Apr 20 14:14:28 2003
+++ b/drivers/ide/ide-io.c	Sun May 11 17:09:46 2003
@@ -850,14 +850,14 @@
 		 * happens anyway when any interrupt comes in, IDE or otherwise
 		 *  -- the kernel masks the IRQ while it is being handled.
 		 */
-		if (hwif->irq != masked_irq)
+		if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
 			disable_irq_nosync(hwif->irq);
 		spin_unlock(&ide_lock);
 		local_irq_enable();
 			/* allow other IRQs while we start this request */
 		startstop = start_request(drive, rq);
 		spin_lock_irq(&ide_lock);
-		if (hwif->irq != masked_irq)
+		if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
 			enable_irq(hwif->irq);
 		if (startstop == ide_released)
 			goto queue_next;
diff -Nru a/drivers/ide/ide-probe.c b/drivers/ide/ide-probe.c
--- a/drivers/ide/ide-probe.c	Wed Apr 23 23:25:24 2003
+++ b/drivers/ide/ide-probe.c	Thu May  8 07:32:59 2003
@@ -803,7 +803,7 @@
 		return;
 
 	if ((hwif->chipset != ide_4drives || !hwif->mate || !hwif->mate->present) &&
-#if CONFIG_BLK_DEV_PDC4030
+#ifdef CONFIG_BLK_DEV_PDC4030
 	    (hwif->chipset != ide_pdc4030 || hwif->channel == 0) &&
 #endif /* CONFIG_BLK_DEV_PDC4030 */
 	    (hwif_check_regions(hwif))) {
@@ -998,6 +998,7 @@
 static void ide_init_queue(ide_drive_t *drive)
 {
 	request_queue_t *q = &drive->queue;
+	ide_hwif_t *hwif = HWIF(drive);
 	int max_sectors = 256;
 
 	/*
@@ -1013,8 +1014,10 @@
 	drive->queue_setup = 1;
 	blk_queue_segment_boundary(q, 0xffff);
 
-	if (HWIF(drive)->rqsize)
-		max_sectors = HWIF(drive)->rqsize;
+	if (!hwif->rqsize)
+		hwif->rqsize = hwif->addressing ? 256 : 65536;
+	if (hwif->rqsize < max_sectors)
+		max_sectors = hwif->rqsize;
 	blk_queue_max_sectors(q, max_sectors);
 
 	/* IDE DMA can do PRD_ENTRIES number of segments. */
@@ -1235,7 +1238,7 @@
 			(void) request_module("ide-disk");
 		if (drive->scsi)
 			(void) request_module("ide-scsi");
-		if (drive->media == ide_cdrom)
+		if (drive->media == ide_cdrom || drive->media == ide_optical)
 			(void) request_module("ide-cd");
 		if (drive->media == ide_tape)
 			(void) request_module("ide-tape");
diff -Nru a/drivers/ide/ide-tape.c b/drivers/ide/ide-tape.c
--- a/drivers/ide/ide-tape.c	Mon Apr 21 11:29:32 2003
+++ b/drivers/ide/ide-tape.c	Wed May  7 08:47:30 2003
@@ -6292,11 +6292,9 @@
 
 	devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor)
 			S_IFCHR | S_IRUGO | S_IWUGO,
-			&idetape_fops, NULL,
 			"%s/mt", drive->devfs_name);
 	devfs_mk_cdev(MKDEV(HWIF(drive)->major, minor + 128),
 			S_IFCHR | S_IRUGO | S_IWUGO,
-			&idetape_fops, NULL,
 			"%s/mtn", drive->devfs_name);
 
 	drive->disk->number = devfs_register_tape(drive->devfs_name);
diff -Nru a/drivers/ide/ide-tcq.c b/drivers/ide/ide-tcq.c
--- a/drivers/ide/ide-tcq.c	Mon Nov 11 16:04:36 2002
+++ b/drivers/ide/ide-tcq.c	Wed May 14 10:09:24 2003
@@ -51,9 +51,58 @@
  */
 #undef IDE_TCQ_FIDDLE_SI
 
+/*
+ * bad drive blacklist, for drives that raport tcq capability but don't
+ * work reliably with the default config. initially from freebsd table.
+ */
+struct ide_tcq_blacklist {
+	char *model;
+	char works;
+	unsigned int max_sectors;
+};
+
+static struct ide_tcq_blacklist ide_tcq_blacklist[] = {
+	{
+		.model =	"IBM-DTTA",
+		.works =	1,
+		.max_sectors =	128,
+	},
+	{
+		.model =	"IBM-DJNA",
+		.works =	0,
+	},
+	{
+		.model =	"WDC AC",
+		.works = 	0,
+	},
+	{
+		.model =	NULL,
+	},
+};
+
 ide_startstop_t ide_dmaq_intr(ide_drive_t *drive);
 ide_startstop_t ide_service(ide_drive_t *drive);
 
+static struct ide_tcq_blacklist *ide_find_drive_blacklist(ide_drive_t *drive)
+{
+	struct ide_tcq_blacklist *itb;
+	int i = 0;
+
+	do {
+		itb = &ide_tcq_blacklist[i];
+
+		if (!itb->model)
+			break;
+
+		if (!strncmp(drive->id->model, itb->model, strlen(itb->model)))
+			return itb;
+
+		i++;
+	} while (1);
+
+	return NULL;
+}
+
 static inline void drive_ctl_nien(ide_drive_t *drive, int set)
 {
 #ifdef IDE_TCQ_NIEN
@@ -502,7 +551,7 @@
 	return 0;
 err:
 	kfree(args);
-	return 1;
+	return -EIO;
 }
 
 /*
@@ -511,6 +560,7 @@
  */
 static int ide_enable_queued(ide_drive_t *drive, int on)
 {
+	struct ide_tcq_blacklist *itb;
 	int depth = drive->using_tcq ? drive->queue_depth : 0;
 
 	/*
@@ -530,6 +580,17 @@
 	}
 
 	/*
+	 * some drives need limited transfer size in tcq
+	 */
+	itb = ide_find_drive_blacklist(drive);
+	if (itb && itb->max_sectors) {
+		if (itb->max_sectors > HWIF(drive)->rqsize)
+			itb->max_sectors = HWIF(drive)->rqsize;
+
+		blk_queue_max_sectors(&drive->queue, itb->max_sectors);
+	}
+
+	/*
 	 * enable block tagging
 	 */
 	if (!blk_queue_tagged(&drive->queue))
@@ -582,13 +643,36 @@
 	return 0;
 }
 
+static int ide_tcq_check_blacklist(ide_drive_t *drive)
+{
+	struct ide_tcq_blacklist *itb = ide_find_drive_blacklist(drive);
+
+	if (!itb)
+		return 0;
+
+	return !itb->works;
+}
+
 int __ide_dma_queued_on(ide_drive_t *drive)
 {
 	if (!drive->using_dma)
 		return 1;
+	if (HWIF(drive)->chipset == ide_pdc4030)
+		return 1;
+	if (ide_tcq_check_blacklist(drive)) {
+		printk(KERN_WARNING "%s: tcq forbidden by blacklist\n",
+					drive->name);
+		return 1;
+	}
+	if (drive->next != drive) {
+		printk(KERN_WARNING "%s: only one drive on a channel supported"
+					" for tcq\n", drive->name);
+		return 1;
+	}
 
 	if (ata_pending_commands(drive)) {
-		printk(KERN_WARNING "ide-tcq; can't toggle tcq feature on busy drive\n");
+		printk(KERN_WARNING "ide-tcq; can't toggle tcq feature on "
+					"busy drive\n");
 		return 1;
 	}
 
diff -Nru a/drivers/ieee1394/amdtp.c b/drivers/ieee1394/amdtp.c
--- a/drivers/ieee1394/amdtp.c	Fri May  2 05:50:34 2003
+++ b/drivers/ieee1394/amdtp.c	Wed May  7 08:47:30 2003
@@ -1205,7 +1205,6 @@
 {
 	struct amdtp_host *ah;
 	int minor;
-	char name[16];
 
 	if (strcmp(host->driver->name, OHCI1394_DRIVER_NAME) != 0)
 		return;
@@ -1223,13 +1222,11 @@
 
 	minor = IEEE1394_MINOR_BLOCK_AMDTP * 16 + ah->ohci->id;
 
-	sprintf(name, "amdtp/%d", ah->ohci->id);
-
 	INIT_LIST_HEAD(&ah->stream_list);
 	spin_lock_init(&ah->stream_list_lock);
 
-	devfs_register(NULL, name, 0, IEEE1394_MAJOR, minor,
-		       S_IFCHR | S_IRUSR | S_IWUSR, &amdtp_fops, NULL);
+	devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor),
+			S_IFCHR|S_IRUSR|S_IWUSR, "amdtp/%d", ah->ohci->id);
 }
 
 static void amdtp_remove_host(struct hpsb_host *host)
diff -Nru a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c
--- a/drivers/ieee1394/dv1394.c	Fri May  2 05:58:46 2003
+++ b/drivers/ieee1394/dv1394.c	Wed May  7 08:47:30 2003
@@ -2420,24 +2420,6 @@
 };
 
 
-#ifdef CONFIG_DEVFS_FS
-static int dv1394_devfs_add_entry(struct video_card *video)
-{
-	char buf[64];
-
-	snprintf(buf, sizeof(buf), "ieee1394/dv/host%d/%s/%s",
-		(video->id>>2),
-		(video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
-		(video->mode == MODE_RECEIVE ? "in" : "out"));
-
-	devfs_register(NULL, buf, 0, IEEE1394_MAJOR,
-			IEEE1394_MINOR_BLOCK_DV1394*16 + video->id,
-			S_IFCHR | S_IRUGO | S_IWUGO, &dv1394_fops, video);
-	return 0;
-}
-#endif /* CONFIG_DEVFS_FS */
-
-
 /*** HOTPLUG STUFF **********************************************************/
 /*
  * Export information about protocols/devices supported by this driver.
@@ -2536,10 +2518,14 @@
 	list_add_tail(&video->list, &dv1394_cards);
 	spin_unlock_irqrestore(&dv1394_cards_lock, flags);
 	
-#ifdef CONFIG_DEVFS_FS
-	if (dv1394_devfs_add_entry(video) < 0)
+	if (devfs_mk_cdev(MKDEV(IEEE1394_MAJOR,
+				IEEE1394_MINOR_BLOCK_DV1394*16 + video->id),
+			S_IFCHR|S_IRUGO|S_IWUGO,
+			 "ieee1394/dv/host%d/%s/%s",
+			 (video->id>>2),
+			 (video->pal_or_ntsc == DV1394_NTSC ? "NTSC" : "PAL"),
+			 (video->mode == MODE_RECEIVE ? "in" : "out")) < 0)
 			goto err_free;
-#endif
 
 	debug_printk("dv1394: dv1394_init() OK on ID %d\n", video->id);
 	
@@ -2562,9 +2548,7 @@
 		(video->mode == MODE_RECEIVE ? "in" : "out")
 		);
 
-#ifdef CONFIG_DEVFS_FS
 	devfs_remove("ieee1394/%s", buf);
-#endif
 #ifdef CONFIG_PROC_FS
 	dv1394_procfs_del(buf);
 #endif
@@ -2602,11 +2586,9 @@
 
 	n = (video->id >> 2);
 
-#ifdef CONFIG_DEVFS_FS
 	devfs_remove("ieee1394/dv/host%d/NTSC", n);
 	devfs_remove("ieee1394/dv/host%d/PAL", n);
 	devfs_remove("ieee1394/dv/host%d", n);
-#endif
 
 #ifdef CONFIG_PROC_FS
 	snprintf(buf, sizeof(buf), "dv/host%d/NTSC", n);
@@ -2642,11 +2624,9 @@
 }
 #endif
 
-#ifdef CONFIG_DEVFS_FS
 	devfs_mk_dir("ieee1394/dv/host%d", ohci->id);
 	devfs_mk_dir("ieee1394/dv/host%d/NTSC", ohci->id);
 	devfs_mk_dir("ieee1394/dv/host%d/PAL", ohci->id);
-#endif
 	
 	dv1394_init(ohci, DV1394_NTSC, MODE_RECEIVE);
 	dv1394_init(ohci, DV1394_NTSC, MODE_TRANSMIT);
@@ -2901,9 +2881,7 @@
 
 	hpsb_unregister_highlevel(&dv1394_highlevel);
 	ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
-#ifdef CONFIG_DEVFS_FS
 	devfs_remove("ieee1394/dv");
-#endif
 #ifdef CONFIG_PROC_FS
 	dv1394_procfs_del("dv");
 #endif
@@ -2920,18 +2898,14 @@
 		return -EIO;
 	}
 
-#ifdef CONFIG_DEVFS_FS
 	devfs_mk_dir("ieee1394/dv");
-#endif
 
 #ifdef CONFIG_PROC_FS
 	ret = dv1394_procfs_add_dir("dv",NULL,NULL);
 	if (ret < 0) {
 		printk(KERN_ERR "dv1394: unable to create /proc/bus/ieee1394/dv\n");
 		ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
-#ifdef CONFIG_DEVFS_FS
 		devfs_remove("ieee1394/dv");
-#endif
 		return -ENOMEM;
 	}
 #endif
diff -Nru a/drivers/ieee1394/eth1394.c b/drivers/ieee1394/eth1394.c
--- a/drivers/ieee1394/eth1394.c	Fri May  2 05:50:35 2003
+++ b/drivers/ieee1394/eth1394.c	Mon May 19 07:50:28 2003
@@ -79,7 +79,7 @@
 	printk(KERN_ERR fmt, ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 918 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 931 $ Ben Collins <bcollins@debian.org>";
 
 /* Our ieee1394 highlevel driver */
 #define ETHER1394_DRIVER_NAME "ether1394"
diff -Nru a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c
--- a/drivers/ieee1394/iso.c	Mon Apr 21 08:37:12 2003
+++ b/drivers/ieee1394/iso.c	Mon May 19 07:50:30 2003
@@ -32,7 +32,6 @@
 	}
 
 	dma_region_free(&iso->data_buf);
-	kfree(iso->infos);
 	kfree(iso);
 }
 
@@ -70,14 +69,11 @@
 
 	/* allocate and write the struct hpsb_iso */
 
-	iso = kmalloc(sizeof(*iso), SLAB_KERNEL);
+	iso = kmalloc(sizeof(*iso) + buf_packets * sizeof(struct hpsb_iso_packet_info), GFP_KERNEL);
 	if(!iso)
 		return NULL;
 
-	/* allocate ringbuffer of packet descriptors */
-	iso->infos = kmalloc(buf_packets * sizeof(struct hpsb_iso_packet_info), SLAB_KERNEL);
-	if(!iso->infos)
-		return NULL;
+	iso->infos = (struct hpsb_iso_packet_info *)(iso + 1);
 
 	iso->type = type;
 	iso->host = host;
diff -Nru a/drivers/ieee1394/iso.h b/drivers/ieee1394/iso.h
--- a/drivers/ieee1394/iso.h	Thu Jan 30 16:48:21 2003
+++ b/drivers/ieee1394/iso.h	Mon May 19 07:50:24 2003
@@ -79,9 +79,6 @@
 	/* size of data_buf, in bytes (always a multiple of PAGE_SIZE) */
 	unsigned int buf_size;
 
-	/* ringbuffer of packet descriptors in regular kernel memory */
-	struct hpsb_iso_packet_info *infos;
-
 	/* # of packets in the ringbuffer */
 	unsigned int buf_packets;
 
@@ -118,6 +115,11 @@
 	/* cycle at which next packet will be transmitted,
 	   -1 if not known */
 	int xmit_cycle;
+
+	/* ringbuffer of packet descriptors in regular kernel memory
+	 * XXX Keep this last, since we use over-allocated memory from
+	 * this entry to fill this field. */
+	struct hpsb_iso_packet_info *infos;
 };
 
 /* functions available to high-level drivers (e.g. raw1394) */
diff -Nru a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c
--- a/drivers/ieee1394/ohci1394.c	Fri May  2 10:50:55 2003
+++ b/drivers/ieee1394/ohci1394.c	Mon May 19 07:50:25 2003
@@ -164,7 +164,7 @@
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-	"$Rev: 921 $ Ben Collins <bcollins@debian.org>";
+	"$Rev: 931 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
 static int phys_dma = 1;
@@ -2446,7 +2446,7 @@
 				reg_write(ohci,OHCI1394_PhyReqFilterLoSet, 0x00000000);
 			}
 
-			DBGMSG(ohci->id, "PhyReqFilter=%08x%08x\n",
+			DBGMSG(ohci->id, "PhyReqFilter=%08x%08x",
 			       reg_read(ohci,OHCI1394_PhyReqFilterHiSet),
 			       reg_read(ohci,OHCI1394_PhyReqFilterLoSet));
 
@@ -3165,7 +3165,7 @@
 	struct config_rom_ptr cr;
 
 	memset(&cr, 0, sizeof(cr));
-	memset(ohci->csr_config_rom_cpu, 0, sizeof (ohci->csr_config_rom_cpu));
+	memset(ohci->csr_config_rom_cpu, 0, sizeof(*ohci->csr_config_rom_cpu));
 
 	cr.data = ohci->csr_config_rom_cpu;
 
diff -Nru a/drivers/ieee1394/raw1394.c b/drivers/ieee1394/raw1394.c
--- a/drivers/ieee1394/raw1394.c	Fri May  2 05:58:11 2003
+++ b/drivers/ieee1394/raw1394.c	Wed May  7 08:47:30 2003
@@ -2531,9 +2531,8 @@
 {
 	hpsb_register_highlevel(&raw1394_highlevel);
 
-        devfs_register(NULL, RAW1394_DEVICE_NAME, 0,
-			IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16,
-			S_IFCHR | S_IRUSR | S_IWUSR, &file_ops, NULL);
+        devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, IEEE1394_MINOR_BLOCK_RAW1394 * 16),
+			S_IFCHR | S_IRUSR | S_IWUSR, RAW1394_DEVICE_NAME);
 
         if (ieee1394_register_chardev(IEEE1394_MINOR_BLOCK_RAW1394,
                                       THIS_MODULE, &file_ops)) {
diff -Nru a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c
--- a/drivers/ieee1394/sbp2.c	Fri May  2 06:13:14 2003
+++ b/drivers/ieee1394/sbp2.c	Mon May 19 07:50:28 2003
@@ -4,6 +4,8 @@
  * Copyright (C) 2000 James Goodwin, Filanet Corporation (www.filanet.com)
  * jamesg@filanet.com (JSG)
  *
+ * Copyright (C) 2003 Ben Collins <bcollins@debian.org>
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -30,228 +32,10 @@
  * You may access any attached SBP-2 storage devices as if they were SCSI
  * devices (e.g. mount /dev/sda1,  fdisk, mkfs, etc.).
  *
- *
- * Module Load Options:
- *
- * max_speed 		- Force max speed allowed 
- *			  (2 = 400mb, 1 = 200mb, 0 = 100mb. default = 2)
- * serialize_io		- Serialize all I/O coming down from the scsi drivers
- *			  (0 = deserialized, 1 = serialized, default = 0)
- * max_sectors, 	- Change max sectors per I/O supported (default = 255)
- * exclusive_login	- Set to zero if you'd like to allow multiple hosts the ability
- *			  to log in at the same time. Sbp2 device must support this,
- *			  and you must know what you're doing (default = 1)
- *
- * (e.g. insmod sbp2 sbp2.serialize_io = 1)
- *
- *
- * Current Support:
- *
- * The SBP-2 driver is still in an early state, but supports a variety of devices.
- * I have read/written many gigabytes of data from/to SBP-2 drives, and have seen 
- * performance of more than 25 MBytes/s on individual drives (limit of the media 
- * transfer rate).
- *
- *
- * Following are a sampling of devices that have been tested successfully:
- *
- *	- Western Digital IEEE-1394 hard drives
- *	- Maxtor IEEE-1394 hard drives
- *	- VST (SmartDisk) IEEE-1394 hard drives and Zip drives (several flavors)
- *	- LaCie IEEE-1394 hard drives (several flavors)
- *	- QPS IEEE-1394 CD-RW/DVD drives and hard drives
- *	- BusLink IEEE-1394 hard drives
- *	- Iomega IEEE-1394 Zip/Jazz/Peerless drives
- *	- ClubMac IEEE-1394 hard drives
- *	- FirePower IEEE-1394 hard drives
- *	- EzQuest IEEE-1394 hard drives and CD-RW drives
- *	- Castlewood/ADS IEEE-1394 ORB drives
- *	- Evergreen IEEE-1394 hard drives and CD-RW drives
- *	- Addonics IEEE-1394 CD-RW drives
- *	- Bellstor IEEE-1394 hard drives and CD-RW drives
- *	- APDrives IEEE-1394 hard drives
- *	- Fujitsu IEEE-1394 MO drives
- *	- Sony IEEE-1394 CD-RW drives
- *	- Epson IEEE-1394 scanners
- *	- ADS IEEE-1394 memory stick and compact flash readers 
- *	- SBP-2 bridge-based devices (LSI, Oxford Semiconductor, Indigita bridges)
- *	- Various other standard IEEE-1394 hard drives and enclosures
- *
- *
- * Performance Issues:
- *
- *	- Make sure you are "not" running fat/fat32 on your attached SBP-2 drives. You'll
- *	  get much better performance formatting the drive ext2 (but you will lose the
- *	  ability to easily move the drive between Windows/Linux).
- *
- *
  * Current Issues:
  *
  *	- Error Handling: SCSI aborts and bus reset requests are handled somewhat
  *	  but the code needs additional debugging.
- *
- *
- * History:
- *
- *	07/25/00 - Initial revision (JSG)
- *	08/11/00 - Following changes/bug fixes were made (JSG):
- *		   * Bug fix to SCSI procfs code (still needs to be synched with 2.4 kernel).
- *		   * Bug fix where request sense commands were actually sent on the bus.
- *		   * Changed bus reset/abort code to deal with devices that spin up quite
- *		     slowly (which result in SCSI time-outs).
- *		   * "More" properly pull information from device's config rom, for enumeration
- *		     of SBP-2 devices, and determining SBP-2 register offsets.
- *		   * Change Simplified Direct Access Device type to Direct Access Device type in
- *		     returned inquiry data, in order to make the SCSI stack happy.
- *		   * Modified driver to register with the SCSI stack "before" enumerating any attached
- *		     SBP-2 devices. This means that you'll have to use procfs scsi-add-device or 
- *		     some sort of script to discover new SBP-2 devices.
- *		   * Minor re-write of some code and other minor changes.
- *	08/28/00 - Following changes/bug fixes were made (JSG):
- *		   * Bug fixes to scatter/gather support (case of one s/g element)
- *		   * Updated direction table for scsi commands (mostly DVD commands)
- *		   * Retries when trying to detect SBP-2 devices (for slow devices)
- *		   * Slightly better error handling (previously none) when commands time-out.
- *		   * Misc. other bug fixes and code reorganization.
- *	09/13/00 - Following changes/bug fixes were made (JSG)
- *		   * Moved detection/enumeration code to a kernel thread which is woken up when IEEE-1394
- *		     bus resets occur.
- *		   * Added code to handle bus resets and hot-plugging while devices are mounted, but full
- *		     hot-plug support is not quite there yet.
- *		   * Now use speed map to determine speed and max payload sizes for ORBs
- *		   * Clean-up of code and reorganization 
- *	09/19/00 - Added better hot-plug support and other minor changes (JSG)
- *	10/15/00 - Fixes for latest 2.4.0 test kernel, minor fix for hot-plug race. (JSG)
- *	12/03/00 - Created pool of request packet structures for use in sending out sbp2 command
- *		   and agent reset requests. This removes the kmallocs/kfrees in the critical I/O paths,
- *		   and also deals with some subtle race conditions related to allocating and freeing
- *		   packets. (JSG)
- *      12/09/00 - Improved the sbp2 device detection by actually reading the root and unit 
- *		   directory (khk@khk.net)
- *	12/23/00 - Following changes/enhancements were made (JSG)
- *		   * Only do SCSI to RBC command conversion for Direct Access and Simplified
- *		     Direct Access Devices (this is pulled from the config rom root directory).
- *		     This is needed because doing the conversion for all device types broke the
- *		     Epson scanner. Still looking for a better way of determining when to convert
- *		     commands (for RBC devices). Thanks to khk for helping on this!
- *		   * Added ability to "emulate" physical dma support, for host adapters such as TILynx.
- *		   * Determine max payload and speed by also looking at the host adapter's max_rec field.
- *	01/19/01 - Added checks to sbp2 login and made the login time-out longer. Also fixed a compile 
- *		   problem for 2.4.0. (JSG)
- *	01/24/01 - Fixed problem when individual s/g elements are 64KB or larger. Needed to break
- *		   up these larger elements, since the sbp2 page table element size is only 16 bits. (JSG)
- *	01/29/01 - Minor byteswap fix for login response (used for reconnect and log out).
- *	03/07/01 - Following changes/enhancements were made (JSG)
- *		   * Changes to allow us to catch the initial scsi bus scan (for detecting sbp2
- *		     devices when first loading sbp2.o). To disable this, un-define 
- *		     SBP2_SUPPORT_INITIAL_BUS_SCAN.
- *		   * Temporary fix to deal with many sbp2 devices that do not support individual
- *		     transfers of greater than 128KB in size. 
- *		   * Mode sense conversion from 6 byte to 10 byte versions for CDRW/DVD devices. (Mark Burton)
- *		   * Define allowing support for goofy sbp2 devices that do not support mode
- *		     sense command at all, allowing them to be mounted rw (such as 1394 memory
- *		     stick and compact flash readers). Define SBP2_MODE_SENSE_WRITE_PROTECT_HACK
- *		     if you need this fix.
- *	03/29/01 - Major performance enhancements and misc. other changes. Thanks to Daniel Berlin for many of
- *		   changes and suggestions for change:
- *		   * Now use sbp2 doorbell and link commands on the fly (instead of serializing requests)
- *		   * Removed all bit fields in an attempt to run on PPC machines (still needs a little more work)
- *		   * Added large request break-up/linking support for sbp2 chipsets that do not support transfers 
- *		     greater than 128KB in size.
- *		   * Bumped up max commands per lun to two, and max total outstanding commands to eight.
- *	04/03/01 - Minor clean-up. Write orb pointer directly if no outstanding commands (saves one 1394 bus
- *		   transaction). Added module load options (bus scan, mode sense hack, max speed, serialize_io,
- *		   no_large_transfers). Better bus reset handling while I/O pending. Set serialize_io to 1 by 
- *		   default (debugging of deserialized I/O in progress).
- *	04/04/01 - Added workaround for PPC Pismo firewire chipset. See #define below. (Daniel Berlin)
- *	04/20/01 - Minor clean-up. Allocate more orb structures when running with sbp2 target chipsets with
- *		   128KB max transfer limit.
- *	06/16/01 - Converted DMA interfaces to pci_dma - Ben Collins
- *							 <bcollins@debian.org
- *	07/22/01 - Use NodeMngr to get info about the local host and
- *		   attached devices. Ben Collins
- *
- *      09/15/01 - Remove detection code, instead subscribe to the nodemgr
- *                 driver management interface.  This also removes the
- *                 initial bus scan stuff since the nodemgr calls
- *                 sbp2_probe for each sbp2 device already on the bus,
- *                 when we register our driver.  This change 
- *                 automtically adds hotplug support to the driver.
- *                                 Kristian Hogsberg <hogsberg@users.sf.net>
- *
- *      11/17/01 - Various bugfixes/cleanups:
- *                 * Remember to logout of device in sbp2_disconnect.
- *                 * If we fail to reconnect to a device after bus reset
- *                   remember to release unit directory, so the ieee1394
- *                   knows we no longer manage it.
- *                 * Unregister scsi hosts in sbp2_remove_host when a
- *                   hpsb_host goes away.
- *                 * Remove stupid hack in sbp2_remove_host.
- *                 * Switched to "manual" module initialization
- *                   (i.e. not scsi_module.c) and moved sbp2_cleanup
- *                   moved sbp2scsi_release to sbp2_module_ext.  The
- *                   release function is called once pr. registered
- *                   scsi host, but sbp2_cleanup should only be called
- *                   upon module unload.  Moved much initialization
- *                   from sbp2scsi_detect to sbp2_module_init.
- *                                 Kristian Hogsberg <hogsberg@users.sf.net>
- *	01/06/02 - Misc bug fixes/enhancements:	(JSG)
- *		   * Enable use_new_eh_code for scsi stuff.
- *		   * Do not write all ones for NULL ORB high/low fields, but
- *		     rather leave reserved areas zeroed (per SBP2 spec).
- *		   * Use newer scsi transfer direction passed down instead of our
- *		     direction table.
- *		   * Bumped login time-out to 20 seconds, as some devices are slow.
- *		   * Fixed a couple scsi unregister bugs on module unload
- *	01/13/02 - Fixed compatibility with certain SBP2 devices, such as Iomega
- *		   1394 devices (Peerless, Jazz). Also a bit of clean-up of the 
- *		   driver, thanks to H.J.Lu (hjl@lucon.org). Removed mode_sense_hack
- *		   module load option, as it's been fixed in the 2.4 scsi stack.
- *	02/10/02 - Added support for max_sectors, minor fix for inquiry command, make
- *		   up sbp2 device type from inquiry response data if not part of 
- *		   device's 1394 unit directory. (JSG)
- *	02/18/02 - Code clean-up and enhancements: (JSG)
- *		   * Finish cleaning out hacked code for dealing with broken sbp2 devices
- *		     which do not support requests of 128KB or greater. Now use 
- *		     max_sectors scsi host entry to limit transfer sizes.
- *		   * Change status fifo address from a single address to a set of addresses,
- *		     with each sbp2 device having its own status fifo address. This makes
- *		     it easier to match the status write to the sbp2 device instance.
- *		   * Minor change to use lun when logging into sbp2 devices. First step in
- *		     supporting multi-lun devices such as CD/DVD changer devices.
- *		   * Added a new module load option for setting max sectors. For use by folk
- *		     who'd like to bump up the max scsi transfer size supported.
- *		   * Enabled deserialized operation by default, allowing for better performance,
- *		     particularily when running with multiple sbp2 devices. For debugging,
- *		     you may enable serialization through use of the sbp2_serialize_io module
- *		     load option (e.g. insmod sbp2 sbp2_serialize_io=1).
- *	02/20/02 - Added a couple additional module load options. 
- *		   Needed to bump down max commands per lun because of the !%@&*^# QPS CDRW 
- *		   drive I have, which doesn't seem to get along with other sbp2 devices 
- *		   (or handle linked commands well).
- *	04/21/02 - Added some additional debug capabilities:
- *		   * Able to handle phys dma requests directly, if host controller has phys
- *		     dma disabled (e.g. insmod ohci1394 phys_dma=0). Undefine CONFIG_IEEE1394_SBP2_PHYS_DMA
- *		     if you'd like to disable sbp2 driver from registering for phys address range. 
- *		   * New packet dump debug define (CONFIG_IEEE1394_SBP2_PACKET_DUMP) which allows
- *		     dumping of all sbp2 related packets sent and received. Especially effective
- *		     when phys dma is disabled on ohci controller (e.g. insmod ohci1394 phys_dma=0).
- *		   * Added new sbp2 module load option (exclusive_login) for allowing
- *		     non-exclusive login to sbp2 device, for special multi-host applications.
- *	04/23/02 - Fix for Sony CD-ROM drives. Only send fetch agent reset to sbp2 device if it
- *		   returns the dead bit in status. Thanks to Chandan (chandan@toad.net) for this one.
- *	04/27/02 - Fix sbp2 login problem on SMP systems, enable real spinlocks by default. (JSG)
- *	06/09/02 - Don't force 36-byte SCSI inquiry, but leave in a define for badly behaved devices. (JSG)   
- *	02/04/03 - Fixed a SMP deadlock (don't hold sbp2_command_lock while calling sbp2scsi_complete_command).
- *		   Also save/restore irq flags in sbp2scsi_complete_command  - Sancho Dauskardt <sda@bdit.de>
- *	02/06/03 - Removed spinlock debugging; use kernel stuff instead (sda)
- *	02/10/03 - Adopt to new hot-plug aware SCSI inferface (hch@lst.de)
- *
- */
-
-
-/*
- * Includes
  */
 
 #include <linux/config.h>
@@ -295,7 +79,7 @@
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-	"$Rev: 919 $ James Goodwin <jamesg@filanet.com>";
+	"$Rev: 931 $ Ben Collins <bcollins@debian.org>";
 
 /*
  * Module load parameter definitions
@@ -829,65 +613,81 @@
 	if (!hi)
 		return -ENODEV;
 
-	return sbp2_start_device(hi, ud);
+	return sbp2_start_ud(hi, ud);
 }
 
 static int sbp2_remove(struct device *dev)
 {
+	struct scsi_id_group *scsi_group;
+	struct list_head *lh, *next;
 	struct unit_directory *ud;
 	struct scsi_id_instance_data *scsi_id;
 
 	SBP2_DEBUG(__FUNCTION__);
 
 	ud = container_of(dev, struct unit_directory, device);
-	scsi_id = ud->device.driver_data;
+	scsi_group = ud->device.driver_data;
 	ud->device.driver_data = NULL;
 
-	if (scsi_id != NULL) {
-		sbp2_logout_device(scsi_id);
- 		sbp2_remove_device(scsi_id);
+	list_for_each_safe (lh, next, &scsi_group->scsi_id_list) {
+		scsi_id = list_entry(lh, struct scsi_id_instance_data, list);
+
+		if (scsi_id != NULL) {
+			sbp2_logout_device(scsi_id);
+ 			sbp2_remove_device(scsi_id);
+		}
 	}
 
+	kfree(scsi_group);
+
 	return 0;
 }
 
 static void sbp2_update(struct unit_directory *ud)
 {
-	struct scsi_id_instance_data *scsi_id = ud->device.driver_data;
-	struct sbp2scsi_host_info *hi = scsi_id->hi;
+	struct sbp2scsi_host_info *hi;
+	struct scsi_id_group *scsi_group = ud->device.driver_data;
+	struct list_head *lh, *next;
+	struct scsi_id_instance_data *scsi_id;
 	unsigned long flags;
 
 	SBP2_DEBUG("sbp2_update");
 
-	if (sbp2_reconnect_device(scsi_id)) {
+	list_for_each_safe (lh, next, &scsi_group->scsi_id_list) {
+		scsi_id = list_entry(lh, struct scsi_id_instance_data, list);
+
+		hi = scsi_id->hi;
+
+		if (sbp2_reconnect_device(scsi_id)) {
 		
-		/* 
-		 * Ok, reconnect has failed. Perhaps we didn't
-		 * reconnect fast enough. Try doing a regular login.
-		 */
-		if (sbp2_login_device(scsi_id)) {
-			/* Login failed too, just remove the device. */
-			SBP2_ERR("sbp2_reconnect_device failed!");
-			sbp2_remove_device(scsi_id);
-			return;
+			/* 
+			 * Ok, reconnect has failed. Perhaps we didn't
+			 * reconnect fast enough. Try doing a regular login.
+			 */
+			if (sbp2_login_device(scsi_id)) {
+				/* Login failed too, just remove the device. */
+				SBP2_ERR("sbp2_reconnect_device failed!");
+				sbp2_remove_device(scsi_id);
+				return;
+			}
 		}
-	}
 
-	/* Set max retries to something large on the device. */
-	sbp2_set_busy_timeout(scsi_id);
+		/* Set max retries to something large on the device. */
+		sbp2_set_busy_timeout(scsi_id);
 
-	/* Do a SBP-2 fetch agent reset. */
-	sbp2_agent_reset(scsi_id, 1);
+		/* Do a SBP-2 fetch agent reset. */
+		sbp2_agent_reset(scsi_id, 1);
 	
-	/* Get the max speed and packet size that we can use. */
-	sbp2_max_speed_and_size(scsi_id);
+		/* Get the max speed and packet size that we can use. */
+		sbp2_max_speed_and_size(scsi_id);
 
-	/* Complete any pending commands with busy (so they get
-	 * retried) and remove them from our queue
-	 */
-	spin_lock_irqsave(&hi->sbp2_command_lock, flags);
-	sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
-	spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
+		/* Complete any pending commands with busy (so they get
+		 * retried) and remove them from our queue
+		 */
+		spin_lock_irqsave(&hi->sbp2_command_lock, flags);
+		sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
+		spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
+	}
 }
 
 /* This functions is called by the sbp2_probe, for each new device. If the
@@ -955,31 +755,60 @@
 	}
 }
 
+static int sbp2_start_ud(struct sbp2scsi_host_info *hi, struct unit_directory *ud)
+{
+	struct scsi_id_instance_data *scsi_id;
+	struct scsi_id_group *scsi_group;
+	struct list_head *lh, *next;
+
+	SBP2_DEBUG("sbp2_start_ud");
+
+	scsi_group = kmalloc(sizeof(*scsi_group), GFP_KERNEL);
+	if (!scsi_group) {
+		SBP2_ERR ("Could not allocate memory for scsi_group");
+		return -ENOMEM;
+	}
+
+	INIT_LIST_HEAD(&scsi_group->scsi_id_list);
+	ud->device.driver_data = scsi_group;
+	sbp2_parse_unit_directory(scsi_group, ud);
+
+	list_for_each_safe (lh, next, &scsi_group->scsi_id_list) {
+		scsi_id = list_entry(lh, struct scsi_id_instance_data, list);
+
+		scsi_id->ne = ud->ne;
+		scsi_id->hi = hi;
+		scsi_id->speed_code = SPEED_100;
+		scsi_id->max_payload_size = hpsb_speedto_maxrec[SPEED_100];
+		atomic_set(&scsi_id->sbp2_login_complete, 0);
+		INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
+		INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
+		scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
+
+		sbp2_start_device(scsi_id);
+	}
+
+	/* Check to see if any of our devices survived the ordeal */
+	if (list_empty(&scsi_group->scsi_id_list)) {
+		kfree(scsi_group);
+		return -ENODEV;
+	}
+
+	return 0;
+}
+
+
 /*
  * This function is where we first pull the node unique ids, and then
  * allocate memory and register a SBP-2 device.
  */
-static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_directory *ud)
+static int sbp2_start_device(struct scsi_id_instance_data *scsi_id)
 {
-	struct scsi_id_instance_data *scsi_id = NULL;
+	struct sbp2scsi_host_info *hi = scsi_id->hi;
 	struct scsi_device *sdev;
-	struct node_entry *ne;
 	int i;
 
 	SBP2_DEBUG("sbp2_start_device");
-	ne = ud->ne;
-
-	/*
-	 * This really is a "new" device plugged in. Let's allocate memory
-	 * for our scsi id instance data.
-	 */
-	scsi_id = (struct scsi_id_instance_data *)kmalloc(sizeof(struct scsi_id_instance_data),
-							  GFP_KERNEL);
-	if (!scsi_id)
-		goto alloc_fail_first;
-	memset(scsi_id, 0, sizeof(struct scsi_id_instance_data));
-
-	scsi_id->hi = hi;
 
 	/* Login FIFO DMA */
 	scsi_id->login_response =
@@ -1068,7 +897,9 @@
 		}
 
 		kfree(scsi_id);
-alloc_fail_first:
+
+		list_del(&scsi_id->list);
+
 		SBP2_ERR ("Could not allocate memory for scsi_id");
 
 		return -ENOMEM;
@@ -1076,31 +907,6 @@
 	SBP2_DMA_ALLOC("consistent DMA region for login ORB");
 
 	/*
-	 * Initialize some of the fields in this structure
-	 */
-	scsi_id->ne = ne;
-	scsi_id->ud = ud;
-	scsi_id->speed_code = SPEED_100;
-	scsi_id->max_payload_size = hpsb_speedto_maxrec[SPEED_100];
-	ud->device.driver_data = scsi_id;
-
-	atomic_set(&scsi_id->sbp2_login_complete, 0);
-
-	/* 
-	 * Initialize structures needed for the command orb pool.
-	 */
-	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
-	INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
-	scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
-
-	/*
-	 * Make sure that we've gotten ahold of the sbp2 management agent
-	 * address. Also figure out the command set being used (SCSI or
-	 * RBC).
-	 */
-	sbp2_parse_unit_directory(scsi_id);
-
-	/*
 	 * Find an empty spot to stick our scsi id instance data. 
 	 */
 	for (i = 0; i < hi->scsi_host->max_id; i++) {
@@ -1235,6 +1041,8 @@
 
 	SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id);
 
+	list_del(&scsi_id->list);
+
 	kfree(scsi_id);
 }
 
@@ -1311,6 +1119,8 @@
 	scsi_id->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
 	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
 		scsi_id->query_logins_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
+		SBP2_DEBUG("sbp2_query_logins: set lun to %d",
+			   ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun));
 	}
 	SBP2_DEBUG("sbp2_query_logins: lun_misc initialized");
 
@@ -1423,6 +1233,8 @@
 	/* Set the lun if we were able to pull it from the device's unit directory */
 	if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
 		scsi_id->login_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
+		SBP2_DEBUG("sbp2_query_logins: set lun to %d",
+			   ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun));
 	}
 	SBP2_DEBUG("sbp2_login_device: lun_misc initialized");
 
@@ -1463,7 +1275,8 @@
 
 	atomic_set(&scsi_id->sbp2_login_complete, 0);
 
-	SBP2_DEBUG("sbp2_login_device: prepared to write");
+	SBP2_DEBUG("sbp2_login_device: prepared to write to %08x",
+		   (unsigned int)scsi_id->sbp2_management_agent_addr);
 	hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
 	SBP2_DEBUG("sbp2_login_device: written");
 
@@ -1694,50 +1507,50 @@
  * directory. Used to determine things like sbp2 management agent offset,
  * and command set used (SCSI or RBC). 
  */
-static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
+static void sbp2_parse_unit_directory(struct scsi_id_group *scsi_group,
+				      struct unit_directory *ud)
 {
-	struct unit_directory *ud;
+	struct scsi_id_instance_data *scsi_id;
+	struct list_head *lh;
+	u64 management_agent_addr;
+	u32 command_set_spec_id, command_set, unit_characteristics,
+		firmware_revision, workarounds;
 	int i;
 
 	SBP2_DEBUG("sbp2_parse_unit_directory");
 
-	/* Initialize some fields, in case an entry does not exist */
-	scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED;
-	scsi_id->sbp2_management_agent_addr = 0x0;
-	scsi_id->sbp2_command_set_spec_id = 0x0;
-	scsi_id->sbp2_command_set = 0x0;
-	scsi_id->sbp2_unit_characteristics = 0x0;
-	scsi_id->sbp2_firmware_revision = 0x0;
-
-	ud = scsi_id->ud;
+	management_agent_addr = 0x0;
+	command_set_spec_id = 0x0;
+	command_set = 0x0;
+	unit_characteristics = 0x0;
+	firmware_revision = 0x0;
 
 	/* Handle different fields in the unit directory, based on keys */
 	for (i = 0; i < ud->length; i++) {
 		switch (CONFIG_ROM_KEY(ud->quadlets[i])) {
 		case SBP2_CSR_OFFSET_KEY:
 			/* Save off the management agent address */
-			scsi_id->sbp2_management_agent_addr =
+			management_agent_addr =
 				CSR_REGISTER_BASE + 
 				(CONFIG_ROM_VALUE(ud->quadlets[i]) << 2);
 
 			SBP2_DEBUG("sbp2_management_agent_addr = %x",
-				   (unsigned int) scsi_id->sbp2_management_agent_addr);
+				   (unsigned int) management_agent_addr);
 			break;
 
 		case SBP2_COMMAND_SET_SPEC_ID_KEY:
 			/* Command spec organization */
-			scsi_id->sbp2_command_set_spec_id
+			command_set_spec_id
 				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_command_set_spec_id = %x",
-				   (unsigned int) scsi_id->sbp2_command_set_spec_id);
+				   (unsigned int) command_set_spec_id);
 			break;
 
 		case SBP2_COMMAND_SET_KEY:
 			/* Command set used by sbp2 device */
-			scsi_id->sbp2_command_set
-				= CONFIG_ROM_VALUE(ud->quadlets[i]);
+			command_set = CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_command_set = %x",
-				   (unsigned int) scsi_id->sbp2_command_set);
+				   (unsigned int) command_set);
 			break;
 
 		case SBP2_UNIT_CHARACTERISTICS_KEY:
@@ -1745,10 +1558,10 @@
 			 * Unit characterisitcs (orb related stuff
 			 * that I'm not yet paying attention to)
 			 */
-			scsi_id->sbp2_unit_characteristics
+			unit_characteristics
 				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_unit_characteristics = %x",
-				   (unsigned int) scsi_id->sbp2_unit_characteristics);
+				   (unsigned int) unit_characteristics);
 			break;
 
 		case SBP2_DEVICE_TYPE_AND_LUN_KEY:
@@ -1756,21 +1569,29 @@
 			 * Device type and lun (used for
 			 * detemining type of sbp2 device)
 			 */
+			scsi_id = kmalloc(sizeof(*scsi_id), GFP_KERNEL);
+			if (!scsi_id) {
+				SBP2_ERR("Out of memory adding scsi_id, not all LUN's will be added");
+				break;
+			}
+			memset(scsi_id, 0, sizeof(*scsi_id));
+
 			scsi_id->sbp2_device_type_and_lun
 				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			SBP2_DEBUG("sbp2_device_type_and_lun = %x",
 				   (unsigned int) scsi_id->sbp2_device_type_and_lun);
+			list_add_tail(&scsi_id->list, &scsi_group->scsi_id_list);
 			break;
 
 		case SBP2_FIRMWARE_REVISION_KEY:
 			/* Firmware revision */
-			scsi_id->sbp2_firmware_revision
+			firmware_revision
 				= CONFIG_ROM_VALUE(ud->quadlets[i]);
 			if (force_inquiry_hack)
 				SBP2_INFO("sbp2_firmware_revision = %x",
-				   (unsigned int) scsi_id->sbp2_firmware_revision);
+				   (unsigned int) firmware_revision);
 			else	SBP2_DEBUG("sbp2_firmware_revision = %x",
-				   (unsigned int) scsi_id->sbp2_firmware_revision);
+				   (unsigned int) firmware_revision);
 			break;
 
 		default:
@@ -1780,7 +1601,7 @@
 
 	/* This is the start of our broken device checking. We try to hack
 	 * around oddities and known defects.  */
-	scsi_id->workarounds = 0x0;
+	workarounds = 0x0;
 
 	/* If the vendor id is 0xa0b8 (Symbios vendor id), then we have a
 	 * bridge with 128KB max transfer size limitation. For sanity, we
@@ -1791,28 +1612,54 @@
 	 * host gets initialized. That way we can down-force the
 	 * max_sectors to account for it. That is not currently
 	 * possible.  */
-	if ((scsi_id->sbp2_firmware_revision & 0xffff00) ==
+	if ((firmware_revision & 0xffff00) ==
 			SBP2_128KB_BROKEN_FIRMWARE &&
 			(max_sectors * 512) > (128*1024)) {
 		SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB max transfer size.",
-				NODE_BUS_ARGS(scsi_id->ne->nodeid));
+				NODE_BUS_ARGS(ud->ne->nodeid));
 		SBP2_WARN("WARNING: Current max_sectors setting is larger than 128KB (%d sectors)!",
 				max_sectors);
-		scsi_id->workarounds |= SBP2_BREAKAGE_128K_MAX_TRANSFER;
+		workarounds |= SBP2_BREAKAGE_128K_MAX_TRANSFER;
 	}
 
 	/* Check for a blacklisted set of devices that require us to force
 	 * a 36 byte host inquiry. This can be overriden as a module param
 	 * (to force all hosts).  */
 	for (i = 0; i < NUM_BROKEN_INQUIRY_DEVS; i++) {
-		if ((scsi_id->sbp2_firmware_revision & 0xffff00) ==
+		if ((firmware_revision & 0xffff00) ==
 				sbp2_broken_inquiry_list[i]) {
 			SBP2_WARN("Node " NODE_BUS_FMT ": Using 36byte inquiry workaround",
-					NODE_BUS_ARGS(scsi_id->ne->nodeid));
-			scsi_id->workarounds |= SBP2_BREAKAGE_INQUIRY_HACK;
+					NODE_BUS_ARGS(ud->ne->nodeid));
+			workarounds |= SBP2_BREAKAGE_INQUIRY_HACK;
 			break; /* No need to continue. */
 		}
 	}
+
+	/* If our list is empty, add a base scsi_id (happens in a normal
+	 * case where there is no logical_unit_number entry */
+	if (list_empty(&scsi_group->scsi_id_list)) {
+		scsi_id = kmalloc(sizeof(*scsi_id), GFP_KERNEL);
+		if (!scsi_id) {
+			SBP2_ERR("Out of memory adding scsi_id");
+			return;
+		}
+		memset(scsi_id, 0, sizeof(*scsi_id));
+
+		scsi_id->sbp2_device_type_and_lun = SBP2_DEVICE_TYPE_LUN_UNINITIALIZED;
+		list_add_tail(&scsi_id->list, &scsi_group->scsi_id_list);
+	}
+
+	/* Update the generic fields in all the LUN's */
+	list_for_each (lh, &scsi_group->scsi_id_list) {
+		scsi_id = list_entry(lh, struct scsi_id_instance_data, list);
+
+		scsi_id->sbp2_management_agent_addr = management_agent_addr;
+		scsi_id->sbp2_command_set_spec_id = command_set_spec_id;
+		scsi_id->sbp2_command_set = command_set;
+		scsi_id->sbp2_unit_characteristics = unit_characteristics;
+		scsi_id->sbp2_firmware_revision = firmware_revision;
+		scsi_id->workarounds = workarounds;
+	}
 }
 
 /*
@@ -3065,7 +2912,7 @@
 		return (length);
 }
 
-MODULE_AUTHOR("James Goodwin <jamesg@filanet.com>");
+MODULE_AUTHOR("Ben Collins <bcollins@debian.org>");
 MODULE_DESCRIPTION("IEEE-1394 SBP-2 protocol driver");
 MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME);
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h
--- a/drivers/ieee1394/sbp2.h	Fri Apr 18 14:13:18 2003
+++ b/drivers/ieee1394/sbp2.h	Mon May 19 07:50:29 2003
@@ -384,7 +384,6 @@
 	/*
 	 * Values pulled from the device's unit directory
 	 */
-	struct unit_directory *ud;
 	u32 sbp2_command_set_spec_id;
 	u32 sbp2_command_set;
 	u32 sbp2_unit_characteristics;
@@ -403,6 +402,8 @@
 	struct list_head sbp2_command_orb_inuse;
 	struct list_head sbp2_command_orb_completed;
 
+	struct list_head list;
+
 	/* Node entry, as retrieved from NodeMgr entries */
 	struct node_entry *ne;
 
@@ -413,6 +414,13 @@
 	u32 workarounds;
 };
 
+
+/* Describes a per-ud scsi_id group */
+struct scsi_id_group {
+	struct list_head scsi_id_list;
+};
+
+
 /*
  * Sbp2 host data structure (one per sbp2 host)
  */
@@ -464,8 +472,9 @@
 static int sbp2_remove(struct device *dev);
 static void sbp2_update(struct unit_directory *ud);
 
-static int sbp2_start_device(struct sbp2scsi_host_info *hi, 
-			     struct unit_directory *ud);
+static int sbp2_start_ud(struct sbp2scsi_host_info *hi,
+			 struct unit_directory *ud);
+static int sbp2_start_device(struct scsi_id_instance_data *scsi_id);
 static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id);
 
 #ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
@@ -499,7 +508,8 @@
 static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data);
 static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd);
 static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt);
-static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id);
+static void sbp2_parse_unit_directory(struct scsi_id_group *scsi_group,
+				      struct unit_directory *ud);
 static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id);
 static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id);
 
diff -Nru a/drivers/ieee1394/video1394.c b/drivers/ieee1394/video1394.c
--- a/drivers/ieee1394/video1394.c	Fri May  2 12:23:57 2003
+++ b/drivers/ieee1394/video1394.c	Wed May  7 08:47:30 2003
@@ -1257,7 +1257,6 @@
 static void video1394_add_host (struct hpsb_host *host)
 {
 	struct ti_ohci *ohci;
-	char name[16];
 	int minor;
 
 	/* We only work with the OHCI-1394 driver */
@@ -1274,12 +1273,10 @@
 	hpsb_set_hostinfo(&video1394_highlevel, host, ohci);
 	hpsb_set_hostinfo_key(&video1394_highlevel, host, ohci->id);
 
-	sprintf(name, "%s/%d", VIDEO1394_DRIVER_NAME, ohci->id);
-	minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->id;
-	devfs_register(NULL, name, 0, IEEE1394_MAJOR, minor,
-		       S_IFCHR | S_IRUSR | S_IWUSR, &video1394_fops, NULL);
-
-	return;
+	minor = IEEE1394_MINOR_BLOCK_VIDEO1394 * 16 + ohci->id; 
+	devfs_mk_cdev(MKDEV(IEEE1394_MAJOR, minor),
+		       S_IFCHR | S_IRUSR | S_IWUSR,
+		       "%s/%d", VIDEO1394_DRIVER_NAME, ohci->id);
 }
 
 
diff -Nru a/drivers/input/evdev.c b/drivers/input/evdev.c
--- a/drivers/input/evdev.c	Mon Apr 28 23:32:21 2003
+++ b/drivers/input/evdev.c	Fri May  2 06:55:04 2003
@@ -17,6 +17,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/input.h>
+#include <linux/major.h>
 #include <linux/smp_lock.h>
 #include <linux/device.h>
 #include <linux/devfs_fs_kernel.h>
@@ -400,7 +401,9 @@
 	sprintf(evdev->name, "event%d", minor);
 
 	evdev_table[minor] = evdev;
-	input_register_minor("input/event%d", minor, EVDEV_MINOR_BASE);
+
+	devfs_mk_cdev(MKDEV(INPUT_MAJOR, EVDEV_MINOR_BASE + minor),
+			S_IFCHR|S_IRUGO|S_IWUSR, "input/event%d", minor);
 
 	return &evdev->handle;
 }
diff -Nru a/drivers/input/input.c b/drivers/input/input.c
--- a/drivers/input/input.c	Mon Apr 28 23:32:21 2003
+++ b/drivers/input/input.c	Fri May  2 06:55:04 2003
@@ -16,6 +16,7 @@
 #include <linux/input.h>
 #include <linux/module.h>
 #include <linux/random.h>
+#include <linux/major.h>
 #include <linux/pm.h>
 #include <linux/proc_fs.h>
 #include <linux/kmod.h>
@@ -32,7 +33,6 @@
 EXPORT_SYMBOL(input_unregister_device);
 EXPORT_SYMBOL(input_register_handler);
 EXPORT_SYMBOL(input_unregister_handler);
-EXPORT_SYMBOL(input_register_minor);
 EXPORT_SYMBOL(input_open_device);
 EXPORT_SYMBOL(input_close_device);
 EXPORT_SYMBOL(input_accept_process);
@@ -40,7 +40,6 @@
 EXPORT_SYMBOL(input_event);
 EXPORT_SYMBOL(input_class);
 
-#define INPUT_MAJOR	13
 #define INPUT_DEVICES	256
 
 static LIST_HEAD(input_dev_list);
@@ -540,15 +539,6 @@
 	.owner = THIS_MODULE,
 	.open = input_open_file,
 };
-
-void input_register_minor(char *name, int minor, int minor_base)
-{
-	char devfs_name[16];
-
-	sprintf(devfs_name, name, minor);
-	devfs_register(NULL, devfs_name, 0, INPUT_MAJOR, minor_base + minor,
-			S_IFCHR|S_IRUGO|S_IWUSR, &input_fops, NULL);
-}
 
 #ifdef CONFIG_PROC_FS
 
diff -Nru a/drivers/input/joydev.c b/drivers/input/joydev.c
--- a/drivers/input/joydev.c	Mon Apr 28 23:32:21 2003
+++ b/drivers/input/joydev.c	Fri May  2 06:55:04 2003
@@ -445,7 +445,9 @@
 	}
 
 	joydev_table[minor] = joydev;
-	input_register_minor("js%d", minor, JOYDEV_MINOR_BASE);
+	
+	devfs_mk_cdev(MKDEV(INPUT_MAJOR, JOYDEV_MINOR_BASE + minor),
+			S_IFCHR|S_IRUGO|S_IWUSR, "js%d", minor);
 
 	return &joydev->handle;
 }
diff -Nru a/drivers/input/mouse/rpcmouse.c b/drivers/input/mouse/rpcmouse.c
--- a/drivers/input/mouse/rpcmouse.c	Wed Feb 12 01:41:01 2003
+++ b/drivers/input/mouse/rpcmouse.c	Mon May 12 16:21:24 2003
@@ -49,7 +49,7 @@
 	},
 };
 
-static void rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rpcmouse_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct input_dev *dev = dev_id;
 	short x, y, dx, dy, b;
@@ -74,6 +74,8 @@
 	input_report_key(dev, BTN_RIGHT,  b & 0x10);
 
 	input_sync(dev);
+
+	return IRQ_HANDLED;
 }
 
 static int __init rpcmouse_init(void)
diff -Nru a/drivers/input/mousedev.c b/drivers/input/mousedev.c
--- a/drivers/input/mousedev.c	Mon Apr 28 23:32:21 2003
+++ b/drivers/input/mousedev.c	Fri May  2 06:55:04 2003
@@ -432,7 +432,9 @@
 		input_open_device(&mousedev->handle);
 
 	mousedev_table[minor] = mousedev;
-	input_register_minor("input/mouse%d", minor, MOUSEDEV_MINOR_BASE);
+
+	devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + minor),
+			S_IFCHR|S_IRUGO|S_IWUSR, "input/mouse%d", minor);
 
 	return &mousedev->handle;
 }
@@ -502,7 +504,10 @@
 	mousedev_table[MOUSEDEV_MIX] = &mousedev_mix;
 	mousedev_mix.exist = 1;
 	mousedev_mix.minor = MOUSEDEV_MIX;
-	input_register_minor("input/mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE);
+
+	devfs_mk_cdev(MKDEV(INPUT_MAJOR, MOUSEDEV_MINOR_BASE + MOUSEDEV_MIX),
+			S_IFCHR|S_IRUGO|S_IWUSR, "input/mice");
+
 
 #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX
 	if (!(mousedev_mix.misc = !misc_register(&psaux_mouse)))
diff -Nru a/drivers/input/serio/ambakmi.c b/drivers/input/serio/ambakmi.c
--- a/drivers/input/serio/ambakmi.c	Wed Feb 12 01:41:01 2003
+++ b/drivers/input/serio/ambakmi.c	Tue May 13 09:30:32 2003
@@ -28,22 +28,27 @@
 struct amba_kmi_port {
 	struct serio		io;
 	struct amba_kmi_port	*next;
-	unsigned long		base;
+	void			*base;
 	unsigned int		irq;
 	unsigned int		divisor;
 	char			name[32];
 	char			phys[16];
+	struct resource		*res;
 };
 
-static void amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t amba_kmi_int(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct amba_kmi_port *kmi = dev_id;
-	unsigned int status = __raw_readb(KMIIR);
+	unsigned int status = readb(KMIIR);
+	int handled = IRQ_NONE;
 
 	while (status & KMIIR_RXINTR) {
-		serio_interrupt(&kmi->io, __raw_readb(KMIDATA), 0, regs);
-		status = __raw_readb(KMIIR);
+		serio_interrupt(&kmi->io, readb(KMIDATA), 0, regs);
+		status = readb(KMIIR);
+		handled = IRQ_HANDLED;
 	}
+
+	return handled;
 }
 
 static int amba_kmi_write(struct serio *io, unsigned char val)
@@ -51,11 +56,11 @@
 	struct amba_kmi_port *kmi = io->driver;
 	unsigned int timeleft = 10000; /* timeout in 100ms */
 
-	while ((__raw_readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--)
+	while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--)
 		udelay(10);
 
 	if (timeleft)
-		__raw_writeb(val, KMIDATA);
+		writeb(val, KMIDATA);
 
 	return timeleft ? 0 : SERIO_TIMEOUT;
 }
@@ -65,17 +70,17 @@
 	struct amba_kmi_port *kmi = io->driver;
 	int ret;
 
-	__raw_writeb(kmi->divisor, KMICLKDIV);
-	__raw_writeb(KMICR_EN, KMICR);
+	writeb(kmi->divisor, KMICLKDIV);
+	writeb(KMICR_EN, KMICR);
 
 	ret = request_irq(kmi->irq, amba_kmi_int, 0, kmi->phys, kmi);
 	if (ret) {
 		printk(KERN_ERR "kmi: failed to claim IRQ%d\n", kmi->irq);
-		__raw_writeb(0, KMICR);
+		writeb(0, KMICR);
 		return ret;
 	}
 
-	__raw_writeb(KMICR_EN | KMICR_RXINTREN, KMICR);
+	writeb(KMICR_EN | KMICR_RXINTREN, KMICR);
 
 	return 0;
 }
@@ -84,9 +89,9 @@
 {
 	struct amba_kmi_port *kmi = io->driver;
 
-	free_irq(kmi->irq, kmi);
+	writeb(0, KMICR);
 
-	__raw_writeb(0, KMICR);
+	free_irq(kmi->irq, kmi);
 }
 
 static struct amba_kmi_port *list;
@@ -109,24 +114,36 @@
 	kmi->io.phys	= kmi->phys;
 	kmi->io.driver	= kmi;
 
-	kmi->base	= base;
+	snprintf(kmi->name, sizeof(kmi->name), "AMBA KMI PS/2 %s port", type);
+	snprintf(kmi->phys, sizeof(kmi->phys), "amba/serio%d", nr);
+
+	kmi->res	= request_mem_region(base, KMI_SIZE, kmi->phys);
+	if (!kmi->res) {
+		kfree(kmi);
+		return -EBUSY;
+	}
+
+	kmi->base	= ioremap(base, KMI_SIZE);
+	if (!kmi->base) {
+		release_resource(kmi->res);
+		kfree(kmi);
+		return -ENOMEM;
+	}
+
 	kmi->irq	= irq;
 	kmi->divisor	= 24 / 8 - 1;
 
 	kmi->next	= list;
 	list		= kmi;
 
-	snprintf(kmi->name, sizeof(kmi->name), "AMBA KMI PS/2 %s port", type);
-	snprintf(kmi->phys, sizeof(kmi->phys), "amba/serio%d", nr);
-
 	serio_register_port(&kmi->io);
 	return 0;
 }
 
 static int __init amba_kmi_init(void)
 {
-	amba_kmi_init_one("keyboard", IO_ADDRESS(KMI0_BASE), IRQ_KMIINT0, 0);
-	amba_kmi_init_one("mouse", IO_ADDRESS(KMI1_BASE), IRQ_KMIINT1, 1);
+	amba_kmi_init_one("keyboard", KMI0_BASE, IRQ_KMIINT0, 0);
+	amba_kmi_init_one("mouse", KMI1_BASE, IRQ_KMIINT1, 1);
 	return 0;
 }
 
@@ -139,6 +156,8 @@
 		next = kmi->next;
 
 		serio_unregister_port(&kmi->io);
+		iounmap(kmi->base);
+		release_resource(kmi->res);
 		kfree(kmi);
 
 		kmi = next;
diff -Nru a/drivers/input/serio/i8042.c b/drivers/input/serio/i8042.c
--- a/drivers/input/serio/i8042.c	Sun Apr 20 14:14:28 2003
+++ b/drivers/input/serio/i8042.c	Wed May  7 21:21:03 2003
@@ -62,6 +62,12 @@
 static unsigned char i8042_mux_open;
 struct timer_list i8042_timer;
 
+/*
+ * Shared IRQ's require a device pointer, but this driver doesn't support
+ * multiple devices
+ */
+#define i8042_request_irq_cookie (&i8042_timer)
+
 static unsigned long i8042_unxlate_seen[256 / BITS_PER_LONG];
 static unsigned char i8042_unxlate_table[128] = {
 	  0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
@@ -235,7 +241,8 @@
 		if (i8042_mux_open++)
 			return 0;
 
-	if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL)) {
+	if (request_irq(values->irq, i8042_interrupt,
+			SA_SHIRQ, "i8042", i8042_request_irq_cookie)) {
 		printk(KERN_ERR "i8042.c: Can't get irq %d for %s, unregistering the port.\n", values->irq, values->name);
 		values->exists = 0;
 		serio_unregister_port(port);
@@ -275,7 +282,7 @@
 		return;
 	}
 
-	free_irq(values->irq, NULL);
+	free_irq(values->irq, i8042_request_irq_cookie);
 
 	i8042_flush();
 }
@@ -572,9 +579,10 @@
  * Check if AUX irq is available.
  */
 
-	if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL))
+	if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ,
+				"i8042", i8042_request_irq_cookie))
                 return -1;
-	free_irq(values->irq, NULL);
+	free_irq(values->irq, i8042_request_irq_cookie);
 
 /*
  * Get rid of bytes in the queue.
@@ -643,9 +651,10 @@
  * in trying to detect AUX presence.
  */
 
-	if (request_irq(values->irq, i8042_interrupt, 0, "i8042", NULL))
+	if (request_irq(values->irq, i8042_interrupt, SA_SHIRQ,
+				"i8042", i8042_request_irq_cookie))
                 return -1;
-	free_irq(values->irq, NULL);
+	free_irq(values->irq, i8042_request_irq_cookie);
 
 /*
  * Get rid of bytes in the queue.
diff -Nru a/drivers/input/serio/rpckbd.c b/drivers/input/serio/rpckbd.c
--- a/drivers/input/serio/rpckbd.c	Wed Feb 12 01:41:01 2003
+++ b/drivers/input/serio/rpckbd.c	Mon May 12 16:21:24 2003
@@ -54,20 +54,24 @@
 	return 0;
 }
 
-static void rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rpckbd_rx(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct serio *port = dev_id;
 	unsigned int byte;
+	int handled = IRQ_NONE;
 
 	while (iomd_readb(IOMD_KCTRL) & (1 << 5)) {
 		byte = iomd_readb(IOMD_KARTRX);
 
 		serio_interrupt(port, byte, 0, regs);
+		handled = IRQ_HANDLED;
 	}
+	return handled;
 }
 
-static void rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t rpckbd_tx(int irq, void *dev_id, struct pt_regs *regs)
 {
+	return IRQ_HANDLED;
 }
 
 static int rpckbd_open(struct serio *port)
diff -Nru a/drivers/input/serio/sa1111ps2.c b/drivers/input/serio/sa1111ps2.c
--- a/drivers/input/serio/sa1111ps2.c	Mon Feb 17 13:17:14 2003
+++ b/drivers/input/serio/sa1111ps2.c	Sat May 17 07:47:27 2003
@@ -41,10 +41,11 @@
  * at the most one, but we loop for safety.  If there was a
  * framing error, we have to manually clear the status.
  */
-static void ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ps2_rxint(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct ps2if *ps2if = dev_id;
 	unsigned int scancode, flag, status;
+	int handled = IRQ_NONE;
 
 	status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
 	while (status & PS2STAT_RXF) {
@@ -62,13 +63,17 @@
 		serio_interrupt(&ps2if->io, scancode, flag, regs);
 
                	status = sa1111_readl(ps2if->base + SA1111_PS2STAT);
+
+               	handled = IRQ_HANDLED;
         }
+
+        return handled;
 }
 
 /*
  * Completion of ps2 write
  */
-static void ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ps2_txint(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct ps2if *ps2if = dev_id;
 	unsigned int status;
@@ -83,6 +88,8 @@
 		ps2if->tail = (ps2if->tail + 1) & (sizeof(ps2if->buf) - 1);
 	}
 	spin_unlock(&ps2if->lock);
+
+	return IRQ_HANDLED;
 }
 
 /*
@@ -340,7 +347,6 @@
 	.drv = {
 		.name		= "sa1111-ps2",
 		.bus		= &sa1111_bus_type,
-		.devclass	= &input_devclass,
 		.probe		= ps2_probe,
 		.remove		= ps2_remove,
 		.suspend	= ps2_suspend,
diff -Nru a/drivers/input/tsdev.c b/drivers/input/tsdev.c
--- a/drivers/input/tsdev.c	Mon Apr 28 23:32:21 2003
+++ b/drivers/input/tsdev.c	Fri May  2 06:55:04 2003
@@ -36,6 +36,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/input.h>
+#include <linux/major.h>
 #include <linux/config.h>
 #include <linux/smp_lock.h>
 #include <linux/random.h>
@@ -329,8 +330,9 @@
 	tsdev->handle.private = tsdev;
 
 	tsdev_table[minor] = tsdev;
-	input_register_minor("input/ts%d", minor, TSDEV_MINOR_BASE);
-
+	
+	devfs_mk_cdev(MKDEV(INPUT_MAJOR, TSDEV_MINOR_BASE + minor),
+			S_IFCHR|S_IRUGO|S_IWUSR, "input/ts%d", minor);
 
 	return &tsdev->handle;
 }
diff -Nru a/drivers/isdn/capi/capi.c b/drivers/isdn/capi/capi.c
--- a/drivers/isdn/capi/capi.c	Thu Apr 24 03:30:41 2003
+++ b/drivers/isdn/capi/capi.c	Wed May  7 23:16:25 2003
@@ -200,10 +200,8 @@
 	unsigned int minor = 0;
 	unsigned long flags;
   
-  	MOD_INC_USE_COUNT;
 	mp = kmalloc(sizeof(*mp), GFP_ATOMIC);
   	if (!mp) {
-  		MOD_DEC_USE_COUNT;
   		printk(KERN_ERR "capi: can't alloc capiminor\n");
 		return 0;
 	}
@@ -249,7 +247,6 @@
 	skb_queue_purge(&mp->outqueue);
 	capiminor_del_all_ack(mp);
 	kfree(mp);
-	MOD_DEC_USE_COUNT;
 }
 
 struct capiminor *capiminor_find(unsigned int minor)
@@ -1280,6 +1277,7 @@
 	
 	memset(drv, 0, sizeof(struct tty_driver));
 	drv->magic = TTY_DRIVER_MAGIC;
+	drv->owner = THIS_MODULE;
 	drv->driver_name = "capi_nc";
 	drv->name = "capi/";
 	drv->major = capi_ttymajor;
@@ -1460,7 +1458,6 @@
 	char *p;
 	char *compileinfo;
 
-	MOD_INC_USE_COUNT;
 
 	if ((p = strchr(revision, ':')) != 0 && p[1]) {
 		strncpy(rev, p + 2, sizeof(rev));
@@ -1472,19 +1469,17 @@
 
 	if (register_chrdev(capi_major, "capi20", &capi_fops)) {
 		printk(KERN_ERR "capi20: unable to get major %d\n", capi_major);
-		MOD_DEC_USE_COUNT;
 		return -EIO;
 	}
 
-	devfs_register (NULL, "isdn/capi20", DEVFS_FL_DEFAULT,
-			capi_major, 0, S_IFCHR | S_IRUSR | S_IWUSR,
-			&capi_fops, NULL);
+	devfs_mk_cdev(MKDEV(capi_major, 0), S_IFCHR | S_IRUSR | S_IWUSR,
+			"isdn/capi20");
+
 	printk(KERN_NOTICE "capi20: started up with major %d\n", capi_major);
 
 #ifdef CONFIG_ISDN_CAPI_MIDDLEWARE
 	if (capinc_tty_init() < 0) {
 		unregister_chrdev(capi_major, "capi20");
-		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 #endif /* CONFIG_ISDN_CAPI_MIDDLEWARE */
@@ -1503,7 +1498,6 @@
 	printk(KERN_NOTICE "capi20: Rev %s: started up with major %d%s\n",
 				rev, capi_major, compileinfo);
 
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
diff -Nru a/drivers/isdn/eicon/eicon_mod.c b/drivers/isdn/eicon/eicon_mod.c
--- a/drivers/isdn/eicon/eicon_mod.c	Mon Dec 30 08:55:26 2002
+++ b/drivers/isdn/eicon/eicon_mod.c	Mon May 12 18:59:22 2003
@@ -245,7 +245,7 @@
 							card->hwif.isa.shmem = (eicon_isa_shmem *)a;
 							return 0;
 						case EICON_BUS_MCA:
-#if CONFIG_MCA
+#ifdef CONFIG_MCA
 							if (eicon_mca_find_card(
 								0, a,
 								card->hwif.isa.irq,
@@ -853,7 +853,7 @@
 		card->type = Type;
 		switch (Type) {
 #ifdef CONFIG_ISDN_DRV_EICON_ISA
-#if CONFIG_MCA /* only needed for MCA */
+#ifdef CONFIG_MCA /* only needed for MCA */
                         case EICON_CTYPE_S:
                         case EICON_CTYPE_SX:
                         case EICON_CTYPE_SCOM:
@@ -1342,7 +1342,7 @@
 static void __exit
 eicon_exit(void)
 {
-#if CONFIG_PCI	
+#ifdef CONFIG_PCI	
 #ifdef CONFIG_ISDN_DRV_EICON_PCI
 	card_t *pCard;
 	word wCardIndex;
@@ -1374,7 +1374,7 @@
 		eicon_freecard(last);
         }
 
-#if CONFIG_PCI	
+#ifdef CONFIG_PCI	
 #ifdef CONFIG_ISDN_DRV_EICON_PCI
 	pCard = DivasCards;
 	for (wCardIndex = 0; wCardIndex < MAX_CARDS; wCardIndex++)
diff -Nru a/drivers/isdn/eicon/eicon_pci.c b/drivers/isdn/eicon/eicon_pci.c
--- a/drivers/isdn/eicon/eicon_pci.c	Sun Oct  6 18:00:18 2002
+++ b/drivers/isdn/eicon/eicon_pci.c	Mon May 12 18:59:22 2003
@@ -26,7 +26,7 @@
 
 char *eicon_pci_revision = "$Revision: 1.1.4.1.2.3 $";
 
-#if CONFIG_PCI	         /* intire stuff is only for PCI */
+#ifdef CONFIG_PCI	         /* entire stuff is only for PCI */
 #ifdef CONFIG_ISDN_DRV_EICON_PCI
 
 int eicon_pci_find_card(char *ID)
diff -Nru a/drivers/isdn/hardware/eicon/divamnt.c b/drivers/isdn/hardware/eicon/divamnt.c
--- a/drivers/isdn/hardware/eicon/divamnt.c	Wed Feb 19 12:18:12 2003
+++ b/drivers/isdn/hardware/eicon/divamnt.c	Wed May  7 08:47:30 2003
@@ -420,10 +420,8 @@
 		       DRIVERLNAME);
 		return (0);
 	}
-	devfs_register(NULL, "DivasMAINT", DEVFS_FL_DEFAULT, major, 0,
-		       S_IFCHR | S_IRUSR | S_IWUSR, &divas_maint_fops,
-		       NULL);
 
+	devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, DivasMAINT);
 	return (1);
 }
 
diff -Nru a/drivers/isdn/hardware/eicon/divasi.c b/drivers/isdn/hardware/eicon/divasi.c
--- a/drivers/isdn/hardware/eicon/divasi.c	Wed Feb 19 12:18:14 2003
+++ b/drivers/isdn/hardware/eicon/divasi.c	Wed May  7 08:47:30 2003
@@ -179,10 +179,8 @@
 		       DRIVERLNAME);
 		return (0);
 	}
-	devfs_register(NULL, "DivasIDI", DEVFS_FL_DEFAULT, major, 0,
-		       S_IFCHR | S_IRUSR | S_IWUSR, &divas_idi_fops,
-		       NULL);
 
+	devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, "DivasIDI");
 	return (1);
 }
 
diff -Nru a/drivers/isdn/hardware/eicon/divasmain.c b/drivers/isdn/hardware/eicon/divasmain.c
--- a/drivers/isdn/hardware/eicon/divasmain.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/isdn/hardware/eicon/divasmain.c	Wed May  7 08:47:30 2003
@@ -788,9 +788,8 @@
 		       DRIVERLNAME);
 		return (0);
 	}
-	devfs_register(NULL, "Divas", DEVFS_FL_DEFAULT, major, 0,
-		       S_IFCHR | S_IRUSR | S_IWUSR, &divas_fops, NULL);
 
+	devfs_mk_cdev(MKDEV(major, 0), S_IFCHR|S_IRUSR|S_IWUSR, "Divas");
 	return (1);
 }
 
diff -Nru a/drivers/isdn/hardware/eicon/maintidi.c b/drivers/isdn/hardware/eicon/maintidi.c
--- a/drivers/isdn/hardware/eicon/maintidi.c	Thu Oct 10 20:09:04 2002
+++ b/drivers/isdn/hardware/eicon/maintidi.c	Sat May 17 14:09:51 2003
@@ -116,7 +116,7 @@
 	}
 
   pmem += sizeof(*pLib);
-	memset (pLib, 0x00, sizeof(pLib));
+	memset(pLib, 0x00, sizeof(*pLib));
 
 	pLib->Adapter  = Adapter;
 
diff -Nru a/drivers/isdn/hisax/avm_pci.c b/drivers/isdn/hisax/avm_pci.c
--- a/drivers/isdn/hisax/avm_pci.c	Thu Mar  6 22:52:04 2003
+++ b/drivers/isdn/hisax/avm_pci.c	Mon May 12 18:59:22 2003
@@ -730,7 +730,7 @@
 			}
 		}
 #endif
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
 		if ((dev_avm = pci_find_device(PCI_VENDOR_ID_AVM,
 			PCI_DEVICE_ID_AVM_A1,  dev_avm))) {
 			if (avm_pci_probe(card->cs, dev_avm))
diff -Nru a/drivers/isdn/hisax/diva.c b/drivers/isdn/hisax/diva.c
--- a/drivers/isdn/hisax/diva.c	Mon Apr 21 03:58:37 2003
+++ b/drivers/isdn/hisax/diva.c	Mon May 12 18:59:22 2003
@@ -772,7 +772,7 @@
 		}
 	}
 #endif
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
 	if ((dev_diva = pci_find_device(PCI_VENDOR_ID_EICON,
 					PCI_DEVICE_ID_EICON_DIVA20,
 					dev_diva))) {
diff -Nru a/drivers/isdn/hisax/elsa.c b/drivers/isdn/hisax/elsa.c
--- a/drivers/isdn/hisax/elsa.c	Mon Apr 21 03:58:37 2003
+++ b/drivers/isdn/hisax/elsa.c	Mon May 12 18:59:22 2003
@@ -1098,7 +1098,7 @@
 			return 0;
 		return 1;
 	} else if (card->typ == ISDN_CTYPE_ELSA_PCI) {
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
 		if ((dev_qs1000 = pci_find_device(PCI_VENDOR_ID_ELSA,
 			PCI_DEVICE_ID_ELSA_MICROLINK, dev_qs1000))) {
 			if (elsa_qs_pci_probe(card->cs, dev_qs1000,
diff -Nru a/drivers/isdn/hisax/niccy.c b/drivers/isdn/hisax/niccy.c
--- a/drivers/isdn/hisax/niccy.c	Mon Apr 21 03:58:37 2003
+++ b/drivers/isdn/hisax/niccy.c	Mon May 12 18:59:22 2003
@@ -319,7 +319,7 @@
 			return 0;
 		return 1;
 	} else {
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
 		if ((niccy_dev = pci_find_device(PCI_VENDOR_ID_SATSAGEM,
 			PCI_DEVICE_ID_SATSAGEM_NICCY, niccy_dev))) {
 			if (niccy_pci_probe(card->cs, niccy_dev) < 0)
diff -Nru a/drivers/isdn/hisax/sedlbauer.c b/drivers/isdn/hisax/sedlbauer.c
--- a/drivers/isdn/hisax/sedlbauer.c	Mon Apr 21 03:58:37 2003
+++ b/drivers/isdn/hisax/sedlbauer.c	Mon May 12 18:59:22 2003
@@ -789,7 +789,7 @@
 	}
 #endif
 /* Probe for Sedlbauer speed pci */
-#if CONFIG_PCI
+#ifdef CONFIG_PCI
 	dev_sedl = pci_find_device(PCI_VENDOR_ID_TIGERJET,
 				   PCI_DEVICE_ID_TIGERJET_100, dev_sedl);
 	if (dev_sedl) {
diff -Nru a/drivers/isdn/i4l/isdn_common.c b/drivers/isdn/i4l/isdn_common.c
--- a/drivers/isdn/i4l/isdn_common.c	Sat Mar 22 07:38:04 2003
+++ b/drivers/isdn/i4l/isdn_common.c	Wed May  7 08:47:30 2003
@@ -37,9 +37,6 @@
 static void isdn_lock_driver(struct isdn_driver *drv);
 static void isdn_unlock_driver(struct isdn_driver *drv);
 
-static void isdn_register_devfs(int);
-static void isdn_unregister_devfs(int);
-
 /* ====================================================================== */
 
 /* Description of hardware-level-driver */
@@ -2157,85 +2154,37 @@
 	return max;
 }
 
-/*
- *****************************************************************************
- * And now the modules code.
- *****************************************************************************
- */
-
-#ifdef CONFIG_DEVFS_FS
-
-static void isdn_register_devfs(int k)
-{
-	char buf[16];
-
-	sprintf (buf, "isdn/isdnctrl%d", k);
-	devfs_register(NULL, buf, DEVFS_FL_DEFAULT,
-		       ISDN_MAJOR, ISDN_MINOR_CTRL + k, 0600 | S_IFCHR,
-		       &isdn_fops, NULL);
-}
-
-static void isdn_unregister_devfs(int k)
+static void isdn_init_devfs(void)
 {
-	devfs_remove("isdn/isdnctrl%d", k);
-}
+	devfs_mk_dir("isdn");
 
-static void isdn_init_devfs(void)
+#ifdef CONFIG_ISDN_PPP
 {
-#  ifdef CONFIG_ISDN_PPP
 	int i;
-#  endif
 
-	devfs_mk_dir("isdn");
-#  ifdef CONFIG_ISDN_PPP
-	for (i = 0; i < ISDN_MAX_CHANNELS; i++) {
-		char buf[16];
+	for (i = 0; i < ISDN_MAX_CHANNELS; i++)
+		devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_PPP + i),
+				0600 | S_IFCHR, "isdn/ippp%d", i);
+}
+#endif
 
-		sprintf (buf, "isdn/ippp%d", i);
-		devfs_register(NULL, buf, DEVFS_FL_DEFAULT,
-			       ISDN_MAJOR, ISDN_MINOR_PPP + i,
-			       0600 | S_IFCHR, &isdn_fops, NULL);
-	}
-#  endif
-
-	devfs_register(NULL, "isdn/isdninfo", DEVFS_FL_DEFAULT,
-		       ISDN_MAJOR, ISDN_MINOR_STATUS, 0600 | S_IFCHR,
-		       &isdn_fops, NULL);
-	devfs_register(NULL, "isdn/isdnctrl", DEVFS_FL_DEFAULT,
-		       ISDN_MAJOR, ISDN_MINOR_CTRL, 0600 | S_IFCHR, 
-		       &isdn_fops, NULL);
+	devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_STATUS),
+			0600 | S_IFCHR, "isdn/isdninfo");
+	devfs_mk_cdev(MKDEV(ISDN_MAJOR, ISDN_MINOR_CTRL),
+			0600 | S_IFCHR, "isdn/isdnctrl");
 }
 
 static void isdn_cleanup_devfs(void)
 {
-#  ifdef CONFIG_ISDN_PPP
+#ifdef CONFIG_ISDN_PPP
 	int i;
 	for (i = 0; i < ISDN_MAX_CHANNELS; i++) 
 		devfs_remove("isdn/ippp%d", i);
-#  endif
+#endif
 	devfs_remove("isdn/isdninfo");
 	devfs_remove("isdn/isdnctrl");
 	devfs_remove("isdn");
 }
-
-#else   /* CONFIG_DEVFS_FS */
-static void isdn_register_devfs(int dummy)
-{
-}
-
-static void isdn_unregister_devfs(int dummy)
-{
-}
-
-static void isdn_init_devfs(void)
-{
-}
-
-static void isdn_cleanup_devfs(void)
-{
-}
-
-#endif  /* CONFIG_DEVFS_FS */
 
 /*
  * Allocate and initialize all data, register modem-devices
diff -Nru a/drivers/isdn/i4l/isdn_net_lib.c b/drivers/isdn/i4l/isdn_net_lib.c
--- a/drivers/isdn/i4l/isdn_net_lib.c	Sat Feb 22 09:17:33 2003
+++ b/drivers/isdn/i4l/isdn_net_lib.c	Mon May 19 23:22:51 2003
@@ -1777,6 +1777,7 @@
 
 	printk(KERN_INFO "%s: disconnected\n", idev->name);
 	fsm_change_state(fi, ST_WAIT_DHUP);
+	return 0;
 }
 
 static int
@@ -1898,7 +1899,7 @@
 static int
 isdn_net_handle_event(isdn_net_dev *idev, int pr, void *arg)
 {
-	fsm_event(&idev->fi, pr, arg);
+	return fsm_event(&idev->fi, pr, arg);
 }
 
 static int
diff -Nru a/drivers/isdn/i4l/isdn_x25iface.c b/drivers/isdn/i4l/isdn_x25iface.c
--- a/drivers/isdn/i4l/isdn_x25iface.c	Tue Oct 29 18:17:00 2002
+++ b/drivers/isdn/i4l/isdn_x25iface.c	Wed May 14 23:46:35 2003
@@ -222,6 +222,8 @@
 		printk(KERN_WARNING 
 		       "isdn_x25iface_connect_ind while unconfigured %s\n"
 		       , MY_DEVNAME(cprot->net_dev) );
+		if (skb)
+			dev_kfree_skb(skb);
 		return -1;
 	}
 	*state_p = WAN_CONNECTED;
diff -Nru a/drivers/isdn/pcbit/drv.c b/drivers/isdn/pcbit/drv.c
--- a/drivers/isdn/pcbit/drv.c	Sun Nov 17 15:08:01 2002
+++ b/drivers/isdn/pcbit/drv.c	Wed May 14 23:43:59 2003
@@ -1071,6 +1071,7 @@
 		ptr->msn = kmalloc(len, GFP_ATOMIC);
 		if (!ptr->msn) {
 			printk(KERN_WARNING "kmalloc failed\n");
+			kfree(ptr);
 			return;
 		}
 
diff -Nru a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c
--- a/drivers/macintosh/adb.c	Fri Mar 21 01:06:37 2003
+++ b/drivers/macintosh/adb.c	Wed May  7 08:47:30 2003
@@ -896,8 +896,6 @@
 	if (register_chrdev(ADB_MAJOR, "adb", &adb_fops))
 		printk(KERN_ERR "adb: unable to get major %d\n", ADB_MAJOR);
 	else
-		devfs_register (NULL, "adb", DEVFS_FL_DEFAULT,
-				ADB_MAJOR, 0,
-				S_IFCHR | S_IRUSR | S_IWUSR,
-				&adb_fops, NULL);
+		devfs_mk_cdev(MKDEV(ADB_MAJOR, 0),
+				S_IFCHR | S_IRUSR | S_IWUSR, "adb");
 }
diff -Nru a/drivers/macintosh/macserial.c b/drivers/macintosh/macserial.c
--- a/drivers/macintosh/macserial.c	Sun Apr 27 00:48:26 2003
+++ b/drivers/macintosh/macserial.c	Wed May  7 07:11:08 2003
@@ -1932,7 +1932,6 @@
 	spin_lock_irqsave(&info->lock, flags);
 
 	if (tty_hung_up_p(filp)) {
-		MOD_DEC_USE_COUNT;
 		spin_unlock_irqrestore(&info->lock, flags);
 		return;
 	}
@@ -1956,7 +1955,6 @@
 		info->count = 0;
 	}
 	if (info->count) {
-		MOD_DEC_USE_COUNT;
 		spin_unlock_irqrestore(&info->lock, flags);
 		return;
 	}
@@ -2026,7 +2024,6 @@
 	info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE|
 			 ZILOG_CLOSING);
 	wake_up_interruptible(&info->close_wait);
-	MOD_DEC_USE_COUNT;
 }
 
 /*
@@ -2233,17 +2230,14 @@
 	int 			retval, line;
 	unsigned long		page;
 
-	MOD_INC_USE_COUNT;
 	line = tty->index;
 	if ((line < 0) || (line >= zs_channels_found)) {
-		MOD_DEC_USE_COUNT;
 		return -ENODEV;
 	}
 	info = zs_soft + line;
 
 #ifdef CONFIG_KGDB
 	if (info->kgdb_channel) {
-		MOD_DEC_USE_COUNT;
 		return -ENODEV;
 	}
 #endif
@@ -2610,6 +2604,7 @@
 
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.owner = THIS_MODULE;
 	serial_driver.driver_name = "macserial";
 #ifdef CONFIG_DEVFS_FS
 	serial_driver.name = "tts/";
diff -Nru a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
--- a/drivers/md/dm-ioctl.c	Wed Apr 30 09:20:30 2003
+++ b/drivers/md/dm-ioctl.c	Sat May 17 14:09:32 2003
@@ -278,6 +278,7 @@
 		DMWARN("asked to rename to an already existing name %s -> %s",
 		       old, new);
 		up_write(&_hash_lock);
+		kfree(new_name);
 		return -EBUSY;
 	}
 
@@ -289,6 +290,7 @@
 		DMWARN("asked to rename a non existent device %s -> %s",
 		       old, new);
 		up_write(&_hash_lock);
+		kfree(new_name);
 		return -ENXIO;
 	}
 
@@ -1113,7 +1115,6 @@
 	       DM_DRIVER_EMAIL);
 	return 0;
 
-      failed:
 	if (misc_deregister(&_dm_misc) < 0)
 		DMERR("misc_deregister failed for control device");
 	dm_hash_exit();
diff -Nru a/drivers/md/dm-target.c b/drivers/md/dm-target.c
--- a/drivers/md/dm-target.c	Thu Jan  2 03:27:04 2003
+++ b/drivers/md/dm-target.c	Sat May 17 12:39:13 2003
@@ -58,14 +58,7 @@
 
 static void load_module(const char *name)
 {
-	char module_name[DM_MOD_NAME_SIZE] = "dm-";
-
-	/* Length check for strcat() below */
-	if (strlen(name) > (DM_MOD_NAME_SIZE - 4))
-		return;
-
-	strcat(module_name, name);
-	request_module(module_name);
+	request_module("dm-%s", name);
 }
 
 struct target_type *dm_get_target_type(const char *name)
@@ -122,6 +115,8 @@
 		list_add(&ti->list, &_targets);
 
 	up_write(&_lock);
+	if (rv)
+		kfree(ti);
 	return rv;
 }
 
diff -Nru a/drivers/md/md.c b/drivers/md/md.c
--- a/drivers/md/md.c	Fri Apr 25 15:16:28 2003
+++ b/drivers/md/md.c	Sat May 17 12:39:13 2003
@@ -1111,8 +1111,10 @@
 
 static void print_desc(mdp_disk_t *desc)
 {
+	char b[BDEVNAME_SIZE];
+
 	printk(" DISK<N:%d,%s(%d,%d),R:%d,S:%d>\n", desc->number,
-		partition_name(MKDEV(desc->major,desc->minor)),
+		__bdevname(MKDEV(desc->major, desc->minor), b),
 		desc->major,desc->minor,desc->raid_disk,desc->state);
 }
 
@@ -1294,6 +1296,7 @@
  */
 static mdk_rdev_t *md_import_device(dev_t newdev, int super_format, int super_minor)
 {
+	char b[BDEVNAME_SIZE];
 	int err;
 	mdk_rdev_t *rdev;
 	sector_t size;
@@ -1301,7 +1304,7 @@
 	rdev = (mdk_rdev_t *) kmalloc(sizeof(*rdev), GFP_KERNEL);
 	if (!rdev) {
 		printk(KERN_ERR "md: could not alloc mem for %s!\n", 
-			partition_name(newdev));
+			__bdevname(newdev, b));
 		return ERR_PTR(-ENOMEM);
 	}
 	memset(rdev, 0, sizeof(*rdev));
@@ -1312,7 +1315,7 @@
 	err = lock_rdev(rdev, newdev);
 	if (err) {
 		printk(KERN_ERR "md: could not lock %s.\n",
-			partition_name(newdev));
+			__bdevname(newdev, b));
 		goto abort_free;
 	}
 	rdev->desc_nr = -1;
@@ -1561,9 +1564,7 @@
 #ifdef CONFIG_KMOD
 	if (!pers[pnum])
 	{
-		char module_name[80];
-		sprintf (module_name, "md-personality-%d", pnum);
-		request_module (module_name);
+		request_module("md-personality-%d", pnum);
 	}
 #endif
 
@@ -1840,6 +1841,7 @@
 
 static int autostart_array(dev_t startdev)
 {
+	char b[BDEVNAME_SIZE];
 	int err = -EINVAL, i;
 	mdp_super_t *sb = NULL;
 	mdk_rdev_t *start_rdev = NULL, *rdev;
@@ -1847,7 +1849,7 @@
 	start_rdev = md_import_device(startdev, 0, 0);
 	if (IS_ERR(start_rdev)) {
 		printk(KERN_WARNING "md: could not import %s!\n",
-			partition_name(startdev));
+			__bdevname(startdev, b));
 		return err;
 	}
 
@@ -1884,7 +1886,7 @@
 		if (IS_ERR(rdev)) {
 			printk(KERN_WARNING "md: could not import %s,"
 				" trying to run array nevertheless.\n",
-				partition_name(dev));
+				__bdevname(dev, b));
 			continue;
 		}
 		list_add(&rdev->same_set, &pending_raid_disks);
@@ -2116,6 +2118,7 @@
 
 static int hot_generate_error(mddev_t * mddev, dev_t dev)
 {
+	char b[BDEVNAME_SIZE];
 	struct request_queue *q;
 	mdk_rdev_t *rdev;
 
@@ -2123,7 +2126,7 @@
 		return -ENODEV;
 
 	printk(KERN_INFO "md: trying to generate %s error in md%d ... \n",
-		partition_name(dev), mdidx(mddev));
+		__bdevname(dev, b), mdidx(mddev));
 
 	rdev = find_rdev(mddev, dev);
 	if (!rdev) {
@@ -2151,13 +2154,14 @@
 
 static int hot_remove_disk(mddev_t * mddev, dev_t dev)
 {
+	char b[BDEVNAME_SIZE];
 	mdk_rdev_t *rdev;
 
 	if (!mddev->pers)
 		return -ENODEV;
 
 	printk(KERN_INFO "md: trying to remove %s from md%d ... \n",
-		partition_name(dev), mdidx(mddev));
+		__bdevname(dev, b), mdidx(mddev));
 
 	rdev = find_rdev(mddev, dev);
 	if (!rdev)
@@ -2178,6 +2182,7 @@
 
 static int hot_add_disk(mddev_t * mddev, dev_t dev)
 {
+	char b[BDEVNAME_SIZE];
 	int err;
 	unsigned int size;
 	mdk_rdev_t *rdev;
@@ -2186,7 +2191,7 @@
 		return -ENODEV;
 
 	printk(KERN_INFO "md: trying to hot-add %s to md%d ... \n",
-		partition_name(dev), mdidx(mddev));
+		__bdevname(dev, b), mdidx(mddev));
 
 	if (mddev->major_version != 0) {
 		printk(KERN_WARNING "md%d: HOT_ADD may only be used with"
@@ -2344,6 +2349,7 @@
 static int md_ioctl(struct inode *inode, struct file *file,
 			unsigned int cmd, unsigned long arg)
 {
+	char b[BDEVNAME_SIZE];
 	unsigned int minor;
 	int err = 0;
 	struct hd_geometry *loc = (struct hd_geometry *) arg;
@@ -2403,7 +2409,7 @@
 		err = autostart_array(arg);
 		if (err) {
 			printk(KERN_WARNING "md: autostart %s failed!\n",
-				partition_name(arg));
+				__bdevname(arg, b));
 			goto abort;
 		}
 		goto done;
@@ -3516,6 +3522,7 @@
 
 static void autostart_arrays(void)
 {
+	char b[BDEVNAME_SIZE];
 	mdk_rdev_t *rdev;
 	int i;
 
@@ -3527,7 +3534,7 @@
 		rdev = md_import_device(dev,0, 0);
 		if (IS_ERR(rdev)) {
 			printk(KERN_ALERT "md: could not import %s!\n",
-				partition_name(dev));
+				__bdevname(dev, b));
 			continue;
 		}
 		if (rdev->faulty) {
diff -Nru a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
--- a/drivers/media/dvb/dvb-core/dvbdev.c	Sat Apr 19 01:48:24 2003
+++ b/drivers/media/dvb/dvb-core/dvbdev.c	Wed May  7 07:40:35 2003
@@ -189,7 +189,6 @@
 			const struct dvb_device *template, void *priv, int type)
 {
 	u32 id;
-	char name [20];
 	struct dvb_device *dvbdev;
 
 	if (down_interruptible (&dvbdev_register_lock))
@@ -219,12 +218,12 @@
 
 	list_add_tail (&dvbdev->list_head, &adap->device_list);
 
-	sprintf(name, "dvb/adapter%d%s%d", adap->num, dnames[type], id);
-	devfs_register(NULL, name, 0, DVB_MAJOR, nums2minor(adap->num, type, id),
-			S_IFCHR | S_IRUSR | S_IWUSR, dvbdev->fops, dvbdev);
+	devfs_mk_cdev(MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)),
+			S_IFCHR | S_IRUSR | S_IWUSR,
+			"dvb/adapter%d/%s%d", adap->num, dnames[type], id);
 
-	dprintk("DVB: register adapter%d/%s @ minor: %i (0x%02x)\n",
-		adap->num, name, nums2minor(adap->num, type, id),
+	dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n",
+		adap->num, dnames[type], id, nums2minor(adap->num, type, id),
 		nums2minor(adap->num, type, id));
 
 	return 0;
@@ -234,7 +233,7 @@
 void dvb_unregister_device(struct dvb_device *dvbdev)
 {
 	if (dvbdev) {
-		devfs_remove("dvb/adapter%d%s%d", dvbdev->adapter->num,
+		devfs_remove("dvb/adapter%d/%s%d", dvbdev->adapter->num,
 				dnames[dvbdev->type], dvbdev->id);
 		list_del(&dvbdev->list_head);
 		kfree(dvbdev);
@@ -322,12 +321,12 @@
 int __init init_dvbdev(void)
 {
 	devfs_mk_dir("dvb");
-#ifndef CONFIG_DVB_DEVFS_ONLY
+
 	if(register_chrdev(DVB_MAJOR,"DVB", &dvb_device_fops)) {
 		printk("video_dev: unable to get major %d\n", DVB_MAJOR);
 		return -EIO;
 	}
-#endif
+
 	return 0;
 }
 
@@ -335,9 +334,7 @@
 static 
 void __exit exit_dvbdev(void)
 {
-#ifndef CONFIG_DVB_DEVFS_ONLY
 	unregister_chrdev(DVB_MAJOR, "DVB");
-#endif
         devfs_remove("dvb");
 }
 
diff -Nru a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
--- a/drivers/media/radio/miropcm20-rds.c	Wed Apr 30 09:21:08 2003
+++ b/drivers/media/radio/miropcm20-rds.c	Wed May 14 23:44:01 2003
@@ -12,6 +12,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/fs.h>
 #include <linux/miscdevice.h>
 #include <asm/uaccess.h>
 #include "miropcm20-rds-core.h"
diff -Nru a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
--- a/drivers/media/video/bt819.c	Sat Mar 22 23:17:51 2003
+++ b/drivers/media/video/bt819.c	Wed May 14 23:43:59 2003
@@ -167,6 +167,7 @@
 	decoder = kmalloc(sizeof(struct bt819), GFP_KERNEL);
 	if (decoder == NULL) {
 		MOD_DEC_USE_COUNT;
+		kfree(client);
 		return -ENOMEM;
 	}
 
diff -Nru a/drivers/media/video/bt832.c b/drivers/media/video/bt832.c
--- a/drivers/media/video/bt832.c	Tue Feb 18 10:50:38 2003
+++ b/drivers/media/video/bt832.c	Tue May  6 08:21:42 2003
@@ -198,25 +198,9 @@
 
 static int bt832_probe(struct i2c_adapter *adap)
 {
-	int rc;
-
-	printk("bt832_probe\n");
-
-	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-	case I2C_ALGO_SAA7134:
-		printk("bt832: probing %s i2c adapter [id=0x%x]\n",
-		       adap->name,adap->id);
-		rc = i2c_probe(adap, &addr_data, bt832_attach);
-		break;
-	default:
-		printk("bt832: ignoring %s i2c adapter [id=0x%x]\n",
-		       adap->name,adap->id);
-		rc = 0;
-		/* nothing */
-	}
-	return rc;
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
+		return i2c_probe(adap, &addr_data, bt832_attach);
+	return 0;
 }
 
 static int bt832_detach(struct i2c_client *client)
diff -Nru a/drivers/media/video/bttv-if.c b/drivers/media/video/bttv-if.c
--- a/drivers/media/video/bttv-if.c	Sat Mar 22 23:17:51 2003
+++ b/drivers/media/video/bttv-if.c	Tue May  6 08:54:00 2003
@@ -7,7 +7,7 @@
 
     Copyright (C) 1996,97,98 Ralph  Metzler (rjkm@thp.uni-koeln.de)
                            & Marcus Metzler (mocm@thp.uni-koeln.de)
-    (c) 1999,2000 Gerd Knorr <kraxel@goldbach.in-berlin.de>
+    (c) 1999-2003 Gerd Knorr <kraxel@bytesex.org>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -195,51 +195,21 @@
 static int attach_inform(struct i2c_client *client)
 {
         struct bttv *btv = i2c_get_adapdata(client->adapter);
-	int i;
 
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (btv->i2c_clients[i] == NULL) {
-			btv->i2c_clients[i] = client;
-			break;
-		}
-	}
-	if (btv->tuner_type != -1)
+	if (btv->tuner_type != UNSET)
 		bttv_call_i2c_clients(btv,TUNER_SET_TYPE,&btv->tuner_type);
-        if (bttv_verbose)
-		printk("bttv%d: i2c attach [client=%s,%s]\n",btv->nr,
-		       client->dev.name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
-        return 0;
-}
-
-static int detach_inform(struct i2c_client *client)
-{
-        struct bttv *btv = i2c_get_adapdata(client->adapter);
-	int i;
 
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (btv->i2c_clients[i] == client) {
-			btv->i2c_clients[i] = NULL;
-			break;
-		}
-	}
-        if (bttv_verbose)
-		printk("bttv%d: i2c detach [client=%s,%s]\n",btv->nr,
-		       client->dev.name, (i < I2C_CLIENTS_MAX) ?  "ok" : "failed");
+        if (bttv_debug)
+		printk("bttv%d: i2c attach [client=%s]\n",
+		       btv->nr, i2c_clientname(client));
         return 0;
 }
 
 void bttv_call_i2c_clients(struct bttv *btv, unsigned int cmd, void *arg)
 {
-	int i;
-	
-	for (i = 0; i < I2C_CLIENTS_MAX; i++) {
-		if (NULL == btv->i2c_clients[i])
-			continue;
-		if (NULL == btv->i2c_clients[i]->driver->command)
-			continue;
-		btv->i2c_clients[i]->driver->command(
-			btv->i2c_clients[i],cmd,arg);
-	}
+	if (0 != btv->i2c_rc)
+		return;
+	i2c_clients_command(&btv->i2c_adap, cmd, arg);
 }
 
 void bttv_i2c_call(unsigned int card, unsigned int cmd, void *arg)
@@ -260,20 +230,16 @@
 };
 
 static struct i2c_adapter bttv_i2c_adap_template = {
-	.owner          = THIS_MODULE,
+	.owner             = THIS_MODULE,
+	I2C_DEVNAME("bt848"),
 	.id                = I2C_HW_B_BT848,
+	.class             = I2C_ADAP_CLASS_TV_ANALOG,
 	.client_register   = attach_inform,
-	.client_unregister = detach_inform,
-	.dev		= {
-		.name	= "bt848",
-	},
 };
 
 static struct i2c_client bttv_i2c_client_template = {
-        .id	= -1,
-        .dev	= {
-		.name = "bttv internal",
-	},
+	I2C_DEVNAME("bttv internal"),
+        .id       = -1,
 };
 
 
@@ -347,8 +313,8 @@
 	memcpy(&btv->i2c_client, &bttv_i2c_client_template,
 	       sizeof(struct i2c_client));
 
-	sprintf(btv->i2c_adap.dev.name+strlen(btv->i2c_adap.dev.name),
-		" #%d", btv->nr);
+	sprintf(btv->i2c_adap.dev.name, "bt848 #%d", btv->nr);
+
         btv->i2c_algo.data = btv;
         i2c_set_adapdata(&btv->i2c_adap, btv);
         btv->i2c_adap.algo_data = &btv->i2c_algo;
diff -Nru a/drivers/media/video/bttv.h b/drivers/media/video/bttv.h
--- a/drivers/media/video/bttv.h	Wed Jan  8 01:59:58 2003
+++ b/drivers/media/video/bttv.h	Tue May  6 08:00:34 2003
@@ -243,7 +243,6 @@
 
 
 /* i2c */
-#define I2C_CLIENTS_MAX 16
 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 -Nru a/drivers/media/video/bttvp.h b/drivers/media/video/bttvp.h
--- a/drivers/media/video/bttvp.h	Wed Mar 12 06:07:06 2003
+++ b/drivers/media/video/bttvp.h	Tue May  6 07:55:01 2003
@@ -62,6 +62,8 @@
 #define RAW_LINES            640
 #define RAW_BPL             1024
 
+#define UNSET (-1U)
+
 /* ---------------------------------------------------------- */
 
 struct bttv_tvnorm 
@@ -276,7 +278,6 @@
 	struct i2c_algo_bit_data   i2c_algo;
 	struct i2c_client          i2c_client;
 	int                        i2c_state, i2c_rc;
-	struct i2c_client         *i2c_clients[I2C_CLIENTS_MAX];
 
 	/* video4linux (1) */
 	struct video_device video_dev;
diff -Nru a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
--- a/drivers/media/video/cpia.c	Thu Apr 24 03:35:15 2003
+++ b/drivers/media/video/cpia.c	Tue May  6 07:30:51 2003
@@ -1409,12 +1409,10 @@
 		LOG("Unable to initialise /proc/cpia\n");
 }
 
-#ifdef MODULE
-static void proc_cpia_destroy(void)
+static void __exit proc_cpia_destroy(void)
 {
 	remove_proc_entry("cpia", 0);
 }
-#endif /*MODULE*/
 #endif /* CONFIG_PROC_FS */
 
 /* ----------------------- debug functions ---------------------- */
diff -Nru a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
--- a/drivers/media/video/dpc7146.c	Mon Apr  7 13:17:33 2003
+++ b/drivers/media/video/dpc7146.c	Tue May  6 04:55:30 2003
@@ -96,7 +96,8 @@
 static int dpc_probe(struct saa7146_dev* dev)
 {
 	struct dpc* dpc = 0;	
-	int i = 0;
+	struct i2c_client *client;
+	struct list_head *item;
 
 	dpc = (struct dpc*)kmalloc(sizeof(struct dpc), GFP_KERNEL);
 	if( NULL == dpc ) {
@@ -117,12 +118,10 @@
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	for(i = 0; i < I2C_CLIENT_MAX; i++) {
-		if( NULL == dpc->i2c_adapter.clients[i] ) {
-			continue;
-		}
-		if( I2C_SAA7111A == dpc->i2c_adapter.clients[i]->addr ) 
-			dpc->saa7111a = dpc->i2c_adapter.clients[i];
+	list_for_each(item,&dpc->i2c_adapter.clients) {
+		client = list_entry(item, struct i2c_client, list);
+		if( I2C_SAA7111A == client->addr ) 
+			dpc->saa7111a = client;
 	}
 
 	/* check if all devices are present */
diff -Nru a/drivers/media/video/msp3400.c b/drivers/media/video/msp3400.c
--- a/drivers/media/video/msp3400.c	Thu Apr 24 04:11:51 2003
+++ b/drivers/media/video/msp3400.c	Sat May 17 14:09:44 2003
@@ -45,13 +45,11 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/videodev.h>
-#include <asm/semaphore.h>
 #include <linux/init.h>
-
-#ifdef CONFIG_SMP
-#include <asm/pgtable.h>
 #include <linux/smp_lock.h>
-#endif
+#include <asm/semaphore.h>
+#include <asm/pgtable.h>
+
 /* kernel_thread */
 #define __KERNEL_SYSCALLS__
 #include <linux/unistd.h>
@@ -59,18 +57,13 @@
 #include <media/audiochip.h>
 #include "msp3400.h"
 
-/* Addresses to scan */
-static unsigned short normal_i2c[] = {I2C_CLIENT_END};
-static unsigned short normal_i2c_range[] = {0x40,0x40,I2C_CLIENT_END};
-I2C_CLIENT_INSMOD;
-
 /* insmod parameters */
-static int debug   = 0;    /* debug output */
-static int once    = 0;    /* no continous stereo monitoring */
-static int amsound = 0;    /* hard-wire AM sound at 6.5 Hz (france),
+static int debug    = 0;    /* debug output */
+static int once     = 0;    /* no continous stereo monitoring */
+static int amsound  = 0;    /* hard-wire AM sound at 6.5 Hz (france),
 			      the autoscan seems work well only with FM... */
-static int simple  = -1;   /* use short programming (>= msp3410 only) */
-static int dolby   = 0;
+static int simple   = -1;   /* use short programming (>= msp3410 only) */
+static int dolby    = 0;
 
 #define DFP_COUNT 0x41
 static const int bl_dfp[] = {
@@ -79,8 +72,9 @@
 };
 
 struct msp3400c {
+	int rev1,rev2;
+	
 	int simple;
-	int nicam;
 	int mode;
 	int norm;
 	int stereo;
@@ -107,6 +101,10 @@
 	struct timer_list    wake_stereo;
 };
 
+#define HAVE_NICAM(msp)   (((msp->rev2>>8) & 0xff) != 00)
+#define HAVE_SIMPLE(msp)  ((msp->rev1      & 0xff) >= 'D'-'@')
+#define HAVE_RADIO(msp)   ((msp->rev1      & 0xff) >= 'G'-'@')
+
 #define MSP3400_MAX 4
 static struct i2c_client *msps[MSP3400_MAX];
 
@@ -124,14 +122,25 @@
 
 MODULE_DESCRIPTION("device driver for msp34xx TV sound processor");
 MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("Dual BSD/GPL"); /* FreeBSD uses this too */
 
 /* ---------------------------------------------------------------------- */
 
 #define I2C_MSP3400C       0x80
+#define I2C_MSP3400C_ALT   0x88
+
 #define I2C_MSP3400C_DEM   0x10
 #define I2C_MSP3400C_DFP   0x12
 
+/* Addresses to scan */
+static unsigned short normal_i2c[] = {
+	I2C_MSP3400C      >> 1,
+	I2C_MSP3400C_ALT  >> 1,
+	I2C_CLIENT_END
+};
+static unsigned short normal_i2c_range[] = {I2C_CLIENT_END,I2C_CLIENT_END};
+I2C_CLIENT_INSMOD;
+
 /* ----------------------------------------------------------------------- */
 /* functions for talking to the MSP3400C Sound processor                   */
 
@@ -354,7 +363,8 @@
 	if (-1 == scarts[out][in])
 		return;
 
-	dprintk("msp34xx: scart switch: %s => %d\n",scart_names[in],out);
+	dprintk(KERN_DEBUG
+		"msp34xx: scart switch: %s => %d\n",scart_names[in],out);
 	msp->acb &= ~scarts[out][SCART_MASK];
 	msp->acb |=  scarts[out][in];
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0013, msp->acb);
@@ -384,7 +394,8 @@
 		balance = ((right-left) * 127) / vol;
 	}
 
-	dprintk("msp34xx: setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
+	dprintk(KERN_DEBUG
+		"msp34xx: setvolume: mute=%s %d:%d  v=0x%02x b=0x%02x\n",
 		muted ? "on" : "off", left, right, val>>8, balance);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0000, val); /* loudspeaker */
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0006, val); /* headphones  */
@@ -397,7 +408,7 @@
 {
 	int val = ((bass-32768) * 0x60 / 65535) << 8;
 
-	dprintk("msp34xx: setbass: %d 0x%02x\n",bass, val>>8);
+	dprintk(KERN_DEBUG "msp34xx: setbass: %d 0x%02x\n",bass, val>>8);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0002, val); /* loudspeaker */
 }
 
@@ -405,7 +416,7 @@
 {
 	int val = ((treble-32768) * 0x60 / 65535) << 8;
 
-	dprintk("msp34xx: settreble: %d 0x%02x\n",treble, val>>8);
+	dprintk(KERN_DEBUG "msp34xx: settreble: %d 0x%02x\n",treble, val>>8);
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x0003, val); /* loudspeaker */
 }
 
@@ -414,7 +425,7 @@
 	struct msp3400c *msp = i2c_get_clientdata(client);
 	int i;
 	
-	dprintk("msp3400: setmode: %d\n",type);
+	dprintk(KERN_DEBUG "msp3400: setmode: %d\n",type);
 	msp->mode   = type;
 	msp->stereo = VIDEO_SOUND_MONO;
 
@@ -460,7 +471,7 @@
 	msp3400c_write(client,I2C_MSP3400C_DFP, 0x000e,
 		       msp_init_data[type].dfp_matrix);
 
-	if (msp->nicam) {
+	if (HAVE_NICAM(msp)) {
 		/* nicam prescale */
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0010, 0x5a00); /* was: 0x3000 */
 	}
@@ -469,8 +480,15 @@
 /* turn on/off nicam + stereo */
 static void msp3400c_setstereo(struct i2c_client *client, int mode)
 {
-	static char *strmode[] = { "0", "mono", "stereo", "3",
-				   "lang1", "5", "6", "7", "lang2" };
+	static char *strmode[16] = {
+#if __GNUC__ >= 3
+		[ 0 ... 15 ]           = "invalid",
+#endif
+		[ VIDEO_SOUND_MONO ]   = "mono",
+		[ VIDEO_SOUND_STEREO ] = "stereo",
+		[ VIDEO_SOUND_LANG1  ] = "lang1",
+		[ VIDEO_SOUND_LANG2  ] = "lang2",
+	};
 	struct msp3400c *msp = i2c_get_clientdata(client);
 	int nicam=0; /* channel source: FM/AM or nicam */
 	int src=0;
@@ -478,7 +496,7 @@
 	/* switch demodulator */
 	switch (msp->mode) {
 	case MSP_MODE_FM_TERRA:
-		dprintk("msp3400: FM setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: FM setstereo: %s\n",strmode[mode]);
 		msp3400c_setcarrier(client,msp->second,msp->main);
 		switch (mode) {
 		case VIDEO_SOUND_STEREO:
@@ -492,7 +510,7 @@
 		}
 		break;
 	case MSP_MODE_FM_SAT:
-		dprintk("msp3400: SAT setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: SAT setstereo: %s\n",strmode[mode]);
 		switch (mode) {
 		case VIDEO_SOUND_MONO:
 			msp3400c_setcarrier(client, MSP_CARRIER(6.5), MSP_CARRIER(6.5));
@@ -511,24 +529,24 @@
 	case MSP_MODE_FM_NICAM1:
 	case MSP_MODE_FM_NICAM2:
 	case MSP_MODE_AM_NICAM:
-		dprintk("msp3400: NICAM setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: NICAM setstereo: %s\n",strmode[mode]);
 		msp3400c_setcarrier(client,msp->second,msp->main);
 		if (msp->nicam_on)
 			nicam=0x0100;
 		break;
 	case MSP_MODE_BTSC:
-		dprintk("msp3400: BTSC setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: BTSC setstereo: %s\n",strmode[mode]);
 		nicam=0x0300;
 		break;
 	case MSP_MODE_EXTERN:
-		dprintk("msp3400: extern setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: extern setstereo: %s\n",strmode[mode]);
 		nicam = 0x0200;
 		break;
 	case MSP_MODE_FM_RADIO:
-		dprintk("msp3400: FM-Radio setstereo: %s\n",strmode[mode]);
+		dprintk(KERN_DEBUG "msp3400: FM-Radio setstereo: %s\n",strmode[mode]);
 		break;
 	default:
-		dprintk("msp3400: mono setstereo\n");
+		dprintk(KERN_DEBUG "msp3400: mono setstereo\n");
 		return;
 	}
 
@@ -557,7 +575,8 @@
 		src = 0x0010 | nicam;
 		break;
 	}
-	dprintk("msp3400: setstereo final source/matrix = 0x%x\n", src);
+	dprintk(KERN_DEBUG
+		"msp3400: setstereo final source/matrix = 0x%x\n", src);
 
 	if (dolby) {
 		msp3400c_write(client,I2C_MSP3400C_DFP, 0x0008,0x0520);
@@ -576,22 +595,22 @@
 msp3400c_print_mode(struct msp3400c *msp)
 {
 	if (msp->main == msp->second) {
-		printk("msp3400: mono sound carrier: %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: mono sound carrier: %d.%03d MHz\n",
 		       msp->main/910000,(msp->main/910)%1000);
 	} else {
-		printk("msp3400: main sound carrier: %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: main sound carrier: %d.%03d MHz\n",
 		       msp->main/910000,(msp->main/910)%1000);
 	}
 	if (msp->mode == MSP_MODE_FM_NICAM1 ||
 	    msp->mode == MSP_MODE_FM_NICAM2)
-		printk("msp3400: NICAM/FM carrier   : %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: NICAM/FM carrier   : %d.%03d MHz\n",
 		       msp->second/910000,(msp->second/910)%1000);
 	if (msp->mode == MSP_MODE_AM_NICAM)
-		printk("msp3400: NICAM/AM carrier   : %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: NICAM/AM carrier   : %d.%03d MHz\n",
 		       msp->second/910000,(msp->second/910)%1000);
 	if (msp->mode == MSP_MODE_FM_TERRA &&
 	    msp->main != msp->second) {
-		printk("msp3400: FM-stereo carrier : %d.%03d MHz\n",
+		printk(KERN_DEBUG "msp3400: FM-stereo carrier : %d.%03d MHz\n",
 		       msp->second/910000,(msp->second/910)%1000);
 	}
 }
@@ -638,8 +657,8 @@
 		val = msp3400c_read(client, I2C_MSP3400C_DFP, 0x18);
 		if (val > 32767)
 			val -= 65536;
-		dprintk("msp34xx: stereo detect register: %d\n",val);
-		
+		dprintk(KERN_DEBUG
+			"msp34xx: stereo detect register: %d\n",val);
 		if (val > 4096) {
 			newstereo = VIDEO_SOUND_STEREO | VIDEO_SOUND_MONO;
 		} else if (val < -4096) {
@@ -653,7 +672,9 @@
 	case MSP_MODE_FM_NICAM2:
 	case MSP_MODE_AM_NICAM:
 		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x23);
-		dprintk("msp34xx: nicam sync=%d, mode=%d\n",val & 1, (val & 0x1e) >> 1);
+		dprintk(KERN_DEBUG
+			"msp34xx: nicam sync=%d, mode=%d\n",
+			val & 1, (val & 0x1e) >> 1);
 
 		if (val & 1) {
 			/* nicam synced */
@@ -685,7 +706,8 @@
 		break;
 	case MSP_MODE_BTSC:
 		val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x200);
-		dprintk("msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
+		dprintk(KERN_DEBUG
+			"msp3410: status=0x%x (pri=%s, sec=%s, %s%s%s)\n",
 			val,
 			(val & 0x0002) ? "no"     : "yes",
 			(val & 0x0004) ? "no"     : "yes",
@@ -699,13 +721,13 @@
 	}
 	if (newstereo != msp->stereo) {
 		update = 1;
-		dprintk("msp34xx: watch: stereo %d => %d\n",
+		dprintk(KERN_DEBUG "msp34xx: watch: stereo %d => %d\n",
 			msp->stereo,newstereo);
 		msp->stereo   = newstereo;
 	}
 	if (newnicam != msp->nicam_on) {
 		update = 1;
-		dprintk("msp34xx: watch: nicam %d => %d\n",
+		dprintk(KERN_DEBUG "msp34xx: watch: nicam %d => %d\n",
 			msp->nicam_on,newnicam);
 		msp->nicam_on = newnicam;
 	}
@@ -734,6 +756,8 @@
 			msp3400c_setstereo(client,VIDEO_SOUND_STEREO);
 		else if (msp->stereo & VIDEO_SOUND_LANG1)
 			msp3400c_setstereo(client,VIDEO_SOUND_LANG1);
+		else if (msp->stereo & VIDEO_SOUND_LANG2)
+			msp3400c_setstereo(client,VIDEO_SOUND_LANG2);
 		else
 			msp3400c_setstereo(client,VIDEO_SOUND_MONO);
 	}
@@ -751,17 +775,10 @@
 	struct CARRIER_DETECT *cd;
 	int count, max1,max2,val1,val2, val,this;
 	
-#ifdef CONFIG_SMP
 	lock_kernel();
-#endif
-	
 	daemonize("msp3400");
-
 	msp->thread = current;
-
-#ifdef CONFIG_SMP
 	unlock_kernel();
-#endif
 
 	printk("msp3400: daemon started\n");
 	if(msp->notify != NULL)
@@ -778,10 +795,6 @@
 		if (msp->rmmod || signal_pending(current))
 			goto done;
 
-		if (VIDEO_MODE_RADIO == msp->norm ||
-		    MSP_MODE_EXTERN  == msp->mode)
-			continue;  /* nothing to do */
-	
 		msp->active = 1;
 
 		if (msp->watch_stereo) {
@@ -798,8 +811,13 @@
 		
 	restart:
 		if (VIDEO_MODE_RADIO == msp->norm ||
-		    MSP_MODE_EXTERN  == msp->mode)
-			continue;  /* nothing to do */
+		    MSP_MODE_EXTERN  == msp->mode) {
+			/* no carrier scan, just unmute */
+			printk("msp3400: thread: no carrier scan\n");
+			msp3400c_setvolume(client, msp->muted,
+					   msp->left, msp->right);
+			continue;
+		}
 		msp->restart = 0;
 		msp3400c_setvolume(client, msp->muted, 0, 0);
 		msp3400c_setmode(client, MSP_MODE_AM_DETECT /* +1 */ );
@@ -884,7 +902,7 @@
 				msp->nicam_on = 0;
 				msp3400c_setstereo(client, VIDEO_SOUND_MONO);
 				msp->watch_stereo = 1;
-			} else if (max2 == 1 && msp->nicam) {
+			} else if (max2 == 1 && HAVE_NICAM(msp)) {
 				/* B/G NICAM */
 				msp->second = carrier_detect_55[max2].cdo;
 				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
@@ -922,7 +940,7 @@
 				/* volume prescale for SCART (AM mono input) */
 				msp3400c_write(client,I2C_MSP3400C_DFP, 0x000d, 0x1900);
 				msp->watch_stereo = 1;
-			} else if (max2 == 0 && msp->nicam) {
+			} else if (max2 == 0 && HAVE_NICAM(msp)) {
 				/* D/K NICAM */
 				msp->second = carrier_detect_65[max2].cdo;
 				msp3400c_setmode(client, MSP_MODE_FM_NICAM1);
@@ -959,7 +977,7 @@
 	}
 
 done:
-	dprintk("msp3400: thread: exit\n");
+	dprintk(KERN_DEBUG "msp3400: thread: exit\n");
 	msp->active = 0;
 	msp->thread = NULL;
 
@@ -1005,17 +1023,10 @@
 	struct msp3400c *msp = i2c_get_clientdata(client);
 	int mode,val,i,std;
     
-#ifdef CONFIG_SMP
 	lock_kernel();
-#endif
-    
 	daemonize("msp3410 [auto]");
-
 	msp->thread = current;
-
-#ifdef CONFIG_SMP
 	unlock_kernel();
-#endif
 
 	printk("msp3410: daemon started\n");
 	if(msp->notify != NULL)
@@ -1025,16 +1036,13 @@
 		if (msp->rmmod)
 			goto done;
 		if (debug > 1)
-			printk("msp3410: thread: sleep\n");
+			printk(KERN_DEBUG "msp3410: thread: sleep\n");
 		interruptible_sleep_on(&msp->wq);
 		if (debug > 1)
-			printk("msp3410: thread: wakeup\n");
+			printk(KERN_DEBUG "msp3410: thread: wakeup\n");
 		if (msp->rmmod || signal_pending(current))
 			goto done;
 
-		if (msp->mode == MSP_MODE_EXTERN)
-			continue;
-		
 		msp->active = 1;
 
 		if (msp->watch_stereo) {
@@ -1050,8 +1058,13 @@
 			goto done;
 
 	restart:
-		if (msp->mode == MSP_MODE_EXTERN)
+		if (msp->mode == MSP_MODE_EXTERN) {
+			/* no carrier scan needed, just unmute */
+			dprintk(KERN_DEBUG "msp3410: thread: no carrier scan\n");
+			msp3400c_setvolume(client, msp->muted,
+					   msp->left, msp->right);
 			continue;
+		}
 		msp->restart = 0;
 		del_timer(&msp->wake_stereo);
 		msp->watch_stereo = 0;
@@ -1073,7 +1086,7 @@
 			mode = 0x0003;
 			std  = 1;
 			break;
-		case VIDEO_MODE_RADIO: 
+		case VIDEO_MODE_RADIO:
 			mode = 0x0003;
 			std  = 0x0040;
 			break;
@@ -1090,7 +1103,7 @@
 			for (i = 0; modelist[i].name != NULL; i++)
 				if (modelist[i].retval == std)
 					break;
-			printk("msp3410: setting mode: %s (0x%04x)\n",
+			printk(KERN_DEBUG "msp3410: setting mode: %s (0x%04x)\n",
 			       modelist[i].name ? modelist[i].name : "unknown",std);
 		}
 
@@ -1111,13 +1124,13 @@
 				val = msp3400c_read(client, I2C_MSP3400C_DEM, 0x7e);
 				if (val < 0x07ff)
 					break;
-				dprintk("msp3410: detection still in progress\n");
+				dprintk(KERN_DEBUG "msp3410: detection still in progress\n");
 			}
 		}
 		for (i = 0; modelist[i].name != NULL; i++)
 			if (modelist[i].retval == val)
 				break;
-		dprintk("msp3410: current mode: %s (0x%04x)\n",
+		dprintk(KERN_DEBUG "msp3410: current mode: %s (0x%04x)\n",
 			modelist[i].name ? modelist[i].name : "unknown",
 			val);
 		msp->main   = modelist[i].main;
@@ -1125,7 +1138,8 @@
 
 		if (amsound && (msp->norm == VIDEO_MODE_SECAM) && (val != 0x0009)) {
 			/* autodetection has failed, let backup */
-			dprintk("msp3410: autodetection failed, switching to backup mode: %s (0x%04x)\n",
+			dprintk(KERN_DEBUG "msp3410: autodetection failed,"
+				" switching to backup mode: %s (0x%04x)\n",
 				modelist[8].name ? modelist[8].name : "unknown",val);
 			val = 0x0009;
 			msp3400c_write(client, I2C_MSP3400C_DEM, 0x20, val);
@@ -1170,11 +1184,24 @@
 			msp->stereo = VIDEO_SOUND_STEREO;
 			msp->nicam_on = 0;
 			msp->watch_stereo = 0;
+			/* not needed in theory if HAVE_RADIO(), but
+			   short programming enables carrier mute */
+			msp3400c_setmode(client,MSP_MODE_FM_RADIO);
+			msp3400c_setcarrier(client, MSP_CARRIER(10.7),
+					    MSP_CARRIER(10.7));
 			/* scart routing */
 			msp3400c_set_scart(client,SCART_IN2,0);
+#if 0
+			/* radio from SCART_IN2 */
 			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0220);
 			msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0220);
 			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0220);
+#else
+			/* msp34xx does radio decoding */
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x08, 0x0020);
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x09, 0x0020);
+			msp3400c_write(client,I2C_MSP3400C_DFP, 0x0b, 0x0020);
+#endif
 			break;
 		case 0x0003:
 			msp->mode   = MSP_MODE_FM_TERRA;
@@ -1197,7 +1224,7 @@
 	}
 
 done:
-	dprintk("msp3410: thread: exit\n");
+	dprintk(KERN_DEBUG "msp3410: thread: exit\n");
 	msp->active = 0;
 	msp->thread = NULL;
 
@@ -1225,11 +1252,9 @@
 
 static struct i2c_client client_template = 
 {
-	.flags  = I2C_CLIENT_ALLOW_USE,
-        .driver = &driver,
-	.dev	= {
-		.name   = "(unset)",
-	},
+	I2C_DEVNAME("(unset)"),
+	.flags     = I2C_CLIENT_ALLOW_USE,
+        .driver    = &driver,
 };
 
 static int msp_attach(struct i2c_adapter *adap, int addr, int kind)
@@ -1237,7 +1262,7 @@
 	DECLARE_MUTEX_LOCKED(sem);
 	struct msp3400c *msp;
         struct i2c_client *c;
-	int              rev1,rev2,i;
+	int i;
 
         client_template.adapter = adap;
         client_template.addr = addr;
@@ -1275,10 +1300,10 @@
 		return -1;
 	}
     
-	rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
-	if (-1 != rev1)
-		rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
-	if ((-1 == rev1) || (0 == rev1 && 0 == rev2)) {
+	msp->rev1 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1e);
+	if (-1 != msp->rev1)
+		msp->rev2 = msp3400c_read(c, I2C_MSP3400C_DFP, 0x1f);
+	if ((-1 == msp->rev1) || (0 == msp->rev1 && 0 == msp->rev2)) {
 		kfree(msp);
 		kfree(c);
 		printk("msp3400: error while reading chip version\n");
@@ -1292,13 +1317,12 @@
 	msp3400c_setvolume(c,msp->muted,msp->left,msp->right);
 
 	snprintf(c->dev.name, DEVICE_NAME_SIZE, "MSP34%02d%c-%c%d",
-		(rev2>>8)&0xff, (rev1&0xff)+'@', ((rev1>>8)&0xff)+'@', rev2&0x1f);
-	msp->nicam = (((rev2>>8)&0xff) != 00) ? 1 : 0;
+		 (msp->rev2>>8)&0xff, (msp->rev1&0xff)+'@',
+		 ((msp->rev1>>8)&0xff)+'@', msp->rev2&0x1f);
 
 	if (simple == -1) {
 		/* default mode */
-		/* msp->simple = (((rev2>>8)&0xff) == 0) ? 0 : 1; */
-		msp->simple = ((rev1&0xff)+'@' > 'C');
+		msp->simple = HAVE_SIMPLE(msp);
 	} else {
 		/* use insmod option */
 		msp->simple = simple;
@@ -1310,13 +1334,16 @@
 	msp->wake_stereo.data     = (unsigned long)msp;
 
 	/* hello world :-) */
-	printk(KERN_INFO "msp34xx: init: chip=%s",c->dev.name);
-	if (msp->nicam)
-		printk(", has NICAM support");
+	printk(KERN_INFO "msp34xx: init: chip=%s",i2c_clientname(c));
+	if (HAVE_NICAM(msp))
+		printk(" +nicam");
+	if (HAVE_SIMPLE(msp))
+		printk(" +simple");
+	if (HAVE_RADIO(msp))
+		printk(" +radio");
 	printk("\n");
 
 	/* startup control thread */
-	MOD_INC_USE_COUNT;
 	msp->notify = &sem;
 	kernel_thread(msp->simple ? msp3410d_thread : msp3400c_thread,
 		      (void *)c, 0);
@@ -1340,7 +1367,7 @@
 static int msp_detach(struct i2c_client *client)
 {
 	DECLARE_MUTEX_LOCKED(sem);
-	struct msp3400c *msp = i2c_get_clientdata(client);
+	struct msp3400c *msp  = i2c_get_clientdata(client);
 	int i;
 	
 	/* shutdown control thread */
@@ -1366,20 +1393,19 @@
 	i2c_detach_client(client);
 	kfree(msp);
 	kfree(client);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
 static int msp_probe(struct i2c_adapter *adap)
 {
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, msp_attach);
 	return 0;
 }
 
 static void msp_wake_thread(struct i2c_client *client)
 {
-	struct msp3400c *msp = i2c_get_clientdata(client);
+	struct msp3400c *msp  = i2c_get_clientdata(client);
 
 	msp3400c_setvolume(client,msp->muted,0,0);
 	msp->watch_stereo=0;
@@ -1391,7 +1417,7 @@
 
 static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
-	struct msp3400c *msp = i2c_get_clientdata(client);
+	struct msp3400c *msp  = i2c_get_clientdata(client);
         __u16           *sarg = arg;
 #if 0
 	int             *iarg = (int*)arg;
@@ -1440,7 +1466,7 @@
 		msp->norm = VIDEO_MODE_RADIO;
 		msp->watch_stereo=0;
 		del_timer(&msp->wake_stereo);
-		dprintk("msp34xx: switching to radio mode\n");
+		dprintk(KERN_DEBUG "msp34xx: switching to radio mode\n");
 		if (msp->simple) {
 			/* the thread will do for us */
 			msp_wake_thread(client);
@@ -1459,11 +1485,11 @@
 	case MSP_SET_DFPREG:
 	{
 		struct msp_dfpreg *r = arg;
-		int i;
+		unsigned int i;
 
 		if (r->reg < 0 || r->reg >= DFP_COUNT)
 			return -EINVAL;
-		for (i = 0; i < sizeof(bl_dfp)/sizeof(int); i++)
+		for (i = 0; i < ARRAY_SIZE(bl_dfp); i++)
 			if (r->reg == bl_dfp[i])
 				return -EINVAL;
 		msp->dfp_regs[r->reg] = r->value;
@@ -1527,11 +1553,11 @@
 		msp3400c_setbass(client,msp->bass);
 		msp3400c_settreble(client,msp->treble);
 
-		if (va->mode != 0) {
+		if (va->mode != 0 && msp->norm != VIDEO_MODE_RADIO) {
 			msp->watch_stereo=0;
 			del_timer(&msp->wake_stereo);
-			msp->stereo = va->mode;
-			msp3400c_setstereo(client,va->mode);
+			msp->stereo = va->mode & 0x0f;
+			msp3400c_setstereo(client,va->mode & 0x0f);
 		}
 		break;
 	}
@@ -1540,7 +1566,6 @@
 		struct video_channel *vc = arg;
 		
 		dprintk(KERN_DEBUG "msp34xx: VIDIOCSCHAN\n");
-		dprintk("msp34xx: switching to TV mode\n");
 		msp->norm = vc->norm;
 		break;
 	}
diff -Nru a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
--- a/drivers/media/video/mxb.c	Thu Apr 24 10:34:20 2003
+++ b/drivers/media/video/mxb.c	Tue May  6 04:53:36 2003
@@ -208,7 +208,8 @@
 static int mxb_probe(struct saa7146_dev* dev)
 {
 	struct mxb* mxb = 0;
-	int i = 0;	
+	struct i2c_client *client;
+	struct list_head *item;
 
 	request_module("tuner");
 	request_module("tea6420");
@@ -235,22 +236,20 @@
 	}
 
 	/* loop through all i2c-devices on the bus and look who is there */
-	for(i = 0; i < I2C_CLIENT_MAX; i++) {
-		if( NULL == mxb->i2c_adapter.clients[i] ) {
-			continue;
-		}
-		if( I2C_TEA6420_1 == mxb->i2c_adapter.clients[i]->addr )
-			mxb->tea6420_1 = mxb->i2c_adapter.clients[i];
-		if( I2C_TEA6420_2 == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->tea6420_2 = mxb->i2c_adapter.clients[i];
-		if( I2C_TEA6415C_2 == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->tea6415c = mxb->i2c_adapter.clients[i];
-		if( I2C_TDA9840 == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->tda9840 = mxb->i2c_adapter.clients[i];
-		if( I2C_SAA7111A == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->saa7111a = mxb->i2c_adapter.clients[i];
-		if( 0x60 == mxb->i2c_adapter.clients[i]->addr ) 
-			mxb->tuner = mxb->i2c_adapter.clients[i];
+	list_for_each(item,&mxb->i2c_adapter.clients) {
+		client = list_entry(item, struct i2c_client, list);
+		if( I2C_TEA6420_1 == client->addr )
+			mxb->tea6420_1 = client;
+		if( I2C_TEA6420_2 == client->addr ) 
+			mxb->tea6420_2 = client;
+		if( I2C_TEA6415C_2 == client->addr ) 
+			mxb->tea6415c = client;
+		if( I2C_TDA9840 == client->addr ) 
+			mxb->tda9840 = client;
+		if( I2C_SAA7111A == client->addr ) 
+			mxb->saa7111a = client;
+		if( 0x60 == client->addr ) 
+			mxb->tuner = client;
 	}
 
 	/* check if all devices are present */
diff -Nru a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
--- a/drivers/media/video/saa5249.c	Thu Apr 24 04:11:51 2003
+++ b/drivers/media/video/saa5249.c	Tue May  6 08:21:57 2003
@@ -224,12 +224,8 @@
  
 static int saa5249_probe(struct i2c_adapter *adap)
 {
-	/* Only attach these chips to the BT848 bus for now */
-	
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
-	{
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, saa5249_attach);
-	}
 	return 0;
 }
 
diff -Nru a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
--- a/drivers/media/video/saa7134/saa7134-cards.c	Wed Mar 12 06:07:06 2003
+++ b/drivers/media/video/saa7134/saa7134-cards.c	Sat May 17 14:09:46 2003
@@ -29,6 +29,7 @@
 static char name_mute[]    = "mute";
 static char name_radio[]   = "Radio";
 static char name_tv[]      = "Television";
+static char name_tv_mono[] = "TV (mono only)";
 static char name_comp1[]   = "Composite1";
 static char name_comp2[]   = "Composite2";
 static char name_svideo[]  = "S-Video";
@@ -61,6 +62,11 @@
 			.vmux = 1,
 			.amux = TV,
 			.tv   = 1,
+		},{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
 		}},
 	},
 	[SAA7134_BOARD_FLYVIDEO3000] = {
@@ -68,27 +74,39 @@
 		.name		= "LifeView FlyVIDEO3000",
 		.audio_clock	= 0x00200000,
 		.tuner_type	= TUNER_PHILIPS_PAL,
+		.gpiomask       = 0xe000,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
 			.amux = TV,
+			.gpio = 0x8000,
+			.tv   = 1,
+                },{
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.gpio = 0x0000,
 			.tv   = 1,
 		},{
 			.name = name_comp1,
 			.vmux = 0,
-			.amux = LINE1,
+			.amux = LINE2,
+			.gpio = 0x4000,
 		},{
 			.name = name_comp2,
 			.vmux = 3,
-			.amux = LINE1,
+			.amux = LINE2,
+			.gpio = 0x4000,
 		},{
 			.name = name_svideo,
 			.vmux = 8,
-			.amux = LINE1,
+			.amux = LINE2,
+			.gpio = 0x4000,
 		}},
 		.radio = {
 			.name = name_radio,
 			.amux = LINE2,
+			.gpio = 0x2000,
 		},
 	},
 	[SAA7134_BOARD_FLYVIDEO2000] = {
@@ -96,7 +114,7 @@
 		.name           = "LifeView FlyVIDEO2000",
 		.audio_clock    = 0x00200000,
 		.tuner_type     = TUNER_LG_PAL_NEW_TAPC,
-		.gpiomask       = 0x6000,
+		.gpiomask       = 0xe000,
 		.inputs         = {{
 			.name = name_tv,
 			.vmux = 1,
@@ -122,10 +140,12 @@
                 .radio = {
                         .name = name_radio,
                         .amux = LINE2,
+			.gpio = 0x2000,
                 },
 		.mute = {
 			.name = name_mute,
-			.amux = LINE1,
+                        .amux = LINE2,
+			.gpio = 0x8000,
 		},
 	},
 	[SAA7134_BOARD_EMPRESS] = {
@@ -190,7 +210,7 @@
 			.tv   = 1,
 		},{
 			/* workaround for problems with normal TV sound */
-			.name = "TV (mono only)",
+			.name = name_tv_mono,
 			.vmux = 1,
 			.amux = LINE2,
 			.tv   = 1,
@@ -270,6 +290,12 @@
 			.amux = TV,
 			.tv   = 1,
 		},{
+			/* workaround for problems with normal TV sound */
+			.name = name_tv_mono,
+			.vmux = 1,
+			.amux = LINE2,
+			.tv   = 1,
+		},{
 			.name = name_comp1,
 			.vmux = 0,
 			.amux = LINE2,
@@ -302,7 +328,7 @@
                 },{
                         .name = name_tv,
                         .vmux = 1,
-                        .amux = TV,
+                        .amux = LINE2,
                         .tv   = 1,
                 }},
         },
@@ -332,7 +358,6 @@
 			.name = name_radio,
 			.amux = LINE2,
                },
-
         },
 	[SAA7134_BOARD_MD7134] = {
 		.name           = "Medion 7134",
@@ -343,7 +368,7 @@
 			.name   = name_tv,
 			.vmux   = 1,
 			.amux   = LINE2,
-			.tv     =   1,
+			.tv     = 1,
 		},{
 			.name   = name_comp1,
 			.vmux   = 0,
@@ -361,9 +386,67 @@
 			.name   = name_radio,
 			.amux   = LINE2,
 		},
-      },
+	},
+	[SAA7134_BOARD_TYPHOON_90031] = {
+		.name           = "Typhoon TV+Radio 90031",
+		.audio_clock    = 0x00200000,
+		.tuner_type     = TUNER_PHILIPS_PAL,
+		.inputs         = {{
+			.name   = name_tv,
+			.vmux   = 1,
+			.amux   = TV,
+			.tv     = 1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 3,
+			.amux   = LINE1,
+		},{
+			.name   = name_svideo,
+			.vmux   = 8,
+			.amux   = LINE1,
+		}},
+		.radio = {
+			.name   = name_radio,
+			.amux   = LINE2,
+		},
+	},
+	[SAA7134_BOARD_ELSA] = {
+		.name           = "ELSA EX-VISION 300TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_HITACHI_NTSC,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 8,
+			.amux = LINE1,
+		},{
+			.name   = name_comp1,
+			.vmux   = 0,
+			.amux   = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 4,
+			.amux = LINE2,
+			.tv   = 1,
+		}},
+        },
+	[SAA7134_BOARD_ELSA_500TV] = {
+		.name           = "ELSA EX-VISION 500TV",
+		.audio_clock    = 0x00187de7,
+		.tuner_type     = TUNER_HITACHI_NTSC,
+		.inputs         = {{
+			.name = name_svideo,
+			.vmux = 7,
+			.amux = LINE1,
+		},{
+			.name = name_tv,
+			.vmux = 8,
+			.amux = TV,
+			.tv   = 1,
+		}},
+        },
+	
 };
-const int saa7134_bcount = (sizeof(saa7134_boards)/sizeof(struct saa7134_board));
+const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
 
 /* ------------------------------------------------------------------ */
 /* PCI ids + subsystem IDs                                            */
@@ -377,6 +460,12 @@
 		.driver_data  = SAA7134_BOARD_PROTEUS_PRO,
         },{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+		.subvendor    = PCI_VENDOR_ID_PHILIPS,
+		.subdevice    = 0x2001,
+		.driver_data  = SAA7134_BOARD_PROTEUS_PRO,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor    = PCI_VENDOR_ID_PHILIPS,
 		.subdevice    = 0x6752,
@@ -407,11 +496,29 @@
 		.driver_data  = SAA7134_BOARD_FLYVIDEO3000,
         },{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x5168,
+		.subdevice    = 0x0138,
+		.driver_data  = SAA7134_BOARD_FLYVIDEO2000,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
 		.subvendor    = 0x16be,
 		.subdevice    = 0x0003,
 		.driver_data  = SAA7134_BOARD_MD7134,
 	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1048,
+		.subdevice    = 0x226b,
+		.driver_data  = SAA7134_BOARD_ELSA,
+	},{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7130,
+		.subvendor    = 0x1048,
+		.subdevice    = 0x226b,
+		.driver_data  = SAA7134_BOARD_ELSA_500TV,
+	},{
 		
 		/* --- boards without eeprom + subsystem ID --- */
                 .vendor       = PCI_VENDOR_ID_PHILIPS,
@@ -435,15 +542,88 @@
 		.driver_data  = SAA7134_BOARD_UNKNOWN,
         },{
 		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7133,
+                .subvendor    = PCI_ANY_ID,
+                .subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
 		.device       = PCI_DEVICE_ID_PHILIPS_SAA7134,
                 .subvendor    = PCI_ANY_ID,
                 .subdevice    = PCI_ANY_ID,
 		.driver_data  = SAA7134_BOARD_UNKNOWN,
+        },{
+		.vendor       = PCI_VENDOR_ID_PHILIPS,
+		.device       = PCI_DEVICE_ID_PHILIPS_SAA7135,
+                .subvendor    = PCI_ANY_ID,
+                .subdevice    = PCI_ANY_ID,
+		.driver_data  = SAA7134_BOARD_UNKNOWN,
 	},{
 		/* --- end of list --- */
 	}
 };
 MODULE_DEVICE_TABLE(pci, saa7134_pci_tbl);
+
+/* ----------------------------------------------------------- */
+/* flyvideo tweaks                                             */
+
+#if 0
+static struct {
+	char  *model;
+	int   tuner_type;
+} fly_list[0x20] = {
+	/* default catch ... */
+	[ 0 ... 0x1f ] = {
+		.model      = "UNKNOWN",
+		.tuner_type = TUNER_ABSENT,
+	},
+	/* ... the ones known so far */
+	[ 0x05 ] = {
+		.model      = "PAL-BG",
+		.tuner_type = TUNER_LG_PAL_NEW_TAPC,
+	},
+	[ 0x10 ] = {
+		.model      = "PAL-BG / PAL-DK",
+		.tuner_type = TUNER_PHILIPS_PAL,
+	},
+	[ 0x15 ] = {
+		.model      = "NTSC",
+		.tuner_type = TUNER_ABSENT /* FIXME */,
+	},
+};
+#endif
+
+static void board_flyvideo(struct saa7134_dev *dev)
+{
+	u32 value;
+	int index;
+
+	saa_writel(SAA7134_GPIO_GPMODE0 >> 2,   0);
+	value = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2);
+#if 0
+	index = (value & 0x1f00) >> 8;
+	printk(KERN_INFO "%s: flyvideo: gpio is 0x%x [model=%s,tuner=%d]\n",
+	       dev->name, value, fly_list[index].model,
+	       fly_list[index].tuner_type);
+	dev->tuner_type = fly_list[index].tuner_type;
+#else
+	printk(KERN_INFO "%s: flyvideo: gpio is 0x%x\n",
+	       dev->name, value);
+#endif
+}
+
+/* ----------------------------------------------------------- */
+
+int saa7134_board_init(struct saa7134_dev *dev)
+{
+	switch (dev->board) {
+	case SAA7134_BOARD_FLYVIDEO2000:
+	case SAA7134_BOARD_FLYVIDEO3000:
+		board_flyvideo(dev);
+		break;
+	}
+	return 0;
+}
 
 /* ----------------------------------------------------------- */
 /*
diff -Nru a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
--- a/drivers/media/video/saa7134/saa7134-core.c	Thu Apr 24 05:18:50 2003
+++ b/drivers/media/video/saa7134/saa7134-core.c	Sat May 17 14:09:46 2003
@@ -2,7 +2,7 @@
  * device driver for philips saa7134 based TV cards
  * driver core
  *
- * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
  *  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
@@ -67,6 +67,10 @@
 MODULE_PARM(radio_nr,"i");
 MODULE_PARM_DESC(radio_nr,"radio device number");
 
+static unsigned int oss = 0;
+MODULE_PARM(oss,"i");
+MODULE_PARM_DESC(oss,"register oss devices (default: no)");
+
 static unsigned int dsp_nr = -1;
 MODULE_PARM(dsp_nr,"i");
 MODULE_PARM_DESC(dsp_nr,"oss dsp device number");
@@ -75,20 +79,20 @@
 MODULE_PARM(mixer_nr,"i");
 MODULE_PARM_DESC(mixer_nr,"oss mixer device number");
 
-static int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = -1};
+static unsigned int tuner[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 MODULE_PARM(tuner,"1-" __stringify(SAA7134_MAXBOARDS) "i");
 MODULE_PARM_DESC(tuner,"tuner type");
 
-static int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = -1};
+static unsigned int card[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
 MODULE_PARM(card,"1-" __stringify(SAA7134_MAXBOARDS) "i");
 MODULE_PARM_DESC(card,"card type");
 
-static int latency = -1;
+static unsigned int latency = UNSET;
 MODULE_PARM(latency,"i");
 MODULE_PARM_DESC(latency,"pci latency timer");
 
 struct list_head  saa7134_devlist;
-int               saa7134_devcount;
+unsigned int      saa7134_devcount;
 
 #define dprintk(fmt, arg...)	if (core_debug) \
 	printk(KERN_DEBUG "%s/core: " fmt, dev->name, ## arg)
@@ -102,7 +106,7 @@
 	"SFREQ", "GAUDIO", "SAUDIO", "SYNC", "MCAPTURE", "GMBUF", "GUNIT",
 	"GCAPTURE", "SCAPTURE", "SPLAYMODE", "SWRITEMODE", "GPLAYINFO",
 	"SMICROCODE", "GVBIFMT", "SVBIFMT" };
-#define V4L1_IOCTLS (sizeof(v4l1_ioctls)/sizeof(char*))
+#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
 
 static const char *v4l2_ioctls[] = {
 	"QUERYCAP", "1", "ENUM_PIXFMT", "ENUM_FBUFFMT", "G_FMT", "S_FMT",
@@ -116,7 +120,7 @@
 	"S_AUDOUT", "ENUMFX", "G_EFFECT", "S_EFFECT", "G_MODULATOR",
 	"S_MODULATOR"
 };
-#define V4L2_IOCTLS (sizeof(v4l2_ioctls)/sizeof(char*))
+#define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
 static const char *osspcm_ioctls[] = {
 	"RESET", "SYNC", "SPEED", "STEREO", "GETBLKSIZE", "SETFMT",
@@ -125,7 +129,7 @@
 	"GETIPTR", "GETOPTR", "MAPINBUF", "MAPOUTBUF", "SETSYNCRO",
 	"SETDUPLEX", "GETODELAY"
 };
-#define OSSPCM_IOCTLS (sizeof(v4l2_ioctls)/sizeof(char*))
+#define OSSPCM_IOCTLS ARRAY_SIZE(v4l2_ioctls)
 
 void saa7134_print_ioctl(char *name, unsigned int cmd)
 {
@@ -236,9 +240,9 @@
 
 /* calc max # of buffers from size (must not exceed the 4MB virtual
  * address space per DMA channel) */
-int saa7134_buffer_count(int size, int count)
+int saa7134_buffer_count(unsigned int size, unsigned int count)
 {
-	int maxcount;
+	unsigned int maxcount;
 	
 	maxcount = 1024 / saa7134_buffer_pages(size);
 	if (count > maxcount)
@@ -277,11 +281,11 @@
 }
 
 int saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
-			  struct scatterlist *list, int length,
-			  int startpage)
+			  struct scatterlist *list, unsigned int length,
+			  unsigned int startpage)
 {
-	u32   *ptr;
-	int   i,p;
+	u32           *ptr;
+	unsigned int  i,p;
 
 	BUG_ON(NULL == pt || NULL == pt->cpu);
 
@@ -319,14 +323,25 @@
 			 struct saa7134_dmaqueue *q,
 			 struct saa7134_buf *buf)
 {
+	struct saa7134_buf *next = NULL;
 #if DEBUG_SPINLOCKS
 	BUG_ON(!spin_is_locked(&dev->slock));
 #endif
 	
 	dprintk("buffer_queue %p\n",buf);
 	if (NULL == q->curr) {
-		q->curr = buf;
-		buf->activate(dev,buf,NULL);
+		if (!q->need_two) {
+			q->curr = buf;
+			buf->activate(dev,buf,NULL);
+		} else if (list_empty(&q->queue)) {
+			list_add_tail(&buf->vb.queue,&q->queue);
+			buf->vb.state = STATE_QUEUED;
+		} else {
+			next = list_entry(q->queue.next,struct saa7134_buf,
+					  vb.queue);
+			q->curr = buf;
+			buf->activate(dev,buf,next);
+		}
 	} else {
 		list_add_tail(&buf->vb.queue,&q->queue);
 		buf->vb.state = STATE_QUEUED;
@@ -336,7 +351,7 @@
 
 void saa7134_buffer_finish(struct saa7134_dev *dev,
 			   struct saa7134_dmaqueue *q,
-			   int state)
+			   unsigned int state)
 {
 #if DEBUG_SPINLOCKS
 	BUG_ON(!spin_is_locked(&dev->slock));
@@ -388,6 +403,14 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->slock,flags);
+
+	/* try to reset the hardware (SWRST) */
+	saa_writeb(SAA7134_REGION_ENABLE, 0x00);
+	saa_writeb(SAA7134_REGION_ENABLE, 0x80);
+	saa_writeb(SAA7134_REGION_ENABLE, 0x00);
+
+	/* flag current buffer as failed,
+	   try to start over with the next one. */
 	if (q->curr) {
 		dprintk("timeout on %p\n",q->curr);
 		saa7134_buffer_finish(dev,q,STATE_ERROR);
@@ -400,7 +423,7 @@
 
 int saa7134_set_dmabits(struct saa7134_dev *dev)
 {
-	unsigned long task=0, ctrl=0, irq=0, split = 0;
+	u32 split, task=0, ctrl=0, irq=0;
 	enum v4l2_field cap = V4L2_FIELD_ANY;
 	enum v4l2_field ov  = V4L2_FIELD_ANY;
 
@@ -460,12 +483,12 @@
 	
 	/* set task conditions + field handling */
 	if (V4L2_FIELD_HAS_BOTH(cap) || V4L2_FIELD_HAS_BOTH(ov) || cap == ov) {
-		/* default config -- use full frames:
-		   odd A, even A, odd B, even B, repeat */
+		/* default config -- use full frames */
 		saa_writeb(SAA7134_TASK_CONDITIONS(TASK_A), 0x0d);
 		saa_writeb(SAA7134_TASK_CONDITIONS(TASK_B), 0x0d);
 		saa_writeb(SAA7134_FIELD_HANDLING(TASK_A),  0x02);
 		saa_writeb(SAA7134_FIELD_HANDLING(TASK_B),  0x02);
+		split = 0;
 	} else {
 		/* split fields between tasks */
 		if (V4L2_FIELD_TOP == cap) {
@@ -494,7 +517,7 @@
 		   SAA7134_MAIN_CTRL_TE5 |
 		   SAA7134_MAIN_CTRL_TE6,
 		   ctrl);
-	dprintk("dmabits: task=0x%02lx ctrl=0x%02lx irq=0x%lx split=%s\n",
+	dprintk("dmabits: task=0x%02x ctrl=0x%02x irq=0x%x split=%s\n",
 		task, ctrl, irq, split ? "no" : "yes");
 
 	return 0;
@@ -508,12 +531,12 @@
 	"AR", "PE", "PWR_ON", "RDCAP", "INTL", "FIDT", "MMC",
 	"TRIG_ERR", "CONF_ERR", "LOAD_ERR"
 };
-#define IRQBITS (sizeof(irqbits)/sizeof(char*))
+#define IRQBITS ARRAY_SIZE(irqbits)
 
 static void print_irqstatus(struct saa7134_dev *dev, int loop,
 			    unsigned long report, unsigned long status)
 {
-	int i;
+	unsigned int i;
 	
 	printk(KERN_DEBUG "%s/irq[%d,%ld]: r=0x%lx s=0x%02lx",
 	       dev->name,loop,jiffies,report,status);
@@ -536,18 +559,19 @@
 {
 	struct saa7134_dev *dev = (struct saa7134_dev*) dev_id;
 	unsigned long report,status;
-	int loop;
+	int loop, handled = 0;
 
 	for (loop = 0; loop < 10; loop++) {
 		report = saa_readl(SAA7134_IRQ_REPORT);
 		status = saa_readl(SAA7134_IRQ_STATUS);
-		saa_writel(SAA7134_IRQ_REPORT,report);
 		if (0 == report) {
 			if (irq_debug > 1)
 				printk(KERN_DEBUG "%s/irq: no (more) work\n",
 				       dev->name);
 			goto out;
 		}
+		handled = 1;
+		saa_writel(SAA7134_IRQ_REPORT,report);
 		if (irq_debug)
 			print_irqstatus(dev,loop,report,status);
 
@@ -582,8 +606,9 @@
 		saa_writel(SAA7134_IRQ1,0);
 		saa_writel(SAA7134_IRQ2,0);
 	}
-out:
-	return IRQ_HANDLED;
+
+ out:
+	return IRQ_RETVAL(handled);
 }
 
 /* ------------------------------------------------------------------ */
@@ -599,8 +624,14 @@
 	saa7134_vbi_init(dev);
 	if (card_has_ts(dev))
 		saa7134_ts_init(dev);
-	if (card_has_audio(dev))
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
 		saa7134_oss_init(dev);
+		break;
+	}
 	
 	/* RAM FIFO config */
 	saa_writel(SAA7134_FIFO_SIZE, 0x08070503);
@@ -634,12 +665,15 @@
 	/* enable peripheral devices */
 	saa_writeb(SAA7134_SPECIAL_MODE, 0x01);
 
+	/* set vertical line numbering start (vbi needs this) */
+	saa_writeb(SAA7134_SOURCE_TIMING2, 0x20);
+	
 	return 0;
 }
 
 static void __devinit must_configure_manually(void)
 {
-	int i,p;
+	unsigned int i,p;
 
 	printk(KERN_WARNING
 	       "saa7134: <rant>\n"
@@ -675,18 +709,39 @@
 		return -ENOMEM;
 	memset(dev,0,sizeof(*dev));
 
-	/* pci stuff */
+	/* pci init */
 	dev->pci = pci_dev;
 	if (pci_enable_device(pci_dev)) {
 		err = -EIO;
 		goto fail1;
 	}
 	sprintf(dev->name,"saa%x[%d]",pci_dev->device,saa7134_devcount);
-	if (-1 != latency) {
+
+	/* pci quirks */
+	if (pci_pci_problems) {
+		if (pci_pci_problems & PCIPCI_TRITON)
+			printk(KERN_INFO "%s: quirk: PCIPCI_TRITON\n", dev->name);
+		if (pci_pci_problems & PCIPCI_NATOMA)
+			printk(KERN_INFO "%s: quirk: PCIPCI_NATOMA\n", dev->name);
+		if (pci_pci_problems & PCIPCI_VIAETBF)
+			printk(KERN_INFO "%s: quirk: PCIPCI_VIAETBF\n", dev->name);
+		if (pci_pci_problems & PCIPCI_VSFX)
+			printk(KERN_INFO "%s: quirk: PCIPCI_VSFX\n",dev->name);
+#ifdef PCIPCI_ALIMAGIK
+		if (pci_pci_problems & PCIPCI_ALIMAGIK) {
+			printk(KERN_INFO "%s: quirk: PCIPCI_ALIMAGIK -- latency fixup\n",
+			       dev->name);
+			latency = 0x0A;
+		}
+#endif
+	}
+	if (UNSET != latency) {
 		printk(KERN_INFO "%s: setting pci latency timer to %d\n",
 		       dev->name,latency);
 		pci_write_config_byte(pci_dev, PCI_LATENCY_TIMER, latency);
 	}
+
+	/* print pci info */
 	pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
         pci_read_config_byte(pci_dev, PCI_LATENCY_TIMER,  &dev->pci_lat);
         printk(KERN_INFO "%s: found at %s, rev: %d, irq: %d, "
@@ -710,7 +765,7 @@
 		dev->board = SAA7134_BOARD_UNKNOWN;
 	}
 	dev->tuner_type = saa7134_boards[dev->board].tuner_type;
-	if (-1 != tuner[saa7134_devcount])
+	if (UNSET != tuner[saa7134_devcount])
 		dev->tuner_type = tuner[saa7134_devcount];
         printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
 	       dev->name,pci_dev->subsystem_vendor,
@@ -730,6 +785,13 @@
 	dev->lmmio = ioremap(pci_resource_start(pci_dev,0), 0x1000);
 	dev->bmmio = (__u8*)dev->lmmio;
 
+	/* register i2c bus */
+	saa7134_i2c_register(dev);
+
+	/* initialize hardware */
+	saa7134_board_init(dev);
+	saa7134_hwinit(dev);
+
 	/* get irq */
 	err = request_irq(pci_dev->irq, saa7134_irq,
 			  SA_SHIRQ | SA_INTERRUPT, dev->name, dev);
@@ -739,12 +801,8 @@
 		goto fail2;
 	}
 
-	/* initialize hardware */
-	saa7134_hwinit(dev);
-
-	/* register i2c bus + load i2c helpers */
-	saa7134_i2c_register(dev);
-	if (TUNER_ABSENT != card(dev).tuner_type)
+	/* load i2c helpers */
+	if (TUNER_ABSENT != dev->tuner_type)
 		request_module("tuner");
 	if (saa7134_boards[dev->board].need_tda9887)
 		request_module("tda9887");
@@ -793,19 +851,27 @@
 	}
 
 	/* register oss devices */
-	if (card_has_audio(dev)) {
-		dev->oss.minor_dsp = register_sound_dsp(&saa7134_dsp_fops,dsp_nr);
-		if (dev->oss.minor_dsp < 0)
-			goto fail7;
-		printk(KERN_INFO "%s: registered device dsp%d\n",
-		       dev->name,dev->oss.minor_dsp >> 4);
-		
-		dev->oss.minor_mixer =
-			register_sound_mixer(&saa7134_mixer_fops,mixer_nr);
-		if (dev->oss.minor_mixer < 0)
-			goto fail8;
-		printk(KERN_INFO "%s: registered device mixer%d\n",
-		       dev->name,dev->oss.minor_mixer >> 4);
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (oss) {
+			err = dev->oss.minor_dsp =
+				register_sound_dsp(&saa7134_dsp_fops,dsp_nr);
+			if (err < 0) {
+				goto fail7;
+			}
+			printk(KERN_INFO "%s: registered device dsp%d\n",
+			       dev->name,dev->oss.minor_dsp >> 4);
+			
+			err = dev->oss.minor_mixer =
+				register_sound_mixer(&saa7134_mixer_fops,mixer_nr);
+			if (err < 0)
+				goto fail8;
+			printk(KERN_INFO "%s: registered device mixer%d\n",
+			       dev->name,dev->oss.minor_mixer >> 4);
+		}
+		break;
 	}
 
 	/* everything worked */
@@ -815,8 +881,14 @@
 	return 0;
 
  fail8:
-	if (card_has_audio(dev))
-		unregister_sound_dsp(dev->oss.minor_dsp);
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (oss)
+			unregister_sound_dsp(dev->oss.minor_dsp);
+		break;
+	}
  fail7:
 	if (card_has_radio(dev))
 		video_unregister_device(&dev->radio_dev);
@@ -828,16 +900,21 @@
  fail4:
 	video_unregister_device(&dev->video_dev);
  fail3:
-	if (card_has_audio(dev))
+	saa7134_i2c_unregister(dev);
+	free_irq(pci_dev->irq, dev);
+ fail2:
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
 		saa7134_oss_fini(dev);
+		break;
+	}
 	if (card_has_ts(dev))
 		saa7134_ts_fini(dev);
 	saa7134_vbi_fini(dev);
 	saa7134_video_fini(dev);
 	saa7134_tvaudio_fini(dev);
-	saa7134_i2c_unregister(dev);
-	free_irq(pci_dev->irq, dev);
- fail2:
 	release_mem_region(pci_resource_start(pci_dev,0),
 			   pci_resource_len(pci_dev,0));
  fail1:
@@ -849,6 +926,13 @@
 {
         struct saa7134_dev *dev = pci_get_drvdata(pci_dev);
 
+	/* debugging ... */
+	if (irq_debug) {
+		u32 report = saa_readl(SAA7134_IRQ_REPORT);
+		u32 status = saa_readl(SAA7134_IRQ_STATUS);
+		print_irqstatus(dev,42,report,status);
+	}
+
 	/* disable peripheral devices */
 	saa_writeb(SAA7134_SPECIAL_MODE,0);
 
@@ -858,8 +942,13 @@
 	saa_writel(SAA7134_MAIN_CTRL,0);
 
 	/* shutdown subsystems */
-	if (card_has_audio(dev))
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
 		saa7134_oss_fini(dev);
+		break;
+	}
 	if (card_has_ts(dev))
 		saa7134_ts_fini(dev);
 	saa7134_vbi_fini(dev);
@@ -874,9 +963,15 @@
 
 	/* unregister */
 	saa7134_i2c_unregister(dev);
-	if (card_has_audio(dev)) {
-		unregister_sound_mixer(dev->oss.minor_mixer);
-		unregister_sound_dsp(dev->oss.minor_dsp);
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (oss) {
+			unregister_sound_mixer(dev->oss.minor_mixer);
+			unregister_sound_dsp(dev->oss.minor_dsp);
+		}
+		break;
 	}
 	if (card_has_radio(dev))
 		video_unregister_device(&dev->radio_dev);
diff -Nru a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
--- a/drivers/media/video/saa7134/saa7134-i2c.c	Sat Mar 22 23:17:51 2003
+++ b/drivers/media/video/saa7134/saa7134-i2c.c	Sat May 17 14:09:46 2003
@@ -153,10 +153,7 @@
 		status = i2c_get_status(dev);
 		if (!i2c_is_busy(status))
 			break;
-		if (need_resched())
-                        schedule();
-		else
-			udelay(I2C_WAIT_DELAY);
+		saa_wait(I2C_WAIT_DELAY);
 	}
 	if (I2C_WAIT_RETRY == count)
 		return FALSE;
@@ -318,7 +315,7 @@
 static int attach_inform(struct i2c_client *client)
 {
         struct saa7134_dev *dev = client->adapter->algo_data;
-	int tuner = card(dev).tuner_type;
+	int tuner = dev->tuner_type;
 
 	saa7134_i2c_call_clients(dev,TUNER_SET_TYPE,&tuner);
         return 0;
@@ -334,19 +331,16 @@
 
 static struct i2c_adapter saa7134_adap_template = {
 	.owner         = THIS_MODULE,
+	.class         = I2C_ADAP_CLASS_TV_ANALOG,
+	I2C_DEVNAME("saa7134"),
 	.id            = I2C_ALGO_SAA7134,
 	.algo          = &saa7134_algo,
 	.client_register = attach_inform,
-	.dev		= {
-		.name	= "saa7134",
-	},
 };
 
 static struct i2c_client saa7134_client_template = {
-        .id   = -1,
-	.dev	= {
-		.name	= "saa7134 internal",
-	},
+	I2C_DEVNAME("saa7134 internal"),
+        .id        = -1,
 };
 
 /* ----------------------------------------------------------- */
@@ -399,22 +393,13 @@
 void saa7134_i2c_call_clients(struct saa7134_dev *dev,
 			      unsigned int cmd, void *arg)
 {
-	int i;
-
-	for (i = 0; i < I2C_CLIENT_MAX; i++) {
-		if (NULL == dev->i2c_adap.clients[i])
-			continue;
-		if (NULL == dev->i2c_adap.clients[i]->driver->command)
-			continue;
-		dev->i2c_adap.clients[i]->driver->command
-			(dev->i2c_adap.clients[i],cmd,arg);
-	}
+	i2c_clients_command(&dev->i2c_adap, cmd, arg);
 }
 
 int saa7134_i2c_register(struct saa7134_dev *dev)
 {
 	dev->i2c_adap = saa7134_adap_template;
-	strncpy(dev->i2c_adap.dev.name, dev->name, DEVICE_NAME_SIZE);
+	strcpy(dev->i2c_adap.dev.name,dev->name);
 	dev->i2c_adap.algo_data = dev;
 	i2c_add_adapter(&dev->i2c_adap);
 	
diff -Nru a/drivers/media/video/saa7134/saa7134-oss.c b/drivers/media/video/saa7134/saa7134-oss.c
--- a/drivers/media/video/saa7134/saa7134-oss.c	Thu Mar 13 16:52:15 2003
+++ b/drivers/media/video/saa7134/saa7134-oss.c	Sat May 17 14:09:46 2003
@@ -94,8 +94,9 @@
 
 static int dsp_rec_start(struct saa7134_dev *dev)
 {
-	int err, fmt, bswap, wswap;
-	unsigned long control,flags;
+	int err, bswap, sign;
+	u32 fmt, control;
+	unsigned long flags;
 
 	/* prepare buffer */
 	if (0 != (err = videobuf_dma_pci_map(dev->pci,&dev->oss.dma)))
@@ -110,45 +111,60 @@
 
 	/* sample format */
 	switch (dev->oss.afmt) {
-	case AFMT_U8:     fmt = 0x00;         break;
-	case AFMT_S8:     fmt = 0x00 | 0x04;  break;
+	case AFMT_U8:
+	case AFMT_S8:     fmt = 0x00;  break;
 	case AFMT_U16_LE:
-	case AFMT_U16_BE: fmt = 0x01;         break;
+	case AFMT_U16_BE:
 	case AFMT_S16_LE:
-	case AFMT_S16_BE: fmt = 0x01 | 0x04;  break;
-/* 4front API specs mention these ones,
-   the (2.4.15) kernel header hasn't them ... */
-#ifdef AFMT_S32_LE
-	case AFMT_S32_LE:
-	case AFMT_S32_BE: fmt = 0x02 | 0x04;  break;
-#endif
+	case AFMT_S16_BE: fmt = 0x01;  break;
 	default:
 		err = -EINVAL;
 		goto fail2;
 	}
 
 	switch (dev->oss.afmt) {
+	case AFMT_S8:     
+	case AFMT_S16_LE:
+	case AFMT_S16_BE: sign = 1; break;
+	default:          sign = 0; break;
+	}
+
+	switch (dev->oss.afmt) {
 	case AFMT_U16_BE:
-	case AFMT_S16_BE: bswap = 1; wswap = 0; break;
-#ifdef AFMT_S32_LE
-	case AFMT_S32_BE: bswap = 1; wswap = 1; break;
-#endif
-	default:          bswap = 0; wswap = 0; break;
+	case AFMT_S16_BE: bswap = 1; break;
+	default:          bswap = 0; break;
 	}
 
-	if (1 == dev->oss.channels)
-		fmt |= (1 << 3);
-	if (2 == dev->oss.channels)
-		fmt |= (3 << 3);
-	fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
-	
-	saa_writeb(SAA7134_NUM_SAMPLES0, (dev->oss.blksize & 0x0000ff));
-	saa_writeb(SAA7134_NUM_SAMPLES1, (dev->oss.blksize & 0x00ff00) >>  8);
-	saa_writeb(SAA7134_NUM_SAMPLES2, (dev->oss.blksize & 0xff0000) >> 16);
-	saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
-	dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c%c\n",
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		if (1 == dev->oss.channels)
+			fmt |= (1 << 3);
+		if (2 == dev->oss.channels)
+			fmt |= (3 << 3);
+		if (sign)
+			fmt |= 0x04;
+		fmt |= (TV == dev->oss.input) ? 0xc0 : 0x80;
+		
+		saa_writeb(SAA7134_NUM_SAMPLES0, (dev->oss.blksize & 0x0000ff));
+		saa_writeb(SAA7134_NUM_SAMPLES1, (dev->oss.blksize & 0x00ff00) >>  8);
+		saa_writeb(SAA7134_NUM_SAMPLES2, (dev->oss.blksize & 0xff0000) >> 16);
+		saa_writeb(SAA7134_AUDIO_FORMAT_CTRL, fmt);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		if (1 == dev->oss.channels)
+			fmt |= (1 << 4);
+		if (2 == dev->oss.channels)
+			fmt |= (2 << 4);
+		if (!sign)
+			fmt |= 0x04;
+		saa_writel(0x588 >> 2, dev->oss.blksize);
+		saa_writel(0x58c >> 2, 0x543210 | (fmt << 24));
+		break;
+	}
+	dprintk("rec_start: afmt=%d ch=%d  =>  fmt=0x%x swap=%c\n",
 		dev->oss.afmt, dev->oss.channels, fmt,
-		bswap ? 'b' : '-', wswap ? 'w' : '-');
+		bswap ? 'b' : '-');
 
 	/* dma: setup channel 6 (= AUDIO) */
 	control = SAA7134_RS_CONTROL_BURST_16 |
@@ -156,8 +172,6 @@
 		(dev->oss.pt.dma >> 12);
 	if (bswap)
 		control |= SAA7134_RS_CONTROL_BSWAP;
-	if (wswap)
-		control |= SAA7134_RS_CONTROL_WSWAP;
 	saa_writel(SAA7134_RS_BA1(6),0);
 	saa_writel(SAA7134_RS_BA2(6),dev->oss.blksize);
 	saa_writel(SAA7134_RS_PITCH(6),0);
@@ -201,7 +215,7 @@
 
 static int dsp_open(struct inode *inode, struct file *file)
 {
-	unsigned int minor = minor(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct saa7134_dev *h,*dev = NULL;
 	struct list_head *list;
 	int err;
@@ -259,7 +273,8 @@
 {
 	struct saa7134_dev *dev = file->private_data;
 	DECLARE_WAITQUEUE(wait, current);
-	int bytes,err,ret = 0;
+	unsigned int bytes;
+	int err,ret = 0;
 
 	add_wait_queue(&dev->oss.wq, &wait);
 	down(&dev->oss.lock);
@@ -390,10 +405,6 @@
 		case AFMT_U16_BE:
 		case AFMT_S16_LE:
 		case AFMT_S16_BE:
-#ifdef AFMT_S32_LE
-		case AFMT_S32_LE:
-		case AFMT_S32_BE:
-#endif
 			down(&dev->oss.lock);
 			dev->oss.afmt = val;
 			if (dev->oss.recording) {
@@ -416,11 +427,6 @@
 		case AFMT_S16_LE:
 		case AFMT_S16_BE:
 			return put_user(16, (int*)arg);
-#ifdef AFMT_S32_LE
-		case AFMT_S32_LE:
-		case AFMT_S32_BE:
-			return put_user(20, (int*)arg);
-#endif
 		default:
 			return -EINVAL;
 		}
@@ -499,14 +505,10 @@
 /* ------------------------------------------------------------------ */
 
 static int
-mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
+mixer_recsrc_7134(struct saa7134_dev *dev)
 {
-	static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
 	int analog_io,rate;
 	
-	dev->oss.count++;
-	dev->oss.input = src;
-	dprintk("mixer input = %s\n",iname[dev->oss.input]);
 	switch (dev->oss.input) {
 	case TV:
 		saa_andorb(SAA7134_AUDIO_FORMAT_CTRL, 0xc0, 0xc0);
@@ -525,27 +527,78 @@
 }
 
 static int
-mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
+mixer_recsrc_7133(struct saa7134_dev *dev)
 {
-	switch (src) {
+	u32 value = 0xbbbbbb;
+	
+	switch (dev->oss.input) {
 	case TV:
-		/* nothing */
+		value = 0xbbbb10;  /* MAIN */
 		break;
 	case LINE1:
-		saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x10,
-			   (100 == level) ? 0x00 : 0x10);
+		value = 0xbbbb32;  /* AUX1 */
 		break;
 	case LINE2:
-		saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
-			   (100 == level) ? 0x00 : 0x20);
+		value = 0xbbbb54;  /* AUX2 */
 		break;
 	}
+	saa_dsp_writel(dev, 0x46c >> 2, value);
 	return 0;
 }
 
+static int
+mixer_recsrc(struct saa7134_dev *dev, enum saa7134_audio_in src)
+{
+	static const char *iname[] = { "Oops", "TV", "LINE1", "LINE2" };
+
+	dev->oss.count++;
+	dev->oss.input = src;
+	dprintk("mixer input = %s\n",iname[dev->oss.input]);
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		mixer_recsrc_7134(dev);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		mixer_recsrc_7133(dev);
+		break;
+	}
+	return 0;
+}
+
+static int
+mixer_level(struct saa7134_dev *dev, enum saa7134_audio_in src, int level)
+{
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		switch (src) {
+		case TV:
+			/* nothing */
+			break;
+		case LINE1:
+			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x10,
+				   (100 == level) ? 0x00 : 0x10);
+			break;
+		case LINE2:
+			saa_andorb(SAA7134_ANALOG_IO_SELECT,  0x20,
+				   (100 == level) ? 0x00 : 0x20);
+			break;
+		}
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		/* nothing */
+		break;
+	}
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
 static int mixer_open(struct inode *inode, struct file *file)
 {
-	unsigned int minor = minor(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct saa7134_dev *h,*dev = NULL;
 	struct list_head *list;
 
@@ -681,13 +734,20 @@
 
 int saa7134_oss_init(struct saa7134_dev *dev)
 {
+	/* general */
         init_MUTEX(&dev->oss.lock);
 	init_waitqueue_head(&dev->oss.wq);
-	dev->oss.line1 = 50;
-	dev->oss.line2 = 50;
-	mixer_level(dev,LINE1,dev->oss.line1);
-	mixer_level(dev,LINE2,dev->oss.line2);
-	
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		saa_writel(0x588 >> 2, 0x00000fff);
+		saa_writel(0x58c >> 2, 0x00543210);
+		saa_dsp_writel(dev, 0x46c >> 2, 0xbbbbbb);
+		break;
+	}
+
+	/* dsp */
 	dev->oss.rate = 32000;
 	if (oss_rate)
 		dev->oss.rate = oss_rate;
@@ -695,7 +755,13 @@
 		dev->oss.rate = saa7134_boards[dev->board].i2s_rate;
 	dev->oss.rate = (dev->oss.rate > 40000) ? 48000 : 32000;
 
+	/* mixer */
+	dev->oss.line1 = 50;
+	dev->oss.line2 = 50;
+	mixer_level(dev,LINE1,dev->oss.line1);
+	mixer_level(dev,LINE2,dev->oss.line2);
 	mixer_recsrc(dev, (dev->oss.rate == 32000) ? TV : LINE2);
+	
 	return 0;
 }
 
@@ -710,7 +776,7 @@
 	int next_blk, reg = 0;
 
 	spin_lock(&dev->slock);
-	if (-1 == dev->oss.dma_blk) {
+	if (UNSET == dev->oss.dma_blk) {
 		dprintk("irq: recording stopped%s\n","");
 		goto done;
 	}
diff -Nru a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
--- a/drivers/media/video/saa7134/saa7134-reg.h	Thu Oct 31 05:27:48 2002
+++ b/drivers/media/video/saa7134/saa7134-reg.h	Sat May 17 14:09:46 2003
@@ -9,9 +9,15 @@
 #ifndef PCI_DEVICE_ID_PHILIPS_SAA7130
 # define PCI_DEVICE_ID_PHILIPS_SAA7130 0x7130
 #endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7133
+# define PCI_DEVICE_ID_PHILIPS_SAA7133 0x7133
+#endif
 #ifndef PCI_DEVICE_ID_PHILIPS_SAA7134
 # define PCI_DEVICE_ID_PHILIPS_SAA7134 0x7134
 #endif
+#ifndef PCI_DEVICE_ID_PHILIPS_SAA7135
+# define PCI_DEVICE_ID_PHILIPS_SAA7135 0x7135
+#endif
 
 /* ------------------------------------------------------------------ */
 /*
@@ -328,6 +334,13 @@
 
 /* test modes */
 #define SAA7134_SPECIAL_MODE                    0x1d0
+
+/* audio -- saa7133 + saa7135 only */
+#define SAA7135_DSP_RWSTATE                     0x580
+#define SAA7135_DSP_RWSTATE_ERR                 (1 << 3)
+#define SAA7135_DSP_RWSTATE_IDA                 (1 << 2)
+#define SAA7135_DSP_RWSTATE_RDB                 (1 << 1)
+#define SAA7135_DSP_RWSTATE_WRR                 (1 << 0)
 
 /* ------------------------------------------------------------------ */
 /*
diff -Nru a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
--- a/drivers/media/video/saa7134/saa7134-ts.c	Thu Apr 24 05:25:35 2003
+++ b/drivers/media/video/saa7134/saa7134-ts.c	Sat May 17 14:09:46 2003
@@ -52,8 +52,9 @@
 {
 	u32 control;
 	
-	dprintk("buffer_activate [%p]\n",buf);
+	dprintk("buffer_activate [%p]",buf);
 	buf->vb.state = STATE_ACTIVE;
+	buf->top_seen = 0;
 	
         /* dma: setup channel 5 (= TS) */
         control = SAA7134_RS_CONTROL_BURST_16 |
@@ -63,11 +64,11 @@
 	if (NULL == next)
 		next = buf;
 	if (V4L2_FIELD_TOP == buf->vb.field) {
-		dprintk("[top]     buf=%p next=%p",buf,next);
+		dprintk("- [top]     buf=%p next=%p\n",buf,next);
 		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(buf));
 		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(next));
 	} else {
-		dprintk("[bottom]  buf=%p next=%p",buf,next);
+		dprintk("- [bottom]  buf=%p next=%p\n",buf,next);
 		saa_writel(SAA7134_RS_BA1(5),saa7134_buffer_base(next));
 		saa_writel(SAA7134_RS_BA2(5),saa7134_buffer_base(buf));
 	}
@@ -86,8 +87,11 @@
 {
 	struct saa7134_dev *dev = file->private_data;
 	struct saa7134_buf *buf = (struct saa7134_buf *)vb;
-	int lines, llength, size, err;
+	unsigned int lines, llength, size;
+	int err;
 	
+	dprintk("buffer_prepare [%p,%s]\n",buf,v4l2_field_names[field]);
+
 	llength = TS_PACKET_SIZE;
 	lines = TS_NR_PACKETS;
 	
@@ -116,7 +120,6 @@
 			goto oops;
 	}
 	buf->vb.state = STATE_PREPARED;
-	buf->top_seen = 0;
 	buf->activate = buffer_activate;
 	buf->vb.field = field;
 	return 0;
@@ -163,7 +166,7 @@
 
 static int ts_open(struct inode *inode, struct file *file)
 {
-	unsigned int minor = minor(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct saa7134_dev *h,*dev = NULL;
 	struct list_head *list;
 	int err;
@@ -414,6 +417,7 @@
 	dev->ts_q.timeout.function = saa7134_buffer_timeout;
 	dev->ts_q.timeout.data     = (unsigned long)(&dev->ts_q);
 	dev->ts_q.dev              = dev;
+	dev->ts_q.need_two         = 1;
 	videobuf_queue_init(&dev->ts.ts, &ts_qops, dev->pci, &dev->slock,
 			    V4L2_BUF_TYPE_VIDEO_CAPTURE,
 			    V4L2_FIELD_ALTERNATE,
@@ -445,7 +449,7 @@
 
 	spin_lock(&dev->slock);
 	if (dev->ts_q.curr) {
-		field = dev->video_q.curr->vb.field;
+		field = dev->ts_q.curr->vb.field;
 		if (field == V4L2_FIELD_TOP) {
 			if ((status & 0x100000) != 0x100000)
 				goto done;
diff -Nru a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c	Thu Mar 13 16:52:15 2003
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c	Sat May 17 14:09:46 2003
@@ -37,13 +37,23 @@
 MODULE_PARM(audio_debug,"i");
 MODULE_PARM_DESC(audio_debug,"enable debug messages [tv audio]");
 
+static unsigned int audio_carrier = 0;
+MODULE_PARM(audio_carrier,"i");
+MODULE_PARM_DESC(audio_carrier,"audio carrier location");
+
 #define dprintk(fmt, arg...)	if (audio_debug) \
 	printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg)
+#define d2printk(fmt, arg...)	if (audio_debug > 1) \
+	printk(KERN_DEBUG "%s/audio: " fmt, dev->name, ## arg)
 
 #define print_regb(reg) printk("%s:   reg 0x%03x [%-16s]: 0x%02x\n", \
 		dev->name,(SAA7134_##reg),(#reg),saa_readb((SAA7134_##reg)))
 
+#define SCAN_INITIAL_DELAY  (HZ)
+#define SCAN_SAMPLE_DELAY   (HZ/10)
+
 /* ------------------------------------------------------------------ */
+/* saa7134 code                                                       */
 
 static struct saa7134_tvaudio tvaudio[] = {
 	{
@@ -95,6 +105,12 @@
 		.carr2         = 5850,
 		.mode          = TVAUDIO_NICAM_AM,
 	},{
+		.name          = "SECAM-D/K",
+		.std           = V4L2_STD_SECAM,
+		.carr1         = 6500,
+		.carr2         = -1,
+		.mode          = TVAUDIO_FM_MONO,
+	},{
 		.name          = "NTSC-M",
 		.std           = V4L2_STD_NTSC,
 		.carr1         = 4500,
@@ -122,7 +138,7 @@
 		schedule();
 	else
 		udelay(10);
-		
+
 	saa_writeb(SAA7134_AUDIO_CLOCK0,      clock        & 0xff);
 	saa_writeb(SAA7134_AUDIO_CLOCK1,     (clock >>  8) & 0xff);
 	saa_writeb(SAA7134_AUDIO_CLOCK2,     (clock >> 16) & 0xff);
@@ -134,9 +150,9 @@
 	saa_writeb(SAA7134_FM_DEMATRIX,      0x80);
 }
 
-static __u32 tvaudio_carr2reg(__u32 carrier)
+static u32 tvaudio_carr2reg(u32 carrier)
 {
-	__u64 a = carrier;
+	u64 a = carrier;
 
 	a <<= 24;
 	do_div(a,12288);
@@ -152,17 +168,19 @@
 	saa_writel(SAA7134_CARRIER2_FREQ0 >> 2, tvaudio_carr2reg(secondary));
 }
 
-static void saa7134_tvaudio_do_mute_input(struct saa7134_dev *dev)
+static void mute_input_7134(struct saa7134_dev *dev)
 {
-	int mute;
+	unsigned int mute;
 	struct saa7134_input *in;
 	int reg = 0;
 	int mask;
 
 	/* look what is to do ... */
 	in   = dev->input;
-	mute = (dev->ctl_mute || dev->automute);
-	if (!card_has_audio(dev) && card(dev).mute.name) {
+	mute = (dev->ctl_mute ||
+		(dev->automute  &&  (&card(dev).radio) != in));
+	if (PCI_DEVICE_ID_PHILIPS_SAA7130 == dev->pci->device &&
+	    card(dev).mute.name) {
 		/* 7130 - we'll mute using some unconnected audio input */
 		if (mute)
 			in = &card(dev).mute;
@@ -171,14 +189,12 @@
 	    dev->hw_input == in)
 		return;
 
-#if 1
 	dprintk("ctl_mute=%d automute=%d input=%s  =>  mute=%d input=%s\n",
 		dev->ctl_mute,dev->automute,dev->input->name,mute,in->name);
-#endif
 	dev->hw_mute  = mute;
 	dev->hw_input = in;
 
-	if (card_has_audio(dev))
+	if (PCI_DEVICE_ID_PHILIPS_SAA7134 == dev->pci->device)
 		/* 7134 mute */
 		saa_writeb(SAA7134_AUDIO_MUTE_CTRL, mute ? 0xff : 0xbb);
 
@@ -199,25 +215,6 @@
 	saa7134_track_gpio(dev,in->name);
 }
 
-void saa7134_tvaudio_setmute(struct saa7134_dev *dev)
-{
-	saa7134_tvaudio_do_mute_input(dev);
-}
-
-void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
-			      struct saa7134_input *in)
-{
-	dev->input = in;
-	saa7134_tvaudio_do_mute_input(dev);
-}
-
-void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level)
-{
-	saa_writeb(SAA7134_CHANNEL1_LEVEL,     level & 0x1f);
-	saa_writeb(SAA7134_CHANNEL2_LEVEL,     level & 0x1f);
-	saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f);
-}
-
 static void tvaudio_setmode(struct saa7134_dev *dev,
 			    struct saa7134_tvaudio *audio,
 			    char *note)
@@ -274,8 +271,77 @@
 	saa_writel(0x174 >> 2, 0x0001e000); /* FIXME */
 }
 
-int saa7134_tvaudio_getstereo(struct saa7134_dev *dev,
-			      struct saa7134_tvaudio *audio)
+static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	
+	add_wait_queue(&dev->thread.wq, &wait);
+	current->state = TASK_INTERRUPTIBLE;
+	schedule_timeout(timeout);
+	remove_wait_queue(&dev->thread.wq, &wait);
+	return dev->thread.scan1 != dev->thread.scan2;
+}
+
+static int tvaudio_checkcarrier(struct saa7134_dev *dev, int carrier)
+{
+	__s32 left,right,value;
+
+	if (audio_debug > 1) {
+		int i;
+		dprintk("debug %d:",carrier);
+		for (i = -150; i <= 150; i += 30) {
+			tvaudio_setcarrier(dev,carrier+i,carrier+i);
+			saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+			if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+				return -1;
+			value = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+			if (0 == i)
+				printk("  #  %6d  # ",value >> 16);
+			else
+				printk(" %6d",value >> 16);
+		}
+		printk("\n");
+	}
+	
+	tvaudio_setcarrier(dev,carrier-90,carrier-90);
+	saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+	if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+		return -1;
+	left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+	tvaudio_setcarrier(dev,carrier+90,carrier+90);
+	saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+	if (tvaudio_sleep(dev,SCAN_SAMPLE_DELAY))
+		return -1;
+	right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+
+	left >>= 16;
+        right >>= 16;
+	value = left > right ? left - right : right - left;
+	dprintk("scanning %d.%03d MHz =>  dc is %5d [%d/%d]\n",
+		carrier/1000,carrier%1000,value,left,right);
+	return value;
+}
+
+#if 0
+static void sifdebug_dump_regs(struct saa7134_dev *dev)
+{
+	print_regb(AUDIO_STATUS);
+	print_regb(IDENT_SIF);
+	print_regb(LEVEL_READOUT1);
+	print_regb(LEVEL_READOUT2);
+	print_regb(DCXO_IDENT_CTRL);
+	print_regb(DEMODULATOR);
+	print_regb(AGC_GAIN_SELECT);
+	print_regb(MONITOR_SELECT);
+	print_regb(FM_DEEMPHASIS);
+	print_regb(FM_DEMATRIX);
+	print_regb(SIF_SAMPLE_FREQ);
+	print_regb(ANALOG_IO_SELECT);
+}
+#endif
+
+static int tvaudio_getstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio)
 {
 	__u32 idp,nicam;
 	int retval = -1;
@@ -321,62 +387,42 @@
 	return retval;
 }
 
-static int tvaudio_sleep(struct saa7134_dev *dev, int timeout)
+static int tvaudio_setstereo(struct saa7134_dev *dev, struct saa7134_tvaudio *audio,
+			     u32 mode)
 {
-	DECLARE_WAITQUEUE(wait, current);
-	
-	add_wait_queue(&dev->thread.wq, &wait);
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(timeout);
-	remove_wait_queue(&dev->thread.wq, &wait);
-	return dev->thread.scan1 != dev->thread.scan2;
-}
-
-static int tvaudio_checkcarrier(struct saa7134_dev *dev, int carrier)
-{
-	__s32 left,right,value;
-	
-	tvaudio_setcarrier(dev,carrier-100,carrier-100);
-	if (tvaudio_sleep(dev,HZ/10))
-		return -1;
-	left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
-	if (tvaudio_sleep(dev,HZ/10))
-		return -1;
-	left = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
-
-	tvaudio_setcarrier(dev,carrier+100,carrier+100);
-	if (tvaudio_sleep(dev,HZ/10))
-		return -1;
-        right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
-	if (tvaudio_sleep(dev,HZ/10))
-		return -1;
-	right = saa_readl(SAA7134_LEVEL_READOUT1 >> 2);
+	static char *name[] = {
+		[ V4L2_TUNER_MODE_MONO   ] = "mono",
+		[ V4L2_TUNER_MODE_STEREO ] = "stereo",
+		[ V4L2_TUNER_MODE_LANG1  ] = "lang1",
+		[ V4L2_TUNER_MODE_LANG2  ] = "lang2",
+	};
+	static u32 fm[] = {
+		[ V4L2_TUNER_MODE_MONO   ] = 0x00,  /* ch1  */
+		[ V4L2_TUNER_MODE_STEREO ] = 0x80,  /* auto */
+		[ V4L2_TUNER_MODE_LANG1  ] = 0x00,  /* ch1  */
+		[ V4L2_TUNER_MODE_LANG2  ] = 0x01,  /* ch2  */
+	};
+	u32 reg;
 
-	left >>= 16;
-        right >>= 16;
-	value = left > right ? left - right : right - left;
-	dprintk("scanning %d.%03d MHz =>  dc is %5d [%d/%d]\n",
-		carrier/1000,carrier%1000,value,left,right);
-	return value;
-}
-
-#if 0
-static void sifdebug_dump_regs(struct saa7134_dev *dev)
-{
-	print_regb(AUDIO_STATUS);
-	print_regb(IDENT_SIF);
-	print_regb(LEVEL_READOUT1);
-	print_regb(LEVEL_READOUT2);
-	print_regb(DCXO_IDENT_CTRL);
-	print_regb(DEMODULATOR);
-	print_regb(AGC_GAIN_SELECT);
-	print_regb(MONITOR_SELECT);
-	print_regb(FM_DEEMPHASIS);
-	print_regb(FM_DEMATRIX);
-	print_regb(SIF_SAMPLE_FREQ);
-	print_regb(ANALOG_IO_SELECT);
+	switch (audio->mode) {
+	case TVAUDIO_FM_MONO:
+		/* nothing to do ... */
+		break;
+	case TVAUDIO_FM_K_STEREO:
+	case TVAUDIO_FM_BG_STEREO:
+		dprintk("setstereo [fm] => %s\n",
+			name[ mode % ARRAY_SIZE(name) ]);
+		reg = fm[ mode % ARRAY_SIZE(fm) ];
+		saa_writeb(SAA7134_FM_DEMATRIX, reg);
+		break;
+	case TVAUDIO_FM_SAT_STEREO:
+	case TVAUDIO_NICAM_AM:
+	case TVAUDIO_NICAM_FM:
+		/* FIXME */
+		break;
+	}
+	return 0;
 }
-#endif
 
 static int tvaudio_thread(void *data)
 {
@@ -388,7 +434,8 @@
 	struct saa7134_dev *dev = data;
 	const int *carr_scan;
 	int carr_vals[4];
-	int i,max,carrier,audio;
+	unsigned int i, audio;
+	int max1,max2,carrier,rx,mode;
 
 	lock_kernel();
 	daemonize("%s", dev->name);
@@ -410,10 +457,10 @@
 		dev->tvaudio  = NULL;
 		tvaudio_init(dev);
 		dev->automute = 1;
-		saa7134_tvaudio_setmute(dev);
+		mute_input_7134(dev);
 
 		/* give the tuner some time */
-		if (tvaudio_sleep(dev,HZ/2))
+		if (tvaudio_sleep(dev,SCAN_INITIAL_DELAY))
 			goto restart;
 
 		/* find the main carrier */
@@ -433,55 +480,280 @@
 			if (dev->thread.scan1 != dev->thread.scan2)
 				goto restart;
 		}
-		for (carrier = 0, max = 0, i = 0; i < MAX_SCAN; i++) {
+		for (carrier = 0, max1 = 0, max2 = 0, i = 0; i < MAX_SCAN; i++) {
 			if (!carr_scan[i])
 				continue;
-			if (max < carr_vals[i]) {
-				max = carr_vals[i];
+			if (max1 < carr_vals[i]) {
+				max2 = max1;
+				max1 = carr_vals[i];
 				carrier = carr_scan[i];
+			} else if (max2 < carr_vals[i]) {
+				max2 = carr_vals[i];
 			}
 		}
-		if (0 == carrier) {
-			/* Oops: autoscan didn't work for some reason :-/ */
-			printk(KERN_WARNING "%s/audio: oops: audio carrier "
-			       "scan failed\n", dev->name);
+
+		if (0 != carrier && max1 > 2000 && max1 > max2*3) {
+			/* found good carrier */
+			dprintk("found %s main sound carrier @ %d.%03d MHz [%d/%d]\n",
+				dev->tvnorm->name, carrier/1000, carrier%1000,
+				max1, max2);
+			dev->last_carrier = carrier;
+		} else if (0 != audio_carrier) {
+			/* no carrier -- try insmod option as fallback */
+			carrier = audio_carrier;
+			printk(KERN_WARNING "%s/audio: audio carrier scan failed, "
+			       "using %d.%03d MHz [insmod option]\n",
+			       dev->name, carrier/1000, carrier%1000);
+		} else if (0 != dev->last_carrier) {
+			/* no carrier -- try last detected one as fallback */
+			carrier = dev->last_carrier;
+			printk(KERN_WARNING "%s/audio: audio carrier scan failed, "
+			       "using %d.%03d MHz [last detected]\n",
+			       dev->name, carrier/1000, carrier%1000);
 		} else {
-			dprintk("found %s main sound carrier @ %d.%03d MHz\n",
-				dev->tvnorm->name,
-				carrier/1000,carrier%1000);
+			/* no carrier + no fallback -- try first in list */
+			carrier = carr_scan[0];
+			printk(KERN_WARNING "%s/audio: audio carrier scan failed, "
+			       "using %d.%03d MHz [default]\n",
+			       dev->name, carrier/1000, carrier%1000);
 		}
 		tvaudio_setcarrier(dev,carrier,carrier);
 		dev->automute = 0;
+		saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x00);
 		saa7134_tvaudio_setmute(dev);
 
 		/* find the exact tv audio norm */
-		for (audio = -1, i = 0; i < TVAUDIO; i++) {
-			if (dev->tvnorm->id != -1 &&
+		for (audio = UNSET, i = 0; i < TVAUDIO; i++) {
+			if (dev->tvnorm->id != UNSET &&
 			    dev->tvnorm->id != tvaudio[i].std)
 				continue;
 			if (tvaudio[i].carr1 != carrier)
 				continue;
 
-			if (-1 == audio)
+			if (UNSET == audio)
 				audio = i;
 			tvaudio_setmode(dev,&tvaudio[i],"trying");
 			if (tvaudio_sleep(dev,HZ))
 				goto restart;
-			if (-1 != saa7134_tvaudio_getstereo(dev,&tvaudio[i])) {
+			if (-1 != tvaudio_getstereo(dev,&tvaudio[i])) {
 				audio = i;
 				break;
 			}
 		}
-		if (-1 == audio)
+		saa_andorb(SAA7134_STEREO_DAC_OUTPUT_SELECT, 0x30, 0x30);
+		if (UNSET == audio)
 			continue;
 		tvaudio_setmode(dev,&tvaudio[audio],"using");
+		tvaudio_setstereo(dev,&tvaudio[audio],V4L2_TUNER_MODE_MONO);
 		dev->tvaudio = &tvaudio[audio];
 
-#if 1
 		if (tvaudio_sleep(dev,3*HZ))
 			goto restart;
-		saa7134_tvaudio_getstereo(dev,&tvaudio[i]);
+		rx = tvaudio_getstereo(dev,&tvaudio[i]);
+		mode = saa7134_tvaudio_rx2mode(rx);
+		tvaudio_setstereo(dev,&tvaudio[audio],mode);
+	}
+
+ done:
+	dev->thread.task = NULL;
+	if(dev->thread.notify != NULL)
+		up(dev->thread.notify);
+	return 0;
+}
+
+/* ------------------------------------------------------------------ */
+/* saa7133 / saa7135 code                                             */
+
+static char *stdres[0x20] = {
+	[0x00] = "no standard detected",
+	[0x01] = "B/G (in progress)",
+	[0x02] = "D/K (in progress)",
+	[0x03] = "M (in progress)",
+
+	[0x04] = "B/G A2",
+	[0x05] = "B/G NICAM",
+	[0x06] = "D/K A2 (1)",
+	[0x07] = "D/K A2 (2)",
+	[0x08] = "D/K A2 (3)",
+	[0x09] = "D/K NICAM",
+	[0x0a] = "L NICAM",
+	[0x0b] = "I NICAM",
+	
+	[0x0c] = "M Korea",
+	[0x0d] = "M BTSC ",
+	[0x0e] = "M EIAJ",
+
+	[0x0f] = "FM radio / IF 10.7 / 50 deemp",
+	[0x10] = "FM radio / IF 10.7 / 75 deemp",
+	[0x11] = "FM radio / IF sel / 50 deemp",
+	[0x12] = "FM radio / IF sel / 75 deemp",
+
+	[0x13 ... 0x1e ] = "unknown",
+	[0x1f] = "??? [in progress]",
+};
+
+#define DSP_RETRY 16
+#define DSP_DELAY 16
+
+static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit)
+{
+	int state, count = DSP_RETRY;
+
+	state = saa_readb(SAA7135_DSP_RWSTATE);
+	if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
+		printk("%s: dsp access error\n",dev->name);
+		/* FIXME: send ack ... */
+		return -EIO;
+	}
+	while (0 == (state & bit)) {
+		if (unlikely(0 == count)) {
+			printk("%s: dsp access wait timeout [bit=%s]\n",
+			       dev->name,
+			       (bit & SAA7135_DSP_RWSTATE_WRR) ? "WRR" :
+			       (bit & SAA7135_DSP_RWSTATE_RDB) ? "RDB" :
+			       (bit & SAA7135_DSP_RWSTATE_IDA) ? "IDA" :
+			       "???");
+			return -EIO;
+		}
+		saa_wait(DSP_DELAY);
+		state = saa_readb(SAA7135_DSP_RWSTATE);
+		count--;
+	}
+	return 0;
+}
+
+#if 0
+static int saa_dsp_readl(struct saa7134_dev *dev, int reg, u32 *value)
+{
+	int err;
+
+	d2printk("dsp read reg 0x%x\n", reg<<2);
+	saa_readl(reg);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_RDB);
+	if (err < 0)
+		return err;
+	*value = saa_readl(reg);
+	d2printk("dsp read   => 0x%06x\n", *value & 0xffffff);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_IDA);
+	if (err < 0)
+		return err;
+	return 0;
+}
 #endif
+
+int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value)
+{
+	int err;
+
+	d2printk("dsp write reg 0x%x = 0x%06x\n",reg<<2,value);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
+	if (err < 0)
+		return err;
+	saa_writel(reg,value);
+	err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
+	if (err < 0)
+		return err;
+	return 0;
+}
+
+static int getstereo_7133(struct saa7134_dev *dev)
+{
+	int retval = V4L2_TUNER_SUB_MONO;
+	u32 value;
+
+	value = saa_readl(0x528 >> 2);
+	if (value & 0x20)
+		retval = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	if (value & 0x40)
+		retval = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
+	return retval;
+}
+
+static int mute_input_7133(struct saa7134_dev *dev)
+{
+	u32 reg = 0;
+	
+	switch (dev->input->amux) {
+	case TV:    reg = 0x02; break;
+	case LINE1: reg = 0x00; break;
+	case LINE2: reg = 0x01; break;
+	}
+	if (dev->ctl_mute)
+		reg = 0x07;
+	saa_writel(0x594 >> 2, reg);
+	return 0;
+}
+
+static int tvaudio_thread_ddep(void *data)
+{
+	struct saa7134_dev *dev = data;
+	u32 value, norms;
+
+	lock_kernel();
+	daemonize("%s", dev->name);
+	dev->thread.task = current;
+	unlock_kernel();
+	if (dev->thread.notify != NULL)
+		up(dev->thread.notify);
+
+	/* unmute */
+	saa_dsp_writel(dev, 0x474 >> 2, 0x00);
+	saa_dsp_writel(dev, 0x450 >> 2, 0x00);
+
+	for (;;) {
+		if (dev->thread.exit || signal_pending(current))
+			goto done;
+		interruptible_sleep_on(&dev->thread.wq);
+		if (dev->thread.exit || signal_pending(current))
+			goto done;
+
+	restart:
+		dev->thread.scan1 = dev->thread.scan2;
+		dprintk("tvaudio thread scan start [%d]\n",dev->thread.scan1);
+
+		norms = 0;
+		if (dev->tvnorm->id & V4L2_STD_PAL)
+			norms |= 0x2c; /* B/G + D/K + I */
+		if (dev->tvnorm->id & V4L2_STD_NTSC)
+			norms |= 0x40; /* M */
+		if (dev->tvnorm->id & V4L2_STD_SECAM)
+			norms |= 0x18; /* L + D/K */
+		if (0 == norms)
+			norms = 0x0000007c;
+
+		/* quick & dirty -- to be fixed up later ... */
+		saa_dsp_writel(dev, 0x454 >> 2, 0);
+		saa_dsp_writel(dev, 0x454 >> 2, norms | 0x80);
+		saa_dsp_writel(dev, 0x464 >> 2, 0x000000);
+		saa_dsp_writel(dev, 0x470 >> 2, 0x101010);
+
+		if (tvaudio_sleep(dev,3*HZ))
+			goto restart;
+		value = saa_readl(0x528 >> 2) & 0xffffff;
+
+		dprintk("tvaudio thread status: 0x%x [%s%s%s]\n",
+			value, stdres[value & 0x1f],
+			(value & 0x000020) ? ",stereo" : "",
+			(value & 0x000040) ? ",dual"   : "");
+		dprintk("detailed status: "
+			"%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
+			(value & 0x000080) ? " A2/EIAJ pilot tone "     : "",
+			(value & 0x000100) ? " A2/EIAJ dual "           : "",
+			(value & 0x000200) ? " A2/EIAJ stereo "         : "",
+			(value & 0x000400) ? " A2/EIAJ noise mute "     : "",
+
+			(value & 0x000800) ? " BTSC/FM radio pilot "    : "",
+			(value & 0x001000) ? " SAP carrier "            : "",
+			(value & 0x002000) ? " BTSC stereo noise mute " : "",
+			(value & 0x004000) ? " SAP noise mute "         : "",
+			(value & 0x008000) ? " VDSP "                   : "",
+			
+			(value & 0x010000) ? " NICST "                  : "",
+			(value & 0x020000) ? " NICDU "                  : "",
+			(value & 0x040000) ? " NICAM muted "            : "",
+			(value & 0x080000) ? " NICAM reserve sound "    : "",
+			
+			(value & 0x100000) ? " init done "              : "");
 	}
 
  done:
@@ -492,14 +764,89 @@
 }
 
 /* ------------------------------------------------------------------ */
+/* common stuff + external entry points                               */
+
+int saa7134_tvaudio_rx2mode(u32 rx)
+{
+	u32 mode;
+	
+	mode = V4L2_TUNER_MODE_MONO;
+	if (rx & V4L2_TUNER_SUB_STEREO)
+		mode = V4L2_TUNER_MODE_STEREO;
+	else if (rx & V4L2_TUNER_SUB_LANG1)
+		mode = V4L2_TUNER_MODE_LANG1;
+	else if (rx & V4L2_TUNER_SUB_LANG2)
+		mode = V4L2_TUNER_MODE_LANG2;
+	return mode;
+}
+	
+void saa7134_tvaudio_setmute(struct saa7134_dev *dev)
+{
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7130:
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		mute_input_7134(dev);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		mute_input_7133(dev);
+		break;
+	}
+}
+
+void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
+			      struct saa7134_input *in)
+{
+	dev->input = in;
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7130:
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		mute_input_7134(dev);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		mute_input_7133(dev);
+		break;
+	}
+}
+
+void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level)
+{
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		saa_writeb(SAA7134_CHANNEL1_LEVEL,     level & 0x1f);
+		saa_writeb(SAA7134_CHANNEL2_LEVEL,     level & 0x1f);
+		saa_writeb(SAA7134_NICAM_LEVEL_ADJUST, level & 0x1f);
+		break;
+	}
+}
+
+int saa7134_tvaudio_getstereo(struct saa7134_dev *dev)
+{
+	int retval = V4L2_TUNER_SUB_MONO;
+
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		if (dev->tvaudio)
+			retval = tvaudio_getstereo(dev,dev->tvaudio);
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		retval = getstereo_7133(dev);
+		break;
+	}
+	return retval;
+}
 
 int saa7134_tvaudio_init(struct saa7134_dev *dev)
 {
 	DECLARE_MUTEX_LOCKED(sem);
+	int (*my_thread)(void *data) = NULL;
 
 	/* enable I2S audio output */
 	if (saa7134_boards[dev->board].i2s_rate) {
-		int rate = (32000 == saa7134_boards[dev->board].i2s_rate) ? 0x01 : 0x03;
+		int rate = (32000 == saa7134_boards[dev->board].i2s_rate)
+			? 0x01 : 0x03;
 		
 		/* set rate */ 
 		saa_andorb(SAA7134_SIF_SAMPLE_FREQ, 0x03, rate);
@@ -512,13 +859,24 @@
 		saa_writeb(SAA7134_I2S_AUDIO_OUTPUT,   0x01);
 	}
 
-	/* start tvaudio thread */
-	init_waitqueue_head(&dev->thread.wq);
-	dev->thread.notify = &sem;
-	kernel_thread(tvaudio_thread,dev,0);
-	down(&sem);
-	dev->thread.notify = NULL;
-	wake_up_interruptible(&dev->thread.wq);
+	switch (dev->pci->device) {
+	case PCI_DEVICE_ID_PHILIPS_SAA7134:
+		my_thread = tvaudio_thread;
+		break;
+	case PCI_DEVICE_ID_PHILIPS_SAA7133:
+	case PCI_DEVICE_ID_PHILIPS_SAA7135:
+		my_thread = tvaudio_thread_ddep;
+		break;
+	}
+	if (my_thread) {
+		/* start tvaudio thread */
+		init_waitqueue_head(&dev->thread.wq);
+		dev->thread.notify = &sem;
+		kernel_thread(my_thread,dev,0);
+		down(&sem);
+		dev->thread.notify = NULL;
+		wake_up_interruptible(&dev->thread.wq);
+	}
 
 	return 0;
 }
@@ -541,8 +899,13 @@
 
 int saa7134_tvaudio_do_scan(struct saa7134_dev *dev)
 {
-	dev->thread.scan2++;
-	wake_up_interruptible(&dev->thread.wq);
+	if (dev->thread.task) {
+		dev->thread.scan2++;
+		wake_up_interruptible(&dev->thread.wq);
+	} else {
+		dev->automute = 0;
+		saa7134_tvaudio_setmute(dev);
+	}
 	return 0;
 }
 
diff -Nru a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
--- a/drivers/media/video/saa7134/saa7134-vbi.c	Thu Mar 13 16:52:15 2003
+++ b/drivers/media/video/saa7134/saa7134-vbi.c	Sat May 17 14:09:46 2003
@@ -85,6 +85,7 @@
 
 	dprintk("buffer_activate [%p]\n",buf);
 	buf->vb.state = STATE_ACTIVE;
+	buf->top_seen = 0;
 
 	task_init(dev,buf,TASK_A);
 	task_init(dev,buf,TASK_B);
@@ -119,7 +120,8 @@
 	struct saa7134_dev *dev = fh->dev;
 	struct saa7134_buf *buf = (struct saa7134_buf *)vb;
 	struct saa7134_tvnorm *norm = dev->tvnorm;
-	int lines, llength, size, err;
+	unsigned int lines, llength, size;
+	int err;
 
 	lines   = norm->vbi_v_stop - norm->vbi_v_start +1;
 	if (lines > VBI_LINE_COUNT)
@@ -155,7 +157,6 @@
 			goto oops;
 	}
 	buf->vb.state = STATE_PREPARED;
-	buf->top_seen = 0;
 	buf->activate = buffer_activate;
 	buf->vb.field = field;
 	return 0;
@@ -166,7 +167,7 @@
 }
 
 static int
-buffer_setup(struct file *file, int *count, int *size)
+buffer_setup(struct file *file, unsigned int *count, unsigned int *size)
 {
 	struct saa7134_fh *fh   = file->private_data;
 	struct saa7134_dev *dev = fh->dev;
@@ -241,7 +242,7 @@
 	if (dev->vbi_q.curr) {
 		dev->vbi_fieldcount++;
 		/* make sure we have seen both fields */
-		if ((status & 0x10) == 0x10) {
+		if ((status & 0x10) == 0x00) {
 			dev->vbi_q.curr->top_seen = 1;
 			goto done;
 		}
diff -Nru a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
--- a/drivers/media/video/saa7134/saa7134-video.c	Thu Apr 24 05:25:35 2003
+++ b/drivers/media/video/saa7134/saa7134-video.c	Sat May 17 14:09:46 2003
@@ -2,7 +2,7 @@
  * device driver for philips saa7134 based TV cards
  * video4linux video interface
  *
- * (c) 2001,02 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+ * (c) 2001-03 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
  *
  *  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
@@ -127,7 +127,7 @@
 		.vshift   = 1,
 	}
 };
-#define FORMATS (sizeof(formats)/sizeof(struct saa7134_format))
+#define FORMATS ARRAY_SIZE(formats)
 
 static struct saa7134_tvnorm tvnorms[] = {
 	{
@@ -141,13 +141,15 @@
 		.chroma_ctrl1  = 0x81,
 		.chroma_gain   = 0x2a,
 		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
 
 		.h_start       = 0,
 		.h_stop        = 719,
 		.video_v_start = 24,
 		.video_v_stop  = 311,
-		.vbi_v_start   = 7-3,  /* FIXME */
-		.vbi_v_stop    = 22-3,
+		.vbi_v_start   = 7,
+		.vbi_v_stop    = 22,
+		.src_timing    = 4,
 	},{
 		.name          = "NTSC",
 		.id            = V4L2_STD_NTSC,
@@ -159,6 +161,7 @@
 		.chroma_ctrl1  = 0x89,
 		.chroma_gain   = 0x2a,
 		.chroma_ctrl2  = 0x0e,
+		.vgate_misc    = 0x18,
 
 		.h_start       = 0,
 		.h_stop        = 719,
@@ -166,17 +169,19 @@
 		.video_v_stop  = 22+240,
 		.vbi_v_start   = 10, /* FIXME */
 		.vbi_v_stop    = 21, /* FIXME */
+		.src_timing    = 1,
 	},{
 		.name          = "SECAM",
 		.id            = V4L2_STD_SECAM,
 		.width         = 720,
 		.height        = 576,
 
-		.sync_control  = 0x58,
+		.sync_control  = 0x18, /* old: 0x58, */
 		.luma_control  = 0x1b,
 		.chroma_ctrl1  = 0xd1,
 		.chroma_gain   = 0x80,
 		.chroma_ctrl2  = 0x00,
+		.vgate_misc    = 0x1c,
 
 		.h_start       = 0,
 		.h_stop        = 719,
@@ -184,6 +189,47 @@
 		.video_v_stop  = 311,
 		.vbi_v_start   = 7,
 		.vbi_v_stop    = 22,
+		.src_timing    = 4,
+	},{
+		.name          = "PAL-M",
+		.id            = V4L2_STD_PAL_M,
+		.width         = 720,
+		.height        = 480,
+
+		.sync_control  = 0x59,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0xb9,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x0e,
+		.vgate_misc    = 0x18,
+
+		.h_start       = 0,
+		.h_stop        = 719,
+		.video_v_start = 22,
+		.video_v_stop  = 22+240,
+		.vbi_v_start   = 10, /* FIXME */
+		.vbi_v_stop    = 21, /* FIXME */
+		.src_timing    = 1,
+	},{
+		.name          = "PAL-Nc",
+		.id            = V4L2_STD_PAL_Nc,
+		.width         = 720,
+		.height        = 576,
+
+		.sync_control  = 0x18,
+		.luma_control  = 0x40,
+		.chroma_ctrl1  = 0xa1,
+		.chroma_gain   = 0x2a,
+		.chroma_ctrl2  = 0x06,
+		.vgate_misc    = 0x1c,
+
+		.h_start       = 0,
+		.h_stop        = 719,
+		.video_v_start = 24,
+		.video_v_stop  = 311,
+		.vbi_v_start   = 7,
+		.vbi_v_stop    = 22,
+		.src_timing    = 4,
 #if 0
 	},{
 		.name          = "AUTO",
@@ -196,6 +242,7 @@
 		.chroma_ctrl1  = 0x8b,
 		.chroma_gain   = 0x00,
 		.chroma_ctrl2  = 0x00,
+		.vgate_misc    = 0x18,
 
 		.h_start       = 0,
 		.h_stop        = 719,
@@ -203,11 +250,11 @@
 		.video_v_stop  = 311,
 		.vbi_v_start   = 7,
 		.vbi_v_stop    = 22,
+		.src_timing    = 4,
 #endif
 	}
 };
-#define TVNORMS (sizeof(tvnorms)/sizeof(struct saa7134_tvnorm))
-
+#define TVNORMS ARRAY_SIZE(tvnorms)
 
 #define V4L2_CID_PRIVATE_INVERT      (V4L2_CID_PRIVATE_BASE + 0)
 #define V4L2_CID_PRIVATE_Y_ODD       (V4L2_CID_PRIVATE_BASE + 1)
@@ -298,11 +345,11 @@
 		.type          = V4L2_CTRL_TYPE_INTEGER,
 	}
 };
-const int CTRLS = (sizeof(video_ctrls)/sizeof(struct v4l2_queryctrl));
+static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls);
 
-static const struct v4l2_queryctrl* ctrl_by_id(int id)
+static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id)
 {
-	int i;
+	unsigned int i;
 	
 	for (i = 0; i < CTRLS; i++)
 		if (video_ctrls[i].id == id)
@@ -310,9 +357,9 @@
 	return NULL;
 }
 
-static struct saa7134_format* format_by_fourcc(int  fourcc)
+static struct saa7134_format* format_by_fourcc(unsigned int fourcc)
 {
-	int i;
+	unsigned int i;
 
 	for (i = 0; i < FORMATS; i++)
 		if (formats[i].fourcc == fourcc)
@@ -323,7 +370,7 @@
 /* ----------------------------------------------------------------------- */
 /* resource management                                                     */
 
-static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, int bit)
+static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bit)
 {
 	if (fh->resources & bit)
 		/* have it already allocated */
@@ -345,19 +392,19 @@
 }
 
 static
-int res_check(struct saa7134_fh *fh, int bit)
+int res_check(struct saa7134_fh *fh, unsigned int bit)
 {
 	return (fh->resources & bit);
 }
 
 static
-int res_locked(struct saa7134_dev *dev, int bit)
+int res_locked(struct saa7134_dev *dev, unsigned int bit)
 {
 	return (dev->resources & bit);
 }
 
 static
-void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, int bits)
+void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
 {
 	if ((fh->resources & bits) != bits)
 		BUG();
@@ -393,7 +440,8 @@
 	saa_writeb(SAA7134_ANALOG_IN_CTRL4,       0x90);
 	saa_writeb(SAA7134_HSYNC_START,           0xeb);
 	saa_writeb(SAA7134_HSYNC_STOP,            0xe0);
-
+	saa_writeb(SAA7134_SOURCE_TIMING1,        norm->src_timing);
+	
 	saa_writeb(SAA7134_SYNC_CTRL,             norm->sync_control);
 	saa_writeb(SAA7134_LUMA_CTRL,             luma_control);
 	saa_writeb(SAA7134_DEC_LUMA_BRIGHT,       dev->ctl_bright);
@@ -410,7 +458,7 @@
 	saa_writeb(SAA7134_ANALOG_ADC,            0x01);
 	saa_writeb(SAA7134_VGATE_START,           0x11);
 	saa_writeb(SAA7134_VGATE_STOP,            0xfe);
-	saa_writeb(SAA7134_MISC_VGATE_MSB,        0x18); /* FIXME */
+	saa_writeb(SAA7134_MISC_VGATE_MSB,        norm->vgate_misc);
 	saa_writeb(SAA7134_RAW_DATA_GAIN,         0x40);
 	saa_writeb(SAA7134_RAW_DATA_OFFSET,       0x80);
 
@@ -454,7 +502,7 @@
 		{    9,  15,    0,    4,   3 },
 		{   10,  16,    1,    5,   3 },
 	};
-	static const int count = sizeof(vals)/sizeof(vals[0]);
+	static const int count = ARRAY_SIZE(vals);
 	int i;
 
 	for (i = 0; i < count; i++)
@@ -532,14 +580,14 @@
 	/* deinterlace y offsets */
 	if (interlace) {
 		y_odd  = dev->ctl_y_odd;
-		y_even = dev->ctl_y_even + yscale / 32;
+		y_even = dev->ctl_y_even;
 		saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd);
 		saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even);
 		saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd);
 		saa_writeb(SAA7134_V_PHASE_OFFSET3(task), y_even);
 	} else {
 		y_odd  = dev->ctl_y_odd;
-		y_even = dev->ctl_y_even + yscale / 64;
+		y_even = dev->ctl_y_even;
 		saa_writeb(SAA7134_V_PHASE_OFFSET0(task), y_odd);
 		saa_writeb(SAA7134_V_PHASE_OFFSET1(task), y_even);
 		saa_writeb(SAA7134_V_PHASE_OFFSET2(task), y_odd);
@@ -688,7 +736,8 @@
 	err = verify_preview(dev,&fh->win);
 	if (0 != err)
 		return err;
-	
+
+	dev->ovfield = fh->win.field;
 	dprintk("start_preview %dx%d+%d+%d %s field=%s\n",
 		fh->win.w.width,fh->win.w.height,
 		fh->win.w.left,fh->win.w.top,
@@ -752,6 +801,7 @@
 
 	dprintk("buffer_activate buf=%p\n",buf);
 	buf->vb.state = STATE_ACTIVE;
+	buf->top_seen = 0;
 	
 	set_size(dev,TASK_A,buf->vb.width,buf->vb.height,
 		 V4L2_FIELD_HAS_BOTH(buf->vb.field));
@@ -828,7 +878,8 @@
 	struct saa7134_fh *fh = file->private_data;
 	struct saa7134_dev *dev = fh->dev;
 	struct saa7134_buf *buf = (struct saa7134_buf *)vb;
-	int size,err;
+	unsigned int size;
+	int err;
 	
 	/* sanity checks */
 	if (NULL == fh->fmt)
@@ -842,8 +893,8 @@
 	if (0 != buf->vb.baddr  &&  buf->vb.bsize < size)
 		return -EINVAL;
 
-	dprintk("buffer_prepare [size=%dx%d,bytes=%d,fields=%s,%s]\n",
-		fh->width,fh->height,size,v4l2_field_names[field],
+	dprintk("buffer_prepare [%d,size=%dx%d,bytes=%d,fields=%s,%s]\n",
+		vb->i,fh->width,fh->height,size,v4l2_field_names[field],
 		fh->fmt->name);
 	if (buf->vb.width  != fh->width  ||
 	    buf->vb.height != fh->height ||
@@ -872,7 +923,6 @@
 			goto oops;
 	}
 	buf->vb.state = STATE_PREPARED;
-	buf->top_seen = 0;
 	buf->activate = buffer_activate;
 	return 0;
 
@@ -1081,7 +1131,7 @@
 
 static int video_open(struct inode *inode, struct file *file)
 {
-	unsigned int minor = minor(inode->i_rdev);
+	int minor = minor(inode->i_rdev);
 	struct saa7134_dev *h,*dev = NULL;
 	struct saa7134_fh *fh;
 	struct list_head *list;
@@ -1117,8 +1167,8 @@
 	fh->radio    = radio;
 	fh->type     = type;
 	fh->fmt      = format_by_fourcc(V4L2_PIX_FMT_BGR24);
-	fh->width    = 320;
-	fh->height   = 240;
+	fh->width    = 768;
+	fh->height   = 576;
 
 	videobuf_queue_init(&fh->cap, &video_qops,
 			    dev->pci, &dev->slock,
@@ -1138,7 +1188,9 @@
 
 	if (fh->radio) {
 		/* switch to radio mode */
+		u32 v = 400*16;
 		saa7134_tvaudio_setinput(dev,&card(dev).radio);
+		saa7134_i2c_call_clients(dev,VIDIOCSFREQ,&v);
 		saa7134_i2c_call_clients(dev,AUDC_SET_RADIO,NULL);
 	} else {
 		/* switch to video/vbi mode */
@@ -1185,7 +1237,7 @@
 			buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
 	} else {
 		down(&fh->cap.lock);
-		if (-1 == fh->cap.read_off) {
+		if (UNSET == fh->cap.read_off) {
                         /* need to capture a new frame */
 			if (res_locked(fh->dev,RESOURCE_VIDEO)) {
                                 up(&fh->cap.lock);
@@ -1263,6 +1315,29 @@
 
 /* ------------------------------------------------------------------ */
 
+void saa7134_vbi_fmt(struct saa7134_dev *dev, struct v4l2_format *f)
+{
+	struct saa7134_tvnorm *norm = dev->tvnorm;
+
+	f->fmt.vbi.sampling_rate = 6750000 * 4;
+	f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
+	f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+	f->fmt.vbi.offset = 64 * 4;
+	f->fmt.vbi.start[0] = norm->vbi_v_start;
+	f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1;
+	f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start +1;
+	f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
+	f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */;
+
+#if 0
+	if (V4L2_STD_PAL == norm->id) {
+		/* FIXME */
+		f->fmt.vbi.start[0] += 3;
+		f->fmt.vbi.start[1] += 3*2;
+	}
+#endif
+}
+
 int saa7134_g_fmt(struct saa7134_dev *dev, struct saa7134_fh *fh,
 		  struct v4l2_format *f)
 {
@@ -1273,27 +1348,17 @@
 		f->fmt.pix.height       = fh->height;
 		f->fmt.pix.field        = fh->cap.field;
 		f->fmt.pix.pixelformat  = fh->fmt->fourcc;
-		f->fmt.pix.sizeimage    =
-			(fh->width*fh->height*fh->fmt->depth)/8;
+		f->fmt.pix.bytesperline =
+			(f->fmt.pix.width * fh->fmt->depth) >> 3;
+		f->fmt.pix.sizeimage =
+			f->fmt.pix.height * f->fmt.pix.bytesperline;
 		return 0;
 	case V4L2_BUF_TYPE_VIDEO_OVERLAY:
 		f->fmt.win = fh->win;
 		return 0;
 	case V4L2_BUF_TYPE_VBI_CAPTURE:
-	{
-		struct saa7134_tvnorm *norm = fh->dev->tvnorm;
-			
-		f->fmt.vbi.sampling_rate = 6750000 * 4;
-		f->fmt.vbi.samples_per_line = 2048 /* VBI_LINE_LENGTH */;
-		f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
-		f->fmt.vbi.offset = 64 * 4;
-		f->fmt.vbi.start[0] = norm->vbi_v_start;
-		f->fmt.vbi.count[0] = norm->vbi_v_stop - norm->vbi_v_start +1;
-		f->fmt.vbi.start[1] = norm->video_v_stop + norm->vbi_v_start + 1;
-		f->fmt.vbi.count[1] = f->fmt.vbi.count[0];
-		f->fmt.vbi.flags = 0; /* VBI_UNSYNC VBI_INTERLACED */;
+		saa7134_vbi_fmt(dev,f);
 		return 0;
-	}
 	default:
 		return -EINVAL;
 	}
@@ -1309,7 +1374,7 @@
 	{
 		struct saa7134_format *fmt;
 		enum v4l2_field field;
-		int maxw, maxh;
+		unsigned int maxw, maxh;
 
 		fmt = format_by_fourcc(f->fmt.pix.pixelformat);
 		if (NULL == fmt)
@@ -1336,12 +1401,18 @@
 		}
 
 		f->fmt.pix.field = field;
+		if (f->fmt.pix.width  < 48)
+			f->fmt.pix.width  = 48;
+		if (f->fmt.pix.height < 32)
+			f->fmt.pix.height = 32;
 		if (f->fmt.pix.width > maxw)
 			f->fmt.pix.width = maxw;
 		if (f->fmt.pix.height > maxh)
 			f->fmt.pix.height = maxh;
+		f->fmt.pix.bytesperline =
+			(f->fmt.pix.width * fmt->depth) >> 3;
 		f->fmt.pix.sizeimage =
-			(fh->width * fh->height * fmt->depth)/8;
+			f->fmt.pix.height * f->fmt.pix.bytesperline;
 		
 		return 0;
 	}
@@ -1350,6 +1421,9 @@
 		if (0 != err)
 			return err;
 		return 0;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		saa7134_vbi_fmt(dev,f);
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -1397,6 +1471,9 @@
 		up(&dev->lock);
 		return 0;
 		break;
+	case V4L2_BUF_TYPE_VBI_CAPTURE:
+		saa7134_vbi_fmt(dev,f);
+		return 0;
 	default:
 		return -EINVAL;
 	}
@@ -1442,10 +1519,10 @@
 	case VIDIOC_ENUMSTD:
 	{
 		struct v4l2_standard *e = arg;
-		int i;
+		unsigned int i;
 
 		i = e->index;
-		if (i < 0 || i >= TVNORMS)
+		if (i >= TVNORMS)
 			return -EINVAL;
 		err = v4l2_video_std_construct(e, tvnorms[e->index].id,
 					       tvnorms[e->index].name);
@@ -1464,7 +1541,7 @@
 	case VIDIOC_S_STD:
 	{
 		v4l2_std_id *id = arg;
-		int i;
+		unsigned int i;
 
 		for(i = 0; i < TVNORMS; i++)
 			if (*id & tvnorms[i].id)
@@ -1489,7 +1566,7 @@
 	case VIDIOC_ENUMINPUT:
 	{
 		struct v4l2_input *i = arg;
-		int n;
+		unsigned int n;
 
 		n = i->index;
 		if (n >= SAA7134_INPUT_MAX)
@@ -1557,22 +1634,8 @@
 				V4L2_TUNER_CAP_LANG1 |
 				V4L2_TUNER_CAP_LANG2;
 			t->rangehigh = 0xffffffffUL;
-			t->rxsubchans = -1;
-			if (dev->tvaudio)
-				t->rxsubchans = saa7134_tvaudio_getstereo
-					(dev,dev->tvaudio);
-			if (-1 == t->rxsubchans)
-				t->rxsubchans = V4L2_TUNER_SUB_MONO;
-#if 1
-			/* fill audmode -- FIXME: allow manual switching */
-			t->audmode = V4L2_TUNER_MODE_MONO;
-			if (t->rxsubchans & V4L2_TUNER_SUB_STEREO)
-				t->audmode = V4L2_TUNER_MODE_STEREO;
-			else if (t->rxsubchans & V4L2_TUNER_SUB_LANG1)
-				t->audmode = V4L2_TUNER_MODE_LANG1;
-			else if (t->rxsubchans & V4L2_TUNER_SUB_LANG2)
-				t->audmode = V4L2_TUNER_MODE_LANG2;
-#endif
+			t->rxsubchans = saa7134_tvaudio_getstereo(dev);
+			t->audmode = saa7134_tvaudio_rx2mode(t->rxsubchans);
 		}
 		if (0 != (saa_readb(SAA7134_STATUS_VIDEO1) & 0x03))
 			t->signal = 0xffff;
@@ -1655,14 +1718,14 @@
 	{
 		struct v4l2_fmtdesc *f = arg;
 		enum v4l2_buf_type type;
-		int index;
+		unsigned int index;
 
 		index = f->index;
 		type  = f->type;
 		switch (type) {
 		case V4L2_BUF_TYPE_VIDEO_CAPTURE:
 		case V4L2_BUF_TYPE_VIDEO_OVERLAY:
-			if (index < 0 || index >= FORMATS)
+			if (index >= FORMATS)
 				return -EINVAL;
 			if (f->type == V4L2_BUF_TYPE_VIDEO_OVERLAY &&
 			    formats[index].planar)
@@ -1760,21 +1823,23 @@
 	{
 		struct video_mbuf *mbuf = arg;
 		struct videobuf_queue *q;
-		int i;
+		struct v4l2_requestbuffers req;
+		unsigned int i;
 
 		q = saa7134_queue(fh);
-		down(&q->lock);
-		err = videobuf_mmap_setup(file,q,gbuffers,gbufsize);
-		if (err < 0) {
-			up(&q->lock);
+		memset(&req,0,sizeof(req));
+		req.type  = q->type;
+		req.count = gbuffers;
+		err = videobuf_reqbufs(file,q,&req);
+		if (err < 0)
 			return err;
-		}
 		memset(mbuf,0,sizeof(*mbuf));
-		mbuf->frames = gbuffers;
-		mbuf->size   = gbuffers * gbufsize;
-		for (i = 0; i < gbuffers; i++)
-			mbuf->offsets[i] = i * gbufsize;
-		up(&q->lock);
+		mbuf->frames = req.count;
+		mbuf->size   = 0;
+		for (i = 0; i < mbuf->frames; i++) {
+			mbuf->offsets[i]  = q->bufs[i]->boff;
+			mbuf->size       += q->bufs[i]->bsize;
+		}
 		return 0;
 	}
 	case VIDIOC_REQBUFS:
@@ -1800,7 +1865,10 @@
 	case VIDIOC_STREAMOFF:
 	{
 		int res = saa7134_resource(fh);
+
 		err = videobuf_streamoff(file,saa7134_queue(fh));
+		if (err < 0)
+			return err;
 		res_free(dev,fh,res);
 		return 0;
 	}
@@ -1879,9 +1947,16 @@
 		strcpy(a->name,"Radio");
 		return 0;
 	}
+	case VIDIOC_G_STD:
+	{
+		v4l2_std_id *id = arg;
+		*id = 0;
+		return 0;
+	}
 	case VIDIOC_S_AUDIO:
 	case VIDIOC_S_TUNER:
 	case VIDIOC_S_INPUT:
+	case VIDIOC_S_STD:
 		return 0;
 
 	case VIDIOC_QUERYCTRL:
@@ -2055,7 +2130,7 @@
 		
 		if (V4L2_FIELD_HAS_BOTH(field)) {
 			/* make sure we have seen both fields */
-			if ((status & 0x10) == 0x10) {
+			if ((status & 0x10) == 0x00) {
 				dev->video_q.curr->top_seen = 1;
 				goto done;
 			}
diff -Nru a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
--- a/drivers/media/video/saa7134/saa7134.h	Wed Mar 12 06:07:06 2003
+++ b/drivers/media/video/saa7134/saa7134.h	Sat May 17 14:09:46 2003
@@ -28,7 +28,7 @@
 #include <media/audiochip.h>
 #include <media/id.h>
 
-#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,2)
+#define SAA7134_VERSION_CODE KERNEL_VERSION(0,2,8)
 
 #ifndef TRUE
 # define TRUE (1==1)
@@ -36,6 +36,7 @@
 #ifndef FALSE
 # define FALSE (1==0)
 #endif
+#define UNSET (-1U)
 
 /* 2.4 / 2.5 driver compatibility stuff */
 
@@ -67,50 +68,52 @@
 struct saa7134_tvnorm {
 	char          *name;
 	v4l2_std_id   id;
-	int           width;
-	int           height;
+	unsigned int  width;
+	unsigned int  height;
 
 	/* video decoder */
-	int           sync_control;
-	int           luma_control;
-	int           chroma_ctrl1;
-	int           chroma_gain;
-	int           chroma_ctrl2;
+	unsigned int  sync_control;
+	unsigned int  luma_control;
+	unsigned int  chroma_ctrl1;
+	unsigned int  chroma_gain;
+	unsigned int  chroma_ctrl2;
+	unsigned int  vgate_misc;
 
 	/* video scaler */
-	int           h_start;
-	int           h_stop;
-	int           video_v_start;
-	int           video_v_stop;
-	int           vbi_v_start;
-	int           vbi_v_stop;
+	unsigned int  h_start;
+	unsigned int  h_stop;
+	unsigned int  video_v_start;
+	unsigned int  video_v_stop;
+	unsigned int  vbi_v_start;
+	unsigned int  vbi_v_stop;
+	unsigned int  src_timing;
 };
 
 struct saa7134_tvaudio {
-	char  *name;
-	int   std;
-	enum  saa7134_tvaudio_mode mode;
-	int   carr1;
-	int   carr2;
+	char         *name;
+	v4l2_std_id  std;
+	enum         saa7134_tvaudio_mode mode;
+	int          carr1;
+	int          carr2;
 };
 
 struct saa7134_format {
-	char  *name;
-	int   fourcc;
-	int   depth;
-	int   pm;
-	int   vshift;   /* vertical downsampling (for planar yuv) */
-	int   hshift;   /* horizontal downsampling (for planar yuv) */
-	int   bswap:1;
-	int   wswap:1;
-	int   yuv:1;
-	int   planar:1;
+	char           *name;
+	unsigned int   fourcc;
+	unsigned int   depth;
+	unsigned int   pm;
+	unsigned int   vshift;   /* vertical downsampling (for planar yuv) */
+	unsigned int   hshift;   /* horizontal downsampling (for planar yuv) */
+	unsigned int   bswap:1;
+	unsigned int   wswap:1;
+	unsigned int   yuv:1;
+	unsigned int   planar:1;
 };
 
 /* ----------------------------------------------------------- */
 /* card configuration                                          */
 
-#define SAA7134_BOARD_NOAUTO           -1
+#define SAA7134_BOARD_NOAUTO        UNSET
 #define SAA7134_BOARD_UNKNOWN           0
 #define SAA7134_BOARD_PROTEUS_PRO       1
 #define SAA7134_BOARD_FLYVIDEO3000      2
@@ -124,38 +127,40 @@
 #define SAA7134_BOARD_KWORLD           10
 #define SAA7134_BOARD_CINERGY600       11
 #define SAA7134_BOARD_MD7134           12
+#define SAA7134_BOARD_TYPHOON_90031    13
+#define SAA7134_BOARD_ELSA             14
+#define SAA7134_BOARD_ELSA_500TV       15
 
 #define SAA7134_INPUT_MAX 8
 
 struct saa7134_input {
 	char                    *name;
-	int                     vmux;
+	unsigned int            vmux;
 	enum saa7134_audio_in   amux;
-	int                     gpio;
-	int                     tv:1;
+	unsigned int            gpio;
+	unsigned int            tv:1;
 };
 
 struct saa7134_board {
 	char                    *name;
-	int                     audio_clock;
+	unsigned int            audio_clock;
 
 	/* input switching */
-	int                     gpiomask;
+	unsigned int            gpiomask;
 	struct saa7134_input    inputs[SAA7134_INPUT_MAX];
 	struct saa7134_input    radio;
 	struct saa7134_input    mute;
 	
 	/* peripheral I/O */
-	int                     i2s_rate;
-	int                     has_ts;
+	unsigned int            i2s_rate;
+	unsigned int            has_ts;
 	enum saa7134_video_out  video_out;
 
 	/* i2c chip info */
-	int                     tuner_type;
-	int                     need_tda9887:1;
+	unsigned int            tuner_type;
+	unsigned int            need_tda9887:1;
 };
 
-#define card_has_audio(dev)   (dev->pci->device == PCI_DEVICE_ID_PHILIPS_SAA7134)
 #define card_has_radio(dev)   (NULL != saa7134_boards[dev->board].radio.name)
 #define card_has_ts(dev)      (saa7134_boards[dev->board].has_ts)
 #define card(dev)             (saa7134_boards[dev->board])
@@ -189,9 +194,9 @@
 	struct task_struct         *task;
 	wait_queue_head_t          wq;
 	struct semaphore           *notify;
-	int                        exit;
-	int                        scan1;
-	int                        scan2;
+	unsigned int               exit;
+	unsigned int               scan1;
+	unsigned int               scan2;
 };
 
 /* buffer for one video/vbi/ts frame */
@@ -201,7 +206,7 @@
 
 	/* saa7134 specific */
 	struct saa7134_format   *fmt;
-	int                     top_seen;
+	unsigned int            top_seen;
 	int (*activate)(struct saa7134_dev *dev,
 			struct saa7134_buf *buf,
 			struct saa7134_buf *next);
@@ -215,22 +220,23 @@
 	struct saa7134_buf         *curr;
 	struct list_head           queue;
 	struct timer_list          timeout;
+	unsigned int               need_two;
 };
 
 /* video filehandle status */
 struct saa7134_fh {
 	struct saa7134_dev         *dev;
-	int                        radio;
+	unsigned int               radio;
 	enum v4l2_buf_type         type;
 
 	struct v4l2_window         win;
 	struct v4l2_clip           clips[8];
-	int                        nclips;
-	int                        resources;
+	unsigned int               nclips;
+	unsigned int               resources;
 
 	/* video capture */
 	struct saa7134_format      *fmt;
-	int                        width,height;
+	unsigned int               width,height;
 	struct videobuf_queue      cap;
 	struct saa7134_pgtable     pt_cap;
 
@@ -241,7 +247,7 @@
 
 /* TS status */
 struct saa7134_ts {
-	int                        users;
+	unsigned int               users;
 
 	/* TS capture */
 	struct videobuf_queue      ts;
@@ -253,28 +259,28 @@
         struct semaphore           lock;
 	int                        minor_mixer;
 	int                        minor_dsp;
-	int                        users_dsp;
+	unsigned int               users_dsp;
 
 	/* mixer */
 	enum saa7134_audio_in      input;
-	int                        count;
-	int                        line1;
-	int                        line2;
+	unsigned int               count;
+	unsigned int               line1;
+	unsigned int               line2;
 
 	/* dsp */
-	int                        afmt;
-	int                        rate;
-	int                        channels;
-	int                        recording;
-	int                        blocks;
-	int                        blksize;
-	int                        bufsize;
+	unsigned int               afmt;
+	unsigned int               rate;
+	unsigned int               channels;
+	unsigned int               recording;
+	unsigned int               blocks;
+	unsigned int               blksize;
+	unsigned int               bufsize;
 	struct saa7134_pgtable     pt;
 	struct videobuf_dmabuf     dma;
 	wait_queue_head_t          wq;
-	int                        dma_blk;
-	int                        read_offset;
-	int                        read_count;
+	unsigned int               dma_blk;
+	unsigned int               read_offset;
+	unsigned int               read_count;
 };
 
 /* global device status */
@@ -284,7 +290,7 @@
        	spinlock_t                 slock;
 
 	/* various device info */
-	int                        resources;
+	unsigned int               resources;
 	struct video_device        video_dev;
 	struct video_device        ts_dev;
 	struct video_device        radio_dev;
@@ -300,8 +306,8 @@
 	__u8                       *bmmio;
 
 	/* config info */
-	int                        board;
-	int                        tuner_type;
+	unsigned int               board;
+	unsigned int               tuner_type;
 
 	/* i2c i/o */
 	struct i2c_adapter         i2c_adap;
@@ -311,19 +317,19 @@
 	/* video overlay */
 	struct v4l2_framebuffer    ovbuf;
 	struct saa7134_format      *ovfmt;
-	int                        ovenable;
+	unsigned int               ovenable;
 	enum v4l2_field            ovfield;
 
 	/* video+ts+vbi capture */
 	struct saa7134_dmaqueue    video_q;
 	struct saa7134_dmaqueue    ts_q;
 	struct saa7134_dmaqueue    vbi_q;
-	int                        vbi_fieldcount;
+	unsigned int               vbi_fieldcount;
 
 	/* various v4l controls */
 	struct saa7134_tvnorm      *tvnorm;              /* video */
 	struct saa7134_tvaudio     *tvaudio;
-	int                        ctl_input;
+	unsigned int               ctl_input;
 	int                        ctl_bright;
 	int                        ctl_contrast;
 	int                        ctl_hue;
@@ -337,11 +343,12 @@
 	int                        ctl_y_even;
 
 	/* other global state info */
-	int                        automute;
+	unsigned int               automute;
 	struct saa7134_thread      thread;
 	struct saa7134_input       *input;
 	struct saa7134_input       *hw_input;
-	int                        hw_mute;
+	unsigned int               hw_mute;
+	int                        last_carrier;
 };
 
 /* ----------------------------------------------------------- */
@@ -362,12 +369,13 @@
 #define saa_setb(reg,bit)          saa_andorb((reg),(bit),(bit))
 #define saa_clearb(reg,bit)        saa_andorb((reg),(bit),0)
 
+#define saa_wait(d) { if (need_resched()) schedule(); else udelay(d);}
 
 /* ----------------------------------------------------------- */
 /* saa7134-core.c                                              */
 
 extern struct list_head  saa7134_devlist;
-extern int               saa7134_devcount;
+extern unsigned int      saa7134_devcount;
 
 void saa7134_print_ioctl(char *name, unsigned int cmd);
 void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
@@ -376,18 +384,18 @@
 
 int saa7134_pgtable_alloc(struct pci_dev *pci, struct saa7134_pgtable *pt);
 int  saa7134_pgtable_build(struct pci_dev *pci, struct saa7134_pgtable *pt,
-			   struct scatterlist *list, int length,
-			   int startpage);
+			   struct scatterlist *list, unsigned int length,
+			   unsigned int startpage);
 void saa7134_pgtable_free(struct pci_dev *pci, struct saa7134_pgtable *pt);
 
-int saa7134_buffer_count(int size, int count);
+int saa7134_buffer_count(unsigned int size, unsigned int count);
 int saa7134_buffer_startpage(struct saa7134_buf *buf);
 unsigned long saa7134_buffer_base(struct saa7134_buf *buf);
 
 int saa7134_buffer_queue(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
 			 struct saa7134_buf *buf);
 void saa7134_buffer_finish(struct saa7134_dev *dev, struct saa7134_dmaqueue *q,
-			   int state);
+			   unsigned int state);
 void saa7134_buffer_next(struct saa7134_dev *dev, struct saa7134_dmaqueue *q);
 void saa7134_buffer_timeout(unsigned long data);
 void saa7134_dma_free(struct saa7134_dev *dev,struct saa7134_buf *buf);
@@ -398,9 +406,11 @@
 /* saa7134-cards.c                                             */
 
 extern struct saa7134_board saa7134_boards[];
-extern const int saa7134_bcount;
+extern const unsigned int saa7134_bcount;
 extern struct pci_device_id __devinitdata saa7134_pci_tbl[];
 
+extern int saa7134_board_init(struct saa7134_dev *dev);
+
 
 /* ----------------------------------------------------------- */
 /* saa7134-i2c.c                                               */
@@ -449,17 +459,19 @@
 /* ----------------------------------------------------------- */
 /* saa7134-tvaudio.c                                           */
 
+int saa7134_tvaudio_rx2mode(u32 rx);
+
 void saa7134_tvaudio_setmute(struct saa7134_dev *dev);
 void saa7134_tvaudio_setinput(struct saa7134_dev *dev,
 			      struct saa7134_input *in);
 void saa7134_tvaudio_setvolume(struct saa7134_dev *dev, int level);
-int saa7134_tvaudio_getstereo(struct saa7134_dev *dev,
-			      struct saa7134_tvaudio *audio);
+int saa7134_tvaudio_getstereo(struct saa7134_dev *dev);
 
 int saa7134_tvaudio_init(struct saa7134_dev *dev);
 int saa7134_tvaudio_fini(struct saa7134_dev *dev);
 int saa7134_tvaudio_do_scan(struct saa7134_dev *dev);
 
+int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value);
 
 /* ----------------------------------------------------------- */
 /* saa7134-oss.c                                               */
diff -Nru a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
--- a/drivers/media/video/tda7432.c	Thu Apr 24 04:11:51 2003
+++ b/drivers/media/video/tda7432.c	Sat May 17 14:09:44 2003
@@ -330,8 +330,6 @@
 	i2c_set_clientdata(client, t);
 	
 	do_tda7432_init(client);
-	MOD_INC_USE_COUNT;
-	strncpy(client->dev.name, "TDA7432", DEVICE_NAME_SIZE);
 	printk(KERN_INFO "tda7432: init\n");
 
 	i2c_attach_client(client);
@@ -340,20 +338,19 @@
 
 static int tda7432_probe(struct i2c_adapter *adap)
 {
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, tda7432_attach);
 	return 0;
 }
 
 static int tda7432_detach(struct i2c_client *client)
 {
-	struct tda7432 *t = i2c_get_clientdata(client);
+	struct tda7432 *t  = i2c_get_clientdata(client);
 
 	do_tda7432_init(client);
 	i2c_detach_client(client);
 	
 	kfree(t);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -525,11 +522,9 @@
 
 static struct i2c_client client_template =
 {
-        .id     = -1,
-	.driver = &driver, 
-        .dev	= {
-		.name	= "tda7432",
-	},
+	I2C_DEVNAME("tda7432"),
+        .id         = -1,
+	.driver     = &driver, 
 };
 
 static int tda7432_init(void)
diff -Nru a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
--- a/drivers/media/video/tda9875.c	Thu Apr 24 04:11:51 2003
+++ b/drivers/media/video/tda9875.c	Sat May 17 14:09:44 2003
@@ -161,7 +161,8 @@
 	struct tda9875 *tda = i2c_get_clientdata(client);
 	unsigned char a;
 
-	dprintk(KERN_DEBUG "tda9875_set(%04x,%04x,%04x,%04x)\n",tda->lvol,tda->rvol,tda->bass,tda->treble);
+	dprintk(KERN_DEBUG "tda9875_set(%04x,%04x,%04x,%04x)\n",
+		tda->lvol,tda->rvol,tda->bass,tda->treble);
 
 
 	a = tda->lvol & 0xff;
@@ -263,8 +264,6 @@
 	}
 	
 	do_tda9875_init(client);
-	MOD_INC_USE_COUNT;
-	strncpy(client->dev.name, "TDA9875", DEVICE_NAME_SIZE);
 	printk(KERN_INFO "tda9875: init\n");
 
 	i2c_attach_client(client);
@@ -273,20 +272,19 @@
 
 static int tda9875_probe(struct i2c_adapter *adap)
 {
-	if (adap->id == (I2C_ALGO_BIT | I2C_HW_B_BT848))
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, tda9875_attach);
 	return 0;
 }
 
 static int tda9875_detach(struct i2c_client *client)
 {
-	struct tda9875 *t = i2c_get_clientdata(client);
+	struct tda9875 *t  = i2c_get_clientdata(client);
 
 	do_tda9875_init(client);
 	i2c_detach_client(client);
 	
 	kfree(t);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -395,11 +393,9 @@
 
 static struct i2c_client client_template =
 {
-        .id      = -1,
-        .driver  = &driver,
-        .dev	= {
-		.name	= "tda9875",
-	},
+        I2C_DEVNAME("tda9875"),
+        .id        = -1,
+        .driver    = &driver,
 };
 
 static int tda9875_init(void)
diff -Nru a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
--- a/drivers/media/video/tda9887.c	Thu Apr 24 04:11:51 2003
+++ b/drivers/media/video/tda9887.c	Sat May 17 14:09:47 2003
@@ -293,8 +293,6 @@
 	unsigned char *buf = NULL;
 	int rc;
 
-	printk("tda9887_configure\n");
-
 	if (t->radio) {
 		dprintk("tda9885/6/7: FM Radio mode\n");
 		buf = buf_fm_stereo;
@@ -358,33 +356,19 @@
                 return -ENOMEM;
 	memset(t,0,sizeof(*t));
 	t->client = client_template;
-        i2c_set_clientdata(&t->client, t);
 	t->pinnacle_id = -1;
+	t->tvnorm=VIDEO_MODE_PAL;
+        i2c_set_clientdata(&t->client, t);
         i2c_attach_client(&t->client);
         
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int tda9887_probe(struct i2c_adapter *adap)
 {
-	int rc;
-
-	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-	case I2C_ALGO_SAA7134:
-		printk("tda9887: probing %s i2c adapter [id=0x%x]\n",
-		       adap->dev.name,adap->id);
-		rc = i2c_probe(adap, &addr_data, tda9887_attach);
-		break;
-	default:
-		printk("tda9887: ignoring %s i2c adapter [id=0x%x]\n",
-		       adap->dev.name,adap->id);
-		rc = 0;
-		/* nothing */
-	}
-	return rc;
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
+		return i2c_probe(adap, &addr_data, tda9887_attach);
+	return 0;
 }
 
 static int tda9887_detach(struct i2c_client *client)
@@ -393,7 +377,6 @@
 
 	i2c_detach_client(client);
 	kfree(t);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -418,6 +401,7 @@
 		int *i = arg;
 
 		t->pinnacle_id = *i;
+		tda9887_miro(t);
 		break;
 	}
 	/* --- v4l ioctls --- */
diff -Nru a/drivers/media/video/tuner.c b/drivers/media/video/tuner.c
--- a/drivers/media/video/tuner.c	Thu Apr 24 04:11:51 2003
+++ b/drivers/media/video/tuner.c	Sat May 17 14:09:47 2003
@@ -20,13 +20,15 @@
 static unsigned short normal_i2c_range[] = {0x60,0x6f,I2C_CLIENT_END};
 I2C_CLIENT_INSMOD;
 
+#define UNSET (-1U)
+
 /* insmod options */
-static int debug =  0;
-static int type  = -1;
-static int addr  =  0;
+static unsigned int debug =  0;
+static unsigned int type  =  UNSET;
+static unsigned int addr  =  0;
 static char *pal =  "b";
-static int tv_range[2]    = { 44, 958 };
-static int radio_range[2] = { 65, 108 };
+static unsigned int tv_range[2]    = { 44, 958 };
+static unsigned int radio_range[2] = { 65, 108 };
 MODULE_PARM(debug,"i");
 MODULE_PARM(type,"i");
 MODULE_PARM(addr,"i");
@@ -45,13 +47,16 @@
 
 struct tuner
 {
-	int type;            /* chip type */
-	int freq;            /* keep track of the current settings */
-	int std;
-
-	int radio;
-	int mode;            /* current norm for multi-norm tuners */
-	int xogc;	     // only for MT2032
+	unsigned int type;            /* chip type */
+	unsigned int freq;            /* keep track of the current settings */
+	unsigned int std;
+	
+	unsigned int radio;
+	unsigned int mode;            /* current norm for multi-norm tuners */
+	
+	// only for MT2032
+	unsigned int xogc;
+	unsigned int radio_if2;
 };
 
 static struct i2c_driver driver;
@@ -217,8 +222,11 @@
 	  16*160.00,16*442.00,0x01,0x02,0x04,0x8e,623 },
 	{ "LG NTSC (newer TAPC series)", LGINNOTEK, NTSC,
           16*170.00, 16*450.00, 0x01,0x02,0x08,0x8e,732},
+
+	{ "HITACHI V7-J180AT", HITACHI, NTSC,
+	  16*170.00, 16*450.00, 0x01,0x02,0x00,0x8e,940 },
 };
-#define TUNERS (sizeof(tuners)/sizeof(struct tunertype))
+#define TUNERS ARRAY_SIZE(tuners)
 
 /* ---------------------------------------------------------------------- */
 
@@ -381,10 +389,15 @@
 	return 1;
 }
 
-static int mt2032_compute_freq(int rfin, int if1, int if2, int spectrum_from,
-	int spectrum_to, unsigned char *buf, int *ret_sel, int xogc) //all in Hz
+static int mt2032_compute_freq(unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int spectrum_from,
+			       unsigned int spectrum_to,
+			       unsigned char *buf,
+			       int *ret_sel,
+			       unsigned int xogc) //all in Hz
 {
-        int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
+        unsigned int fref,lo1,lo1n,lo1a,s,sel,lo1freq, desired_lo1,
 		desired_lo2,lo2,lo2n,lo2a,lo2num,lo2freq;
 
         fref= 5250 *1000; //5.25MHz
@@ -513,7 +526,9 @@
 }
 
 
-static void mt2032_set_if_freq(struct i2c_client *c,int rfin, int if1, int if2, int from, int to)
+static void mt2032_set_if_freq(struct i2c_client *c, unsigned int rfin,
+			       unsigned int if1, unsigned int if2,
+			       unsigned int from, unsigned int to)
 {
 	unsigned char buf[21];
 	int lint_try,ret,sel,lock=0;
@@ -568,28 +583,30 @@
 }
 
 
-static void mt2032_set_tv_freq(struct i2c_client *c, int freq, int norm)
+static void mt2032_set_tv_freq(struct i2c_client *c,
+			       unsigned int freq, unsigned int norm)
 {
 	int if2,from,to;
 
 	// signal bandwidth and picture carrier
-	if(norm==VIDEO_MODE_NTSC) {
+	if (norm==VIDEO_MODE_NTSC) {
 		from=40750*1000;
 		to=46750*1000;
 		if2=45750*1000; 
-	}
-	else {  // Pal 
+	} else {
+		// Pal 
 		from=32900*1000;
 		to=39900*1000;
 		if2=38900*1000;
 	}
 
-        mt2032_set_if_freq(c,freq* 1000*1000/16, 1090*1000*1000, if2, from, to);
+        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+			   1090*1000*1000, if2, from, to);
 }
 
 
 // Set tuner frequency,  freq in Units of 62.5kHz = 1/16MHz
-static void set_tv_freq(struct i2c_client *c, int freq)
+static void set_tv_freq(struct i2c_client *c, unsigned int freq)
 {
 	u8 config;
 	u16 div;
@@ -598,7 +615,7 @@
         unsigned char buffer[4];
 	int rc;
 
-	if (t->type == -1) {
+	if (t->type == UNSET) {
 		printk("tuner: tuner type not set\n");
 		return;
 	}
@@ -720,22 +737,23 @@
 
 }
 
-static void mt2032_set_radio_freq(struct i2c_client *c,int freq)
-{               
-        int if2;
-
-        if2=10700*1000; //  10.7MHz FM intermediate frequency
+static void mt2032_set_radio_freq(struct i2c_client *c, unsigned int freq)
+{
+	struct tuner *t = i2c_get_clientdata(c);
+	int if2 = t->radio_if2;
 
 	// per Manual for FM tuning: first if center freq. 1085 MHz
-        mt2032_set_if_freq(c,freq* 1000*1000/16, 1085*1000*1000,if2,if2,if2);
+        mt2032_set_if_freq(c, freq*62500 /* freq*1000*1000/16 */,
+			   1085*1000*1000,if2,if2,if2);
 }
 
-static void set_radio_freq(struct i2c_client *c, int freq)
+static void set_radio_freq(struct i2c_client *c, unsigned int freq)
 {
 	struct tunertype *tun;
 	struct tuner *t = i2c_get_clientdata(c);
         unsigned char buffer[4];
-	int rc,div;
+	unsigned div;
+	int rc;
 
 	if (freq < radio_range[0]*16 || freq > radio_range[1]*16) {
 		printk("tuner: radio freq (%d.%02d) out of range (%d-%d)\n",
@@ -743,7 +761,7 @@
 		       radio_range[0],radio_range[1]);
 		return;
 	}
-	if (t->type == -1) {
+	if (t->type == UNSET) {
 		printk("tuner: tuner type not set\n");
 		return;
 	}
@@ -798,48 +816,34 @@
                 kfree(client);
                 return -ENOMEM;
         }
-	i2c_set_clientdata(client, t);
         memset(t,0,sizeof(struct tuner));
-	if (type >= 0 && type < TUNERS) {
+	i2c_set_clientdata(client, t);
+	t->type       = UNSET;
+	t->radio_if2  = 10700*1000; // 10.7MHz - FM radio
+
+	if (type < TUNERS) {
 		t->type = type;
 		printk("tuner(bttv): type forced to %d (%s) [insmod]\n",t->type,tuners[t->type].name);
 		strncpy(client->dev.name, tuners[t->type].name, DEVICE_NAME_SIZE);
-	} else {
-		t->type = -1;
 	}
         i2c_attach_client(client);
         if (t->type == TUNER_MT2032)
                  mt2032_init(client);
 
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int tuner_probe(struct i2c_adapter *adap)
 {
-	int rc;
-
 	if (0 != addr) {
 		normal_i2c_range[0] = addr;
 		normal_i2c_range[1] = addr;
 	}
 	this_adap = 0;
-	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-	case I2C_ALGO_SAA7134:
-	case I2C_ALGO_SAA7146:
-		printk("tuner: probing %s i2c adapter [id=0x%x]\n",
-		       adap->dev.name,adap->id);
-		rc = i2c_probe(adap, &addr_data, tuner_attach);
-		break;
-	default:
-		printk("tuner: ignoring %s i2c adapter [id=0x%x]\n",
-		       adap->dev.name,adap->id);
-		rc = 0;
-		/* nothing */
-	}
-	return rc;
+
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
+		return i2c_probe(adap, &addr_data, tuner_attach);
+	return 0;
 }
 
 static int tuner_detach(struct i2c_client *client)
@@ -849,7 +853,6 @@
 	i2c_detach_client(client);
 	kfree(t);
 	kfree(client);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -857,20 +860,17 @@
 tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
 {
 	struct tuner *t = i2c_get_clientdata(client);
-        int   *iarg = (int*)arg;
-#if 0
-        __u16 *sarg = (__u16*)arg;
-#endif
+        unsigned int *iarg = (int*)arg;
 
         switch (cmd) {
 
 	/* --- configuration --- */
 	case TUNER_SET_TYPE:
-		if (t->type != -1) {
+		if (t->type != UNSET) {
 			printk("tuner: type already set (%d)\n",t->type);
 			return 0;
 		}
-		if (*iarg < 0 || *iarg >= TUNERS)
+		if (*iarg >= TUNERS)
 			return 0;
 		t->type = *iarg;
 		printk("tuner: type set to %d (%s)\n",
@@ -882,6 +882,18 @@
 	case AUDC_SET_RADIO:
 		t->radio = 1;
 		break;
+	case AUDC_CONFIG_PINNACLE:
+		switch (*iarg) {
+		case 2:
+			dprintk("tuner: pinnacle pal\n");
+			t->radio_if2 = 33300 * 1000;
+			break;
+		case 3:
+			dprintk("tuner: pinnacle ntsc\n");
+			t->radio_if2 = 41300 * 1000;
+			break;
+		}
+                break;
 		
 	/* --- v4l ioctls --- */
 	/* take care: bttv does userspace copying, we'll get a
@@ -927,35 +939,6 @@
 			va->mode = (tuner_stereo(client) ? VIDEO_SOUND_STEREO : VIDEO_SOUND_MONO);
 		return 0;
 	}
-	
-#if 0
-	/* --- old, obsolete interface --- */
-	case TUNER_SET_TVFREQ:
-		dprintk("tuner: tv freq set to %d.%02d\n",
-			(*iarg)/16,(*iarg)%16*100/16);
-		set_tv_freq(client,*iarg);
-		t->radio = 0;
-		t->freq = *iarg;
-		break;
-
-	case TUNER_SET_RADIOFREQ:
-		dprintk("tuner: radio freq set to %d.%02d\n",
-			(*iarg)/16,(*iarg)%16*100/16);
-		set_radio_freq(client,*iarg);
-		t->radio = 1;
-		t->freq = *iarg;
-		break;
-	case TUNER_SET_MODE:
-		if (t->type != TUNER_PHILIPS_SECAM) {
-			dprintk("tuner: trying to change mode for other than TUNER_PHILIPS_SECAM\n");
-		} else {
-			int mode=(*sarg==VIDEO_MODE_SECAM)?1:0;
-			dprintk("tuner: mode set to %d\n", *sarg);
-			t->mode = mode;
-			set_tv_freq(client,t->freq);
-		}
-		break;
-#endif
 	default:
 		/* nothing */
 		break;
@@ -978,9 +961,9 @@
 static struct i2c_client client_template =
 {
 	.flags  = I2C_CLIENT_ALLOW_USE,
-        .driver = &driver,
-        .dev	= {
-		.name	= "(tuner unset)",
+	.driver = &driver,
+	.dev  = {
+		.name   = "(tuner unset)",
 	},
 };
 
diff -Nru a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
--- a/drivers/media/video/tvaudio.c	Thu Apr 24 04:11:51 2003
+++ b/drivers/media/video/tvaudio.c	Sat May 17 14:09:44 2003
@@ -34,19 +34,19 @@
 
 #include "tvaudio.h"
 
-
 /* ---------------------------------------------------------------------- */
 /* insmod args                                                            */
 
 MODULE_PARM(debug,"i");
 static int debug = 0;	/* insmod parameter */
 
-#define dprintk  if (debug) printk
-
 MODULE_DESCRIPTION("device driver for various i2c TV sound decoder / audiomux chips");
 MODULE_AUTHOR("Eric Sandeen, Steve VanDeBogart, Greg Alexander, Gerd Knorr");
 MODULE_LICENSE("GPL");
 
+#define UNSET    (-1U)
+#define dprintk  if (debug) printk
+
 /* ---------------------------------------------------------------------- */
 /* our structs                                                            */
 
@@ -161,22 +161,24 @@
 	unsigned char buffer[2];
 
 	if (-1 == subaddr) {
-		dprintk("%s: chip_write: 0x%x\n", chip->c.dev.name, val);
+		dprintk("%s: chip_write: 0x%x\n",
+			i2c_clientname(&chip->c), val);
 		chip->shadow.bytes[1] = val;
 		buffer[0] = val;
 		if (1 != i2c_master_send(&chip->c,buffer,1)) {
 			printk(KERN_WARNING "%s: I/O error (write 0x%x)\n",
-			       chip->c.dev.name, val);
+			       i2c_clientname(&chip->c), val);
 			return -1;
 		}
 	} else {
-		dprintk("%s: chip_write: reg%d=0x%x\n", chip->c.dev.name, subaddr, val);
+		dprintk("%s: chip_write: reg%d=0x%x\n",
+			i2c_clientname(&chip->c), subaddr, val);
 		chip->shadow.bytes[subaddr+1] = val;
 		buffer[0] = subaddr;
 		buffer[1] = val;
 		if (2 != i2c_master_send(&chip->c,buffer,2)) {
 			printk(KERN_WARNING "%s: I/O error (write reg%d=0x%x)\n",
-			       chip->c.dev.name, subaddr, val);
+			       i2c_clientname(&chip->c), subaddr, val);
 			return -1;
 		}
 	}
@@ -201,10 +203,10 @@
 
 	if (1 != i2c_master_recv(&chip->c,&buffer,1)) {
 		printk(KERN_WARNING "%s: I/O error (read)\n",
-		       chip->c.dev.name);
+		       i2c_clientname(&chip->c));
 		return -1;
 	}
-	dprintk("%s: chip_read: 0x%x\n",chip->c.dev.name,buffer); 
+	dprintk("%s: chip_read: 0x%x\n",i2c_clientname(&chip->c),buffer); 
 	return buffer;
 }
 
@@ -220,11 +222,11 @@
 
 	if (2 != i2c_transfer(chip->c.adapter,msgs,2)) {
 		printk(KERN_WARNING "%s: I/O error (read2)\n",
-		       chip->c.dev.name);
+		       i2c_clientname(&chip->c));
 		return -1;
 	}
 	dprintk("%s: chip_read2: reg%d=0x%x\n",
-		chip->c.dev.name,subaddr,read[0]); 
+		i2c_clientname(&chip->c),subaddr,read[0]); 
 	return read[0];
 }
 
@@ -237,7 +239,7 @@
 
 	/* update our shadow register set; print bytes if (debug > 0) */
 	dprintk("%s: chip_cmd(%s): reg=%d, data:",
-		chip->c.dev.name,name,cmd->bytes[0]);
+		i2c_clientname(&chip->c),name,cmd->bytes[0]);
 	for (i = 1; i < cmd->count; i++) {
 		dprintk(" 0x%x",cmd->bytes[i]);
 		chip->shadow.bytes[i+cmd->bytes[0]] = cmd->bytes[i];
@@ -246,7 +248,7 @@
 
 	/* send data to the chip */
 	if (cmd->count != i2c_master_send(&chip->c,cmd->bytes,cmd->count)) {
-		printk(KERN_WARNING "%s: I/O error (%s)\n", chip->c.dev.name, name);
+		printk(KERN_WARNING "%s: I/O error (%s)\n", i2c_clientname(&chip->c), name);
 		return -1;
 	}
 	return 0;
@@ -270,22 +272,18 @@
         struct CHIPSTATE *chip = data;
 	struct CHIPDESC  *desc = chiplist + chip->type;
 	
-#ifdef CONFIG_SMP
 	lock_kernel();
-#endif
-	daemonize("%s", chip->c.dev.name);
+	daemonize("%s",i2c_clientname(&chip->c));
 	chip->thread = current;
-#ifdef CONFIG_SMP
 	unlock_kernel();
-#endif
 
-	dprintk("%s: thread started\n", chip->c.dev.name);
+	dprintk("%s: thread started\n", i2c_clientname(&chip->c));
 	if(chip->notify != NULL)
 		up(chip->notify);
 
 	for (;;) {
 		interruptible_sleep_on(&chip->wq);
-		dprintk("%s: thread wakeup\n", chip->c.dev.name);
+		dprintk("%s: thread wakeup\n", i2c_clientname(&chip->c));
 		if (chip->done || signal_pending(current))
 			break;
 
@@ -301,7 +299,7 @@
 	}
 
 	chip->thread = NULL;
-	dprintk("%s: thread exiting\n", chip->c.dev.name);
+	dprintk("%s: thread exiting\n", i2c_clientname(&chip->c));
 	if(chip->notify != NULL)
 		up(chip->notify);
 
@@ -316,7 +314,7 @@
 	if (mode == chip->prevmode)
 	    return;
 
-	dprintk("%s: thread checkmode\n", chip->c.dev.name);
+	dprintk("%s: thread checkmode\n", i2c_clientname(&chip->c));
 	chip->prevmode = mode;
 
 	if (mode & VIDEO_SOUND_STEREO)
@@ -764,9 +762,9 @@
 static int tda9874a_dic = -1;		/* device id. code */
 
 /* insmod options for tda9874a */
-static int tda9874a_SIF = -1;
-static int tda9874a_AMSEL = -1;
-static int tda9874a_STD = -1;
+static unsigned int tda9874a_SIF   = UNSET;
+static unsigned int tda9874a_AMSEL = UNSET;
+static unsigned int tda9874a_STD   = UNSET;
 MODULE_PARM(tda9874a_SIF,"i");
 MODULE_PARM(tda9874a_AMSEL,"i");
 MODULE_PARM(tda9874a_STD,"i");
@@ -981,7 +979,7 @@
 	dprintk("tda9874a_checkit(): DIC=0x%X, SIC=0x%X.\n", dic, sic);
 
 	if((dic == 0x11)||(dic == 0x07)) {
-		dprintk("tvaudio: found tda9874%s.\n",(dic == 0x11) ? "a (new)":"h (old)");
+		printk("tvaudio: found tda9874%s.\n", (dic == 0x11) ? "a":"h");
 		tda9874a_dic = dic;	/* remember device id. */
 		return 1;
 	}
@@ -990,35 +988,27 @@
 
 static int tda9874a_initialize(struct CHIPSTATE *chip)
 {
-	if(tda9874a_SIF != -1) {
-		if(tda9874a_SIF == 1)
-			tda9874a_GCONR = 0xc0;	/* sound IF input 1 */
-		else if(tda9874a_SIF == 2)
-			tda9874a_GCONR = 0xc1;	/* sound IF input 2 */
-		else
-			printk(KERN_WARNING "tda9874a: SIF parameter must be 1 or 2.\n");
-	}
+	if (tda9874a_SIF > 2)
+		tda9874a_SIF = 1;
+	if (tda9874a_STD >= 8)
+		tda9874a_STD = 0;
+	if(tda9874a_AMSEL > 1)
+		tda9874a_AMSEL = 0;
 
-	if(tda9874a_STD != -1) {
-		if((tda9874a_STD >= 0)&&(tda9874a_STD <= 8)) {
-			tda9874a_ESP = tda9874a_STD;
-			tda9874a_mode = (tda9874a_STD < 5) ? 0 : 1;
-		} else {
-			printk(KERN_WARNING "tda9874a: STD parameter must be between 0 and 8.\n");
-		}
-	}
+	if(tda9874a_SIF == 1)
+		tda9874a_GCONR = 0xc0;	/* sound IF input 1 */
+	else
+		tda9874a_GCONR = 0xc1;	/* sound IF input 2 */
 
-	if(tda9874a_AMSEL != -1) {
-		if(tda9874a_AMSEL == 0)
-			tda9874a_NCONR = 0x01; /* auto-mute: analog mono input */
-		else if(tda9874a_AMSEL == 1)
-			tda9874a_NCONR = 0x05; /* auto-mute: 1st carrier FM or AM */
-		else
-			printk(KERN_WARNING "tda9874a: AMSEL parameter must be 0 or 1.\n");
-	}
+	tda9874a_ESP = tda9874a_STD;
+	tda9874a_mode = (tda9874a_STD < 5) ? 0 : 1;
 
-	tda9874a_setup(chip);
+	if(tda9874a_AMSEL == 0)
+		tda9874a_NCONR = 0x01; /* auto-mute: analog mono input */
+	else
+		tda9874a_NCONR = 0x05; /* auto-mute: 1st carrier FM or AM */
 
+	tda9874a_setup(chip);
 	return 0;
 }
 
@@ -1132,6 +1122,87 @@
 #define PIC16C54_MISC_SWITCH_TUNER     0x40 /* bit 6	, Switch to Line-in */
 #define PIC16C54_MISC_SWITCH_LINE      0x80 /* bit 7	, Switch to Tuner */
 
+/* ---------------------------------------------------------------------- */
+/* audio chip descriptions - defines+functions for TA8874Z                */
+
+// write 1st byte
+#define TA8874Z_LED_STE	0x80
+#define TA8874Z_LED_BIL	0x40
+#define TA8874Z_LED_EXT	0x20
+#define TA8874Z_MONO_SET	0x10
+#define TA8874Z_MUTE	0x08
+#define TA8874Z_F_MONO	0x04
+#define TA8874Z_MODE_SUB	0x02
+#define TA8874Z_MODE_MAIN	0x01
+
+// write 2nd byte
+//#define TA8874Z_TI	0x80  // test mode
+#define TA8874Z_SEPARATION	0x3f
+#define TA8874Z_SEPARATION_DEFAULT	0x10
+
+// read
+#define TA8874Z_B1	0x80
+#define TA8874Z_B0	0x40
+#define TA8874Z_CHAG_FLAG	0x20
+
+//        B1 B0
+// mono    L  H
+// stereo  L  L
+// BIL     H  L
+
+static int ta8874z_getmode(struct CHIPSTATE *chip)
+{
+	int val, mode;
+	
+	val = chip_read(chip);
+	mode = VIDEO_SOUND_MONO;
+	if (val & TA8874Z_B1){
+		mode |= VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
+	}else if (!(val & TA8874Z_B0)){
+		mode |= VIDEO_SOUND_STEREO;
+	}
+	//dprintk ("ta8874z_getmode(): raw chip read: 0x%02x, return: 0x%02x\n", val, mode);
+	return mode;
+}
+
+static audiocmd ta8874z_stereo = { 2, {0, TA8874Z_SEPARATION_DEFAULT}};
+static audiocmd ta8874z_mono = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}};
+static audiocmd ta8874z_main = {2, { 0, TA8874Z_SEPARATION_DEFAULT}};
+static audiocmd ta8874z_sub = {2, { TA8874Z_MODE_SUB, TA8874Z_SEPARATION_DEFAULT}};
+
+static void ta8874z_setmode(struct CHIPSTATE *chip, int mode)
+{
+	int update = 1;
+	audiocmd *t = NULL;
+	dprintk("ta8874z_setmode(): mode: 0x%02x\n", mode);
+
+	switch(mode){
+	case VIDEO_SOUND_MONO:
+		t = &ta8874z_mono;
+		break;
+	case VIDEO_SOUND_STEREO:
+		t = &ta8874z_stereo;
+		break;
+	case VIDEO_SOUND_LANG1:
+		t = &ta8874z_main;
+		break;
+	case VIDEO_SOUND_LANG2:
+		t = &ta8874z_sub;
+		break;
+	default:
+		update = 0;
+	}
+
+	if(update)
+		chip_cmd(chip, "TA8874Z", t);
+}
+
+static int ta8874z_checkit(struct CHIPSTATE *chip)
+{
+	int rc;
+	rc = chip_read(chip);
+	return ((rc & 0x1f) == 0x1f) ? 1 : 0;
+}
 
 /* ---------------------------------------------------------------------- */
 /* audio chip descriptions - struct CHIPDESC                              */
@@ -1143,9 +1214,11 @@
 int tda9855  = 1;
 int tda9873  = 1;
 int tda9874a = 1;
-int tea6300  = 0;
+int tea6300  = 0;  // address clash with msp34xx
 int tea6420  = 1;
 int pic16c54 = 1;
+int ta8874z  = 0;  // address clash with tda9840
+
 MODULE_PARM(tda8425,"i");
 MODULE_PARM(tda9840,"i");
 MODULE_PARM(tda9850,"i");
@@ -1155,6 +1228,7 @@
 MODULE_PARM(tea6300,"i");
 MODULE_PARM(tea6420,"i");
 MODULE_PARM(pic16c54,"i");
+MODULE_PARM(ta8874z,"i");
 
 static struct CHIPDESC chiplist[] = {
 	{
@@ -1319,7 +1393,23 @@
 			     PIC16C54_MISC_SND_NOTMUTE},
 		.inputmute  = PIC16C54_MISC_SND_MUTE,
 	},
-	{ name: NULL } /* EOF */
+	{
+		.name       = "ta8874z",
+		.id         = -1,
+		//.id         = I2C_DRIVERID_TA8874Z,
+		.checkit    = ta8874z_checkit,
+		.insmodopt  = &ta8874z,
+		.addr_lo    = I2C_TDA9840 >> 1,
+		.addr_hi    = I2C_TDA9840 >> 1,
+		.registers  = 2,
+
+		.getmode    = ta8874z_getmode,
+		.setmode    = ta8874z_setmode,
+		.checkmode  = generic_checkmode,
+
+	        .init       = {2, { TA8874Z_MONO_SET, TA8874Z_SEPARATION_DEFAULT}},
+	},
+	{ .name = NULL } /* EOF */
 };
 
 
@@ -1356,19 +1446,18 @@
 		dprintk("tvaudio: no matching chip description found\n");
 		return -EIO;
 	}
-	printk("tvaudio: found %s\n",desc->name);
+	printk("tvaudio: found %s @ 0x%x\n", desc->name, addr<<1);
 	dprintk("tvaudio: matches:%s%s%s.\n",
 		(desc->flags & CHIP_HAS_VOLUME)     ? " volume"      : "",
 		(desc->flags & CHIP_HAS_BASSTREBLE) ? " bass/treble" : "",
 		(desc->flags & CHIP_HAS_INPUTSEL)   ? " audiomux"    : "");
 
 	/* fill required data structures */
-	strncpy(chip->c.dev.name, desc->name, DEVICE_NAME_SIZE);
+	strcpy(i2c_clientname(&chip->c),desc->name);
 	chip->type = desc-chiplist;
 	chip->shadow.count = desc->registers+1;
         chip->prevmode = -1;
 	/* register */
-	MOD_INC_USE_COUNT;
 	i2c_attach_client(&chip->c);
 
 	/* initialization  */
@@ -1408,14 +1497,9 @@
 
 static int chip_probe(struct i2c_adapter *adap)
 {
-	switch (adap->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
+	if (adap->class & I2C_ADAP_CLASS_TV_ANALOG)
 		return i2c_probe(adap, &addr_data, chip_attach);
-	default:
-		/* ignore this i2c bus */
-		return 0;
-	}
+	return 0;
 }
 
 static int chip_detach(struct i2c_client *client)
@@ -1435,7 +1519,6 @@
 	
 	i2c_detach_client(&chip->c);
 	kfree(chip);
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -1449,7 +1532,7 @@
 	struct CHIPSTATE *chip = i2c_get_clientdata(client);
 	struct CHIPDESC  *desc = chiplist + chip->type;
 
-	dprintk("%s: chip_command 0x%x\n",chip->c.dev.name,cmd);
+	dprintk("%s: chip_command 0x%x\n",i2c_clientname(&chip->c),cmd);
 
 	switch (cmd) {
 	case AUDC_SET_INPUT:
@@ -1557,11 +1640,9 @@
 
 static struct i2c_client client_template =
 {
-	.flags  = I2C_CLIENT_ALLOW_USE,
-        .driver = &driver,
-        .dev	= {
-		.name	= "(unset)",
-	},
+	I2C_DEVNAME("(unset)"),
+	.flags      = I2C_CLIENT_ALLOW_USE,
+        .driver     = &driver,
 };
 
 static int audiochip_init_module(void)
diff -Nru a/drivers/media/video/tvaudio.h b/drivers/media/video/tvaudio.h
--- a/drivers/media/video/tvaudio.h	Fri Mar  8 04:42:43 2002
+++ b/drivers/media/video/tvaudio.h	Sat May 17 14:09:44 2003
@@ -3,7 +3,7 @@
  */
 
 #define I2C_TDA8425        0x82
-#define I2C_TDA9840        0x84
+#define I2C_TDA9840        0x84 /* also used by TA8874Z */
 #define I2C_TDA985x_L      0xb4 /* also used by 9873 */
 #define I2C_TDA985x_H      0xb6
 #define I2C_TDA9874        0xb0 /* also used by 9875 */
diff -Nru a/drivers/media/video/tvmixer.c b/drivers/media/video/tvmixer.c
--- a/drivers/media/video/tvmixer.c	Tue Mar 25 00:37:07 2003
+++ b/drivers/media/video/tvmixer.c	Sat May 17 14:09:44 2003
@@ -10,19 +10,16 @@
 #include <linux/videodev.h>
 #include <linux/init.h>
 #include <linux/kdev_t.h>
-#include <asm/semaphore.h>
-
 #include <linux/sound.h>
 #include <linux/soundcard.h>
+
+#include <asm/semaphore.h>
 #include <asm/uaccess.h>
 
 
 #define DEV_MAX  4
 
-static int debug = 0;
 static int devnr = -1;
-
-MODULE_PARM(debug,"i");
 MODULE_PARM(devnr,"i");
 
 MODULE_AUTHOR("Gerd Knorr");
@@ -87,7 +84,7 @@
         if (cmd == SOUND_MIXER_INFO) {
                 mixer_info info;
                 strncpy(info.id, "tv card", sizeof(info.id));
-                strncpy(info.name, client->dev.name, sizeof(info.name));
+                strncpy(info.name, i2c_clientname(client), sizeof(info.name));
                 info.modify_counter = 42 /* FIXME */;
                 if (copy_to_user((void *)arg, &info, sizeof(info)))
                         return -EFAULT;
@@ -96,7 +93,7 @@
         if (cmd == SOUND_OLD_MIXER_INFO) {
                 _old_mixer_info info;
                 strncpy(info.id, "tv card", sizeof(info.id));
-                strncpy(info.name, client->dev.name, sizeof(info.name));
+                strncpy(info.name, i2c_clientname(client), sizeof(info.name));
                 if (copy_to_user((void *)arg, &info, sizeof(info)))
                         return -EFAULT;
                 return 0;
@@ -143,7 +140,7 @@
 	case MIXER_READ(SOUND_MIXER_VOLUME):
 		left  = (min(65536 - va.balance,32768) *
 			 va.volume) / 32768;
-		right = (min(va.balance,32768) *
+		right = (min(va.balance,(u16)32768) *
 			 va.volume) / 32768;
 		ret = v4l_to_mix2(left,right);
 		break;
@@ -217,7 +214,8 @@
 	.owner           = THIS_MODULE,
 	.name            = "tv card mixer driver",
         .id              = I2C_DRIVERID_TVMIXER,
-	.flags           = I2C_DF_DUMMY,
+	.flags           = I2C_DF_NOTIFY,
+        .detach_adapter  = tvmixer_adapters,
         .attach_adapter  = tvmixer_adapters,
         .detach_client   = tvmixer_clients,
 };
@@ -234,14 +232,12 @@
 
 static int tvmixer_adapters(struct i2c_adapter *adap)
 {
-	int i;
+	struct list_head  *item;
+	struct i2c_client *client;
 
-	if (debug)
-		printk("tvmixer: adapter %s\n",adap->dev.name);
-	for (i=0; i<I2C_CLIENT_MAX; i++) {
-		if (!adap->clients[i])
-			continue;
-		tvmixer_clients(adap->clients[i]);
+	list_for_each(item,&adap->clients) {
+		client = list_entry(item, struct i2c_client, list);
+		tvmixer_clients(client);
 	}
 	return 0;
 }
@@ -251,20 +247,8 @@
 	struct video_audio va;
 	int i,minor;
 
-	/* TV card ??? */
-	switch (client->adapter->id) {
-	case I2C_ALGO_BIT | I2C_HW_B_BT848:
-	case I2C_ALGO_BIT | I2C_HW_B_RIVA:
-		/* ok, have a look ... */
-		break;
-	default:
-		/* ignore that one */
-		if (debug)
-			printk("tvmixer: %s is not a tv card\n",
-			       client->adapter->dev.name);
+	if (!(client->adapter->class & I2C_ADAP_CLASS_TV_ANALOG))
 		return -1;
-	}
-	printk("tvmixer: debug: %s\n",client->dev.name);
 
 	/* unregister ?? */
 	for (i = 0; i < DEV_MAX; i++) {
@@ -273,7 +257,8 @@
 			unregister_sound_mixer(devices[i].minor);
 			devices[i].dev = NULL;
 			devices[i].minor = -1;
-			printk("tvmixer: %s unregistered (#1)\n",client->dev.name);
+			printk("tvmixer: %s unregistered (#1)\n",
+			       i2c_clientname(client));
 			return 0;
 		}
 	}
@@ -288,25 +273,13 @@
 	}
 
 	/* audio chip with mixer ??? */
-	if (NULL == client->driver->command) {
-		if (debug)
-			printk("tvmixer: %s: driver->command is NULL\n",
-			       client->driver->name);
+	if (NULL == client->driver->command)
 		return -1;
-	}
 	memset(&va,0,sizeof(va));
-	if (0 != client->driver->command(client,VIDIOCGAUDIO,&va)) {
-		if (debug)
-			printk("tvmixer: %s: VIDIOCGAUDIO failed\n",
-			       client->dev.name);
+	if (0 != client->driver->command(client,VIDIOCGAUDIO,&va))
 		return -1;
-	}
-	if (0 == (va.flags & VIDEO_AUDIO_VOLUME)) {
-		if (debug)
-			printk("tvmixer: %s: has no volume control\n",
-			       client->dev.name);
+	if (0 == (va.flags & VIDEO_AUDIO_VOLUME))
 		return -1;
-	}
 
 	/* everything is fine, register */
 	if ((minor = register_sound_mixer(&tvmixer_fops,devnr)) < 0) {
@@ -344,7 +317,7 @@
 		if (devices[i].minor != -1) {
 			unregister_sound_mixer(devices[i].minor);
 			printk("tvmixer: %s unregistered (#2)\n",
-			       devices[i].dev->dev.name);
+			       i2c_clientname(devices[i].dev));
 		}
 	}
 }
diff -Nru a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
--- a/drivers/media/video/v4l1-compat.c	Wed Jan  8 01:59:58 2003
+++ b/drivers/media/video/v4l1-compat.c	Sat May 17 14:09:42 2003
@@ -127,6 +127,8 @@
 	return 0;
 }
 
+/* ----------------------------------------------------------------- */
+
 static int palette2pixelformat[] = {
 	[VIDEO_PALETTE_GREY]    = V4L2_PIX_FMT_GREY,
 	[VIDEO_PALETTE_RGB555]  = V4L2_PIX_FMT_RGB555,
@@ -145,16 +147,16 @@
 	[VIDEO_PALETTE_YUV422P] = V4L2_PIX_FMT_YUV422P,
 };
 
-static int
-palette_to_pixelformat(int palette)
+static unsigned int
+palette_to_pixelformat(unsigned int palette)
 {
-	if (palette < sizeof(palette2pixelformat)/sizeof(int))
+	if (palette < ARRAY_SIZE(palette2pixelformat))
 		return palette2pixelformat[palette];
 	else
 		return 0;
 }
 
-static int
+static unsigned int
 pixelformat_to_palette(int pixelformat)
 {
 	int	palette = 0;
@@ -199,66 +201,43 @@
 	return palette;
 }
 
-/*  Do an 'in' (wait for input) select on a single file descriptor  */
-/*  This stuff plaigarized from linux/fs/select.c     */
-#define __FD_IN(fds, n)	(fds->in + n)
-#define BIT(i)		(1UL << ((i)&(__NFDBITS-1)))
-#define SET(i,m)	(*(m) |= (i))
-extern int do_select(int n, fd_set_bits *fds, long *timeout);
-
+/* ----------------------------------------------------------------- */
 
-static int
-simple_select(struct file *file)
+static int poll_one(struct file *file)
 {
-	fd_set_bits fds;
-	char *bits;
-	long timeout;
-	int i, fd, n, ret, size;
-
-	for (i = 0; i < current->files->max_fds; ++i)
-		if (file == current->files->fd[i])
-			break;
-	if (i == current->files->max_fds)
-		return -EINVAL;
-	fd = i;
-	n = fd + 1;
-
-	timeout = MAX_SCHEDULE_TIMEOUT;
-	/*
-	 * We need 6 bitmaps (in/out/ex for both incoming and outgoing),
-	 * since we used fdset we need to allocate memory in units of
-	 * long-words. 
-	 */
-	ret = -ENOMEM;
-	size = FDS_BYTES(n);
-	bits = kmalloc(6 * size, GFP_KERNEL);
-	if (!bits)
-		goto out_nofds;
-	fds.in      = (unsigned long *)  bits;
-	fds.out     = (unsigned long *) (bits +   size);
-	fds.ex      = (unsigned long *) (bits + 2*size);
-	fds.res_in  = (unsigned long *) (bits + 3*size);
-	fds.res_out = (unsigned long *) (bits + 4*size);
-	fds.res_ex  = (unsigned long *) (bits + 5*size);
-
-	/*  All zero except our one file descriptor bit, for input  */
-	memset(bits, 0, 6 * size);
-	SET(BIT(fd), __FD_IN((&fds), fd / __NFDBITS));
-
-	ret = do_select(n, &fds, &timeout);
-
-	if (ret < 0)
-		goto out;
-	if (!ret) {
-		ret = -ERESTARTNOHAND;
-		if (signal_pending(current))
-			goto out;
-		ret = 0;
-	}
-out:
-	kfree(bits);
-out_nofds:
-	return ret;
+	int retval = 1;
+	poll_table *table;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
+	poll_table wait_table;
+
+	poll_initwait(&wait_table);
+	table = &wait_table;
+#else
+	struct poll_wqueues pwq;
+
+	poll_initwait(&pwq);
+	table = &pwq.pt;
+#endif
+	for (;;) {
+		int mask;
+		set_current_state(TASK_INTERRUPTIBLE);
+		mask = file->f_op->poll(file, table);
+		if (mask & POLLIN)
+			break;
+		table = NULL;
+		if (signal_pending(current)) {
+			retval = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,48)
+	poll_freewait(&wait_table);
+#else
+	poll_freewait(&pwq);
+#endif
+	return retval;
 }
 
 static int count_inputs(struct inode         *inode,
@@ -306,6 +285,7 @@
 	return 0;
 }
 
+/* ----------------------------------------------------------------- */
 
 /*
  *	This function is exported.
@@ -317,26 +297,36 @@
 			   void			*arg,
 			   v4l2_kioctl          drv)
 {
-	int	             err = -ENOIOCTLCMD;
+	struct v4l2_capability  *cap2 = NULL;
+	struct v4l2_format	*fmt2 = NULL;
 
-	switch (cmd)
-	{
+	struct v4l2_framebuffer fbuf2;
+	struct v4l2_input	input2;
+	struct v4l2_tuner	tun2;
+	struct v4l2_standard	std2;
+	struct v4l2_frequency   freq2;
+	struct v4l2_audio	aud2;
+	struct v4l2_queryctrl	qctrl2;
+	struct v4l2_buffer	buf2;
+	v4l2_std_id    		sid;
+	int i, err = 0;
+
+	switch (cmd) {
 	case VIDIOCGCAP:	/* capability */
 	{
 		struct video_capability *cap = arg;
-		struct v4l2_capability cap2;
-		struct v4l2_framebuffer fbuf2;
-		
+
+		cap2 = kmalloc(sizeof(*cap2),GFP_KERNEL);
 		memset(cap, 0, sizeof(*cap));
-		memset(&cap2, 0, sizeof(cap2));
+		memset(cap2, 0, sizeof(*cap2));
 		memset(&fbuf2, 0, sizeof(fbuf2));
 
-		err = drv(inode, file, VIDIOC_QUERYCAP, &cap2);
+		err = drv(inode, file, VIDIOC_QUERYCAP, cap2);
 		if (err < 0) {
 			dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n",err);
 			break;
 		}
-		if (cap2.capabilities & V4L2_CAP_VIDEO_OVERLAY) {
+		if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) {
 			err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
 			if (err < 0) {
 				dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n",err);
@@ -345,16 +335,16 @@
 			err = 0;
 		}
 
-		memcpy(cap->name, cap2.card, 
-		       min(sizeof(cap->name), sizeof(cap2.card)));
+		memcpy(cap->name, cap2->card, 
+		       min(sizeof(cap->name), sizeof(cap2->card)));
 		cap->name[sizeof(cap->name) - 1] = 0;
-		if (cap2.capabilities & V4L2_CAP_VIDEO_CAPTURE)
+		if (cap2->capabilities & V4L2_CAP_VIDEO_CAPTURE)
 			cap->type |= VID_TYPE_CAPTURE;
-		if (cap2.capabilities & V4L2_CAP_TUNER)
+		if (cap2->capabilities & V4L2_CAP_TUNER)
 			cap->type |= VID_TYPE_TUNER;
-		if (cap2.capabilities & V4L2_CAP_VBI_CAPTURE)
+		if (cap2->capabilities & V4L2_CAP_VBI_CAPTURE)
 			cap->type |= VID_TYPE_TELETEXT;
-		if (cap2.capabilities & V4L2_CAP_VIDEO_OVERLAY)
+		if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY)
 			cap->type |= VID_TYPE_OVERLAY;
 		if (fbuf2.capability & V4L2_FBUF_CAP_LIST_CLIPPING)
 			cap->type |= VID_TYPE_CLIPPING;
@@ -370,7 +360,6 @@
 	case VIDIOCGFBUF: /*  get frame buffer  */
 	{
 		struct video_buffer	*buffer = arg;
-		struct v4l2_framebuffer	fbuf2;
 
 		err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
 		if (err < 0) {
@@ -412,7 +401,6 @@
 	case VIDIOCSFBUF: /*  set frame buffer  */
 	{
 		struct video_buffer	*buffer = arg;
-		struct v4l2_framebuffer	fbuf2;
 
 		memset(&fbuf2, 0, sizeof(fbuf2));
 		fbuf2.base       = buffer->base;
@@ -444,36 +432,36 @@
 	case VIDIOCGWIN: /*  get window or capture dimensions  */
 	{
 		struct video_window	*win = arg;
-		struct v4l2_format	fmt2;
 
+		fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
 		memset(win,0,sizeof(*win));
-		memset(&fmt2,0,sizeof(fmt2));
+		memset(fmt2,0,sizeof(*fmt2));
 
-		fmt2.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
-		err = drv(inode, file, VIDIOC_G_FMT, &fmt2);
+		fmt2->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
 		if (err < 0)
 			dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %d\n",err);
 		if (err == 0) {
-			win->x         = fmt2.fmt.win.w.left;
-			win->y         = fmt2.fmt.win.w.top;
-			win->width     = fmt2.fmt.win.w.width;
-			win->height    = fmt2.fmt.win.w.height;
-			win->chromakey = fmt2.fmt.win.chromakey;
+			win->x         = fmt2->fmt.win.w.left;
+			win->y         = fmt2->fmt.win.w.top;
+			win->width     = fmt2->fmt.win.w.width;
+			win->height    = fmt2->fmt.win.w.height;
+			win->chromakey = fmt2->fmt.win.chromakey;
 			win->clips     = NULL;
 			win->clipcount = 0;
 			break;
 		}
 
-		fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_G_FMT, &fmt2);
+		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
 		if (err < 0) {
 			dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %d\n",err);
 			break;
 		}
 		win->x         = 0;
 		win->y         = 0;
-		win->width     = fmt2.fmt.pix.width;
-		win->height    = fmt2.fmt.pix.height;
+		win->width     = fmt2->fmt.pix.width;
+		win->height    = fmt2->fmt.pix.height;
 		win->chromakey = 0;
 		win->clips     = NULL;
 		win->clipcount = 0;
@@ -482,37 +470,41 @@
 	case VIDIOCSWIN: /*  set window and/or capture dimensions  */
 	{
 		struct video_window	*win = arg;
-		struct v4l2_format	fmt2;
+		int err1,err2;
 
-		memset(&fmt2,0,sizeof(fmt2));
-		fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_G_FMT, &fmt2);
-		if (err < 0)
+		fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
+		memset(fmt2,0,sizeof(*fmt2));
+		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		err1 = drv(inode, file, VIDIOC_G_FMT, fmt2);
+		if (err1 < 0)
 			dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %d\n",err);
-		if (err == 0) {
-			fmt2.fmt.pix.width  = win->width;
-			fmt2.fmt.pix.height = win->height;
-			fmt2.fmt.pix.field  = V4L2_FIELD_ANY;
-			err = drv(inode, file, VIDIOC_S_FMT, &fmt2);
+		if (err1 == 0) {
+			fmt2->fmt.pix.width  = win->width;
+			fmt2->fmt.pix.height = win->height;
+			fmt2->fmt.pix.field  = V4L2_FIELD_ANY;
+			err = drv(inode, file, VIDIOC_S_FMT, fmt2);
 			if (err < 0)
 				dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n",
 					err);
-			win->width  = fmt2.fmt.pix.width;
-			win->height = fmt2.fmt.pix.height;
+			win->width  = fmt2->fmt.pix.width;
+			win->height = fmt2->fmt.pix.height;
 		}
 
-		memset(&fmt2,0,sizeof(fmt2));
-		fmt2.type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
-		fmt2.fmt.win.w.left    = win->x;
-		fmt2.fmt.win.w.top     = win->y;
-		fmt2.fmt.win.w.width   = win->width;
-		fmt2.fmt.win.w.height  = win->height;
-		fmt2.fmt.win.chromakey = win->chromakey;
-		fmt2.fmt.win.clips     = (void *)win->clips;
-		fmt2.fmt.win.clipcount = win->clipcount;
-		err = drv(inode, file, VIDIOC_S_FMT, &fmt2);
-		if (err < 0)
+		memset(fmt2,0,sizeof(*fmt2));
+		fmt2->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+		fmt2->fmt.win.w.left    = win->x;
+		fmt2->fmt.win.w.top     = win->y;
+		fmt2->fmt.win.w.width   = win->width;
+		fmt2->fmt.win.w.height  = win->height;
+		fmt2->fmt.win.chromakey = win->chromakey;
+		fmt2->fmt.win.clips     = (void *)win->clips;
+		fmt2->fmt.win.clipcount = win->clipcount;
+		err2 = drv(inode, file, VIDIOC_S_FMT, fmt2);
+		if (err2 < 0)
 			dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %d\n",err);
+
+		if (err1 != 0 && err2 != 0)
+			err = err1;
 		break;
 	}
 	case VIDIOCCAPTURE: /*  turn on/off preview  */
@@ -525,8 +517,6 @@
 	case VIDIOCGCHAN: /*  get input information  */
 	{
 		struct video_channel	*chan = arg;
-		struct v4l2_input	input2;
-		v4l2_std_id    		sid;
 
 		memset(&input2,0,sizeof(input2));
 		input2.index = chan->channel;
@@ -568,16 +558,32 @@
 	case VIDIOCSCHAN: /*  set input  */
 	{
 		struct video_channel *chan = arg;
-		
+
+		sid = 0;
 		err = drv(inode, file, VIDIOC_S_INPUT, &chan->channel);
 		if (err < 0)
 			dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %d\n",err);
+		switch (chan->norm) {
+		case VIDEO_MODE_PAL:
+			sid = V4L2_STD_PAL;
+			break;
+		case VIDEO_MODE_NTSC:
+			sid = V4L2_STD_NTSC;
+			break;
+		case VIDEO_MODE_SECAM:
+			sid = V4L2_STD_SECAM;
+			break;
+		}
+		if (0 != sid) {
+			err = drv(inode, file, VIDIOC_S_STD, &sid);
+			if (err < 0)
+				dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %d\n",err);
+		}
 		break;
 	}
 	case VIDIOCGPICT: /*  get tone controls & partial capture format  */
 	{
 		struct video_picture	*pict = arg;
-		struct v4l2_format	fmt2;
 
 		pict->brightness = get_v4l_control(inode, file,
 						   V4L2_CID_BRIGHTNESS,drv);
@@ -590,25 +596,24 @@
 		pict->whiteness = get_v4l_control(inode, file,
 						  V4L2_CID_WHITENESS, drv);
 
-		memset(&fmt2,0,sizeof(fmt2));
-		fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_G_FMT, &fmt2);
+		fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
+		memset(fmt2,0,sizeof(*fmt2));
+		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
 		if (err < 0) {
 			dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n",err);
 			break;
 		}
 #if 0 /* FIXME */
-		pict->depth   = fmt2.fmt.pix.depth;
+		pict->depth   = fmt2->fmt.pix.depth;
 #endif
 		pict->palette = pixelformat_to_palette(
-			fmt2.fmt.pix.pixelformat);
+			fmt2->fmt.pix.pixelformat);
 		break;
 	}
 	case VIDIOCSPICT: /*  set tone controls & partial capture format  */
 	{
 		struct video_picture	*pict = arg;
-		struct v4l2_format	fmt2;
-		struct v4l2_framebuffer	fbuf2;
 
 		set_v4l_control(inode, file,
 				V4L2_CID_BRIGHTNESS, pict->brightness, drv);
@@ -621,16 +626,17 @@
 		set_v4l_control(inode, file,
 				V4L2_CID_WHITENESS, pict->whiteness, drv);
 
-		memset(&fmt2,0,sizeof(fmt2));
-		fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_G_FMT, &fmt2);
+		fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
+		memset(fmt2,0,sizeof(*fmt2));
+		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
 		if (err < 0)
 			dprintk("VIDIOCSPICT / VIDIOC_G_FMT: %d\n",err);
-		if (fmt2.fmt.pix.pixelformat != 
+		if (fmt2->fmt.pix.pixelformat != 
 		    palette_to_pixelformat(pict->palette)) {
-			fmt2.fmt.pix.pixelformat = palette_to_pixelformat(
+			fmt2->fmt.pix.pixelformat = palette_to_pixelformat(
 				pict->palette);
-			err = drv(inode, file, VIDIOC_S_FMT, &fmt2);
+			err = drv(inode, file, VIDIOC_S_FMT, fmt2);
 			if (err < 0)
 				dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n",err);
 		}
@@ -652,8 +658,6 @@
 	case VIDIOCGTUNER: /*  get tuner information  */
 	{
 		struct video_tuner	*tun = arg;
-		struct v4l2_tuner	tun2;
-		v4l2_std_id    		sid;
 
 		memset(&tun2,0,sizeof(tun2));
 		err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
@@ -669,6 +673,19 @@
 		tun->flags = 0;
 		tun->mode = VIDEO_MODE_AUTO;
 
+		for (i = 0; i < 64; i++) {
+			memset(&std2,0,sizeof(std2));
+			std2.index = i;
+			if (0 != drv(inode, file, VIDIOC_ENUMSTD, &std2))
+				break;
+			if (std2.id & V4L2_STD_PAL)
+				tun->flags |= VIDEO_TUNER_PAL;
+			if (std2.id & V4L2_STD_NTSC)
+				tun->flags |= VIDEO_TUNER_NTSC;
+			if (std2.id & V4L2_STD_SECAM)
+				tun->flags |= VIDEO_TUNER_SECAM;
+		}
+
 		err = drv(inode, file, VIDIOC_G_STD, &sid);
 		if (err < 0)
 			dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %d\n",err);
@@ -688,21 +705,20 @@
 		tun->signal = tun2.signal;
 		break;
 	}
-#if 0 /* FIXME */
 	case VIDIOCSTUNER: /*  select a tuner input  */
 	{
-		int	i;
-
+#if 0 /* FIXME */
 		err = drv(inode, file, VIDIOC_S_INPUT, &i);
 		if (err < 0)
 			dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n",err);
+#else
+		err = 0;
+#endif
 		break;
 	}
-#endif
 	case VIDIOCGFREQ: /*  get frequency  */
 	{
 		int *freq = arg;
-		struct v4l2_frequency freq2;
 		
 		err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
 		if (err < 0)
@@ -714,7 +730,6 @@
 	case VIDIOCSFREQ: /*  set frequency  */
 	{
 		int *freq = arg;
-		struct v4l2_frequency freq2;
 
 		drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
 		freq2.frequency = *freq;
@@ -726,10 +741,6 @@
 	case VIDIOCGAUDIO: /*  get audio properties/controls  */
 	{
 		struct video_audio	*aud = arg;
-		struct v4l2_audio	aud2;
-		struct v4l2_queryctrl	qctrl2;
-		struct v4l2_tuner	tun2;
-		int			v;
 
 		err = drv(inode, file, VIDIOC_G_AUDIO, &aud2);
 		if (err < 0) {
@@ -741,34 +752,29 @@
 		aud->name[sizeof(aud->name) - 1] = 0;
 		aud->audio = aud2.index;
 		aud->flags = 0;
-		v = get_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME, drv);
-		if (v >= 0)
-		{
-			aud->volume = v;
+		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME, drv);
+		if (i >= 0) {
+			aud->volume = i;
 			aud->flags |= VIDEO_AUDIO_VOLUME;
 		}
-		v = get_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, drv);
-		if (v >= 0)
-		{
-			aud->bass = v;
+		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, drv);
+		if (i >= 0) {
+			aud->bass = i;
 			aud->flags |= VIDEO_AUDIO_BASS;
 		}
-		v = get_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, drv);
-		if (v >= 0)
-		{
-			aud->treble = v;
+		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, drv);
+		if (i >= 0) {
+			aud->treble = i;
 			aud->flags |= VIDEO_AUDIO_TREBLE;
 		}
-		v = get_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, drv);
-		if (v >= 0)
-		{
-			aud->balance = v;
+		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, drv);
+		if (i >= 0) {
+			aud->balance = i;
 			aud->flags |= VIDEO_AUDIO_BALANCE;
 		}
-		v = get_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE, drv);
-		if (v >= 0)
-		{
-			if (v)
+		i = get_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE, drv);
+		if (i >= 0) {
+			if (i)
 				aud->flags |= VIDEO_AUDIO_MUTE;
 			aud->flags |= VIDEO_AUDIO_MUTABLE;
 		}
@@ -795,8 +801,6 @@
 	case VIDIOCSAUDIO: /*  set audio controls  */
 	{
 		struct video_audio	*aud = arg;
-		struct v4l2_audio	aud2;
-		struct v4l2_tuner	tun2;
 
 		memset(&aud2,0,sizeof(aud2));
 		memset(&tun2,0,sizeof(tun2));
@@ -844,83 +848,36 @@
 		break;
 	}
 #if 0
-	case VIDIOCGMBUF: /*  get mmap parameters  */
-	{
-		struct video_mbuf		*mbuf = arg;
-		struct v4l2_requestbuffers	reqbuf2;
-		struct v4l2_buffer		buf2;
-		struct v4l2_format		fmt2, fmt2o;
-		struct v4l2_capability		cap2;
-		int				i;
-
-		/*  Set the format to maximum dimensions  */
-		if ((err = drv(inode, file, VIDIOC_QUERYCAP, &cap2)) < 0)
-			break;
-		fmt2o.type = V4L2_BUF_TYPE_CAPTURE;
-		if ((err = drv(inode, file, VIDIOC_G_FMT, &fmt2o)) < 0)
-			break;
-		fmt2 = fmt2o;
-		fmt2.fmt.pix.width = cap2.maxwidth;
-		fmt2.fmt.pix.height = cap2.maxheight;
-		fmt2.fmt.pix.flags |= V4L2_FMT_FLAG_INTERLACED;
-		if ((err = drv(inode, file, VIDIOC_S_FMT, &fmt2)) < 0)
-			break;
-		reqbuf2.count = 2; /* v4l always used two buffers */
-		reqbuf2.type = V4L2_BUF_TYPE_CAPTURE | V4L2_BUF_REQ_CONTIG;
-		err = drv(inode, file, VIDIOC_REQBUFS, &reqbuf2);
-		if (err < 0 || reqbuf2.count < 2 || reqbuf2.type
-		    != (V4L2_BUF_TYPE_CAPTURE | V4L2_BUF_REQ_CONTIG))
-		{/*	Driver doesn't support v4l back-compatibility  */
-			fmt2o.fmt.pix.flags |= V4L2_FMT_FLAG_INTERLACED;
-			drv(inode, file, VIDIOC_S_FMT, &fmt2o);
-			reqbuf2.count = 1;
-			reqbuf2.type = V4L2_BUF_TYPE_CAPTURE;
-			err = drv(inode, file, VIDIOC_REQBUFS, &reqbuf2);
-			if (err < 0)
-			{
-				err = -EINVAL;
-				break;
-			}
-			printk(KERN_INFO"V4L2: Device \"%s\" doesn't support"
-			       " v4l memory mapping\n", vfl->name);
-		}
-		buf2.index = 0;
-		buf2.type = V4L2_BUF_TYPE_CAPTURE;
-		err = drv(inode, file, VIDIOC_QUERYBUF, &buf2);
-		mbuf->size = buf2.length * reqbuf2.count;
-		mbuf->frames = reqbuf2.count;
-		memset(mbuf->offsets, 0, sizeof(mbuf->offsets));
-		for (i = 0; i < mbuf->frames; ++i)
-			mbuf->offsets[i] = i * buf2.length;
-		break;
-	}
+	case VIDIOCGMBUF:
+		/* v4l2 drivers must implement that themself.  The
+		   mmap() differences can't be translated fully
+		   transparent, thus there is no point to try that */
 #endif
 	case VIDIOCMCAPTURE: /*  capture a frame  */
 	{
 		struct video_mmap	*mm = arg;
-		struct v4l2_buffer	buf2;
-		struct v4l2_format	fmt2;
 
+		fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
 		memset(&buf2,0,sizeof(buf2));
-		memset(&fmt2,0,sizeof(fmt2));
+		memset(fmt2,0,sizeof(*fmt2));
 		
-		fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-		err = drv(inode, file, VIDIOC_G_FMT, &fmt2);
+		fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
 		if (err < 0) {
 			dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\n",err);
 			break;
 		}
-		if (mm->width   != fmt2.fmt.pix.width || 
-		    mm->height != fmt2.fmt.pix.height ||
+		if (mm->width   != fmt2->fmt.pix.width  || 
+		    mm->height  != fmt2->fmt.pix.height ||
 		    palette_to_pixelformat(mm->format) != 
-		    fmt2.fmt.pix.pixelformat)
+		    fmt2->fmt.pix.pixelformat)
 		{/* New capture format...  */
-			fmt2.fmt.pix.width = mm->width;
-			fmt2.fmt.pix.height = mm->height;
-			fmt2.fmt.pix.pixelformat =
+			fmt2->fmt.pix.width = mm->width;
+			fmt2->fmt.pix.height = mm->height;
+			fmt2->fmt.pix.pixelformat =
 				palette_to_pixelformat(mm->format);
-			fmt2.fmt.pix.field = V4L2_FIELD_ANY;
-			err = drv(inode, file, VIDIOC_S_FMT, &fmt2);
+			fmt2->fmt.pix.field = V4L2_FIELD_ANY;
+			err = drv(inode, file, VIDIOC_S_FMT, fmt2);
 			if (err < 0) {
 				dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n",err);
 				break;
@@ -946,7 +903,6 @@
 	case VIDIOCSYNC: /*  wait for a frame  */
 	{
 		int			*i = arg;
-		struct v4l2_buffer	buf2;
 
 		buf2.index = *i;
 		buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -967,7 +923,7 @@
 			(V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))
 		       == V4L2_BUF_FLAG_QUEUED)
 		{
-			err = simple_select(file);
+			err = poll_one(file);
 			if (err < 0 ||	/* error or sleep was interrupted  */
 			    err == 0)	/* timeout? Shouldn't occur.  */
 				break;
@@ -984,20 +940,80 @@
 		} while (err == 0 && buf2.index != *i);
 		break;
 	}
-	case VIDIOCGUNIT: /*  get related device minors  */
-		/*  No translation  */
-		break;
-	case VIDIOCGCAPTURE: /*    */
-		/*  No translation, yet...  */
-		printk(KERN_INFO"v4l1-compat: VIDIOCGCAPTURE not implemented."
-		       " Send patches to bdirks@pacbell.net :-)\n");
-		break;
-	case VIDIOCSCAPTURE: /*    */
-		/*  No translation, yet...  */
-		printk(KERN_INFO"v4l1-compat: VIDIOCSCAPTURE not implemented."
-		       " Send patches to bdirks@pacbell.net :-)\n");
+
+	case VIDIOCGVBIFMT: /* query VBI data capture format */
+	{
+		struct vbi_format      *fmt = arg;
+		
+		fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
+		memset(fmt2, 0, sizeof(*fmt2));
+		fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		
+		err = drv(inode, file, VIDIOC_G_FMT, fmt2);
+		if (err < 0) {
+			dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
+			break;
+		}
+		memset(fmt, 0, sizeof(*fmt));
+		fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line;
+		fmt->sampling_rate    = fmt2->fmt.vbi.sampling_rate;
+		fmt->sample_format    = VIDEO_PALETTE_RAW;
+		fmt->start[0]         = fmt2->fmt.vbi.start[0];
+		fmt->count[0]         = fmt2->fmt.vbi.count[0];
+		fmt->start[1]         = fmt2->fmt.vbi.start[1];
+		fmt->count[1]         = fmt2->fmt.vbi.count[1];
+		fmt->flags            = fmt2->fmt.vbi.flags & 0x03;
+                break;
+	}
+	case VIDIOCSVBIFMT:
+	{
+		struct vbi_format      *fmt = arg;
+		
+		fmt2 = kmalloc(sizeof(*fmt2),GFP_KERNEL);
+		memset(fmt2, 0, sizeof(*fmt2));
+
+		fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+		fmt2->fmt.vbi.samples_per_line = fmt->samples_per_line;
+		fmt2->fmt.vbi.sampling_rate    = fmt->sampling_rate;
+		fmt2->fmt.vbi.sample_format    = V4L2_PIX_FMT_GREY;
+		fmt2->fmt.vbi.start[0]         = fmt->start[0]; 
+		fmt2->fmt.vbi.count[0]         = fmt->count[0]; 
+		fmt2->fmt.vbi.start[1]         = fmt->start[1]; 
+		fmt2->fmt.vbi.count[1]         = fmt->count[1]; 
+		fmt2->fmt.vbi.flags            = fmt->flags;
+		err = drv(inode, file, VIDIOC_TRY_FMT, fmt2);
+		if (err < 0) {
+			dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %d\n", err);
+			break;
+		}
+
+		if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line ||
+		    fmt2->fmt.vbi.sampling_rate    != fmt->sampling_rate    ||
+		    fmt2->fmt.vbi.sample_format    != V4L2_PIX_FMT_GREY     ||
+		    fmt2->fmt.vbi.start[0]         != fmt->start[0]         ||
+		    fmt2->fmt.vbi.count[0]         != fmt->count[0]         ||
+		    fmt2->fmt.vbi.start[1]         != fmt->start[1]         ||
+		    fmt2->fmt.vbi.count[1]         != fmt->count[1]         ||
+		    fmt2->fmt.vbi.flags            != fmt->flags) {
+			err = -EINVAL;
+			break;
+		}
+		err = drv(inode, file, VIDIOC_S_FMT, fmt2);
+		if (err < 0) {
+			dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err);
+			break;
+		}
+	}
+	
+	default:
+		err = -ENOIOCTLCMD;
 		break;
 	}
+
+	if (cap2)
+		kfree(cap2);
+	if (fmt2)
+		kfree(fmt2);
 	return err;
 }
 
diff -Nru a/drivers/media/video/video-buf.c b/drivers/media/video/video-buf.c
--- a/drivers/media/video/video-buf.c	Wed Mar 12 06:07:06 2003
+++ b/drivers/media/video/video-buf.c	Sat May 17 14:09:40 2003
@@ -362,21 +362,33 @@
 {
 	int i;
 	
-	if (q->reading)
+	if (q->streaming) {
+		dprintk(1,"busy: streaming active\n");
 		return 1;
-	if (q->streaming)
+	}
+	if (q->reading) {
+		dprintk(1,"busy: pending read #1\n");
 		return 1;
-	if (q->read_buf)
+	}
+	if (q->read_buf) {
+		dprintk(1,"busy: pending read #2\n");
 		return 1;
+	}
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		if (NULL == q->bufs[i])
 			continue;
-		if (q->bufs[i]->map)
+		if (q->bufs[i]->map) {
+			dprintk(1,"busy: buffer #%d mapped\n",i);
 			return 1;
-		if (q->bufs[i]->state == STATE_QUEUED)
+		}
+		if (q->bufs[i]->state == STATE_QUEUED) {
+			dprintk(1,"busy: buffer #%d queued\n",i);
 			return 1;
-		if (q->bufs[i]->state == STATE_ACTIVE)
+		}
+		if (q->bufs[i]->state == STATE_ACTIVE) {
+			dprintk(1,"busy: buffer #%d avtive\n",i);
 			return 1;
+		}
 	}
 	return 0;
 }
@@ -569,7 +581,7 @@
 	if (list_empty(&q->stream))
 		goto done;
 	buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
-	retval = videobuf_waiton(buf,1,1);
+	retval = videobuf_waiton(buf, file->f_flags & O_NONBLOCK, 1);
 	if (retval < 0)
 		goto done;
 	switch (buf->state) {
@@ -925,6 +937,9 @@
 videobuf_vm_open(struct vm_area_struct *vma)
 {
 	struct videobuf_mapping *map = vma->vm_private_data;
+
+	dprintk(2,"vm_open %p [count=%d,vma=%08lx-%08lx]\n",map,
+		map->count,vma->vm_start,vma->vm_end);
 	map->count++;
 }
 
@@ -934,6 +949,9 @@
 	struct videobuf_mapping *map = vma->vm_private_data;
 	int i;
 
+	dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
+		map->count,vma->vm_start,vma->vm_end);
+
 	/* down(&fh->lock); FIXME */
 	map->count--;
 	if (0 == map->count) {
@@ -1081,11 +1099,11 @@
 		q->bufs[i]->map   = map;
 		q->bufs[i]->baddr = vma->vm_start + size;
 	}
-	map->count   = 1;
-	map->start   = vma->vm_start;
-	map->end     = vma->vm_end;
-	map->q       = q;
-	vma->vm_ops  = &videobuf_vm_ops;
+	map->count    = 1;
+	map->start    = vma->vm_start;
+	map->end      = vma->vm_end;
+	map->q        = q;
+	vma->vm_ops   = &videobuf_vm_ops;
 	vma->vm_flags |= VM_DONTEXPAND;
 	vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
 	vma->vm_private_data = map;
@@ -1119,6 +1137,7 @@
 EXPORT_SYMBOL_GPL(videobuf_queue_cancel);
 EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
 
+EXPORT_SYMBOL_GPL(videobuf_next_field);
 EXPORT_SYMBOL_GPL(videobuf_status);
 EXPORT_SYMBOL_GPL(videobuf_reqbufs);
 EXPORT_SYMBOL_GPL(videobuf_querybuf);
diff -Nru a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
--- a/drivers/media/video/videodev.c	Sun Apr 20 16:21:18 2003
+++ b/drivers/media/video/videodev.c	Sat May 17 12:39:13 2003
@@ -83,11 +83,8 @@
 	down(&videodev_lock);
 	vfl=video_device[minor];
 	if(vfl==NULL) {
-		char modname[20];
-
 		up(&videodev_lock);
-		sprintf (modname, "char-major-%d-%d", VIDEO_MAJOR, minor);
-		request_module(modname);
+		request_module("char-major-%d-%d", VIDEO_MAJOR, minor);
 		down(&videodev_lock);
 		vfl=video_device[minor];
 		if (vfl==NULL) {
@@ -311,8 +308,10 @@
 		return;
 
 	p = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, video_dev_proc_entry);
-	if (!p)
+	if (!p) {
+		kfree(d);
 		return;
+	}
 	p->data = vfd;
 	p->read_proc = videodev_proc_read;
 
@@ -427,8 +426,8 @@
 	up(&videodev_lock);
 
 	sprintf(vfd->devfs_name, "v4l/%s%d", name_base, i - base);
-	devfs_register(NULL, vfd->devfs_name, 0, VIDEO_MAJOR, vfd->minor,
-			S_IFCHR | S_IRUSR | S_IWUSR, &video_fops, NULL);
+	devfs_mk_cdev(MKDEV(VIDEO_MAJOR, vfd->minor),
+			S_IFCHR | S_IRUSR | S_IWUSR, vfd->devfs_name);
 	init_MUTEX(&vfd->lock);
 	
 #ifdef CONFIG_VIDEO_PROC_FS
diff -Nru a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
--- a/drivers/message/fusion/mptscsih.c	Tue Feb 25 02:44:12 2003
+++ b/drivers/message/fusion/mptscsih.c	Sun May  4 02:56:42 2003
@@ -3631,8 +3631,30 @@
 /* see mptscsih.h */
 
 #ifdef MPT_SCSIHOST_NEED_ENTRY_EXIT_HOOKUPS
-	static Scsi_Host_Template driver_template = MPT_SCSIHOST;
-#	include "../../scsi/scsi_module.c"
+static Scsi_Host_Template driver_template = {
+	.proc_name			= "mptscsih",
+	.proc_info			= x_scsi_proc_info,
+	.name				= "MPT SCSI Host",
+	.detect				= x_scsi_detect,
+	.release			= x_scsi_release,
+	.info				= x_scsi_info,	
+	.queuecommand			= x_scsi_queuecommand,
+	.slave_alloc			= x_scsi_slave_alloc,
+	.slave_configure		= x_scsi_slave_configure,
+	.slave_destroy			= x_scsi_slave_destroy,
+	.eh_abort_handler		= x_scsi_abort,
+	.eh_device_reset_handler	= x_scsi_dev_reset,
+	.eh_bus_reset_handler		= x_scsi_bus_reset,
+	.eh_host_reset_handler		= x_scsi_host_reset,
+	.bios_param			= x_scsi_bios_param,
+	.can_queue			= MPT_SCSI_CAN_QUEUE,
+	.this_id			= -1,
+	.sg_tablesize			= MPT_SCSI_SG_DEPTH,
+	.max_sectors			= MPT_SCSI_MAX_SECTORS,
+	.cmd_per_lun			= MPT_SCSI_CMD_PER_LUN,
+	.use_clustering			= ENABLE_CLUSTERING,
+};
+#include "../../scsi/scsi_module.c"
 #endif
 
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
diff -Nru a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
--- a/drivers/message/fusion/mptscsih.h	Fri Feb 21 06:26:39 2003
+++ b/drivers/message/fusion/mptscsih.h	Sun May  4 02:56:43 2003
@@ -201,36 +201,6 @@
 extern	void		 x_scsi_slave_destroy(Scsi_Device *);
 extern	int		 x_scsi_proc_info(char *, char **, off_t, int, int, int);
 
-#define PROC_SCSI_DECL  .proc_name = "mptscsih",
-
-#define MPT_SCSIHOST {						\
-	PROC_SCSI_DECL						\
-	.proc_info			= x_scsi_proc_info,	\
-	.name				= "MPT SCSI Host",	\
-	.detect				= x_scsi_detect,	\
-	.release			= x_scsi_release,	\
-	.info				= x_scsi_info,		\
-	.command			= NULL,			\
-	.queuecommand			= x_scsi_queuecommand,	\
-	.slave_alloc			= x_scsi_slave_alloc,	\
-	.slave_configure		= x_scsi_slave_configure,	\
-	.slave_destroy			= x_scsi_slave_destroy,	\
-	.eh_strategy_handler		= NULL,			\
-	.eh_abort_handler		= x_scsi_abort,		\
-	.eh_device_reset_handler	= x_scsi_dev_reset,	\
-	.eh_bus_reset_handler		= x_scsi_bus_reset,	\
-	.eh_host_reset_handler		= x_scsi_host_reset,	\
-	.bios_param			= x_scsi_bios_param,	\
-	.can_queue			= MPT_SCSI_CAN_QUEUE,	\
-	.this_id			= -1,			\
-	.sg_tablesize			= MPT_SCSI_SG_DEPTH,	\
-	.max_sectors			= MPT_SCSI_MAX_SECTORS,	\
-	.cmd_per_lun			= MPT_SCSI_CMD_PER_LUN,	\
-	.unchecked_isa_dma		= 0,			\
-	.use_clustering			= ENABLE_CLUSTERING,	\
-}
-
-
 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
 
 /*  include/scsi/scsi.h may not be quite complete...  */
diff -Nru a/drivers/message/i2o/i2o_core.c b/drivers/message/i2o/i2o_core.c
--- a/drivers/message/i2o/i2o_core.c	Thu Apr 24 05:17:30 2003
+++ b/drivers/message/i2o/i2o_core.c	Wed May 14 23:43:59 2003
@@ -2018,15 +2018,14 @@
 	{
 		printk(KERN_ERR "%s: Unable to set SysTab (status=%#x).\n", 
 			iop->name, -ret);
-		kfree(privbuf);
 	}
 	else
 	{
 		dprintk(KERN_INFO "%s: SysTab set.\n", iop->name);
-		kfree(privbuf);
 	}
 	i2o_status_get(iop); // Entered READY state
 
+	kfree(privbuf);
 	return ret;	
 
  }
diff -Nru a/drivers/mtd/chips/cfi_cmdset_0001.c b/drivers/mtd/chips/cfi_cmdset_0001.c
--- a/drivers/mtd/chips/cfi_cmdset_0001.c	Wed Feb 26 05:20:48 2003
+++ b/drivers/mtd/chips/cfi_cmdset_0001.c	Wed May 14 23:43:59 2003
@@ -203,6 +203,7 @@
 	if (!mtd->eraseregions) { 
 		printk(KERN_ERR "Failed to allocate memory for MTD erase region info\n");
 		kfree(cfi->cmdset_priv);
+		kfree(mtd);
 		return NULL;
 	}
 	
@@ -227,6 +228,7 @@
 			printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
 			kfree(mtd->eraseregions);
 			kfree(cfi->cmdset_priv);
+			kfree(mtd);
 			return NULL;
 		}
 
diff -Nru a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
--- a/drivers/mtd/chips/cfi_cmdset_0002.c	Wed Feb 26 05:21:22 2003
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c	Wed May 14 23:43:59 2003
@@ -174,6 +174,7 @@
 		if (!mtd->eraseregions) { 
 			printk(KERN_WARNING "Failed to allocate memory for MTD erase region info\n");
 			kfree(cfi->cmdset_priv);
+			kfree(mtd);
 			return NULL;
 		}
 			
@@ -197,6 +198,7 @@
 			printk(KERN_WARNING "Sum of regions (%lx) != total size of set of interleaved chips (%lx)\n", offset, devsize);
 			kfree(mtd->eraseregions);
 			kfree(cfi->cmdset_priv);
+			kfree(mtd);
 			return NULL;
 		}
 #if 0
diff -Nru a/drivers/mtd/chips/chipreg.c b/drivers/mtd/chips/chipreg.c
--- a/drivers/mtd/chips/chipreg.c	Mon Dec 30 09:03:52 2002
+++ b/drivers/mtd/chips/chipreg.c	Sat May 17 12:39:13 2003
@@ -64,7 +64,7 @@
 
 	drv = get_mtd_chip_driver(name);
 
-	if (!drv && !request_module(name))
+	if (!drv && !request_module("%s", name))
 		drv = get_mtd_chip_driver(name);
 
 	if (!drv)
diff -Nru a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
--- a/drivers/mtd/chips/sharp.c	Thu Apr 24 05:25:35 2003
+++ b/drivers/mtd/chips/sharp.c	Wed May 14 23:43:59 2003
@@ -116,8 +116,10 @@
 		return NULL;
 
 	sharp = kmalloc(sizeof(*sharp), GFP_KERNEL);
-	if(!sharp)
+	if(!sharp) {
+		kfree(mtd);
 		return NULL;
+	}
 
 	memset(mtd, 0, sizeof(*mtd));
 
diff -Nru a/drivers/mtd/maps/sa1100-flash.c b/drivers/mtd/maps/sa1100-flash.c
--- a/drivers/mtd/maps/sa1100-flash.c	Fri Jan 24 12:07:56 2003
+++ b/drivers/mtd/maps/sa1100-flash.c	Mon May 12 18:59:22 2003
@@ -337,7 +337,7 @@
 
 #ifdef CONFIG_SA1100_FREEBIRD
 static struct mtd_partition freebird_partitions[] = {
-#if CONFIG_SA1100_FREEBIRD_NEW
+#ifdef CONFIG_SA1100_FREEBIRD_NEW
 	{
 		.name		= "firmware",
 		.size		= 0x00040000,
diff -Nru a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
--- a/drivers/mtd/mtdchar.c	Sat Mar 22 07:38:05 2003
+++ b/drivers/mtd/mtdchar.c	Wed May  7 08:47:30 2003
@@ -461,22 +461,12 @@
 
 static void mtd_notify_add(struct mtd_info* mtd)
 {
-	char name[16];
-
 	if (!mtd)
 		return;
-
-	sprintf(name, "mtd/%d", mtd->index);
-	devfs_register(NULL, name,
-			DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2,
-			S_IFCHR | S_IRUGO | S_IWUGO,
-			&mtd_fops, NULL);
-
-	sprintf(name, "mtd/%dro", mtd->index);
-	devfs_register(NULL, name,
-			DEVFS_FL_DEFAULT, MTD_CHAR_MAJOR, mtd->index*2+1,
-			S_IFCHR | S_IRUGO | S_IWUGO,
-			&mtd_fops, NULL);
+	devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2),
+			S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%d", mtd->index);
+	devfs_mk_cdev(MKDEV(MTD_CHAR_MAJOR, mtd->index*2+1),
+			S_IFCHR | S_IRUGO | S_IWUGO, "mtd/%dro", mtd->index);
 }
 
 static void mtd_notify_remove(struct mtd_info* mtd)
diff -Nru a/drivers/net/3c59x.c b/drivers/net/3c59x.c
--- a/drivers/net/3c59x.c	Sun Apr 20 22:41:08 2003
+++ b/drivers/net/3c59x.c	Tue May 20 20:02:19 2003
@@ -466,6 +466,9 @@
 	CH_3C920,
 	CH_3C982A,
 	CH_3C982B,
+
+	CH_905BT4,
+	CH_920B_EMB_WNM,
 };
 
 
@@ -565,6 +568,11 @@
 	{"3c982 Hydra Dual Port B",
 	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_HWCKSM|HAS_NWAY, 128, },
 
+	{"3c905B-T4",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, },
+	{"3c920B-EMB-WNM Tornado",
+	 PCI_USES_IO|PCI_USES_MASTER, IS_TORNADO|HAS_NWAY|HAS_HWCKSM, 128, },
+
 	{0,}, /* 0 terminated list. */
 };
 
@@ -611,6 +619,10 @@
 	{ 0x10B7, 0x9201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C920 },
 	{ 0x10B7, 0x1201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C982A },
 	{ 0x10B7, 0x1202, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_3C982B },
+
+	{ 0x10B7, 0x9056, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_905BT4 },
+	{ 0x10B7, 0x9210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CH_920B_EMB_WNM },
+
 	{0,}						/* 0 terminated list. */
 };
 MODULE_DEVICE_TABLE(pci, vortex_pci_tbl);
@@ -1103,6 +1115,7 @@
 		goto out;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, gendev);
 	vp = dev->priv;
 
 	option = global_options;
@@ -2321,7 +2334,6 @@
 	long ioaddr;
 	int status;
 	int work_done = max_interrupt_work;
-	int handled;
 
 	ioaddr = dev->base_addr;
 
@@ -2336,18 +2348,14 @@
 	if (vortex_debug > 6)
 		printk(KERN_DEBUG "boomerang_interrupt. status=0x%4x\n", status);
 
-	if ((status & IntLatch) == 0) {
-		handled = 0;
+	if ((status & IntLatch) == 0)
 		goto handler_exit;		/* No interrupt: shared IRQs can cause this */
-	}
 
 	if (status == 0xffff) {		/* h/w no longer present (hotplug)? */
 		if (vortex_debug > 1)
 			printk(KERN_DEBUG "boomerang_interrupt(1): status = 0xffff\n");
-		handled = 0;
 		goto handler_exit;
 	}
-	handled = 1;
 
 	if (status & IntReq) {
 		status |= vp->deferred;
@@ -2442,7 +2450,7 @@
 			   dev->name, status);
 handler_exit:
 	spin_unlock(&vp->lock);
-	return IRQ_RETVAL(handled);
+	return IRQ_HANDLED;
 }
 
 static int vortex_rx(struct net_device *dev)
diff -Nru a/drivers/net/8139cp.c b/drivers/net/8139cp.c
--- a/drivers/net/8139cp.c	Sun Apr 27 10:26:59 2003
+++ b/drivers/net/8139cp.c	Tue May 20 20:02:19 2003
@@ -1801,6 +1801,8 @@
 	if (!dev)
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
 	cp = dev->priv;
 	cp->pdev = pdev;
 	cp->board_type = board_type;
diff -Nru a/drivers/net/8139too.c b/drivers/net/8139too.c
--- a/drivers/net/8139too.c	Sun Apr 20 22:09:47 2003
+++ b/drivers/net/8139too.c	Tue May 20 20:02:19 2003
@@ -768,6 +768,8 @@
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
 	tp = dev->priv;
 	tp->pci_dev = pdev;
 
diff -Nru a/drivers/net/Kconfig b/drivers/net/Kconfig
--- a/drivers/net/Kconfig	Sun Apr 27 21:05:07 2003
+++ b/drivers/net/Kconfig	Sat May 17 08:48:38 2003
@@ -158,7 +158,7 @@
 
 config NET_SB1000
 	tristate "General Instruments Surfboard 1000"
-	depends on NETDEVICES && ISAPNP
+	depends on NETDEVICES && PNP
 	---help---
 	  This is a driver for the General Instrument (also known as
 	  NextLevel) SURFboard 1000 internal
@@ -221,14 +221,7 @@
 	  or internal device.  It is safe to say Y or M here even if your
 	  ethernet card lack MII.
 
-config ARM_AM79C961A
-	bool "ARM EBSA110 AM79C961A support"
-	depends on NET_ETHERNET && ARM && ARCH_EBSA110
-	help
-	  If you wish to compile a kernel for the EBSA-110, then you should
-	  always answer Y to this.
-
-source "drivers/acorn/net/Kconfig"
+source "drivers/net/arm/Kconfig"
 
 config MACE
 	tristate "MACE (Power Mac ethernet) support"
diff -Nru a/drivers/net/Makefile b/drivers/net/Makefile
--- a/drivers/net/Makefile	Sun Apr 27 21:05:07 2003
+++ b/drivers/net/Makefile	Mon May 19 23:38:39 2003
@@ -24,7 +24,7 @@
 obj-$(CONFIG_SUNQE) += sunqe.o
 obj-$(CONFIG_SUNBMAC) += sunbmac.o
 obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o
-obj-$(CONFIG_SUNGEM) += sungem.o
+obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o
 
 obj-$(CONFIG_MACE) += mace.o
 obj-$(CONFIG_BMAC) += bmac.o
@@ -77,7 +77,6 @@
 obj-$(CONFIG_SMC9194) += smc9194.o
 obj-$(CONFIG_FEC) += fec.o
 obj-$(CONFIG_68360_ENET) += 68360enet.o
-obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o
 obj-$(CONFIG_ARM_ETHERH) += 8390.o
 obj-$(CONFIG_WD80x3) += wd.o 8390.o
 obj-$(CONFIG_EL2) += 3c503.o 8390.o
@@ -179,7 +178,7 @@
 # non-drivers/net drivers who want mii lib
 obj-$(CONFIG_PCMCIA_SMC91C92) += mii.o
 
-obj-$(CONFIG_ARCH_ACORN) += ../acorn/net/
+obj-$(CONFIG_ARM) += arm/
 obj-$(CONFIG_NET_FC) += fc/
 obj-$(CONFIG_DEV_APPLETALK) += appletalk/
 obj-$(CONFIG_TR) += tokenring/
diff -Nru a/drivers/net/Space.c b/drivers/net/Space.c
--- a/drivers/net/Space.c	Thu Mar  6 20:30:51 2003
+++ b/drivers/net/Space.c	Tue May 20 18:56:26 2003
@@ -131,26 +131,20 @@
 {
 	struct devprobe *p = plist;
 	unsigned long base_addr = dev->base_addr;
-#ifdef CONFIG_NET_DIVERT
 	int ret;
-#endif /* CONFIG_NET_DIVERT */
 
 	while (p->probe != NULL) {
 		if (base_addr && p->probe(dev) == 0) {	/* probe given addr */
-#ifdef CONFIG_NET_DIVERT
 			ret = alloc_divert_blk(dev);
 			if (ret)
 				return ret;
-#endif /* CONFIG_NET_DIVERT */
 			return 0;
 		} else if (p->status == 0) {		/* has autoprobe failed yet? */
 			p->status = p->probe(dev);	/* no, try autoprobe */
 			if (p->status == 0) {
-#ifdef CONFIG_NET_DIVERT
 				ret = alloc_divert_blk(dev);
 				if (ret)
 					return ret;
-#endif /* CONFIG_NET_DIVERT */
 				return 0;
 			}
 		}
diff -Nru a/drivers/net/acenic.c b/drivers/net/acenic.c
--- a/drivers/net/acenic.c	Mon Apr  7 00:03:41 2003
+++ b/drivers/net/acenic.c	Tue May 20 20:02:19 2003
@@ -188,6 +188,9 @@
 #define ACE_MOD_DEC_USE_COUNT		do{} while(0)
 #endif
 
+#ifndef SET_NETDEV_DEV
+#define SET_NETDEV_DEV(net, pdev)	do{} while(0)
+#endif
 
 #if LINUX_VERSION_CODE >= 0x2051c
 #define ace_sync_irq(irq)	synchronize_irq(irq)
@@ -651,6 +654,7 @@
 		}
 
 		SET_MODULE_OWNER(dev);
+		SET_NETDEV_DEV(dev, &pdev->dev);
 
 		if (!dev->priv)
 			dev->priv = kmalloc(sizeof(*ap), GFP_KERNEL);
@@ -1871,7 +1875,9 @@
 	} else {
 		printk(KERN_DEBUG "%s: BUG... transmitter died. Kicking it.\n",
 		       dev->name);
+#if 0
 		netif_wake_queue(dev);
+#endif
 	}
 }
 
@@ -2426,7 +2432,7 @@
 }
 
 
-static void ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
+static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	struct ace_private *ap;
 	struct ace_regs *regs;
@@ -2444,7 +2450,7 @@
 	 * spending any time in here.
 	 */
 	if (!(readl(&regs->HostCtrl) & IN_INT))
-		return;
+		return IRQ_NONE;
 
 	/*
 	 * ACK intr now. Otherwise we will lose updates to rx_ret_prd,
@@ -2550,6 +2556,8 @@
 			tasklet_schedule(&ap->ace_tasklet);
 		}
 	}
+
+	return IRQ_HANDLED;
 }
 
 
diff -Nru a/drivers/net/acenic.h b/drivers/net/acenic.h
--- a/drivers/net/acenic.h	Thu Sep 26 09:48:12 2002
+++ b/drivers/net/acenic.h	Tue May 20 19:05:13 2003
@@ -781,7 +781,7 @@
 static void ace_load_std_rx_ring(struct ace_private *ap, int nr_bufs);
 static void ace_load_mini_rx_ring(struct ace_private *ap, int nr_bufs);
 static void ace_load_jumbo_rx_ring(struct ace_private *ap, int nr_bufs);
-static void ace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t ace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int ace_load_firmware(struct net_device *dev);
 static int ace_open(struct net_device *dev);
 static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev);
diff -Nru a/drivers/net/am79c961a.c b/drivers/net/am79c961a.c
--- a/drivers/net/am79c961a.c	Sun Apr 27 20:36:18 2003
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,685 +0,0 @@
-/*
- *  linux/drivers/net/am79c961.c
- *
- *  by Russell King <rmk@arm.linux.org.uk> 1995-2001.
- *
- * 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.
- *
- * Derived from various things including skeleton.c
- *
- * This is a special driver for the am79c961A Lance chip used in the
- * Intel (formally Digital Equipment Corp) EBSA110 platform.  Please
- * note that this can not be built as a module (it doesn't make sense).
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ioport.h>
-#include <linux/in.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
-
-#include <asm/system.h>
-#include <asm/bitops.h>
-#include <asm/irq.h>
-#include <asm/io.h>
-#include <asm/dma.h>
-
-#define TX_BUFFERS 15
-#define RX_BUFFERS 25
-
-#include "am79c961a.h"
-
-static irqreturn_t
-am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
-
-static unsigned int net_debug = NET_DEBUG;
-
-static const char version[] =
-	"am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n";
-
-/* --------------------------------------------------------------------------- */
-
-#ifdef __arm__
-static void write_rreg(u_long base, u_int reg, u_int val)
-{
-	__asm__("str%?h	%1, [%2]	@ NET_RAP
-		str%?h	%0, [%2, #-4]	@ NET_RDP
-		" : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
-}
-
-static inline unsigned short read_rreg(u_long base_addr, u_int reg)
-{
-	unsigned short v;
-	__asm__("str%?h	%1, [%2]	@ NET_RAP
-		ldr%?h	%0, [%2, #-4]	@ NET_RDP
-		" : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464));
-	return v;
-}
-
-static inline void write_ireg(u_long base, u_int reg, u_int val)
-{
-	__asm__("str%?h	%1, [%2]	@ NET_RAP
-		str%?h	%0, [%2, #8]	@ NET_IDP
-		" : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
-}
-
-#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
-#define am_readword(dev,off)      __raw_readw(ISAMEM_BASE + ((off) << 1))
-
-static inline void
-am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
-{
-	offset = ISAMEM_BASE + (offset << 1);
-	length = (length + 1) & ~1;
-	if ((int)buf & 2) {
-		__asm__ __volatile__("str%?h	%2, [%0], #4"
-		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
-		buf += 2;
-		length -= 2;
-	}
-	while (length > 8) {
-		unsigned int tmp, tmp2;
-		__asm__ __volatile__("
-			ldm%?ia	%1!, {%2, %3}
-			str%?h	%2, [%0], #4
-			mov%?	%2, %2, lsr #16
-			str%?h	%2, [%0], #4
-			str%?h	%3, [%0], #4
-			mov%?	%3, %3, lsr #16
-			str%?h	%3, [%0], #4
-		" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
-		  : "0" (offset), "1" (buf));
-		length -= 8;
-	}
-	while (length > 0) {
-		__asm__ __volatile__("str%?h	%2, [%0], #4"
-		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
-		buf += 2;
-		length -= 2;
-	}
-}
-
-static inline void
-am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
-{
-	offset = ISAMEM_BASE + (offset << 1);
-	length = (length + 1) & ~1;
-	if ((int)buf & 2) {
-		unsigned int tmp;
-		__asm__ __volatile__("
-			ldr%?h	%2, [%0], #4
-			str%?b	%2, [%1], #1
-			mov%?	%2, %2, lsr #8
-			str%?b	%2, [%1], #1
-		" : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
-		length -= 2;
-	}
-	while (length > 8) {
-		unsigned int tmp, tmp2, tmp3;
-		__asm__ __volatile__("
-			ldr%?h	%2, [%0], #4
-			ldr%?h	%3, [%0], #4
-			orr%?	%2, %2, %3, lsl #16
-			ldr%?h	%3, [%0], #4
-			ldr%?h	%4, [%0], #4
-			orr%?	%3, %3, %4, lsl #16
-			stm%?ia	%1!, {%2, %3}
-		" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
-		  : "0" (offset), "1" (buf));
-		length -= 8;
-	}
-	while (length > 0) {
-		unsigned int tmp;
-		__asm__ __volatile__("
-			ldr%?h	%2, [%0], #4
-			str%?b	%2, [%1], #1
-			mov%?	%2, %2, lsr #8
-			str%?b	%2, [%1], #1
-		" : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
-		length -= 2;
-	}
-}
-#else
-#error Not compatible
-#endif
-
-static int
-am79c961_ramtest(struct net_device *dev, unsigned int val)
-{
-	unsigned char *buffer = kmalloc (65536, GFP_KERNEL);
-	int i, error = 0, errorcount = 0;
-
-	if (!buffer)
-		return 0;
-	memset (buffer, val, 65536);
-	am_writebuffer(dev, 0, buffer, 65536);
-	memset (buffer, val ^ 255, 65536);
-	am_readbuffer(dev, 0, buffer, 65536);
-	for (i = 0; i < 65536; i++) {
-		if (buffer[i] != val && !error) {
-			printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i);
-			error = 1;
-			errorcount ++;
-		} else if (error && buffer[i] == val) {
-			printk ("%05X\n", i);
-			error = 0;
-		}
-	}
-	if (error)
-		printk ("10000\n");
-	kfree (buffer);
-	return errorcount;
-}
-
-static void
-am79c961_init_for_open(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	unsigned long flags;
-	unsigned char *p;
-	u_int hdr_addr, first_free_addr;
-	int i;
-
-	/*
-	 * Stop the chip.
-	 */
-	spin_lock_irqsave(priv->chip_lock, flags);
-	write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP);
-	spin_unlock_irqrestore(priv->chip_lock, flags);
-
-	write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */
-	write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */
-	write_ireg (dev->base_addr, 7, 0x0090); /* XMIT LED */
-	write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */
-
-	for (i = LADRL; i <= LADRH; i++)
-		write_rreg (dev->base_addr, i, 0);
-
-	for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
-		write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
-
-	i = MODE_PORT_10BT;
-	if (dev->flags & IFF_PROMISC)
-		i |= MODE_PROMISC;
-
-	write_rreg (dev->base_addr, MODE, i);
-	write_rreg (dev->base_addr, POLLINT, 0);
-	write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
-	write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
-
-	first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16;
-	hdr_addr = 0;
-
-	priv->rxhead = 0;
-	priv->rxtail = 0;
-	priv->rxhdr = hdr_addr;
-
-	for (i = 0; i < RX_BUFFERS; i++) {
-		priv->rxbuffer[i] = first_free_addr;
-		am_writeword (dev, hdr_addr, first_free_addr);
-		am_writeword (dev, hdr_addr + 2, RMD_OWN);
-		am_writeword (dev, hdr_addr + 4, (-1600));
-		am_writeword (dev, hdr_addr + 6, 0);
-		first_free_addr += 1600;
-		hdr_addr += 8;
-	}
-	priv->txhead = 0;
-	priv->txtail = 0;
-	priv->txhdr = hdr_addr;
-	for (i = 0; i < TX_BUFFERS; i++) {
-		priv->txbuffer[i] = first_free_addr;
-		am_writeword (dev, hdr_addr, first_free_addr);
-		am_writeword (dev, hdr_addr + 2, TMD_STP|TMD_ENP);
-		am_writeword (dev, hdr_addr + 4, 0xf000);
-		am_writeword (dev, hdr_addr + 6, 0);
-		first_free_addr += 1600;
-		hdr_addr += 8;
-	}
-
-	write_rreg (dev->base_addr, BASERXL, priv->rxhdr);
-	write_rreg (dev->base_addr, BASERXH, 0);
-	write_rreg (dev->base_addr, BASETXL, priv->txhdr);
-	write_rreg (dev->base_addr, BASERXH, 0);
-	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
-	write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
-	write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
-}
-
-/*
- * Open/initialize the board.
- */
-static int
-am79c961_open(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	int ret;
-
-	memset (&priv->stats, 0, sizeof (priv->stats));
-
-	ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev);
-	if (ret)
-		return ret;
-
-	am79c961_init_for_open(dev);
-
-	netif_start_queue(dev);
-
-	return 0;
-}
-
-/*
- * The inverse routine to am79c961_open().
- */
-static int
-am79c961_close(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	unsigned long flags;
-
-	netif_stop_queue(dev);
-
-	spin_lock_irqsave(priv->chip_lock, flags);
-	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
-	write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
-	spin_unlock_irqrestore(priv->chip_lock, flags);
-
-	free_irq (dev->irq, dev);
-
-	return 0;
-}
-
-/*
- * Get the current statistics.
- */
-static struct net_device_stats *am79c961_getstats (struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	return &priv->stats;
-}
-
-static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
-{
-	if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
-		int idx, bit;
-		u32 crc;
-
-		crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
-
-		idx = crc >> 30;
-		bit = (crc >> 26) & 15;
-
-		hash[idx] |= 1 << bit;
-	}
-}
-
-/*
- * Set or clear promiscuous/multicast mode filter for this adapter.
- */
-static void am79c961_setmulticastlist (struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	unsigned long flags;
-	unsigned short multi_hash[4], mode;
-	int i, stopped;
-
-	mode = MODE_PORT_10BT;
-
-	if (dev->flags & IFF_PROMISC) {
-		mode |= MODE_PROMISC;
-	} else if (dev->flags & IFF_ALLMULTI) {
-		memset(multi_hash, 0xff, sizeof(multi_hash));
-	} else {
-		struct dev_mc_list *dmi;
-
-		memset(multi_hash, 0x00, sizeof(multi_hash));
-
-		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
-			am79c961_mc_hash(dmi, multi_hash);
-	}
-
-	spin_lock_irqsave(priv->chip_lock, flags);
-
-	stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;
-
-	if (!stopped) {
-		/*
-		 * Put the chip into suspend mode
-		 */
-		write_rreg(dev->base_addr, CTRL1, CTRL1_SPND);
-
-		/*
-		 * Spin waiting for chip to report suspend mode
-		 */
-		while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) {
-			spin_unlock_irqrestore(priv->chip_lock, flags);
-			nop();
-			spin_lock_irqsave(priv->chip_lock, flags);
-		}
-	}
-
-	/*
-	 * Update the multicast hash table
-	 */
-	for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)
-		write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
-
-	/*
-	 * Write the mode register
-	 */
-	write_rreg(dev->base_addr, MODE, mode);
-
-	if (!stopped) {
-		/*
-		 * Put the chip back into running mode
-		 */
-		write_rreg(dev->base_addr, CTRL1, 0);
-	}
-
-	spin_unlock_irqrestore(priv->chip_lock, flags);
-}
-
-static void am79c961_timeout(struct net_device *dev)
-{
-	printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n",
-		dev->name);
-
-	/*
-	 * ought to do some setup of the tx side here
-	 */
-
-	netif_wake_queue(dev);
-}
-
-/*
- * Transmit a packet
- */
-static int
-am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	unsigned int length = skb->len;
-	unsigned int hdraddr, bufaddr;
-	unsigned int head;
-	unsigned long flags;
-	
-	/* FIXME: I thought the 79c961 could do padding - RMK ??? */
-	if (length < ETH_ZLEN) {
-		skb = skb_padto(skb, ETH_ZLEN);
-		if (skb == NULL)
-			return 0;
-		length = ETH_ZLEN;
-	}
-
-	head = priv->txhead;
-	hdraddr = priv->txhdr + (head << 3);
-	bufaddr = priv->txbuffer[head];
-	head += 1;
-	if (head >= TX_BUFFERS)
-		head = 0;
-
-	am_writebuffer (dev, bufaddr, skb->data, length);
-	am_writeword (dev, hdraddr + 4, -length);
-	am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
-	priv->txhead = head;
-
-	spin_lock_irqsave(priv->chip_lock, flags);
-	write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
-	dev->trans_start = jiffies;
-	spin_unlock_irqrestore(priv->chip_lock, flags);
-
-	/*
-	 * If the next packet is owned by the ethernet device,
-	 * then the tx ring is full and we can't add another
-	 * packet.
-	 */
-	if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
-		netif_stop_queue(dev);
-
-	dev_kfree_skb(skb);
-
-	return 0;
-}
-
-/*
- * If we have a good packet(s), get it/them out of the buffers.
- */
-static void
-am79c961_rx(struct net_device *dev, struct dev_priv *priv)
-{
-	do {
-		struct sk_buff *skb;
-		u_int hdraddr;
-		u_int pktaddr;
-		u_int status;
-		int len;
-
-		hdraddr = priv->rxhdr + (priv->rxtail << 3);
-		pktaddr = priv->rxbuffer[priv->rxtail];
-
-		status = am_readword (dev, hdraddr + 2);
-		if (status & RMD_OWN) /* do we own it? */
-			break;
-
-		priv->rxtail ++;
-		if (priv->rxtail >= RX_BUFFERS)
-			priv->rxtail = 0;
-
-		if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
-			am_writeword (dev, hdraddr + 2, RMD_OWN);
-			priv->stats.rx_errors ++;
-			if (status & RMD_ERR) {
-				if (status & RMD_FRAM)
-					priv->stats.rx_frame_errors ++;
-				if (status & RMD_CRC)
-					priv->stats.rx_crc_errors ++;
-			} else if (status & RMD_STP)
-				priv->stats.rx_length_errors ++;
-			continue;
-		}
-
-		len = am_readword(dev, hdraddr + 6);
-		skb = dev_alloc_skb(len + 2);
-
-		if (skb) {
-			skb->dev = dev;
-			skb_reserve(skb, 2);
-
-			am_readbuffer(dev, pktaddr, skb_put(skb, len), len);
-			am_writeword(dev, hdraddr + 2, RMD_OWN);
-			skb->protocol = eth_type_trans(skb, dev);
-			netif_rx(skb);
-			dev->last_rx = jiffies;
-			priv->stats.rx_bytes += len;
-			priv->stats.rx_packets ++;
-		} else {
-			am_writeword (dev, hdraddr + 2, RMD_OWN);
-			printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
-			priv->stats.rx_dropped ++;
-			break;
-		}
-	} while (1);
-}
-
-/*
- * Update stats for the transmitted packet
- */
-static void
-am79c961_tx(struct net_device *dev, struct dev_priv *priv)
-{
-	do {
-		u_int hdraddr;
-		u_int status;
-
-		hdraddr = priv->txhdr + (priv->txtail << 3);
-		status = am_readword (dev, hdraddr + 2);
-		if (status & TMD_OWN)
-			break;
-
-		priv->txtail ++;
-		if (priv->txtail >= TX_BUFFERS)
-			priv->txtail = 0;
-
-		if (status & TMD_ERR) {
-			u_int status2;
-
-			priv->stats.tx_errors ++;
-
-			status2 = am_readword (dev, hdraddr + 6);
-
-			/*
-			 * Clear the error byte
-			 */
-			am_writeword (dev, hdraddr + 6, 0);
-
-			if (status2 & TST_RTRY)
-				priv->stats.collisions += 16;
-			if (status2 & TST_LCOL)
-				priv->stats.tx_window_errors ++;
-			if (status2 & TST_LCAR)
-				priv->stats.tx_carrier_errors ++;
-			if (status2 & TST_UFLO)
-				priv->stats.tx_fifo_errors ++;
-			continue;
-		}
-		priv->stats.tx_packets ++;
-	} while (priv->txtail != priv->txhead);
-
-	netif_wake_queue(dev);
-}
-
-static irqreturn_t
-am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
-{
-	struct net_device *dev = (struct net_device *)dev_id;
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-	u_int status;
-	int handled = 0;
-
-	status = read_rreg(dev->base_addr, CSR0);
-	write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
-
-	if (status & CSR0_RINT) {
-		handled = 1;
-		am79c961_rx(dev, priv);
-	}
-	if (status & CSR0_TINT) {
-		handled = 1;
-		am79c961_tx(dev, priv);
-	}
-	if (status & CSR0_MISS) {
-		handled = 1;
-		priv->stats.rx_dropped ++;
-	}
-	return IRQ_RETVAL(handled);
-}
-
-/*
- * Initialise the chip.  Note that we always expect
- * to be entered with interrupts enabled.
- */
-static int
-am79c961_hw_init(struct net_device *dev)
-{
-	struct dev_priv *priv = (struct dev_priv *)dev->priv;
-
-	spin_lock_irq(priv->chip_lock);
-	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
-	write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
-	spin_unlock_irq(priv->chip_lock);
-
-	am79c961_ramtest(dev, 0x66);
-	am79c961_ramtest(dev, 0x99);
-
-	return 0;
-}
-
-static void __init am79c961_banner(void)
-{
-	static unsigned version_printed;
-
-	if (net_debug && version_printed++ == 0)
-		printk(KERN_INFO "%s", version);
-}
-
-static int __init am79c961_init(void)
-{
-	struct net_device *dev;
-	struct dev_priv *priv;
-	int i, ret;
-
-	dev = init_etherdev(NULL, sizeof(struct dev_priv));
-	ret = -ENOMEM;
-	if (!dev)
-		goto out;
-
-	priv = dev->priv;
-
-	/*
-	 * Fixed address and IRQ lines here.
-	 * The PNP initialisation should have been
-	 * done by the ether bootp loader.
-	 */
-	dev->base_addr = 0x220;
-	dev->irq = IRQ_EBSA110_ETHERNET;
-
-	/*
-	 * Reset the device.
-	 */
-	inb(dev->base_addr + NET_RESET);
-	udelay(5);
-
-	/*
-	 * Check the manufacturer part of the
-	 * ether address.
-	 */
-    	ret = -ENODEV;
-	if (inb(dev->base_addr) != 0x08 ||
-	    inb(dev->base_addr + 2) != 0x00 ||
-	    inb(dev->base_addr + 4) != 0x2b)
-	    	goto nodev;
-
-	if (!request_region(dev->base_addr, 0x18, dev->name))
-		goto nodev;
-
-	am79c961_banner();
-	printk(KERN_INFO "%s: ether address ", dev->name);
-
-	/* Retrive and print the ethernet address. */
-	for (i = 0; i < 6; i++) {
-		dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
-		printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
-	}
-
-	if (am79c961_hw_init(dev))
-		goto release;
-
-	dev->open		= am79c961_open;
-	dev->stop		= am79c961_close;
-	dev->hard_start_xmit	= am79c961_sendpacket;
-	dev->get_stats		= am79c961_getstats;
-	dev->set_multicast_list	= am79c961_setmulticastlist;
-	dev->tx_timeout		= am79c961_timeout;
-
-	return 0;
-
-release:
-	release_region(dev->base_addr, 0x18);
-nodev:
-	unregister_netdev(dev);
-	kfree(dev);
-out:
-	return ret;
-}
-
-__initcall(am79c961_init);
diff -Nru a/drivers/net/am79c961a.h b/drivers/net/am79c961a.h
--- a/drivers/net/am79c961a.h	Tue Feb  5 09:40:03 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,130 +0,0 @@
-/*
- * linux/drivers/net/am79c961.h
- *
- * 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.
- */
-
-#ifndef _LINUX_am79c961a_H
-#define _LINUX_am79c961a_H
-
-/* use 0 for production, 1 for verification, >2 for debug. debug flags: */
-#define DEBUG_TX	 2
-#define DEBUG_RX	 4
-#define DEBUG_INT	 8
-#define DEBUG_IC	16
-#ifndef NET_DEBUG
-#define NET_DEBUG 	0
-#endif
-
-#define NET_UID		0
-#define NET_RDP		0x10
-#define NET_RAP		0x12
-#define NET_RESET	0x14
-#define NET_IDP		0x16
-
-/*
- * RAP registers
- */
-#define CSR0		0
-#define CSR0_INIT	0x0001
-#define CSR0_STRT	0x0002
-#define CSR0_STOP	0x0004
-#define CSR0_TDMD	0x0008
-#define CSR0_TXON	0x0010
-#define CSR0_RXON	0x0020
-#define CSR0_IENA	0x0040
-#define CSR0_INTR	0x0080
-#define CSR0_IDON	0x0100
-#define CSR0_TINT	0x0200
-#define CSR0_RINT	0x0400
-#define CSR0_MERR	0x0800
-#define CSR0_MISS	0x1000
-#define CSR0_CERR	0x2000
-#define CSR0_BABL	0x4000
-#define CSR0_ERR	0x8000
-
-#define CSR3		3
-#define CSR3_EMBA	0x0008
-#define CSR3_DXMT2PD	0x0010
-#define CSR3_LAPPEN	0x0020
-#define CSR3_DXSUFLO	0x0040
-#define CSR3_IDONM	0x0100
-#define CSR3_TINTM	0x0200
-#define CSR3_RINTM	0x0400
-#define CSR3_MERRM	0x0800
-#define CSR3_MISSM	0x1000
-#define CSR3_BABLM	0x4000
-#define CSR3_MASKALL	0x5F00
-
-#define CTRL1		5
-#define CTRL1_SPND	0x0001
-
-#define LADRL		8
-#define LADRM1		9
-#define LADRM2		10
-#define LADRH		11
-#define PADRL		12
-#define PADRM		13
-#define PADRH		14
-
-#define MODE		15
-#define MODE_DISRX	0x0001
-#define MODE_DISTX	0x0002
-#define MODE_LOOP	0x0004
-#define MODE_DTCRC	0x0008
-#define MODE_COLL	0x0010
-#define MODE_DRETRY	0x0020
-#define MODE_INTLOOP	0x0040
-#define MODE_PORT_AUI	0x0000
-#define MODE_PORT_10BT	0x0080
-#define MODE_DRXPA	0x2000
-#define MODE_DRXBA	0x4000
-#define MODE_PROMISC	0x8000
-
-#define BASERXL		24
-#define BASERXH		25
-#define BASETXL		30
-#define BASETXH		31
-
-#define POLLINT		47
-
-#define SIZERXR		76
-#define SIZETXR		78
-
-#define RMD_ENP		0x0100
-#define RMD_STP		0x0200
-#define RMD_CRC		0x0800
-#define RMD_FRAM	0x2000
-#define RMD_ERR		0x4000
-#define RMD_OWN		0x8000
-
-#define TMD_ENP		0x0100
-#define TMD_STP		0x0200
-#define TMD_MORE	0x1000
-#define TMD_ERR		0x4000
-#define TMD_OWN		0x8000
-
-#define TST_RTRY	0x0400
-#define TST_LCAR	0x0800
-#define TST_LCOL	0x1000
-#define TST_UFLO	0x4000
-#define TST_BUFF	0x8000
-
-struct dev_priv {
-    struct net_device_stats stats;
-    unsigned long	rxbuffer[RX_BUFFERS];
-    unsigned long	txbuffer[TX_BUFFERS];
-    unsigned char	txhead;
-    unsigned char	txtail;
-    unsigned char	rxhead;
-    unsigned char	rxtail;
-    unsigned long	rxhdr;
-    unsigned long	txhdr;
-    spinlock_t		chip_lock;
-};
-
-extern int	am79c961_probe (struct net_device *dev);
-
-#endif
diff -Nru a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c
--- a/drivers/net/amd8111e.c	Sun Apr 20 22:41:09 2003
+++ b/drivers/net/amd8111e.c	Tue May 20 20:02:19 2003
@@ -1542,6 +1542,7 @@
 	}
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 #if AMD8111E_VLAN_TAG_USED
 	dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX ;
diff -Nru a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c
--- a/drivers/net/arcnet/arcnet.c	Fri Apr  4 09:43:08 2003
+++ b/drivers/net/arcnet/arcnet.c	Thu May 15 17:23:26 2003
@@ -340,7 +340,7 @@
 	dev->hard_header_len = sizeof(struct archdr);
 	dev->mtu = choose_mtu();
 
-	dev->addr_len = 1;
+	dev->addr_len = ARCNET_ALEN;
 	dev->tx_queue_len = 30;
 	dev->broadcast[0] = 0x00;	/* for us, broadcasts are address 0 */
 	dev->watchdog_timeo = TX_TIMEOUT;
diff -Nru a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c
--- a/drivers/net/arcnet/rfc1201.c	Thu Apr  4 01:39:23 2002
+++ b/drivers/net/arcnet/rfc1201.c	Thu May 15 17:23:26 2003
@@ -56,6 +56,7 @@
 void __init arcnet_rfc1201_init(void)
 {
 	arc_proto_map[ARC_P_IP]
+	    = arc_proto_map[ARC_P_IPV6]
 	    = arc_proto_map[ARC_P_ARP]
 	    = arc_proto_map[ARC_P_RARP]
 	    = arc_proto_map[ARC_P_IPX]
@@ -114,6 +115,8 @@
 	switch (soft->proto) {
 	case ARC_P_IP:
 		return htons(ETH_P_IP);
+	case ARC_P_IPV6:
+		return htons(ETH_P_IPV6);
 	case ARC_P_ARP:
 		return htons(ETH_P_ARP);
 	case ARC_P_RARP:
@@ -388,6 +391,9 @@
 	switch (type) {
 	case ETH_P_IP:
 		soft->proto = ARC_P_IP;
+		break;
+	case ETH_P_IPV6:
+		soft->proto = ARC_P_IPV6;
 		break;
 	case ETH_P_ARP:
 		soft->proto = ARC_P_ARP;
diff -Nru a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/Kconfig	Sat May 17 06:52:31 2003
@@ -0,0 +1,45 @@
+#
+# Acorn Network device configuration
+#  These are for Acorn's Expansion card network interfaces
+#
+config ARM_AM79C961A
+	bool "ARM EBSA110 AM79C961A support"
+	depends on NET_ETHERNET && ARM && ARCH_EBSA110
+	help
+	  If you wish to compile a kernel for the EBSA-110, then you should
+	  always answer Y to this.
+
+config ARM_ETHER1
+	tristate "Acorn Ether1 support"
+	depends on NET_ETHERNET && ARM && ARCH_ACORN
+	help
+	  If you have an Acorn system with one of these (AKA25) network cards,
+	  you should say Y to this option if you wish to use it with Linux.
+
+config ARM_ETHER3
+	tristate "Acorn/ANT Ether3 support"
+	depends on NET_ETHERNET && ARM && ARCH_ACORN
+	help
+	  If you have an Acorn system with one of these network cards, you
+	  should say Y to this option if you wish to use it with Linux.
+
+config ARM_ETHERH
+	tristate "I-cubed EtherH/ANT EtherM support"
+	depends on NET_ETHERNET && ARM && ARCH_ACORN
+	help
+	  If you have an Acorn system with one of these network cards, you
+	  should say Y to this option if you wish to use it with Linux.
+
+config ARM_ETHER00
+	tristate "Altera Ether00 support"
+	depends on NET_ETHERNET && ARM && ARCH_CAMELOT
+	help
+	  This is the driver for Altera's ether00 ethernet mac IP core. Say
+	  Y here if you want to build support for this into the kernel. It
+	  is also available as a module (say M here) that can be inserted/
+	  removed from the kernel at the same time as the PLD is configured.
+	  If this driver is running on an epxa10 development board then it
+	  will generate a suitable hw address based on the board serial
+	  number (MTD support is required for this). Otherwise you will
+	  need to set a suitable hw address using ifconfig.
+
diff -Nru a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/Makefile	Sat May 17 06:52:31 2003
@@ -0,0 +1,10 @@
+# File: drivers/net/arm/Makefile
+#
+# Makefile for the ARM network device drivers
+#
+
+obj-$(CONFIG_ARM_AM79C961A)	+= am79c961a.o
+obj-$(CONFIG_ARM_ETHER00)	+= ether00.o
+obj-$(CONFIG_ARM_ETHERH)	+= etherh.o
+obj-$(CONFIG_ARM_ETHER3)	+= ether3.o
+obj-$(CONFIG_ARM_ETHER1)	+= ether1.o
diff -Nru a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/am79c961a.c	Fri May 16 03:06:59 2003
@@ -0,0 +1,685 @@
+/*
+ *  linux/drivers/net/am79c961.c
+ *
+ *  by Russell King <rmk@arm.linux.org.uk> 1995-2001.
+ *
+ * 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.
+ *
+ * Derived from various things including skeleton.c
+ *
+ * This is a special driver for the am79c961A Lance chip used in the
+ * Intel (formally Digital Equipment Corp) EBSA110 platform.  Please
+ * note that this can not be built as a module (it doesn't make sense).
+ */
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#define TX_BUFFERS 15
+#define RX_BUFFERS 25
+
+#include "am79c961a.h"
+
+static irqreturn_t
+am79c961_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+
+static unsigned int net_debug = NET_DEBUG;
+
+static const char version[] =
+	"am79c961 ethernet driver (C) 1995-2001 Russell King v0.04\n";
+
+/* --------------------------------------------------------------------------- */
+
+#ifdef __arm__
+static void write_rreg(u_long base, u_int reg, u_int val)
+{
+	__asm__("str%?h	%1, [%2]	@ NET_RAP
+		str%?h	%0, [%2, #-4]	@ NET_RDP
+		" : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
+}
+
+static inline unsigned short read_rreg(u_long base_addr, u_int reg)
+{
+	unsigned short v;
+	__asm__("str%?h	%1, [%2]	@ NET_RAP
+		ldr%?h	%0, [%2, #-4]	@ NET_RDP
+		" : "=r" (v): "r" (reg), "r" (ISAIO_BASE + 0x0464));
+	return v;
+}
+
+static inline void write_ireg(u_long base, u_int reg, u_int val)
+{
+	__asm__("str%?h	%1, [%2]	@ NET_RAP
+		str%?h	%0, [%2, #8]	@ NET_IDP
+		" : : "r" (val), "r" (reg), "r" (ISAIO_BASE + 0x0464));
+}
+
+#define am_writeword(dev,off,val) __raw_writew(val, ISAMEM_BASE + ((off) << 1))
+#define am_readword(dev,off)      __raw_readw(ISAMEM_BASE + ((off) << 1))
+
+static inline void
+am_writebuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
+{
+	offset = ISAMEM_BASE + (offset << 1);
+	length = (length + 1) & ~1;
+	if ((int)buf & 2) {
+		__asm__ __volatile__("str%?h	%2, [%0], #4"
+		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+		buf += 2;
+		length -= 2;
+	}
+	while (length > 8) {
+		unsigned int tmp, tmp2;
+		__asm__ __volatile__("
+			ldm%?ia	%1!, {%2, %3}
+			str%?h	%2, [%0], #4
+			mov%?	%2, %2, lsr #16
+			str%?h	%2, [%0], #4
+			str%?h	%3, [%0], #4
+			mov%?	%3, %3, lsr #16
+			str%?h	%3, [%0], #4
+		" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2)
+		  : "0" (offset), "1" (buf));
+		length -= 8;
+	}
+	while (length > 0) {
+		__asm__ __volatile__("str%?h	%2, [%0], #4"
+		 : "=&r" (offset) : "0" (offset), "r" (buf[0] | (buf[1] << 8)));
+		buf += 2;
+		length -= 2;
+	}
+}
+
+static inline void
+am_readbuffer(struct net_device *dev, u_int offset, unsigned char *buf, unsigned int length)
+{
+	offset = ISAMEM_BASE + (offset << 1);
+	length = (length + 1) & ~1;
+	if ((int)buf & 2) {
+		unsigned int tmp;
+		__asm__ __volatile__("
+			ldr%?h	%2, [%0], #4
+			str%?b	%2, [%1], #1
+			mov%?	%2, %2, lsr #8
+			str%?b	%2, [%1], #1
+		" : "=&r" (offset), "=&r" (buf), "=r" (tmp): "0" (offset), "1" (buf));
+		length -= 2;
+	}
+	while (length > 8) {
+		unsigned int tmp, tmp2, tmp3;
+		__asm__ __volatile__("
+			ldr%?h	%2, [%0], #4
+			ldr%?h	%3, [%0], #4
+			orr%?	%2, %2, %3, lsl #16
+			ldr%?h	%3, [%0], #4
+			ldr%?h	%4, [%0], #4
+			orr%?	%3, %3, %4, lsl #16
+			stm%?ia	%1!, {%2, %3}
+		" : "=&r" (offset), "=&r" (buf), "=r" (tmp), "=r" (tmp2), "=r" (tmp3)
+		  : "0" (offset), "1" (buf));
+		length -= 8;
+	}
+	while (length > 0) {
+		unsigned int tmp;
+		__asm__ __volatile__("
+			ldr%?h	%2, [%0], #4
+			str%?b	%2, [%1], #1
+			mov%?	%2, %2, lsr #8
+			str%?b	%2, [%1], #1
+		" : "=&r" (offset), "=&r" (buf), "=r" (tmp) : "0" (offset), "1" (buf));
+		length -= 2;
+	}
+}
+#else
+#error Not compatible
+#endif
+
+static int
+am79c961_ramtest(struct net_device *dev, unsigned int val)
+{
+	unsigned char *buffer = kmalloc (65536, GFP_KERNEL);
+	int i, error = 0, errorcount = 0;
+
+	if (!buffer)
+		return 0;
+	memset (buffer, val, 65536);
+	am_writebuffer(dev, 0, buffer, 65536);
+	memset (buffer, val ^ 255, 65536);
+	am_readbuffer(dev, 0, buffer, 65536);
+	for (i = 0; i < 65536; i++) {
+		if (buffer[i] != val && !error) {
+			printk ("%s: buffer error (%02X %02X) %05X - ", dev->name, val, buffer[i], i);
+			error = 1;
+			errorcount ++;
+		} else if (error && buffer[i] == val) {
+			printk ("%05X\n", i);
+			error = 0;
+		}
+	}
+	if (error)
+		printk ("10000\n");
+	kfree (buffer);
+	return errorcount;
+}
+
+static void
+am79c961_init_for_open(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	unsigned long flags;
+	unsigned char *p;
+	u_int hdr_addr, first_free_addr;
+	int i;
+
+	/*
+	 * Stop the chip.
+	 */
+	spin_lock_irqsave(priv->chip_lock, flags);
+	write_rreg (dev->base_addr, CSR0, CSR0_BABL|CSR0_CERR|CSR0_MISS|CSR0_MERR|CSR0_TINT|CSR0_RINT|CSR0_STOP);
+	spin_unlock_irqrestore(priv->chip_lock, flags);
+
+	write_ireg (dev->base_addr, 5, 0x00a0); /* Receive address LED */
+	write_ireg (dev->base_addr, 6, 0x0081); /* Collision LED */
+	write_ireg (dev->base_addr, 7, 0x0090); /* XMIT LED */
+	write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */
+
+	for (i = LADRL; i <= LADRH; i++)
+		write_rreg (dev->base_addr, i, 0);
+
+	for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2)
+		write_rreg (dev->base_addr, i, p[0] | (p[1] << 8));
+
+	i = MODE_PORT_10BT;
+	if (dev->flags & IFF_PROMISC)
+		i |= MODE_PROMISC;
+
+	write_rreg (dev->base_addr, MODE, i);
+	write_rreg (dev->base_addr, POLLINT, 0);
+	write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS);
+	write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS);
+
+	first_free_addr = RX_BUFFERS * 8 + TX_BUFFERS * 8 + 16;
+	hdr_addr = 0;
+
+	priv->rxhead = 0;
+	priv->rxtail = 0;
+	priv->rxhdr = hdr_addr;
+
+	for (i = 0; i < RX_BUFFERS; i++) {
+		priv->rxbuffer[i] = first_free_addr;
+		am_writeword (dev, hdr_addr, first_free_addr);
+		am_writeword (dev, hdr_addr + 2, RMD_OWN);
+		am_writeword (dev, hdr_addr + 4, (-1600));
+		am_writeword (dev, hdr_addr + 6, 0);
+		first_free_addr += 1600;
+		hdr_addr += 8;
+	}
+	priv->txhead = 0;
+	priv->txtail = 0;
+	priv->txhdr = hdr_addr;
+	for (i = 0; i < TX_BUFFERS; i++) {
+		priv->txbuffer[i] = first_free_addr;
+		am_writeword (dev, hdr_addr, first_free_addr);
+		am_writeword (dev, hdr_addr + 2, TMD_STP|TMD_ENP);
+		am_writeword (dev, hdr_addr + 4, 0xf000);
+		am_writeword (dev, hdr_addr + 6, 0);
+		first_free_addr += 1600;
+		hdr_addr += 8;
+	}
+
+	write_rreg (dev->base_addr, BASERXL, priv->rxhdr);
+	write_rreg (dev->base_addr, BASERXH, 0);
+	write_rreg (dev->base_addr, BASETXL, priv->txhdr);
+	write_rreg (dev->base_addr, BASERXH, 0);
+	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+	write_rreg (dev->base_addr, CSR3, CSR3_IDONM|CSR3_BABLM|CSR3_DXSUFLO);
+	write_rreg (dev->base_addr, CSR0, CSR0_IENA|CSR0_STRT);
+}
+
+/*
+ * Open/initialize the board.
+ */
+static int
+am79c961_open(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	int ret;
+
+	memset (&priv->stats, 0, sizeof (priv->stats));
+
+	ret = request_irq(dev->irq, am79c961_interrupt, 0, dev->name, dev);
+	if (ret)
+		return ret;
+
+	am79c961_init_for_open(dev);
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+/*
+ * The inverse routine to am79c961_open().
+ */
+static int
+am79c961_close(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	unsigned long flags;
+
+	netif_stop_queue(dev);
+
+	spin_lock_irqsave(priv->chip_lock, flags);
+	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+	write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
+	spin_unlock_irqrestore(priv->chip_lock, flags);
+
+	free_irq (dev->irq, dev);
+
+	return 0;
+}
+
+/*
+ * Get the current statistics.
+ */
+static struct net_device_stats *am79c961_getstats (struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	return &priv->stats;
+}
+
+static void am79c961_mc_hash(struct dev_mc_list *dmi, unsigned short *hash)
+{
+	if (dmi->dmi_addrlen == ETH_ALEN && dmi->dmi_addr[0] & 0x01) {
+		int idx, bit;
+		u32 crc;
+
+		crc = ether_crc_le(ETH_ALEN, dmi->dmi_addr);
+
+		idx = crc >> 30;
+		bit = (crc >> 26) & 15;
+
+		hash[idx] |= 1 << bit;
+	}
+}
+
+/*
+ * Set or clear promiscuous/multicast mode filter for this adapter.
+ */
+static void am79c961_setmulticastlist (struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	unsigned long flags;
+	unsigned short multi_hash[4], mode;
+	int i, stopped;
+
+	mode = MODE_PORT_10BT;
+
+	if (dev->flags & IFF_PROMISC) {
+		mode |= MODE_PROMISC;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		memset(multi_hash, 0xff, sizeof(multi_hash));
+	} else {
+		struct dev_mc_list *dmi;
+
+		memset(multi_hash, 0x00, sizeof(multi_hash));
+
+		for (dmi = dev->mc_list; dmi; dmi = dmi->next)
+			am79c961_mc_hash(dmi, multi_hash);
+	}
+
+	spin_lock_irqsave(priv->chip_lock, flags);
+
+	stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP;
+
+	if (!stopped) {
+		/*
+		 * Put the chip into suspend mode
+		 */
+		write_rreg(dev->base_addr, CTRL1, CTRL1_SPND);
+
+		/*
+		 * Spin waiting for chip to report suspend mode
+		 */
+		while ((read_rreg(dev->base_addr, CTRL1) & CTRL1_SPND) == 0) {
+			spin_unlock_irqrestore(priv->chip_lock, flags);
+			nop();
+			spin_lock_irqsave(priv->chip_lock, flags);
+		}
+	}
+
+	/*
+	 * Update the multicast hash table
+	 */
+	for (i = 0; i < sizeof(multi_hash) / sizeof(multi_hash[0]); i++)
+		write_rreg(dev->base_addr, i + LADRL, multi_hash[i]);
+
+	/*
+	 * Write the mode register
+	 */
+	write_rreg(dev->base_addr, MODE, mode);
+
+	if (!stopped) {
+		/*
+		 * Put the chip back into running mode
+		 */
+		write_rreg(dev->base_addr, CTRL1, 0);
+	}
+
+	spin_unlock_irqrestore(priv->chip_lock, flags);
+}
+
+static void am79c961_timeout(struct net_device *dev)
+{
+	printk(KERN_WARNING "%s: transmit timed out, network cable problem?\n",
+		dev->name);
+
+	/*
+	 * ought to do some setup of the tx side here
+	 */
+
+	netif_wake_queue(dev);
+}
+
+/*
+ * Transmit a packet
+ */
+static int
+am79c961_sendpacket(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	unsigned int length = skb->len;
+	unsigned int hdraddr, bufaddr;
+	unsigned int head;
+	unsigned long flags;
+	
+	/* FIXME: I thought the 79c961 could do padding - RMK ??? */
+	if (length < ETH_ZLEN) {
+		skb = skb_padto(skb, ETH_ZLEN);
+		if (skb == NULL)
+			return 0;
+		length = ETH_ZLEN;
+	}
+
+	head = priv->txhead;
+	hdraddr = priv->txhdr + (head << 3);
+	bufaddr = priv->txbuffer[head];
+	head += 1;
+	if (head >= TX_BUFFERS)
+		head = 0;
+
+	am_writebuffer (dev, bufaddr, skb->data, length);
+	am_writeword (dev, hdraddr + 4, -length);
+	am_writeword (dev, hdraddr + 2, TMD_OWN|TMD_STP|TMD_ENP);
+	priv->txhead = head;
+
+	spin_lock_irqsave(priv->chip_lock, flags);
+	write_rreg (dev->base_addr, CSR0, CSR0_TDMD|CSR0_IENA);
+	dev->trans_start = jiffies;
+	spin_unlock_irqrestore(priv->chip_lock, flags);
+
+	/*
+	 * If the next packet is owned by the ethernet device,
+	 * then the tx ring is full and we can't add another
+	 * packet.
+	 */
+	if (am_readword(dev, priv->txhdr + (priv->txhead << 3) + 2) & TMD_OWN)
+		netif_stop_queue(dev);
+
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
+/*
+ * If we have a good packet(s), get it/them out of the buffers.
+ */
+static void
+am79c961_rx(struct net_device *dev, struct dev_priv *priv)
+{
+	do {
+		struct sk_buff *skb;
+		u_int hdraddr;
+		u_int pktaddr;
+		u_int status;
+		int len;
+
+		hdraddr = priv->rxhdr + (priv->rxtail << 3);
+		pktaddr = priv->rxbuffer[priv->rxtail];
+
+		status = am_readword (dev, hdraddr + 2);
+		if (status & RMD_OWN) /* do we own it? */
+			break;
+
+		priv->rxtail ++;
+		if (priv->rxtail >= RX_BUFFERS)
+			priv->rxtail = 0;
+
+		if ((status & (RMD_ERR|RMD_STP|RMD_ENP)) != (RMD_STP|RMD_ENP)) {
+			am_writeword (dev, hdraddr + 2, RMD_OWN);
+			priv->stats.rx_errors ++;
+			if (status & RMD_ERR) {
+				if (status & RMD_FRAM)
+					priv->stats.rx_frame_errors ++;
+				if (status & RMD_CRC)
+					priv->stats.rx_crc_errors ++;
+			} else if (status & RMD_STP)
+				priv->stats.rx_length_errors ++;
+			continue;
+		}
+
+		len = am_readword(dev, hdraddr + 6);
+		skb = dev_alloc_skb(len + 2);
+
+		if (skb) {
+			skb->dev = dev;
+			skb_reserve(skb, 2);
+
+			am_readbuffer(dev, pktaddr, skb_put(skb, len), len);
+			am_writeword(dev, hdraddr + 2, RMD_OWN);
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			priv->stats.rx_bytes += len;
+			priv->stats.rx_packets ++;
+		} else {
+			am_writeword (dev, hdraddr + 2, RMD_OWN);
+			printk (KERN_WARNING "%s: memory squeeze, dropping packet.\n", dev->name);
+			priv->stats.rx_dropped ++;
+			break;
+		}
+	} while (1);
+}
+
+/*
+ * Update stats for the transmitted packet
+ */
+static void
+am79c961_tx(struct net_device *dev, struct dev_priv *priv)
+{
+	do {
+		u_int hdraddr;
+		u_int status;
+
+		hdraddr = priv->txhdr + (priv->txtail << 3);
+		status = am_readword (dev, hdraddr + 2);
+		if (status & TMD_OWN)
+			break;
+
+		priv->txtail ++;
+		if (priv->txtail >= TX_BUFFERS)
+			priv->txtail = 0;
+
+		if (status & TMD_ERR) {
+			u_int status2;
+
+			priv->stats.tx_errors ++;
+
+			status2 = am_readword (dev, hdraddr + 6);
+
+			/*
+			 * Clear the error byte
+			 */
+			am_writeword (dev, hdraddr + 6, 0);
+
+			if (status2 & TST_RTRY)
+				priv->stats.collisions += 16;
+			if (status2 & TST_LCOL)
+				priv->stats.tx_window_errors ++;
+			if (status2 & TST_LCAR)
+				priv->stats.tx_carrier_errors ++;
+			if (status2 & TST_UFLO)
+				priv->stats.tx_fifo_errors ++;
+			continue;
+		}
+		priv->stats.tx_packets ++;
+	} while (priv->txtail != priv->txhead);
+
+	netif_wake_queue(dev);
+}
+
+static irqreturn_t
+am79c961_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	u_int status;
+	int handled = 0;
+
+	status = read_rreg(dev->base_addr, CSR0);
+	write_rreg(dev->base_addr, CSR0, status & (CSR0_TINT|CSR0_RINT|CSR0_MISS|CSR0_IENA));
+
+	if (status & CSR0_RINT) {
+		handled = 1;
+		am79c961_rx(dev, priv);
+	}
+	if (status & CSR0_TINT) {
+		handled = 1;
+		am79c961_tx(dev, priv);
+	}
+	if (status & CSR0_MISS) {
+		handled = 1;
+		priv->stats.rx_dropped ++;
+	}
+	return IRQ_RETVAL(handled);
+}
+
+/*
+ * Initialise the chip.  Note that we always expect
+ * to be entered with interrupts enabled.
+ */
+static int
+am79c961_hw_init(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+
+	spin_lock_irq(priv->chip_lock);
+	write_rreg (dev->base_addr, CSR0, CSR0_STOP);
+	write_rreg (dev->base_addr, CSR3, CSR3_MASKALL);
+	spin_unlock_irq(priv->chip_lock);
+
+	am79c961_ramtest(dev, 0x66);
+	am79c961_ramtest(dev, 0x99);
+
+	return 0;
+}
+
+static void __init am79c961_banner(void)
+{
+	static unsigned version_printed;
+
+	if (net_debug && version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+}
+
+static int __init am79c961_init(void)
+{
+	struct net_device *dev;
+	struct dev_priv *priv;
+	int i, ret;
+
+	dev = init_etherdev(NULL, sizeof(struct dev_priv));
+	ret = -ENOMEM;
+	if (!dev)
+		goto out;
+
+	priv = dev->priv;
+
+	/*
+	 * Fixed address and IRQ lines here.
+	 * The PNP initialisation should have been
+	 * done by the ether bootp loader.
+	 */
+	dev->base_addr = 0x220;
+	dev->irq = IRQ_EBSA110_ETHERNET;
+
+	/*
+	 * Reset the device.
+	 */
+	inb(dev->base_addr + NET_RESET);
+	udelay(5);
+
+	/*
+	 * Check the manufacturer part of the
+	 * ether address.
+	 */
+    	ret = -ENODEV;
+	if (inb(dev->base_addr) != 0x08 ||
+	    inb(dev->base_addr + 2) != 0x00 ||
+	    inb(dev->base_addr + 4) != 0x2b)
+	    	goto nodev;
+
+	if (!request_region(dev->base_addr, 0x18, dev->name))
+		goto nodev;
+
+	am79c961_banner();
+	printk(KERN_INFO "%s: ether address ", dev->name);
+
+	/* Retrive and print the ethernet address. */
+	for (i = 0; i < 6; i++) {
+		dev->dev_addr[i] = inb(dev->base_addr + i * 2) & 0xff;
+		printk (i == 5 ? "%02x\n" : "%02x:", dev->dev_addr[i]);
+	}
+
+	if (am79c961_hw_init(dev))
+		goto release;
+
+	dev->open		= am79c961_open;
+	dev->stop		= am79c961_close;
+	dev->hard_start_xmit	= am79c961_sendpacket;
+	dev->get_stats		= am79c961_getstats;
+	dev->set_multicast_list	= am79c961_setmulticastlist;
+	dev->tx_timeout		= am79c961_timeout;
+
+	return 0;
+
+release:
+	release_region(dev->base_addr, 0x18);
+nodev:
+	unregister_netdev(dev);
+	kfree(dev);
+out:
+	return ret;
+}
+
+__initcall(am79c961_init);
diff -Nru a/drivers/net/arm/am79c961a.h b/drivers/net/arm/am79c961a.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/am79c961a.h	Fri May 16 03:07:00 2003
@@ -0,0 +1,130 @@
+/*
+ * linux/drivers/net/am79c961.h
+ *
+ * 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.
+ */
+
+#ifndef _LINUX_am79c961a_H
+#define _LINUX_am79c961a_H
+
+/* use 0 for production, 1 for verification, >2 for debug. debug flags: */
+#define DEBUG_TX	 2
+#define DEBUG_RX	 4
+#define DEBUG_INT	 8
+#define DEBUG_IC	16
+#ifndef NET_DEBUG
+#define NET_DEBUG 	0
+#endif
+
+#define NET_UID		0
+#define NET_RDP		0x10
+#define NET_RAP		0x12
+#define NET_RESET	0x14
+#define NET_IDP		0x16
+
+/*
+ * RAP registers
+ */
+#define CSR0		0
+#define CSR0_INIT	0x0001
+#define CSR0_STRT	0x0002
+#define CSR0_STOP	0x0004
+#define CSR0_TDMD	0x0008
+#define CSR0_TXON	0x0010
+#define CSR0_RXON	0x0020
+#define CSR0_IENA	0x0040
+#define CSR0_INTR	0x0080
+#define CSR0_IDON	0x0100
+#define CSR0_TINT	0x0200
+#define CSR0_RINT	0x0400
+#define CSR0_MERR	0x0800
+#define CSR0_MISS	0x1000
+#define CSR0_CERR	0x2000
+#define CSR0_BABL	0x4000
+#define CSR0_ERR	0x8000
+
+#define CSR3		3
+#define CSR3_EMBA	0x0008
+#define CSR3_DXMT2PD	0x0010
+#define CSR3_LAPPEN	0x0020
+#define CSR3_DXSUFLO	0x0040
+#define CSR3_IDONM	0x0100
+#define CSR3_TINTM	0x0200
+#define CSR3_RINTM	0x0400
+#define CSR3_MERRM	0x0800
+#define CSR3_MISSM	0x1000
+#define CSR3_BABLM	0x4000
+#define CSR3_MASKALL	0x5F00
+
+#define CTRL1		5
+#define CTRL1_SPND	0x0001
+
+#define LADRL		8
+#define LADRM1		9
+#define LADRM2		10
+#define LADRH		11
+#define PADRL		12
+#define PADRM		13
+#define PADRH		14
+
+#define MODE		15
+#define MODE_DISRX	0x0001
+#define MODE_DISTX	0x0002
+#define MODE_LOOP	0x0004
+#define MODE_DTCRC	0x0008
+#define MODE_COLL	0x0010
+#define MODE_DRETRY	0x0020
+#define MODE_INTLOOP	0x0040
+#define MODE_PORT_AUI	0x0000
+#define MODE_PORT_10BT	0x0080
+#define MODE_DRXPA	0x2000
+#define MODE_DRXBA	0x4000
+#define MODE_PROMISC	0x8000
+
+#define BASERXL		24
+#define BASERXH		25
+#define BASETXL		30
+#define BASETXH		31
+
+#define POLLINT		47
+
+#define SIZERXR		76
+#define SIZETXR		78
+
+#define RMD_ENP		0x0100
+#define RMD_STP		0x0200
+#define RMD_CRC		0x0800
+#define RMD_FRAM	0x2000
+#define RMD_ERR		0x4000
+#define RMD_OWN		0x8000
+
+#define TMD_ENP		0x0100
+#define TMD_STP		0x0200
+#define TMD_MORE	0x1000
+#define TMD_ERR		0x4000
+#define TMD_OWN		0x8000
+
+#define TST_RTRY	0x0400
+#define TST_LCAR	0x0800
+#define TST_LCOL	0x1000
+#define TST_UFLO	0x4000
+#define TST_BUFF	0x8000
+
+struct dev_priv {
+    struct net_device_stats stats;
+    unsigned long	rxbuffer[RX_BUFFERS];
+    unsigned long	txbuffer[TX_BUFFERS];
+    unsigned char	txhead;
+    unsigned char	txtail;
+    unsigned char	rxhead;
+    unsigned char	rxtail;
+    unsigned long	rxhdr;
+    unsigned long	txhdr;
+    spinlock_t		chip_lock;
+};
+
+extern int	am79c961_probe (struct net_device *dev);
+
+#endif
diff -Nru a/drivers/net/arm/ether00.c b/drivers/net/arm/ether00.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/ether00.c	Sat May 17 06:52:34 2003
@@ -0,0 +1,1025 @@
+/*
+ *  drivers/net/ether00.c
+ *
+ *  Copyright (C) 2001 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* includes */
+
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/sched.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/module.h>
+#include <linux/tqueue.h>
+#include <linux/mtd/mtd.h>
+#include <linux/pld/pld_hotswap.h>
+#include <asm/arch/excalibur.h>
+#include <asm/arch/hardware.h>
+#include <asm/irq.h>
+#include <asm/io.h>
+#include <asm/sizes.h>
+
+#include <asm/arch/ether00.h>
+#include <asm/arch/tdkphy.h>
+
+
+MODULE_AUTHOR("Clive Davies");
+MODULE_DESCRIPTION("Altera Ether00 IP core driver");
+MODULE_LICENSE("GPL");
+
+#define PKT_BUF_SZ 1540 /* Size of each rx buffer */
+#define ETH_NR 4 /* Number of MACs this driver supports */
+
+#define DEBUG(x)
+
+#define __dma_va(x) (unsigned int)((unsigned int)priv->dma_data+(((unsigned int)(x))&(EXC_SPSRAM_BLOCK0_SIZE-1)))
+#define __dma_pa(x) (unsigned int)(EXC_SPSRAM_BLOCK0_BASE+(((unsigned int)(x))-(unsigned int)priv->dma_data))
+
+#define ETHER00_BASE	0
+#define	ETHER00_TYPE
+#define ETHER00_NAME "ether00"
+#define MAC_REG_SIZE 0x400 /* size of MAC register area */
+
+
+
+/* typedefs */
+
+/* The definition of the driver control structure */
+
+#define RX_NUM_BUFF     10
+#define RX_NUM_FDESC    10
+#define TX_NUM_FDESC    10
+
+struct tx_fda_ent{
+	FDA_DESC  fd;
+	BUF_DESC  bd;
+	BUF_DESC  pad;
+};
+struct rx_fda_ent{
+	FDA_DESC  fd;
+	BUF_DESC  bd;
+	BUF_DESC  pad;
+};
+struct rx_blist_ent{
+	FDA_DESC  fd;
+	BUF_DESC  bd;
+	BUF_DESC  pad;
+};
+struct net_priv
+{
+	struct net_device_stats stats;
+	struct sk_buff* skb;
+	void* dma_data;
+	struct rx_blist_ent*  rx_blist_vp;
+	struct rx_fda_ent* rx_fda_ptr;
+	struct tx_fda_ent* tx_fdalist_vp;
+	struct tq_struct  tq_memupdate;
+	unsigned char   memupdate_scheduled;
+	unsigned char   rx_disabled;
+	unsigned char   queue_stopped;
+	spinlock_t rx_lock;
+};
+
+static const char vendor_id[2]={0x07,0xed};
+
+#ifdef ETHER00_DEBUG
+
+/* Dump (most) registers for debugging puposes */
+
+static void dump_regs(struct net_device *dev){
+	struct net_priv* priv=dev->priv;
+	unsigned int* i;
+
+	printk("\n RX free descriptor area:\n");
+
+	for(i=(unsigned int*)priv->rx_fda_ptr;
+	    i<((unsigned int*)(priv->rx_fda_ptr+RX_NUM_FDESC));){
+		printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3));
+		i+=4;
+	}
+
+	printk("\n RX buffer list:\n");
+
+	for(i=(unsigned int*)priv->rx_blist_vp;
+	    i<((unsigned int*)(priv->rx_blist_vp+RX_NUM_BUFF));){
+		printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3));
+		i+=4;
+	}
+
+	printk("\n TX frame descriptor list:\n");
+
+	for(i=(unsigned int*)priv->tx_fdalist_vp;
+	    i<((unsigned int*)(priv->tx_fdalist_vp+TX_NUM_FDESC));){
+		printk("%#8x %#8x %#8x %#8x\n",*i,*(i+1),*(i+2),*(i+3));
+		i+=4;
+	}
+
+	printk("\ndma ctl=%#x\n",readw(ETHER_DMA_CTL(dev->base_addr)));
+	printk("txfrmptr=%#x\n",readw(ETHER_TXFRMPTR(dev->base_addr)));
+	printk("txthrsh=%#x\n",readw(ETHER_TXTHRSH(dev->base_addr)));
+	printk("txpollctr=%#x\n",readw(ETHER_TXPOLLCTR(dev->base_addr)));
+	printk("blfrmptr=%#x\n",readw(ETHER_BLFRMPTR(dev->base_addr)));
+	printk("rxfragsize=%#x\n",readw(ETHER_RXFRAGSIZE(dev->base_addr)));
+	printk("tx_int_en=%#x\n",readw(ETHER_INT_EN(dev->base_addr)));
+	printk("fda_bas=%#x\n",readw(ETHER_FDA_BAS(dev->base_addr)));
+	printk("fda_lim=%#x\n",readw(ETHER_FDA_LIM(dev->base_addr)));
+	printk("int_src=%#x\n",readw(ETHER_INT_SRC(dev->base_addr)));
+	printk("pausecnt=%#x\n",readw(ETHER_PAUSECNT(dev->base_addr)));
+	printk("rempaucnt=%#x\n",readw(ETHER_REMPAUCNT(dev->base_addr)));
+	printk("txconfrmstat=%#x\n",readw(ETHER_TXCONFRMSTAT(dev->base_addr)));
+	printk("mac_ctl=%#x\n",readw(ETHER_MAC_CTL(dev->base_addr)));
+	printk("arc_ctl=%#x\n",readw(ETHER_ARC_CTL(dev->base_addr)));
+	printk("tx_ctl=%#x\n",readw(ETHER_TX_CTL(dev->base_addr)));
+}
+#endif /* ETHER00_DEBUG */
+
+
+static int ether00_write_phy(struct net_device *dev, short address, short value)
+{
+	volatile int count = 1024;
+	writew(value,ETHER_MD_DATA(dev->base_addr));
+	writew( ETHER_MD_CA_BUSY_MSK |
+		ETHER_MD_CA_WR_MSK |
+		(address & ETHER_MD_CA_ADDR_MSK),
+		ETHER_MD_CA(dev->base_addr));
+
+	/* Wait for the command to complete */
+	while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){
+		count--;
+	}
+	if (!count){
+		printk("Write to phy failed, addr=%#x, data=%#x\n",address, value);
+		return -EIO;
+	}
+	return 0;
+}
+
+static int ether00_read_phy(struct net_device *dev, short address)
+{
+	volatile int count = 1024;
+	writew( ETHER_MD_CA_BUSY_MSK |
+		(address & ETHER_MD_CA_ADDR_MSK),
+		ETHER_MD_CA(dev->base_addr));
+
+	/* Wait for the command to complete */
+	while((readw(ETHER_MD_CA(dev->base_addr)) & ETHER_MD_CA_BUSY_MSK)&&count){
+		count--;
+	}
+	if (!count){
+		printk(KERN_WARNING "Read from phy timed out\n");
+		return -EIO;
+	}
+	return readw(ETHER_MD_DATA(dev->base_addr));
+}
+
+static void ether00_phy_int(int irq_num, void* dev_id, struct pt_regs* regs)
+{
+	struct net_device* dev=dev_id;
+	int irq_status;
+
+	irq_status=ether00_read_phy(dev, PHY_IRQ_CONTROL);
+
+	if(irq_status & PHY_IRQ_CONTROL_ANEG_COMP_INT_MSK){
+		/*
+		 * Autonegotiation complete on epxa10db. The mac doesn't
+		 * twig if we're in full duplex so we need to check the
+		 * phy status register and configure the mac accordingly
+		 */
+		if(ether00_read_phy(dev, PHY_STATUS)&(PHY_STATUS_10T_F_MSK|PHY_STATUS_100_X_F_MSK)){
+			int tmp;
+			tmp=readl(ETHER_MAC_CTL(dev->base_addr));
+			writel(tmp|ETHER_MAC_CTL_FULLDUP_MSK,ETHER_MAC_CTL(dev->base_addr));
+		}
+	}
+
+	if(irq_status&PHY_IRQ_CONTROL_LS_CHG_INT_MSK){
+
+		if(ether00_read_phy(dev, PHY_STATUS)& PHY_STATUS_LINK_MSK){
+			/* Link is up */
+			netif_carrier_on(dev);
+			//printk("Carrier on\n");
+		}else{
+			netif_carrier_off(dev);
+			//printk("Carrier off\n");
+
+		}
+	}
+
+}
+
+static void setup_blist_entry(struct sk_buff* skb,struct rx_blist_ent* blist_ent_ptr){
+	/* Make the buffer consistent with the cache as the mac is going to write
+	 * directly into it*/
+	blist_ent_ptr->fd.FDSystem=(unsigned int)skb;
+	blist_ent_ptr->bd.BuffData=(char*)__pa(skb->data);
+	consistent_sync(skb->data,PKT_BUF_SZ,PCI_DMA_FROMDEVICE);
+        /* align IP on 16 Byte (DMA_CTL set to skip 2 bytes) */
+	skb_reserve(skb,2);
+	blist_ent_ptr->bd.BuffLength=PKT_BUF_SZ-2;
+	blist_ent_ptr->fd.FDLength=1;
+	blist_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK;
+	blist_ent_ptr->bd.BDCtl=BDCTL_COWNSBD_MSK;
+}
+
+
+static int ether00_mem_init(struct net_device* dev)
+{
+	struct net_priv* priv=dev->priv;
+	struct tx_fda_ent *tx_fd_ptr,*tx_end_ptr;
+	struct rx_blist_ent* blist_ent_ptr;
+	int i;
+
+	/*
+	 * Grab a block of on chip SRAM to contain the control stuctures for
+	 * the ethernet MAC. This uncached becuase it needs to be accesses by both
+	 * bus masters (cpu + mac). However, it shouldn't matter too much in terms
+	 * of speed as its on chip memory
+	 */
+	priv->dma_data=ioremap_nocache(EXC_SPSRAM_BLOCK0_BASE,EXC_SPSRAM_BLOCK0_SIZE );
+	if (!priv->dma_data)
+		return -ENOMEM;
+
+	priv->rx_fda_ptr=(struct rx_fda_ent*)priv->dma_data;
+	/*
+	 * Now share it out amongst the Frame descriptors and the buffer list
+	 */
+	priv->rx_blist_vp=(struct rx_blist_ent*)((unsigned int)priv->dma_data+RX_NUM_FDESC*sizeof(struct rx_fda_ent));
+
+	/*
+	 *Initalise the FDA list
+	 */
+	/* set ownership to the controller */
+	memset(priv->rx_fda_ptr,0x80,RX_NUM_FDESC*sizeof(struct rx_fda_ent));
+
+	/*
+	 *Initialise the buffer list
+	 */
+	blist_ent_ptr=priv->rx_blist_vp;
+	i=0;
+	while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){
+		struct sk_buff *skb;
+		blist_ent_ptr->fd.FDLength=1;
+		skb=dev_alloc_skb(PKT_BUF_SZ);
+		if(skb){
+			setup_blist_entry(skb,blist_ent_ptr);
+			blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(blist_ent_ptr+1);
+			blist_ent_ptr->bd.BDStat=i++;
+			blist_ent_ptr++;
+		}
+		else
+		{
+			printk("Failed to initalise buffer list\n");
+		}
+
+	}
+	blist_ent_ptr--;
+	blist_ent_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->rx_blist_vp);
+
+	priv->tx_fdalist_vp=(struct tx_fda_ent*)(priv->rx_blist_vp+RX_NUM_BUFF);
+
+	/* Initialise the buffers to be a circular list. The mac will then go poll
+	 * the list until it finds a frame ready to transmit */
+	tx_end_ptr=priv->tx_fdalist_vp+TX_NUM_FDESC;
+	for(tx_fd_ptr=priv->tx_fdalist_vp;tx_fd_ptr<tx_end_ptr;tx_fd_ptr++){
+		tx_fd_ptr->fd.FDNext=(FDA_DESC*)__dma_pa((tx_fd_ptr+1));
+		tx_fd_ptr->fd.FDCtl=1;
+		tx_fd_ptr->fd.FDStat=0;
+		tx_fd_ptr->fd.FDLength=1;
+
+	}
+	/* Change the last FDNext pointer to make a circular list */
+	tx_fd_ptr--;
+	tx_fd_ptr->fd.FDNext=(FDA_DESC*)__dma_pa(priv->tx_fdalist_vp);
+
+	/* Point the device at the chain of Rx and Tx Buffers */
+	writel((unsigned int)__dma_pa(priv->rx_fda_ptr),ETHER_FDA_BAS(dev->base_addr));
+	writel((RX_NUM_FDESC-1)*sizeof(struct rx_fda_ent),ETHER_FDA_LIM(dev->base_addr));
+	writel((unsigned int)__dma_pa(priv->rx_blist_vp),ETHER_BLFRMPTR(dev->base_addr));
+
+	writel((unsigned int)__dma_pa(priv->tx_fdalist_vp),ETHER_TXFRMPTR(dev->base_addr));
+
+	return 0;
+}
+
+
+void ether00_mem_update(void* dev_id)
+{
+	struct net_device* dev=dev_id;
+	struct net_priv* priv=dev->priv;
+	struct sk_buff* skb;
+	struct tx_fda_ent *fda_ptr=priv->tx_fdalist_vp;
+	struct rx_blist_ent* blist_ent_ptr;
+	unsigned long flags;
+
+	priv->tq_memupdate.sync=0;
+	//priv->tq_memupdate.list=
+	priv->memupdate_scheduled=0;
+
+	/* Transmit interrupt */
+	while(fda_ptr<(priv->tx_fdalist_vp+TX_NUM_FDESC)){
+		if(!(FDCTL_COWNSFD_MSK&fda_ptr->fd.FDCtl) && (ETHER_TX_STAT_COMP_MSK&fda_ptr->fd.FDStat)){
+			priv->stats.tx_packets++;
+			priv->stats.tx_bytes+=fda_ptr->bd.BuffLength;
+			skb=(struct sk_buff*)fda_ptr->fd.FDSystem;
+			//printk("%d:txcln:fda=%#x skb=%#x\n",jiffies,fda_ptr,skb);
+			dev_kfree_skb(skb);
+			fda_ptr->fd.FDSystem=0;
+			fda_ptr->fd.FDStat=0;
+			fda_ptr->fd.FDCtl=0;
+		}
+		fda_ptr++;
+	}
+	/* Fill in any missing buffers from the received queue */
+	spin_lock_irqsave(&priv->rx_lock,flags);
+	blist_ent_ptr=priv->rx_blist_vp;
+	while(blist_ent_ptr<(priv->rx_blist_vp+RX_NUM_BUFF)){
+		/* fd.FDSystem of 0 indicates we failed to allocate the buffer in the ISR */
+		if(!blist_ent_ptr->fd.FDSystem){
+			struct sk_buff *skb;
+			skb=dev_alloc_skb(PKT_BUF_SZ);
+			blist_ent_ptr->fd.FDSystem=(unsigned int)skb;
+			if(skb){
+				setup_blist_entry(skb,blist_ent_ptr);
+			}
+			else
+			{
+				break;
+			}
+		}
+		blist_ent_ptr++;
+	}
+	spin_unlock_irqrestore(&priv->rx_lock,flags);
+	if(priv->queue_stopped){
+		//printk("%d:cln:start q\n",jiffies);
+		netif_start_queue(dev);
+	}
+	if(priv->rx_disabled){
+		//printk("%d:enable_irq\n",jiffies);
+		priv->rx_disabled=0;
+		writel(ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr));
+
+	}
+}
+
+
+static void ether00_int( int irq_num, void* dev_id, struct pt_regs* regs)
+{
+	struct net_device* dev=dev_id;
+	struct net_priv* priv=dev->priv;
+
+	unsigned int   interruptValue;
+
+	interruptValue=readl(ETHER_INT_SRC(dev->base_addr));
+
+	//printk("INT_SRC=%x\n",interruptValue);
+
+	if(!(readl(ETHER_INT_SRC(dev->base_addr)) & ETHER_INT_SRC_IRQ_MSK))
+	{
+		return;		/* Interrupt wasn't caused by us!! */
+	}
+
+	if(readl(ETHER_INT_SRC(dev->base_addr))&
+	   (ETHER_INT_SRC_INTMACRX_MSK |
+	    ETHER_INT_SRC_FDAEX_MSK |
+	    ETHER_INT_SRC_BLEX_MSK)) {
+		struct rx_blist_ent* blist_ent_ptr;
+		struct rx_fda_ent* fda_ent_ptr;
+		struct sk_buff* skb;
+
+		fda_ent_ptr=priv->rx_fda_ptr;
+		spin_lock(&priv->rx_lock);
+		while(fda_ent_ptr<(priv->rx_fda_ptr+RX_NUM_FDESC)){
+			int result;
+
+			if(!(fda_ent_ptr->fd.FDCtl&FDCTL_COWNSFD_MSK))
+			{
+				/* This frame is ready for processing */
+				/*find the corresponding buffer in the bufferlist */
+				blist_ent_ptr=priv->rx_blist_vp+fda_ent_ptr->bd.BDStat;
+				skb=(struct sk_buff*)blist_ent_ptr->fd.FDSystem;
+
+				/* Pass this skb up the stack */
+				skb->dev=dev;
+				skb_put(skb,fda_ent_ptr->fd.FDLength);
+				skb->protocol=eth_type_trans(skb,dev);
+				skb->ip_summed=CHECKSUM_UNNECESSARY;
+				result=netif_rx(skb);
+				/* Update statistics */
+				priv->stats.rx_packets++;
+				priv->stats.rx_bytes+=fda_ent_ptr->fd.FDLength;
+
+				/* Free the FDA entry */
+				fda_ent_ptr->bd.BDStat=0xff;
+				fda_ent_ptr->fd.FDCtl=FDCTL_COWNSFD_MSK;
+
+				/* Allocate a new skb and point the bd entry to it */
+				blist_ent_ptr->fd.FDSystem=0;
+				skb=dev_alloc_skb(PKT_BUF_SZ);
+				//printk("allocskb=%#x\n",skb);
+				if(skb){
+					setup_blist_entry(skb,blist_ent_ptr);
+
+				}
+				else if(!priv->memupdate_scheduled){
+					int tmp;
+					/* There are no buffers at the moment, so schedule */
+					/* the background task to sort this out */
+					schedule_task(&priv->tq_memupdate);
+					priv->memupdate_scheduled=1;
+					printk(KERN_DEBUG "%s:No buffers",dev->name);
+					/* If this interrupt was due to a lack of buffers then
+					 * we'd better stop the receiver too */
+					if(interruptValue&ETHER_INT_SRC_BLEX_MSK){
+						priv->rx_disabled=1;
+						tmp=readl(ETHER_INT_SRC(dev->base_addr));
+						writel(tmp&~ETHER_RX_CTL_RXEN_MSK,ETHER_RX_CTL(dev->base_addr));
+						printk(KERN_DEBUG "%s:Halting rx",dev->name);
+					}
+
+				}
+
+			}
+			fda_ent_ptr++;
+		}
+		spin_unlock(&priv->rx_lock);
+
+		/* Clear the  interrupts */
+		writel(ETHER_INT_SRC_INTMACRX_MSK | ETHER_INT_SRC_FDAEX_MSK
+		       | ETHER_INT_SRC_BLEX_MSK,ETHER_INT_SRC(dev->base_addr));
+
+	}
+
+	if(readl(ETHER_INT_SRC(dev->base_addr))&ETHER_INT_SRC_INTMACTX_MSK){
+
+		if(!priv->memupdate_scheduled){
+			schedule_task(&priv->tq_memupdate);
+			priv->memupdate_scheduled=1;
+		}
+		/* Clear the interrupt */
+		writel(ETHER_INT_SRC_INTMACTX_MSK,ETHER_INT_SRC(dev->base_addr));
+	}
+
+	if (readl(ETHER_INT_SRC(dev->base_addr)) & (ETHER_INT_SRC_SWINT_MSK|
+						    ETHER_INT_SRC_INTEARNOT_MSK|
+						    ETHER_INT_SRC_INTLINK_MSK|
+						    ETHER_INT_SRC_INTEXBD_MSK|
+						    ETHER_INT_SRC_INTTXCTLCMP_MSK))
+	{
+		/*
+		 *	Not using any of these so they shouldn't happen
+		 *
+		 *	In the cased of INTEXBD - if you allocate more
+		 *      than 28 decsriptors you may need to think about this
+		 */
+		printk("Not using this interrupt\n");
+	}
+
+	if (readl(ETHER_INT_SRC(dev->base_addr)) &
+	    (ETHER_INT_SRC_INTSBUS_MSK |
+	     ETHER_INT_SRC_INTNRABT_MSK
+	     |ETHER_INT_SRC_DMPARERR_MSK))
+	{
+		/*
+		 * Hardware errors, we can either ignore them and hope they go away
+		 *or reset the device, I'll try the first for now to see if they happen
+		 */
+		printk("Hardware error\n");
+	}
+}
+
+static void ether00_setup_ethernet_address(struct net_device* dev)
+{
+	int tmp;
+
+	dev->addr_len=6;
+	writew(0,ETHER_ARC_ADR(dev->base_addr));
+	writel((dev->dev_addr[0]<<24) |
+		(dev->dev_addr[1]<<16) |
+		(dev->dev_addr[2]<<8) |
+		dev->dev_addr[3],
+		ETHER_ARC_DATA(dev->base_addr));
+
+	writew(4,ETHER_ARC_ADR(dev->base_addr));
+	tmp=readl(ETHER_ARC_DATA(dev->base_addr));
+	tmp&=0xffff;
+	tmp|=(dev->dev_addr[4]<<24) | (dev->dev_addr[5]<<16);
+	writel(tmp, ETHER_ARC_DATA(dev->base_addr));
+	/* Enable this entry in the ARC */
+
+	writel(1,ETHER_ARC_ENA(dev->base_addr));
+
+	return;
+}
+
+
+static void ether00_reset(struct net_device *dev)
+{
+	/* reset the controller */
+	writew(ETHER_MAC_CTL_RESET_MSK,ETHER_MAC_CTL(dev->base_addr));
+
+	/*
+	 * Make sure we're not going to send anything
+	 */
+
+	writew(ETHER_TX_CTL_TXHALT_MSK,ETHER_TX_CTL(dev->base_addr));
+
+	/*
+	 * Make sure we're not going to receive anything
+	 */
+	writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr));
+
+	/*
+	 * Disable Interrupts for now, and set the burst size to 8 bytes
+	 */
+
+	writel(ETHER_DMA_CTL_INTMASK_MSK |
+	       ((8 << ETHER_DMA_CTL_DMBURST_OFST) & ETHER_DMA_CTL_DMBURST_MSK)
+	       |(2<<ETHER_DMA_CTL_RXALIGN_OFST),
+	       ETHER_DMA_CTL(dev->base_addr));
+
+
+	/*
+	 * Set TxThrsh - start transmitting a packet after 1514
+	 * bytes or when a packet is complete, whichever comes first
+	 */
+	 writew(1514,ETHER_TXTHRSH(dev->base_addr));
+
+	/*
+	 * Set TxPollCtr.  Each cycle is
+	 * 61.44 microseconds with a 33 MHz bus
+	 */
+	 writew(1,ETHER_TXPOLLCTR(dev->base_addr));
+
+	/*
+	 * Set Rx_Ctl - Turn off reception and let RxData turn it
+	 * on later
+	 */
+	 writew(ETHER_RX_CTL_RXHALT_MSK,ETHER_RX_CTL(dev->base_addr));
+
+}
+
+
+static void ether00_set_multicast(struct net_device* dev)
+{
+	int count=dev->mc_count;
+
+	/* Set promiscuous mode if it's asked for. */
+
+	if (dev->flags&IFF_PROMISC){
+
+		writew( ETHER_ARC_CTL_COMPEN_MSK |
+			ETHER_ARC_CTL_BROADACC_MSK |
+			ETHER_ARC_CTL_GROUPACC_MSK |
+			ETHER_ARC_CTL_STATIONACC_MSK,
+			ETHER_ARC_CTL(dev->base_addr));
+		return;
+	}
+
+	/*
+	 * Get all multicast packets if required, or if there are too
+	 * many addresses to fit in hardware
+	 */
+	if (dev->flags & IFF_ALLMULTI){
+		writew( ETHER_ARC_CTL_COMPEN_MSK |
+			ETHER_ARC_CTL_GROUPACC_MSK |
+			ETHER_ARC_CTL_BROADACC_MSK,
+			ETHER_ARC_CTL(dev->base_addr));
+		return;
+	}
+	if (dev->mc_count > (ETHER_ARC_SIZE - 1)){
+
+		printk(KERN_WARNING "Too many multicast addresses for hardware to filter - receiving all multicast packets\n");
+		writew( ETHER_ARC_CTL_COMPEN_MSK |
+			ETHER_ARC_CTL_GROUPACC_MSK |
+			ETHER_ARC_CTL_BROADACC_MSK,
+			ETHER_ARC_CTL(dev->base_addr));
+		return;
+	}
+
+	if(dev->mc_count){
+		struct dev_mc_list *mc_list_ent=dev->mc_list;
+		unsigned int temp,i;
+		DEBUG(printk("mc_count=%d mc_list=%#x\n",dev-> mc_count, dev->mc_list));
+		DEBUG(printk("mc addr=%02#x%02x%02x%02x%02x%02x\n",
+			     mc_list_ent->dmi_addr[5],
+			     mc_list_ent->dmi_addr[4],
+			     mc_list_ent->dmi_addr[3],
+			     mc_list_ent->dmi_addr[2],
+			     mc_list_ent->dmi_addr[1],
+			     mc_list_ent->dmi_addr[0]);)
+
+		/*
+		 * The first 6 bytes are the MAC address, so
+		 * don't change them!
+		 */
+		writew(4,ETHER_ARC_ADR(dev->base_addr));
+		temp=readl(ETHER_ARC_DATA(dev->base_addr));
+		temp&=0xffff0000;
+
+		/* Disable the current multicast stuff */
+		writel(1,ETHER_ARC_ENA(dev->base_addr));
+
+		for(;;){
+			temp|=mc_list_ent->dmi_addr[1] |
+				mc_list_ent->dmi_addr[0]<<8;
+			writel(temp,ETHER_ARC_DATA(dev->base_addr));
+
+			i=readl(ETHER_ARC_ADR(dev->base_addr));
+			writew(i+4,ETHER_ARC_ADR(dev->base_addr));
+
+			temp=mc_list_ent->dmi_addr[5]|
+				mc_list_ent->dmi_addr[4]<<8 |
+				mc_list_ent->dmi_addr[3]<<16 |
+				mc_list_ent->dmi_addr[2]<<24;
+			writel(temp,ETHER_ARC_DATA(dev->base_addr));
+
+			count--;
+			if(!mc_list_ent->next || !count){
+				break;
+			}
+			DEBUG(printk("mc_list_next=%#x\n",mc_list_ent->next);)
+			mc_list_ent=mc_list_ent->next;
+
+
+			i=readl(ETHER_ARC_ADR(dev->base_addr));
+			writel(i+4,ETHER_ARC_ADR(dev->base_addr));
+
+			temp=mc_list_ent->dmi_addr[3]|
+				mc_list_ent->dmi_addr[2]<<8 |
+				mc_list_ent->dmi_addr[1]<<16 |
+				mc_list_ent->dmi_addr[0]<<24;
+			writel(temp,ETHER_ARC_DATA(dev->base_addr));
+
+			i=readl(ETHER_ARC_ADR(dev->base_addr));
+			writel(i+4,ETHER_ARC_ADR(dev->base_addr));
+
+			temp=mc_list_ent->dmi_addr[4]<<16 |
+				mc_list_ent->dmi_addr[5]<<24;
+
+			writel(temp,ETHER_ARC_DATA(dev->base_addr));
+
+			count--;
+			if(!mc_list_ent->next || !count){
+				break;
+			}
+			mc_list_ent=mc_list_ent->next;
+		}
+
+
+		if(count)
+			printk(KERN_WARNING "Multicast list size error\n");
+
+
+		writew( ETHER_ARC_CTL_BROADACC_MSK|
+			ETHER_ARC_CTL_COMPEN_MSK,
+			ETHER_ARC_CTL(dev->base_addr));
+
+	}
+
+	/* enable the active ARC enties */
+	writew((1<<(count+2))-1,ETHER_ARC_ENA(dev->base_addr));
+}
+
+
+static int ether00_open(struct net_device* dev)
+{
+	int result,tmp;
+	struct net_priv* priv;
+
+	if (!is_valid_ether_addr(dev->dev_addr))
+		return -EINVAL;
+
+	/* Allocate private memory */
+	dev->priv=kmalloc(sizeof(struct net_priv),GFP_KERNEL);
+	if(!dev->priv)
+		return -ENOMEM;
+	memset(dev->priv,0,sizeof(struct net_priv));
+	priv=(struct net_priv*)dev->priv;
+	priv->tq_memupdate.routine=ether00_mem_update;
+	priv->tq_memupdate.data=(void*) dev;
+	spin_lock_init(&priv->rx_lock);
+
+	/* Install interrupt handlers */
+	result=request_irq(dev->irq,ether00_int,0,"ether00",dev);
+	if(result)
+		goto open_err1;
+
+	result=request_irq(2,ether00_phy_int,0,"ether00_phy",dev);
+	if(result)
+		goto open_err2;
+
+	ether00_reset(dev);
+	result=ether00_mem_init(dev);
+	if(result)
+		goto open_err3;
+
+
+	ether00_setup_ethernet_address(dev);
+
+	ether00_set_multicast(dev);
+
+	result=ether00_write_phy(dev,PHY_CONTROL, PHY_CONTROL_ANEGEN_MSK | PHY_CONTROL_RANEG_MSK);
+	if(result)
+		goto open_err4;
+	result=ether00_write_phy(dev,PHY_IRQ_CONTROL, PHY_IRQ_CONTROL_LS_CHG_IE_MSK |
+				 PHY_IRQ_CONTROL_ANEG_COMP_IE_MSK);
+	if(result)
+		goto open_err4;
+
+	/* Start the device enable interrupts */
+	writew(ETHER_RX_CTL_RXEN_MSK
+//	       | ETHER_RX_CTL_STRIPCRC_MSK
+	       | ETHER_RX_CTL_ENGOOD_MSK
+	       | ETHER_RX_CTL_ENRXPAR_MSK| ETHER_RX_CTL_ENLONGERR_MSK
+	       | ETHER_RX_CTL_ENOVER_MSK| ETHER_RX_CTL_ENCRCERR_MSK,
+	       ETHER_RX_CTL(dev->base_addr));
+
+	writew(ETHER_TX_CTL_TXEN_MSK|
+	       ETHER_TX_CTL_ENEXDEFER_MSK|
+	       ETHER_TX_CTL_ENLCARR_MSK|
+	       ETHER_TX_CTL_ENEXCOLL_MSK|
+	       ETHER_TX_CTL_ENLATECOLL_MSK|
+	       ETHER_TX_CTL_ENTXPAR_MSK|
+	       ETHER_TX_CTL_ENCOMP_MSK,
+	       ETHER_TX_CTL(dev->base_addr));
+
+	tmp=readl(ETHER_DMA_CTL(dev->base_addr));
+	writel(tmp&~ETHER_DMA_CTL_INTMASK_MSK,ETHER_DMA_CTL(dev->base_addr));
+
+	return 0;
+
+ open_err4:
+	ether00_reset(dev);
+ open_err3:
+	free_irq(2,dev);
+ open_err2:
+	free_irq(dev->irq,dev);
+ open_err1:
+	kfree(dev->priv);
+	return result;
+
+}
+
+
+static int ether00_tx(struct sk_buff* skb, struct net_device* dev)
+{
+	struct net_priv *priv=dev->priv;
+	struct tx_fda_ent *fda_ptr;
+	int i;
+
+
+	/*
+	 *	Find an empty slot in which to stick the frame
+	 */
+	fda_ptr=(struct tx_fda_ent*)__dma_va(readl(ETHER_TXFRMPTR(dev->base_addr)));
+	i=0;
+	while(i<TX_NUM_FDESC){
+		if (fda_ptr->fd.FDStat||(fda_ptr->fd.FDCtl & FDCTL_COWNSFD_MSK)){
+			fda_ptr =(struct tx_fda_ent*) __dma_va((struct tx_fda_ent*)fda_ptr->fd.FDNext);
+		}
+		else {
+			break;
+		}
+		i++;
+	}
+
+	/* Write the skb data from the cache*/
+	consistent_sync(skb->data,skb->len,PCI_DMA_TODEVICE);
+	fda_ptr->bd.BuffData=(char*)__pa(skb->data);
+	fda_ptr->bd.BuffLength=(unsigned short)skb->len;
+	/* Save the pointer to the skb for freeing later */
+	fda_ptr->fd.FDSystem=(unsigned int)skb;
+	fda_ptr->fd.FDStat=0;
+	/* Pass ownership of the buffers to the controller */
+	fda_ptr->fd.FDCtl=1;
+	fda_ptr->fd.FDCtl|=FDCTL_COWNSFD_MSK;
+
+	/* If the next buffer in the list is full, stop the queue */
+	fda_ptr=(struct tx_fda_ent*)__dma_va(fda_ptr->fd.FDNext);
+	if ((fda_ptr->fd.FDStat)||(fda_ptr->fd.FDCtl & FDCTL_COWNSFD_MSK)){
+		netif_stop_queue(dev);
+		priv->queue_stopped=1;
+	}
+
+	return 0;
+}
+
+static struct net_device_stats *ether00_stats(struct net_device* dev)
+{
+	struct net_priv *priv=dev->priv;
+	return &priv->stats;
+}
+
+
+static int ether00_stop(struct net_device* dev)
+{
+	struct net_priv *priv=dev->priv;
+	int tmp;
+
+	/* Stop/disable the device. */
+	tmp=readw(ETHER_RX_CTL(dev->base_addr));
+	tmp&=~(ETHER_RX_CTL_RXEN_MSK | ETHER_RX_CTL_ENGOOD_MSK);
+	tmp|=ETHER_RX_CTL_RXHALT_MSK;
+	writew(tmp,ETHER_RX_CTL(dev->base_addr));
+
+	tmp=readl(ETHER_TX_CTL(dev->base_addr));
+	tmp&=~ETHER_TX_CTL_TXEN_MSK;
+	tmp|=ETHER_TX_CTL_TXHALT_MSK;
+	writel(tmp,ETHER_TX_CTL(dev->base_addr));
+
+	/* Free up system resources */
+	free_irq(dev->irq,dev);
+	free_irq(2,dev);
+	iounmap(priv->dma_data);
+	kfree(priv);
+
+	return 0;
+}
+
+
+static void ether00_get_ethernet_address(struct net_device* dev)
+{
+	struct mtd_info *mymtd=NULL;
+	int i;
+	size_t retlen;
+
+	/*
+	 * For the Epxa10 dev board (camelot), the ethernet MAC
+	 * address is of the form  00:aa:aa:00:xx:xx where
+	 * 00:aa:aa is the Altera vendor ID and xx:xx is the
+	 * last 2 bytes of the board serial number, as programmed
+	 * into the OTP area of the flash device on EBI1. If this
+	 * isn't an expa10 dev board, or there's no mtd support to
+	 * read the serial number from flash then we'll force the
+	 * use to set their own mac address using ifconfig.
+	 */
+
+#ifdef CONFIG_ARCH_CAMELOT
+#ifdef CONFIG_MTD
+	/* get the mtd_info structure for the first mtd device*/
+	for(i=0;i<MAX_MTD_DEVICES;i++){
+		mymtd=get_mtd_device(NULL,i);
+		if(!mymtd||!strcmp(mymtd->name,"EPXA10DB flash"))
+			break;
+	}
+
+	if(!mymtd || !mymtd->read_user_prot_reg){
+		printk(KERN_WARNING "%s: Failed to read MAC address from flash\n",dev->name);
+	}else{
+		mymtd->read_user_prot_reg(mymtd,2,1,&retlen,&dev->dev_addr[5]);
+		mymtd->read_user_prot_reg(mymtd,3,1,&retlen,&dev->dev_addr[4]);
+		dev->dev_addr[3]=0;
+		dev->dev_addr[2]=vendor_id[1];
+		dev->dev_addr[1]=vendor_id[0];
+		dev->dev_addr[0]=0;
+	}
+#else
+	printk(KERN_WARNING "%s: MTD support required to read MAC address from EPXA10 dev board\n", dev->name);
+#endif
+#endif
+
+	if (!is_valid_ether_addr(dev->dev_addr))
+		printk("%s: Invalid ethernet MAC address.  Please set using "
+			"ifconfig\n", dev->name);
+
+}
+
+static int ether00_init(struct net_device* dev)
+{
+
+	ether_setup(dev);
+
+	dev->open=ether00_open;
+	dev->stop=ether00_stop;
+	dev->set_multicast_list=ether00_set_multicast;
+	dev->hard_start_xmit=ether00_tx;
+	dev->get_stats=ether00_stats;
+
+	ether00_get_ethernet_address(dev);
+
+	SET_MODULE_OWNER(dev);
+	return 0;
+}
+
+/*
+ * Keep a mapping of dev_info addresses -> port lines to use when
+ * removing ports dev==NULL indicates unused entry
+ */
+
+
+static struct net_device* dev_list[ETH_NR];
+
+static int ether00_add_device(struct pldhs_dev_info* dev_info,void* dev_ps_data)
+{
+	struct net_device *dev;
+	void *map_addr;
+	int result;
+	int i;
+
+
+	i=0;
+	while(dev_list[i])
+		i++;
+
+	if(i==ETH_NR){
+		printk(KERN_WARNING "ether00: Maximum number of ports reached\n");
+		return 0;
+	}
+
+
+	dev=kmalloc(sizeof(struct net_device),GFP_KERNEL);
+	if(!dev){
+		return -ENOMEM;
+	}
+	memset(dev,0,sizeof(struct net_device));
+	map_addr=ioremap_nocache(dev_info->base_addr,SZ_4K);
+	if(!map_addr){
+		return -ENOMEM;
+	}
+
+	dev->init=ether00_init;
+	strcpy(dev->name,"eth%d");
+	dev->base_addr=(unsigned int)map_addr;
+	dev->irq=dev_info->irq;
+	dev->features=NETIF_F_DYNALLOC | NETIF_F_HW_CSUM;
+
+	if(check_mem_region((unsigned int)map_addr, MAC_REG_SIZE)){
+		return -EBUSY;
+	}
+	request_mem_region((unsigned int)map_addr, MAC_REG_SIZE, "ether00");
+
+	result=register_netdev(dev);
+	if(result){
+		printk("Ether00: Error %i registering driver\n",result);
+		return result;
+	}
+	printk("registered ether00 device at %#x\n",dev_info->base_addr);
+
+	dev_list[i]=dev;
+
+	return result;
+}
+
+
+static int ether00_remove_devices(void)
+{
+	int i;
+
+	for(i=0;i<ETH_NR;i++){
+		if(dev_list[i]){
+			netif_device_detach(dev_list[i]);
+			unregister_netdev(dev_list[i]);
+			iounmap((void*)dev_list[i]->base_addr);
+			release_mem_region(dev_list[i]->base_addr, MAC_REG_SIZE);
+			kfree(dev_list[i]);
+			dev_list[i]=0;
+		}
+	}
+	return 0;
+}
+
+static struct pld_hotswap_ops ether00_pldhs_ops={
+	name: ETHER00_NAME,
+	add_device: ether00_add_device,
+	remove_devices: ether00_remove_devices,
+};
+
+
+static void __exit ether00_cleanup_module(void)
+{
+	int result;
+	result=ether00_remove_devices();
+	if(result)
+		printk(KERN_WARNING "ether00: failed to remove all devices\n");
+
+	pldhs_unregister_driver(ETHER00_NAME);
+}
+module_exit(ether00_cleanup_module);
+
+
+static int __init ether00_mod_init(void)
+{
+	printk("mod init\n");
+	return pldhs_register_driver(&ether00_pldhs_ops);
+
+}
+
+module_init(ether00_mod_init);
+
diff -Nru a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/ether1.c	Sat May 17 07:56:28 2003
@@ -0,0 +1,1106 @@
+/*
+ *  linux/drivers/acorn/net/ether1.c
+ *
+ *  Copyright (C) 1996-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.
+ *
+ *  Acorn ether1 driver (82586 chip) for Acorn machines
+ *
+ * We basically keep two queues in the cards memory - one for transmit
+ * and one for receive.  Each has a head and a tail.  The head is where
+ * we/the chip adds packets to be transmitted/received, and the tail
+ * is where the transmitter has got to/where the receiver will stop.
+ * Both of these queues are circular, and since the chip is running
+ * all the time, we have to be careful when we modify the pointers etc
+ * so that the buffer memory contents is valid all the time.
+ *
+ * Change log:
+ * 1.00	RMK			Released
+ * 1.01	RMK	19/03/1996	Transfers the last odd byte onto/off of the card now.
+ * 1.02	RMK	25/05/1997	Added code to restart RU if it goes not ready
+ * 1.03	RMK	14/09/1997	Cleaned up the handling of a reset during the TX interrupt.
+ *				Should prevent lockup.
+ * 1.04 RMK	17/09/1997	Added more info when initialsation of chip goes wrong.
+ *				TDR now only reports failure when chip reports non-zero
+ *				TDR time-distance.
+ * 1.05	RMK	31/12/1997	Removed calls to dev_tint for 2.1
+ * 1.06	RMK	10/02/2000	Updated for 2.3.43
+ * 1.07	RMK	13/05/2000	Updated for 2.3.99-pre8
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/ecard.h>
+
+#define __ETHER1_C
+#include "ether1.h"
+
+static unsigned int net_debug = NET_DEBUG;
+
+#define BUFFER_SIZE	0x10000
+#define TX_AREA_START	0x00100
+#define TX_AREA_END	0x05000
+#define RX_AREA_START	0x05000
+#define RX_AREA_END	0x0fc00
+
+static int ether1_open(struct net_device *dev);
+static int ether1_sendpacket(struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t ether1_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int ether1_close(struct net_device *dev);
+static struct net_device_stats *ether1_getstats(struct net_device *dev);
+static void ether1_setmulticastlist(struct net_device *dev);
+static void ether1_timeout(struct net_device *dev);
+
+/* ------------------------------------------------------------------------- */
+
+static char version[] __initdata = "ether1 ethernet driver (c) 2000 Russell King v1.07\n";
+
+#define BUS_16 16
+#define BUS_8  8
+
+/* ------------------------------------------------------------------------- */
+
+#define DISABLEIRQS 1
+#define NORMALIRQS  0
+
+#define ether1_inw(dev, addr, type, offset, svflgs) ether1_inw_p (dev, addr + (int)(&((type *)0)->offset), svflgs)
+#define ether1_outw(dev, val, addr, type, offset, svflgs) ether1_outw_p (dev, val, addr + (int)(&((type *)0)->offset), svflgs)
+
+static inline unsigned short
+ether1_inw_p (struct net_device *dev, int addr, int svflgs)
+{
+	unsigned long flags;
+	unsigned short ret;
+
+	if (svflgs)
+		local_irq_save (flags);
+
+	outb (addr >> 12, REG_PAGE);
+	ret = inw (ETHER1_RAM + ((addr & 4095) >> 1));
+	if (svflgs)
+		local_irq_restore (flags);
+	return ret;
+}
+
+static inline void
+ether1_outw_p (struct net_device *dev, unsigned short val, int addr, int svflgs)
+{
+	unsigned long flags;
+
+	if (svflgs)
+		local_irq_save (flags);
+
+	outb (addr >> 12, REG_PAGE);
+	outw (val, ETHER1_RAM + ((addr & 4095) >> 1));
+	if (svflgs)
+		local_irq_restore (flags);
+}
+
+/*
+ * Some inline assembler to allow fast transfers on to/off of the card.
+ * Since this driver depends on some features presented by the ARM
+ * specific architecture, and that you can't configure this driver
+ * without specifiing ARM mode, this is not a problem.
+ *
+ * This routine is essentially an optimised memcpy from the card's
+ * onboard RAM to kernel memory.
+ */
+static void
+ether1_writebuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
+{
+	unsigned int page, thislen, offset, addr;
+
+	offset = start & 4095;
+	page = start >> 12;
+	addr = ioaddr(ETHER1_RAM + (offset >> 1));
+
+	if (offset + length > 4096)
+		thislen = 4096 - offset;
+	else
+		thislen = length;
+
+	do {
+		int used;
+
+		outb(page, REG_PAGE);
+		length -= thislen;
+
+		__asm__ __volatile__(
+	"subs	%3, %3, #2
+	bmi	2f
+1:	ldr	%0, [%1], #2
+	mov	%0, %0, lsl #16
+	orr	%0, %0, %0, lsr #16
+	str	%0, [%2], #4
+	subs	%3, %3, #2
+	bmi	2f
+	ldr	%0, [%1], #2
+	mov	%0, %0, lsl #16
+	orr	%0, %0, %0, lsr #16
+	str	%0, [%2], #4
+	subs	%3, %3, #2
+	bmi	2f
+	ldr	%0, [%1], #2
+	mov	%0, %0, lsl #16
+	orr	%0, %0, %0, lsr #16
+	str	%0, [%2], #4
+	subs	%3, %3, #2
+	bmi	2f
+	ldr	%0, [%1], #2
+	mov	%0, %0, lsl #16
+	orr	%0, %0, %0, lsr #16
+	str	%0, [%2], #4
+	subs	%3, %3, #2
+	bpl	1b
+2:	adds	%3, %3, #1
+	ldreqb	%0, [%1]
+	streqb	%0, [%2]"
+		: "=&r" (used), "=&r" (data)
+		: "r"  (addr), "r" (thislen), "1" (data));
+
+		addr = ioaddr(ETHER1_RAM);
+
+		thislen = length;
+		if (thislen > 4096)
+			thislen = 4096;
+		page++;
+	} while (thislen);
+}
+
+static void
+ether1_readbuffer (struct net_device *dev, void *data, unsigned int start, unsigned int length)
+{
+	unsigned int page, thislen, offset, addr;
+
+	offset = start & 4095;
+	page = start >> 12;
+	addr = ioaddr(ETHER1_RAM + (offset >> 1));
+
+	if (offset + length > 4096)
+		thislen = 4096 - offset;
+	else
+		thislen = length;
+
+	do {
+		int used;
+
+		outb(page, REG_PAGE);
+		length -= thislen;
+
+		__asm__ __volatile__(
+	"subs	%3, %3, #2
+	bmi	2f
+1:	ldr	%0, [%2], #4
+	strb	%0, [%1], #1
+	mov	%0, %0, lsr #8
+	strb	%0, [%1], #1
+	subs	%3, %3, #2
+	bmi	2f
+	ldr	%0, [%2], #4
+	strb	%0, [%1], #1
+	mov	%0, %0, lsr #8
+	strb	%0, [%1], #1
+	subs	%3, %3, #2
+	bmi	2f
+	ldr	%0, [%2], #4
+	strb	%0, [%1], #1
+	mov	%0, %0, lsr #8
+	strb	%0, [%1], #1
+	subs	%3, %3, #2
+	bmi	2f
+	ldr	%0, [%2], #4
+	strb	%0, [%1], #1
+	mov	%0, %0, lsr #8
+	strb	%0, [%1], #1
+	subs	%3, %3, #2
+	bpl	1b
+2:	adds	%3, %3, #1
+	ldreqb	%0, [%2]
+	streqb	%0, [%1]"
+		: "=&r" (used), "=&r" (data)
+		: "r"  (addr), "r" (thislen), "1" (data));
+
+		addr = ioaddr(ETHER1_RAM);
+
+		thislen = length;
+		if (thislen > 4096)
+			thislen = 4096;
+		page++;
+	} while (thislen);
+}
+
+static int __init
+ether1_ramtest(struct net_device *dev, unsigned char byte)
+{
+	unsigned char *buffer = kmalloc (BUFFER_SIZE, GFP_KERNEL);
+	int i, ret = BUFFER_SIZE;
+	int max_errors = 15;
+	int bad = -1;
+	int bad_start = 0;
+
+	if (!buffer)
+		return 1;
+
+	memset (buffer, byte, BUFFER_SIZE);
+	ether1_writebuffer (dev, buffer, 0, BUFFER_SIZE);
+	memset (buffer, byte ^ 0xff, BUFFER_SIZE);
+	ether1_readbuffer (dev, buffer, 0, BUFFER_SIZE);
+
+	for (i = 0; i < BUFFER_SIZE; i++) {
+		if (buffer[i] != byte) {
+			if (max_errors >= 0 && bad != buffer[i]) {
+				if (bad != -1)
+					printk ("\n");
+				printk (KERN_CRIT "%s: RAM failed with (%02X instead of %02X) at 0x%04X",
+					dev->name, buffer[i], byte, i);
+				ret = -ENODEV;
+				max_errors --;
+				bad = buffer[i];
+				bad_start = i;
+			}
+		} else {
+			if (bad != -1) {
+			    	if (bad_start == i - 1)
+					printk ("\n");
+				else
+					printk (" - 0x%04X\n", i - 1);
+				bad = -1;
+			}
+		}
+	}
+
+	if (bad != -1)
+		printk (" - 0x%04X\n", BUFFER_SIZE);
+	kfree (buffer);
+
+	return ret;
+}
+
+static int
+ether1_reset (struct net_device *dev)
+{
+	outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
+	return BUS_16;
+}
+
+static int __init
+ether1_init_2(struct net_device *dev)
+{
+	int i;
+	dev->mem_start = 0;
+
+	i = ether1_ramtest (dev, 0x5a);
+
+	if (i > 0)
+		i = ether1_ramtest (dev, 0x1e);
+
+	if (i <= 0)
+	    	return -ENODEV;
+
+	dev->mem_end = i;
+	return 0;
+}
+
+/*
+ * These are the structures that are loaded into the ether RAM card to
+ * initialise the 82586
+ */
+
+/* at 0x0100 */
+#define NOP_ADDR	(TX_AREA_START)
+#define NOP_SIZE	(0x06)
+static nop_t  init_nop  = {
+	0,
+	CMD_NOP,
+	NOP_ADDR
+};
+
+/* at 0x003a */
+#define TDR_ADDR	(0x003a)
+#define TDR_SIZE	(0x08)
+static tdr_t  init_tdr	= {
+	0,
+	CMD_TDR | CMD_INTR,
+	NOP_ADDR,
+	0
+};
+
+/* at 0x002e */
+#define MC_ADDR		(0x002e)
+#define MC_SIZE		(0x0c)
+static mc_t   init_mc   = {
+	0,
+	CMD_SETMULTICAST,
+	TDR_ADDR,
+	0,
+	{ { 0, } }
+};
+
+/* at 0x0022 */
+#define SA_ADDR		(0x0022)
+#define SA_SIZE		(0x0c)
+static sa_t   init_sa   = {
+	0,
+	CMD_SETADDRESS,
+	MC_ADDR,
+	{ 0, }
+};
+
+/* at 0x0010 */
+#define CFG_ADDR	(0x0010)
+#define CFG_SIZE	(0x12)
+static cfg_t  init_cfg  = {
+	0,
+	CMD_CONFIG,
+	SA_ADDR,
+	8,
+	8,
+	CFG8_SRDY,
+	CFG9_PREAMB8 | CFG9_ADDRLENBUF | CFG9_ADDRLEN(6),
+	0,
+	0x60,
+	0,
+	CFG13_RETRY(15) | CFG13_SLOTH(2),
+	0,
+};
+
+/* at 0x0000 */
+#define SCB_ADDR	(0x0000)
+#define SCB_SIZE	(0x10)
+static scb_t  init_scb  = {
+	0,
+	SCB_CMDACKRNR | SCB_CMDACKCNA | SCB_CMDACKFR | SCB_CMDACKCX,
+	CFG_ADDR,
+	RX_AREA_START,
+	0,
+	0,
+	0,
+	0
+};
+
+/* at 0xffee */
+#define ISCP_ADDR	(0xffee)
+#define ISCP_SIZE	(0x08)
+static iscp_t init_iscp = {
+	1,
+	SCB_ADDR,
+	0x0000,
+	0x0000
+};
+
+/* at 0xfff6 */
+#define SCP_ADDR	(0xfff6)
+#define SCP_SIZE	(0x0a)
+static scp_t  init_scp  = {
+	SCP_SY_16BBUS,
+	{ 0, 0 },
+	ISCP_ADDR,
+	0
+};
+
+#define RFD_SIZE	(0x16)
+static rfd_t  init_rfd	= {
+	0,
+	0,
+	0,
+	0,
+	{ 0, },
+	{ 0, },
+	0
+};
+
+#define RBD_SIZE	(0x0a)
+static rbd_t  init_rbd	= {
+	0,
+	0,
+	0,
+	0,
+	ETH_FRAME_LEN + 8
+};
+
+#define TX_SIZE		(0x08)
+#define TBD_SIZE	(0x08)
+
+static int
+ether1_init_for_open (struct net_device *dev)
+{
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	int i, status, addr, next, next2;
+	int failures = 0;
+	unsigned long timeout;
+
+	outb (CTRL_RST|CTRL_ACK, REG_CONTROL);
+
+	for (i = 0; i < 6; i++)
+		init_sa.sa_addr[i] = dev->dev_addr[i];
+
+	/* load data structures into ether1 RAM */
+	ether1_writebuffer (dev, &init_scp,  SCP_ADDR,  SCP_SIZE);
+	ether1_writebuffer (dev, &init_iscp, ISCP_ADDR, ISCP_SIZE);
+	ether1_writebuffer (dev, &init_scb,  SCB_ADDR,  SCB_SIZE);
+	ether1_writebuffer (dev, &init_cfg,  CFG_ADDR,  CFG_SIZE);
+	ether1_writebuffer (dev, &init_sa,   SA_ADDR,   SA_SIZE);
+	ether1_writebuffer (dev, &init_mc,   MC_ADDR,   MC_SIZE);
+	ether1_writebuffer (dev, &init_tdr,  TDR_ADDR,  TDR_SIZE);
+	ether1_writebuffer (dev, &init_nop,  NOP_ADDR,  NOP_SIZE);
+
+	if (ether1_inw (dev, CFG_ADDR, cfg_t, cfg_command, NORMALIRQS) != CMD_CONFIG) {
+		printk (KERN_ERR "%s: detected either RAM fault or compiler bug\n",
+			dev->name);
+		return 1;
+	}
+
+	/*
+	 * setup circularly linked list of { rfd, rbd, buffer }, with
+	 * all rfds circularly linked, rbds circularly linked.
+	 * First rfd is linked to scp, first rbd is linked to first
+	 * rfd.  Last rbd has a suspend command.
+	 */
+	addr = RX_AREA_START;
+	do {
+		next = addr + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
+		next2 = next + RFD_SIZE + RBD_SIZE + ETH_FRAME_LEN + 10;
+
+		if (next2 >= RX_AREA_END) {
+			next = RX_AREA_START;
+			init_rfd.rfd_command = RFD_CMDEL | RFD_CMDSUSPEND;
+			priv->rx_tail = addr;
+		} else
+			init_rfd.rfd_command = 0;
+		if (addr == RX_AREA_START)
+			init_rfd.rfd_rbdoffset = addr + RFD_SIZE;
+		else
+			init_rfd.rfd_rbdoffset = 0;
+		init_rfd.rfd_link = next;
+		init_rbd.rbd_link = next + RFD_SIZE;
+		init_rbd.rbd_bufl = addr + RFD_SIZE + RBD_SIZE;
+
+		ether1_writebuffer (dev, &init_rfd, addr, RFD_SIZE);
+		ether1_writebuffer (dev, &init_rbd, addr + RFD_SIZE, RBD_SIZE);
+		addr = next;
+	} while (next2 < RX_AREA_END);
+
+	priv->tx_link = NOP_ADDR;
+	priv->tx_head = NOP_ADDR + NOP_SIZE;
+	priv->tx_tail = TDR_ADDR;
+	priv->rx_head = RX_AREA_START;
+
+	/* release reset & give 586 a prod */
+	priv->resetting = 1;
+	priv->initialising = 1;
+	outb (CTRL_RST, REG_CONTROL);
+	outb (0, REG_CONTROL);
+	outb (CTRL_CA, REG_CONTROL);
+
+	/* 586 should now unset iscp.busy */
+	timeout = jiffies + HZ/2;
+	while (ether1_inw (dev, ISCP_ADDR, iscp_t, iscp_busy, DISABLEIRQS) == 1) {
+		if (time_after(jiffies, timeout)) {
+			printk (KERN_WARNING "%s: can't initialise 82586: iscp is busy\n", dev->name);
+			return 1;
+		}
+	}
+
+	/* check status of commands that we issued */
+	timeout += HZ/10;
+	while (((status = ether1_inw (dev, CFG_ADDR, cfg_t, cfg_status, DISABLEIRQS))
+			& STAT_COMPLETE) == 0) {
+		if (time_after(jiffies, timeout))
+			break;
+	}
+
+	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+		printk (KERN_WARNING "%s: can't initialise 82586: config status %04X\n", dev->name, status);
+		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+		failures += 1;
+	}
+
+	timeout += HZ/10;
+	while (((status = ether1_inw (dev, SA_ADDR, sa_t, sa_status, DISABLEIRQS))
+			& STAT_COMPLETE) == 0) {
+		if (time_after(jiffies, timeout))
+			break;
+	}
+
+	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+		printk (KERN_WARNING "%s: can't initialise 82586: set address status %04X\n", dev->name, status);
+		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+		failures += 1;
+	}
+
+	timeout += HZ/10;
+	while (((status = ether1_inw (dev, MC_ADDR, mc_t, mc_status, DISABLEIRQS))
+			& STAT_COMPLETE) == 0) {
+		if (time_after(jiffies, timeout))
+			break;
+	}
+
+	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+		printk (KERN_WARNING "%s: can't initialise 82586: set multicast status %04X\n", dev->name, status);
+		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+		failures += 1;
+	}
+
+	timeout += HZ;
+	while (((status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_status, DISABLEIRQS))
+			& STAT_COMPLETE) == 0) {
+		if (time_after(jiffies, timeout))
+			break;
+	}
+
+	if ((status & (STAT_COMPLETE | STAT_OK)) != (STAT_COMPLETE | STAT_OK)) {
+		printk (KERN_WARNING "%s: can't tdr (ignored)\n", dev->name);
+		printk (KERN_DEBUG "%s: SCB=[STS=%04X CMD=%04X CBL=%04X RFA=%04X]\n", dev->name,
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_command, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS),
+			ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset, NORMALIRQS));
+	} else {
+		status = ether1_inw (dev, TDR_ADDR, tdr_t, tdr_result, DISABLEIRQS);
+		if (status & TDR_XCVRPROB)
+			printk (KERN_WARNING "%s: i/f failed tdr: transceiver problem\n", dev->name);
+		else if ((status & (TDR_SHORT|TDR_OPEN)) && (status & TDR_TIME)) {
+#ifdef FANCY
+			printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d.%d us away\n", dev->name,
+				status & TDR_SHORT ? "short" : "open", (status & TDR_TIME) / 10,
+				(status & TDR_TIME) % 10);
+#else
+			printk (KERN_WARNING "%s: i/f failed tdr: cable %s %d clks away\n", dev->name,
+				status & TDR_SHORT ? "short" : "open", (status & TDR_TIME));
+#endif
+		}
+	}
+
+	if (failures)
+		ether1_reset (dev);
+	return failures ? 1 : 0;
+}
+
+/* ------------------------------------------------------------------------- */
+
+static int
+ether1_txalloc (struct net_device *dev, int size)
+{
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	int start, tail;
+
+	size = (size + 1) & ~1;
+	tail = priv->tx_tail;
+
+	if (priv->tx_head + size > TX_AREA_END) {
+		if (tail > priv->tx_head)
+			return -1;
+		start = TX_AREA_START;
+		if (start + size > tail)
+			return -1;
+		priv->tx_head = start + size;
+	} else {
+		if (priv->tx_head < tail && (priv->tx_head + size) > tail)
+			return -1;
+		start = priv->tx_head;
+		priv->tx_head += size;
+	}
+
+	return start;
+}
+
+static int
+ether1_open (struct net_device *dev)
+{
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
+			dev->name);
+		return -EINVAL;
+	}
+
+	if (request_irq(dev->irq, ether1_interrupt, 0, "ether1", dev))
+		return -EAGAIN;
+
+	memset (&priv->stats, 0, sizeof (struct net_device_stats));
+
+	if (ether1_init_for_open (dev)) {
+		free_irq (dev->irq, dev);
+		return -EAGAIN;
+	}
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+static void
+ether1_timeout(struct net_device *dev)
+{
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+
+	printk(KERN_WARNING "%s: transmit timeout, network cable problem?\n",
+		dev->name);
+	printk(KERN_WARNING "%s: resetting device\n", dev->name);
+
+	ether1_reset (dev);
+
+	if (ether1_init_for_open (dev))
+		printk (KERN_ERR "%s: unable to restart interface\n", dev->name);
+
+	priv->stats.tx_errors++;
+	netif_wake_queue(dev);
+}
+
+static int
+ether1_sendpacket (struct sk_buff *skb, struct net_device *dev)
+{
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	int len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+	int tmp, tst, nopaddr, txaddr, tbdaddr, dataddr;
+	unsigned long flags;
+	tx_t tx;
+	tbd_t tbd;
+	nop_t nop;
+
+	if (priv->restart) {
+		printk(KERN_WARNING "%s: resetting device\n", dev->name);
+
+		ether1_reset(dev);
+
+		if (ether1_init_for_open(dev))
+			printk(KERN_ERR "%s: unable to restart interface\n", dev->name);
+		else
+			priv->restart = 0;
+	}
+
+	/*
+	 * insert packet followed by a nop
+	 */
+	txaddr = ether1_txalloc (dev, TX_SIZE);
+	tbdaddr = ether1_txalloc (dev, TBD_SIZE);
+	dataddr = ether1_txalloc (dev, len);
+	nopaddr = ether1_txalloc (dev, NOP_SIZE);
+
+	tx.tx_status = 0;
+	tx.tx_command = CMD_TX | CMD_INTR;
+	tx.tx_link = nopaddr;
+	tx.tx_tbdoffset = tbdaddr;
+	tbd.tbd_opts = TBD_EOL | len;
+	tbd.tbd_link = I82586_NULL;
+	tbd.tbd_bufl = dataddr;
+	tbd.tbd_bufh = 0;
+	nop.nop_status = 0;
+	nop.nop_command = CMD_NOP;
+	nop.nop_link = nopaddr;
+
+	local_irq_save(flags);
+	ether1_writebuffer (dev, &tx, txaddr, TX_SIZE);
+	ether1_writebuffer (dev, &tbd, tbdaddr, TBD_SIZE);
+	ether1_writebuffer (dev, skb->data, dataddr, len);
+	ether1_writebuffer (dev, &nop, nopaddr, NOP_SIZE);
+	tmp = priv->tx_link;
+	priv->tx_link = nopaddr;
+
+	/* now reset the previous nop pointer */
+	ether1_outw (dev, txaddr, tmp, nop_t, nop_link, NORMALIRQS);
+
+	local_irq_restore(flags);
+
+	/* handle transmit */
+	dev->trans_start = jiffies;
+
+	/* check to see if we have room for a full sized ether frame */
+	tmp = priv->tx_head;
+	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
+	priv->tx_head = tmp;
+	dev_kfree_skb (skb);
+
+	if (tst == -1)
+		netif_stop_queue(dev);
+
+	return 0;
+}
+
+static void
+ether1_xmit_done (struct net_device *dev)
+{
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	nop_t nop;
+	int caddr, tst;
+
+	caddr = priv->tx_tail;
+
+again:
+	ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
+
+	switch (nop.nop_command & CMD_MASK) {
+	case CMD_TDR:
+		/* special case */
+		if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+				!= (unsigned short)I82586_NULL) {
+			ether1_outw(dev, SCB_CMDCUCSTART | SCB_CMDRXSTART, SCB_ADDR, scb_t,
+				    scb_command, NORMALIRQS);
+			outb (CTRL_CA, REG_CONTROL);
+		}
+		priv->tx_tail = NOP_ADDR;
+		return;
+
+	case CMD_NOP:
+		if (nop.nop_link == caddr) {
+			if (priv->initialising == 0)
+				printk (KERN_WARNING "%s: strange command complete with no tx command!\n", dev->name);
+			else
+			        priv->initialising = 0;
+			return;
+		}
+		if (caddr == nop.nop_link)
+			return;
+		caddr = nop.nop_link;
+		goto again;
+
+	case CMD_TX:
+		if (nop.nop_status & STAT_COMPLETE)
+			break;
+		printk (KERN_ERR "%s: strange command complete without completed command\n", dev->name);
+		priv->restart = 1;
+		return;
+
+	default:
+		printk (KERN_WARNING "%s: strange command %d complete! (offset %04X)", dev->name,
+			nop.nop_command & CMD_MASK, caddr);
+		priv->restart = 1;
+		return;
+	}
+
+	while (nop.nop_status & STAT_COMPLETE) {
+		if (nop.nop_status & STAT_OK) {
+			priv->stats.tx_packets ++;
+			priv->stats.collisions += (nop.nop_status & STAT_COLLISIONS);
+		} else {
+			priv->stats.tx_errors ++;
+
+			if (nop.nop_status & STAT_COLLAFTERTX)
+				priv->stats.collisions ++;
+			if (nop.nop_status & STAT_NOCARRIER)
+				priv->stats.tx_carrier_errors ++;
+			if (nop.nop_status & STAT_TXLOSTCTS)
+				printk (KERN_WARNING "%s: cts lost\n", dev->name);
+			if (nop.nop_status & STAT_TXSLOWDMA)
+				priv->stats.tx_fifo_errors ++;
+			if (nop.nop_status & STAT_COLLEXCESSIVE)
+				priv->stats.collisions += 16;
+		}
+
+		if (nop.nop_link == caddr) {
+			printk (KERN_ERR "%s: tx buffer chaining error: tx command points to itself\n", dev->name);
+			break;
+		}
+
+		caddr = nop.nop_link;
+		ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
+		if ((nop.nop_command & CMD_MASK) != CMD_NOP) {
+			printk (KERN_ERR "%s: tx buffer chaining error: no nop after tx command\n", dev->name);
+			break;
+		}
+
+		if (caddr == nop.nop_link)
+			break;
+
+		caddr = nop.nop_link;
+		ether1_readbuffer (dev, &nop, caddr, NOP_SIZE);
+		if ((nop.nop_command & CMD_MASK) != CMD_TX) {
+			printk (KERN_ERR "%s: tx buffer chaining error: no tx command after nop\n", dev->name);
+			break;
+		}
+	}
+	priv->tx_tail = caddr;
+
+	caddr = priv->tx_head;
+	tst = ether1_txalloc (dev, TX_SIZE + TBD_SIZE + NOP_SIZE + ETH_FRAME_LEN);
+	priv->tx_head = caddr;
+	if (tst != -1)
+		netif_wake_queue(dev);
+}
+
+static void
+ether1_recv_done (struct net_device *dev)
+{
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	int status;
+	int nexttail, rbdaddr;
+	rbd_t rbd;
+
+	do {
+		status = ether1_inw (dev, priv->rx_head, rfd_t, rfd_status, NORMALIRQS);
+		if ((status & RFD_COMPLETE) == 0)
+			break;
+
+		rbdaddr = ether1_inw (dev, priv->rx_head, rfd_t, rfd_rbdoffset, NORMALIRQS);
+		ether1_readbuffer (dev, &rbd, rbdaddr, RBD_SIZE);
+
+		if ((rbd.rbd_status & (RBD_EOF | RBD_ACNTVALID)) == (RBD_EOF | RBD_ACNTVALID)) {
+			int length = rbd.rbd_status & RBD_ACNT;
+			struct sk_buff *skb;
+
+			length = (length + 1) & ~1;
+			skb = dev_alloc_skb (length + 2);
+
+			if (skb) {
+				skb->dev = dev;
+				skb_reserve (skb, 2);
+
+				ether1_readbuffer (dev, skb_put (skb, length), rbd.rbd_bufl, length);
+
+				skb->protocol = eth_type_trans (skb, dev);
+				netif_rx (skb);
+				priv->stats.rx_packets ++;
+			} else
+				priv->stats.rx_dropped ++;
+		} else {
+			printk(KERN_WARNING "%s: %s\n", dev->name,
+				(rbd.rbd_status & RBD_EOF) ? "oversized packet" : "acnt not valid");
+			priv->stats.rx_dropped ++;
+		}
+
+		nexttail = ether1_inw (dev, priv->rx_tail, rfd_t, rfd_link, NORMALIRQS);
+		/* nexttail should be rx_head */
+		if (nexttail != priv->rx_head)
+			printk(KERN_ERR "%s: receiver buffer chaining error (%04X != %04X)\n",
+				dev->name, nexttail, priv->rx_head);
+		ether1_outw (dev, RFD_CMDEL | RFD_CMDSUSPEND, nexttail, rfd_t, rfd_command, NORMALIRQS);
+		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_command, NORMALIRQS);
+		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_status, NORMALIRQS);
+		ether1_outw (dev, 0, priv->rx_tail, rfd_t, rfd_rbdoffset, NORMALIRQS);
+	
+		priv->rx_tail = nexttail;
+		priv->rx_head = ether1_inw (dev, priv->rx_head, rfd_t, rfd_link, NORMALIRQS);
+	} while (1);
+}
+
+static irqreturn_t
+ether1_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	int status;
+
+	status = ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS);
+
+	if (status) {
+		ether1_outw(dev, status & (SCB_STRNR | SCB_STCNA | SCB_STFR | SCB_STCX),
+			    SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+		outb (CTRL_CA | CTRL_ACK, REG_CONTROL);
+		if (status & SCB_STCX) {
+			ether1_xmit_done (dev);
+		}
+		if (status & SCB_STCNA) {
+			if (priv->resetting == 0)
+				printk (KERN_WARNING "%s: CU went not ready ???\n", dev->name);
+			else
+				priv->resetting += 1;
+			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_cbl_offset, NORMALIRQS)
+					!= (unsigned short)I82586_NULL) {
+				ether1_outw (dev, SCB_CMDCUCSTART, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+				outb (CTRL_CA, REG_CONTROL);
+			}
+			if (priv->resetting == 2)
+				priv->resetting = 0;
+		}
+		if (status & SCB_STFR) {
+			ether1_recv_done (dev);
+		}
+		if (status & SCB_STRNR) {
+			if (ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS) & SCB_STRXSUSP) {
+				printk (KERN_WARNING "%s: RU went not ready: RU suspended\n", dev->name);
+				ether1_outw (dev, SCB_CMDRXRESUME, SCB_ADDR, scb_t, scb_command, NORMALIRQS);
+				outb (CTRL_CA, REG_CONTROL);
+				priv->stats.rx_dropped ++;	/* we suspended due to lack of buffer space */
+			} else
+				printk(KERN_WARNING "%s: RU went not ready: %04X\n", dev->name,
+					ether1_inw (dev, SCB_ADDR, scb_t, scb_status, NORMALIRQS));
+			printk (KERN_WARNING "RU ptr = %04X\n", ether1_inw (dev, SCB_ADDR, scb_t, scb_rfa_offset,
+						NORMALIRQS));
+		}
+	} else
+		outb (CTRL_ACK, REG_CONTROL);
+
+	return IRQ_HANDLED;
+}
+
+static int
+ether1_close (struct net_device *dev)
+{
+	ether1_reset (dev);
+
+	free_irq(dev->irq, dev);
+
+	return 0;
+}
+
+static struct net_device_stats *
+ether1_getstats (struct net_device *dev)
+{
+	struct ether1_priv *priv = (struct ether1_priv *)dev->priv;
+	return &priv->stats;
+}
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ * 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.
+ */
+static void
+ether1_setmulticastlist (struct net_device *dev)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+
+static void __init ether1_banner(void)
+{
+	static unsigned int version_printed = 0;
+
+	if (net_debug && version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+}
+
+static int __devinit
+ether1_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct net_device *dev;
+	struct ether1_priv *priv;
+	int i, ret = 0;
+
+	ether1_banner();
+
+	dev = init_etherdev(NULL, sizeof(struct ether1_priv));
+	if (!dev) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	SET_MODULE_OWNER(dev);
+
+	dev->base_addr	= ecard_address(ec, ECARD_IOC, ECARD_FAST);
+	dev->irq	= ec->irq;
+
+	/*
+	 * these will not fail - the nature of the bus ensures this
+	 */
+	request_region(dev->base_addr, 16, dev->name);
+	request_region(dev->base_addr + 0x800, 4096, dev->name);
+
+	priv = (struct ether1_priv *)dev->priv;
+	if ((priv->bus_type = ether1_reset(dev)) == 0) {
+		ret = -ENODEV;
+		goto release;
+	}
+
+	printk(KERN_INFO "%s: ether1 in slot %d, ",
+		dev->name, ec->slot_no);
+    
+	for (i = 0; i < 6; i++) {
+		dev->dev_addr[i] = inb(IDPROM_ADDRESS + i);
+		printk ("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+	}
+
+	if (ether1_init_2(dev)) {
+		ret = -ENODEV;
+		goto release;
+	}
+
+	dev->open		= ether1_open;
+	dev->stop		= ether1_close;
+	dev->hard_start_xmit    = ether1_sendpacket;
+	dev->get_stats		= ether1_getstats;
+	dev->set_multicast_list = ether1_setmulticastlist;
+	dev->tx_timeout		= ether1_timeout;
+	dev->watchdog_timeo	= 5 * HZ / 100;
+
+	ecard_set_drvdata(ec, dev);
+	return 0;
+
+release:
+	release_region(dev->base_addr, 16);
+	release_region(dev->base_addr + 0x800, 4096);
+	unregister_netdev(dev);
+	kfree(dev);
+out:
+	return ret;
+}
+
+static void __devexit ether1_remove(struct expansion_card *ec)
+{
+	struct net_device *dev = ecard_get_drvdata(ec);
+
+	ecard_set_drvdata(ec, NULL);	
+
+	unregister_netdev(dev);
+
+	release_region(dev->base_addr, 16);
+	release_region(dev->base_addr + 0x800, 4096);
+	kfree(dev);
+}
+
+static const struct ecard_id ether1_ids[] = {
+	{ MANU_ACORN, PROD_ACORN_ETHER1 },
+	{ 0xffff, 0xffff }
+};
+
+static struct ecard_driver ether1_driver = {
+	.probe		= ether1_probe,
+	.remove		= __devexit_p(ether1_remove),
+	.id_table	= ether1_ids,
+	.drv = {
+		.name	= "ether1",
+	},
+};
+
+static int __init ether1_init(void)
+{
+	return ecard_register_driver(&ether1_driver);
+}
+
+static void __exit ether1_exit(void)
+{
+	ecard_remove_driver(&ether1_driver);
+}
+
+module_init(ether1_init);
+module_exit(ether1_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/net/arm/ether1.h b/drivers/net/arm/ether1.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/ether1.h	Thu May 15 17:41:33 2003
@@ -0,0 +1,278 @@
+/*
+ *  linux/drivers/acorn/net/ether1.h
+ *
+ *  Copyright (C) 1996 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.
+ *
+ *  Network driver for Acorn Ether1 cards.
+ */
+
+#ifndef _LINUX_ether1_H
+#define _LINUX_ether1_H
+
+#ifdef __ETHER1_C
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 0
+#endif
+
+/* Page register */
+#define REG_PAGE	(dev->base_addr + 0x00)
+
+/* Control register */
+#define REG_CONTROL	(dev->base_addr + 0x01)
+#define CTRL_RST	0x01
+#define CTRL_LOOPBACK	0x02
+#define CTRL_CA		0x04
+#define CTRL_ACK	0x08
+
+#define ETHER1_RAM	(dev->base_addr + 0x800)
+
+/* HW address */
+#define IDPROM_ADDRESS	(dev->base_addr + 0x09)
+
+struct ether1_priv {
+	struct net_device_stats stats;
+	unsigned int tx_link;
+	unsigned int tx_head;
+	volatile unsigned int tx_tail;
+	volatile unsigned int rx_head;
+	volatile unsigned int rx_tail;
+	unsigned char bus_type;
+	unsigned char resetting;
+	unsigned char initialising : 1;
+	unsigned char restart      : 1;
+};
+
+#define I82586_NULL (-1)
+
+typedef struct { /* tdr */
+	unsigned short tdr_status;
+	unsigned short tdr_command;
+	unsigned short tdr_link;
+	unsigned short tdr_result;
+#define TDR_TIME	(0x7ff)
+#define TDR_SHORT	(1 << 12)
+#define TDR_OPEN	(1 << 13)
+#define TDR_XCVRPROB	(1 << 14)
+#define TDR_LNKOK	(1 << 15)
+} tdr_t;
+
+typedef struct { /* transmit */
+	unsigned short tx_status;
+	unsigned short tx_command;
+	unsigned short tx_link;
+	unsigned short tx_tbdoffset;
+} tx_t;
+
+typedef struct { /* tbd */
+	unsigned short tbd_opts;
+#define TBD_CNT		(0x3fff)
+#define TBD_EOL		(1 << 15)
+	unsigned short tbd_link;
+	unsigned short tbd_bufl;
+	unsigned short tbd_bufh;
+} tbd_t;
+
+typedef struct { /* rfd */
+	unsigned short rfd_status;
+#define RFD_NOEOF	(1 << 6)
+#define RFD_FRAMESHORT	(1 << 7)
+#define RFD_DMAOVRN	(1 << 8)
+#define RFD_NORESOURCES	(1 << 9)
+#define RFD_ALIGNERROR	(1 << 10)
+#define RFD_CRCERROR	(1 << 11)
+#define RFD_OK		(1 << 13)
+#define RFD_FDCONSUMED	(1 << 14)
+#define RFD_COMPLETE	(1 << 15)
+	unsigned short rfd_command;
+#define RFD_CMDSUSPEND	(1 << 14)
+#define RFD_CMDEL	(1 << 15)
+	unsigned short rfd_link;
+	unsigned short rfd_rbdoffset;
+	unsigned char  rfd_dest[6];
+	unsigned char  rfd_src[6];
+	unsigned short rfd_len;
+} rfd_t;
+
+typedef struct { /* rbd */
+	unsigned short rbd_status;
+#define RBD_ACNT	(0x3fff)
+#define RBD_ACNTVALID	(1 << 14)
+#define RBD_EOF		(1 << 15)
+	unsigned short rbd_link;
+	unsigned short rbd_bufl;
+	unsigned short rbd_bufh;
+	unsigned short rbd_len;
+} rbd_t;
+
+typedef struct { /* nop */
+	unsigned short nop_status;
+	unsigned short nop_command;
+	unsigned short nop_link;
+} nop_t;
+
+typedef struct { /* set multicast */
+	unsigned short mc_status;
+	unsigned short mc_command;
+	unsigned short mc_link;
+	unsigned short mc_cnt;
+	unsigned char  mc_addrs[1][6];
+} mc_t;
+
+typedef struct { /* set address */
+	unsigned short sa_status;
+	unsigned short sa_command;
+	unsigned short sa_link;
+	unsigned char  sa_addr[6];
+} sa_t;
+
+typedef struct { /* config command */
+	unsigned short cfg_status;
+	unsigned short cfg_command;
+	unsigned short cfg_link;
+	unsigned char  cfg_bytecnt;	/* size foll data: 4 - 12		 */
+	unsigned char  cfg_fifolim;	/* FIFO threshold			 */
+	unsigned char  cfg_byte8;
+#define CFG8_SRDY	(1 << 6)
+#define CFG8_SAVEBADF	(1 << 7)
+	unsigned char  cfg_byte9;
+#define CFG9_ADDRLEN(x)	(x)
+#define CFG9_ADDRLENBUF	(1 << 3)
+#define CFG9_PREAMB2	(0 << 4)
+#define CFG9_PREAMB4	(1 << 4)
+#define CFG9_PREAMB8	(2 << 4)
+#define CFG9_PREAMB16	(3 << 4)
+#define CFG9_ILOOPBACK	(1 << 6)
+#define CFG9_ELOOPBACK	(1 << 7)
+	unsigned char  cfg_byte10;
+#define CFG10_LINPRI(x)	(x)
+#define CFG10_ACR(x)	(x << 4)
+#define CFG10_BOFMET	(1 << 7)
+	unsigned char  cfg_ifs;
+	unsigned char  cfg_slotl;
+	unsigned char  cfg_byte13;
+#define CFG13_SLOTH(x)	(x)
+#define CFG13_RETRY(x)	(x << 4)
+	unsigned char  cfg_byte14;
+#define CFG14_PROMISC	(1 << 0)
+#define CFG14_DISBRD	(1 << 1)
+#define CFG14_MANCH	(1 << 2)
+#define CFG14_TNCRS	(1 << 3)
+#define CFG14_NOCRC	(1 << 4)
+#define CFG14_CRC16	(1 << 5)
+#define CFG14_BTSTF	(1 << 6)
+#define CFG14_FLGPAD	(1 << 7)
+	unsigned char  cfg_byte15;
+#define CFG15_CSTF(x)	(x)
+#define CFG15_ICSS	(1 << 3)
+#define CFG15_CDTF(x)	(x << 4)
+#define CFG15_ICDS	(1 << 7)
+	unsigned short cfg_minfrmlen;
+} cfg_t;
+
+typedef struct { /* scb */
+	unsigned short scb_status;	/* status of 82586			*/
+#define SCB_STRXMASK		(7 << 4)	/* Receive unit status		*/
+#define SCB_STRXIDLE		(0 << 4)	/* Idle				*/
+#define SCB_STRXSUSP		(1 << 4)	/* Suspended			*/
+#define SCB_STRXNRES		(2 << 4)	/* No resources			*/
+#define SCB_STRXRDY		(4 << 4)	/* Ready			*/
+#define SCB_STCUMASK		(7 << 8)	/* Command unit status		*/
+#define SCB_STCUIDLE		(0 << 8)	/* Idle				*/
+#define SCB_STCUSUSP		(1 << 8)	/* Suspended			*/
+#define SCB_STCUACTV		(2 << 8)	/* Active			*/
+#define SCB_STRNR		(1 << 12)	/* Receive unit not ready	*/
+#define SCB_STCNA		(1 << 13)	/* Command unit not ready	*/
+#define SCB_STFR		(1 << 14)	/* Frame received		*/
+#define SCB_STCX		(1 << 15)	/* Command completed		*/
+	unsigned short scb_command;	/* Next command				*/
+#define SCB_CMDRXSTART		(1 << 4)	/* Start (at rfa_offset)	*/
+#define SCB_CMDRXRESUME		(2 << 4)	/* Resume reception		*/
+#define SCB_CMDRXSUSPEND	(3 << 4)	/* Suspend reception		*/
+#define SCB_CMDRXABORT		(4 << 4)	/* Abort reception		*/
+#define SCB_CMDCUCSTART		(1 << 8)	/* Start (at cbl_offset)	*/
+#define SCB_CMDCUCRESUME	(2 << 8)	/* Resume execution		*/
+#define SCB_CMDCUCSUSPEND	(3 << 8)	/* Suspend execution		*/
+#define SCB_CMDCUCABORT		(4 << 8)	/* Abort execution		*/
+#define SCB_CMDACKRNR		(1 << 12)	/* Ack RU not ready		*/
+#define SCB_CMDACKCNA		(1 << 13)	/* Ack CU not ready		*/
+#define SCB_CMDACKFR		(1 << 14)	/* Ack Frame received		*/
+#define SCB_CMDACKCX		(1 << 15)	/* Ack Command complete		*/
+	unsigned short scb_cbl_offset;	/* Offset of first command unit		*/
+	unsigned short scb_rfa_offset;	/* Offset of first receive frame area	*/
+	unsigned short scb_crc_errors;	/* Properly aligned frame with CRC error*/
+	unsigned short scb_aln_errors;	/* Misaligned frames			*/
+	unsigned short scb_rsc_errors;	/* Frames lost due to no space		*/
+	unsigned short scb_ovn_errors;	/* Frames lost due to slow bus		*/
+} scb_t;
+
+typedef struct { /* iscp */
+	unsigned short iscp_busy;	/* set by CPU before CA			*/
+	unsigned short iscp_offset;	/* offset of SCB			*/
+	unsigned short iscp_basel;	/* base of SCB				*/
+	unsigned short iscp_baseh;
+} iscp_t;
+
+    /* this address must be 0xfff6 */
+typedef struct { /* scp */
+	unsigned short scp_sysbus;	/* bus size */
+#define SCP_SY_16BBUS	0x00
+#define SCP_SY_8BBUS	0x01
+	unsigned short scp_junk[2];	/* junk */
+	unsigned short scp_iscpl;	/* lower 16 bits of iscp */
+	unsigned short scp_iscph;	/* upper 16 bits of iscp */
+} scp_t;
+
+/* commands */
+#define CMD_NOP			0
+#define CMD_SETADDRESS		1
+#define CMD_CONFIG		2
+#define CMD_SETMULTICAST	3
+#define CMD_TX			4
+#define CMD_TDR			5
+#define CMD_DUMP		6
+#define CMD_DIAGNOSE		7
+
+#define CMD_MASK		7
+
+#define CMD_INTR		(1 << 13)
+#define CMD_SUSP		(1 << 14)
+#define CMD_EOL			(1 << 15)
+
+#define STAT_COLLISIONS		(15)
+#define STAT_COLLEXCESSIVE	(1 << 5)
+#define STAT_COLLAFTERTX	(1 << 6)
+#define STAT_TXDEFERRED		(1 << 7)
+#define STAT_TXSLOWDMA		(1 << 8)
+#define STAT_TXLOSTCTS		(1 << 9)
+#define STAT_NOCARRIER		(1 << 10)
+#define STAT_FAIL		(1 << 11)
+#define STAT_ABORTED		(1 << 12)
+#define STAT_OK			(1 << 13)
+#define STAT_BUSY		(1 << 14)
+#define STAT_COMPLETE		(1 << 15)
+#endif
+#endif
+
+/*
+ * Ether1 card definitions:
+ *
+ * FAST accesses:
+ *	+0	Page register
+ * 			16 pages
+ *	+4	Control
+ *			'1' = reset
+ *			'2' = loopback
+ *			'4' = CA
+ *			'8' = int ack
+ *
+ * RAM at address + 0x2000
+ * Pod. Prod id = 3
+ * Words after ID block [base + 8 words]
+ *	+0 pcb issue (0x0c and 0xf3 invalid)
+ *	+1 - +6 eth hw address
+ */
diff -Nru a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/ether3.c	Thu May 15 17:41:33 2003
@@ -0,0 +1,947 @@
+/*
+ *  linux/drivers/acorn/net/ether3.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.
+ *
+ * SEEQ nq8005 ethernet driver for Acorn/ANT Ether3 card
+ *  for Acorn machines
+ *
+ * By Russell King, with some suggestions from borris@ant.co.uk
+ *
+ * Changelog:
+ * 1.04	RMK	29/02/1996	Won't pass packets that are from our ethernet
+ *				address up to the higher levels - they're
+ *				silently ignored.  I/F can now be put into
+ *				multicast mode.  Receiver routine optimised.
+ * 1.05	RMK	30/02/1996	Now claims interrupt at open when part of
+ *				the kernel rather than when a module.
+ * 1.06	RMK	02/03/1996	Various code cleanups
+ * 1.07	RMK	13/10/1996	Optimised interrupt routine and transmit
+ *				routines.
+ * 1.08	RMK	14/10/1996	Fixed problem with too many packets,
+ *				prevented the kernel message about dropped
+ *				packets appearing too many times a second.
+ *				Now does not disable all IRQs, only the IRQ
+ *				used by this card.
+ * 1.09	RMK	10/11/1996	Only enables TX irq when buffer space is low,
+ *				but we still service the TX queue if we get a
+ *				RX interrupt.
+ * 1.10	RMK	15/07/1997	Fixed autoprobing of NQ8004.
+ * 1.11	RMK	16/11/1997	Fixed autoprobing of NQ8005A.
+ * 1.12	RMK	31/12/1997	Removed reference to dev_tint for Linux 2.1.
+ *      RMK	27/06/1998	Changed asm/delay.h to linux/delay.h.
+ * 1.13	RMK	29/06/1998	Fixed problem with transmission of packets.
+ *				Chip seems to have a bug in, whereby if the
+ *				packet starts two bytes from the end of the
+ *				buffer, it corrupts the receiver chain, and
+ *				never updates the transmit status correctly.
+ * 1.14	RMK	07/01/1998	Added initial code for ETHERB addressing.
+ * 1.15	RMK	30/04/1999	More fixes to the transmit routine for buggy
+ *				hardware.
+ * 1.16	RMK	10/02/2000	Updated for 2.3.43
+ * 1.17	RMK	13/05/2000	Updated for 2.3.99-pre8
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+static char version[] __initdata = "ether3 ethernet driver (c) 1995-2000 R.M.King v1.17\n";
+
+#include "ether3.h"
+
+static unsigned int net_debug = NET_DEBUG;
+
+static void	ether3_setmulticastlist(struct net_device *dev);
+static int	ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt);
+static void	ether3_tx(struct net_device *dev, struct dev_priv *priv);
+static int	ether3_open (struct net_device *dev);
+static int	ether3_sendpacket (struct sk_buff *skb, struct net_device *dev);
+static irqreturn_t ether3_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+static int	ether3_close (struct net_device *dev);
+static struct net_device_stats *ether3_getstats (struct net_device *dev);
+static void	ether3_setmulticastlist (struct net_device *dev);
+static void	ether3_timeout(struct net_device *dev);
+
+#define BUS_16		2
+#define BUS_8		1
+#define BUS_UNKNOWN	0
+
+/* --------------------------------------------------------------------------- */
+
+typedef enum {
+	buffer_write,
+	buffer_read
+} buffer_rw_t;
+
+/*
+ * ether3 read/write.  Slow things down a bit...
+ * The SEEQ8005 doesn't like us writing to its registers
+ * too quickly.
+ */
+static inline void ether3_outb(int v, const int r)
+{
+	outb(v, r);
+	udelay(1);
+}
+
+static inline void ether3_outw(int v, const int r)
+{
+	outw(v, r);
+	udelay(1);
+}
+#define ether3_inb(r)		({ unsigned int __v = inb((r)); udelay(1); __v; })
+#define ether3_inw(r)		({ unsigned int __v = inw((r)); udelay(1); __v; })
+
+static int
+ether3_setbuffer(struct net_device *dev, buffer_rw_t read, int start)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	int timeout = 1000;
+
+	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
+
+	while ((ether3_inw(REG_STATUS) & STAT_FIFOEMPTY) == 0) {
+		if (!timeout--) {
+			printk("%s: setbuffer broken\n", dev->name);
+			priv->broken = 1;
+			return 1;
+		}
+		udelay(1);
+	}
+
+	if (read == buffer_read) {
+		ether3_outw(start, REG_DMAADDR);
+		ether3_outw(priv->regs.command | CMD_FIFOREAD, REG_COMMAND);
+	} else {
+		ether3_outw(priv->regs.command | CMD_FIFOWRITE, REG_COMMAND);
+		ether3_outw(start, REG_DMAADDR);
+	}
+	return 0;
+}
+
+/*
+ * write data to the buffer memory
+ */
+#define ether3_writebuffer(dev,data,length)			\
+	outsw(REG_BUFWIN, (data), (length) >> 1)
+
+#define ether3_writeword(dev,data)				\
+	outw((data), REG_BUFWIN)
+
+#define ether3_writelong(dev,data)	{			\
+	unsigned long reg_bufwin = REG_BUFWIN;			\
+	outw((data), reg_bufwin);				\
+	outw((data) >> 16, reg_bufwin);				\
+}
+
+/*
+ * read data from the buffer memory
+ */
+#define ether3_readbuffer(dev,data,length)			\
+	insw(REG_BUFWIN, (data), (length) >> 1)
+
+#define ether3_readword(dev)					\
+	inw(REG_BUFWIN)
+
+#define ether3_readlong(dev)	 				\
+	inw(REG_BUFWIN) | (inw(REG_BUFWIN) << 16)
+
+/*
+ * Switch LED off...
+ */
+static void
+ether3_ledoff(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	ether3_outw(priv->regs.config2 |= CFG2_CTRLO, REG_CONFIG2);
+}
+
+/*
+ * switch LED on...
+ */
+static inline void
+ether3_ledon(struct net_device *dev, struct dev_priv *priv)
+{
+	del_timer(&priv->timer);
+	priv->timer.expires = jiffies + HZ / 50; /* leave on for 1/50th second */
+	priv->timer.data = (unsigned long)dev;
+	priv->timer.function = ether3_ledoff;
+	add_timer(&priv->timer);
+	if (priv->regs.config2 & CFG2_CTRLO)
+		ether3_outw(priv->regs.config2 &= ~CFG2_CTRLO, REG_CONFIG2);
+}
+
+/*
+ * Read the ethernet address string from the on board rom.
+ * This is an ascii string!!!
+ */
+static int __init
+ether3_addr(char *addr, struct expansion_card *ec)
+{
+	struct in_chunk_dir cd;
+	char *s;
+	
+	if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
+		int i;
+		for (i = 0; i<6; i++) {
+			addr[i] = simple_strtoul(s + 1, &s, 0x10);
+			if (*s != (i==5?')' : ':' ))
+				break;
+		}
+		if (i == 6)
+			return 0;
+	}
+	/* I wonder if we should even let the user continue in this case
+	 *   - no, it would be better to disable the device
+	 */
+	printk(KERN_ERR "ether3: Couldn't read a valid MAC address from card.\n");
+	return -ENODEV;
+}
+
+/* --------------------------------------------------------------------------- */
+
+static int __init
+ether3_ramtest(struct net_device *dev, unsigned char byte)
+{
+	unsigned char *buffer = kmalloc(RX_END, GFP_KERNEL);
+	int i,ret = 0;
+	int max_errors = 4;
+	int bad = -1;
+
+	if (!buffer)
+		return 1;
+
+	memset(buffer, byte, RX_END);
+	ether3_setbuffer(dev, buffer_write, 0);
+	ether3_writebuffer(dev, buffer, TX_END);
+	ether3_setbuffer(dev, buffer_write, RX_START);
+	ether3_writebuffer(dev, buffer + RX_START, RX_LEN);
+	memset(buffer, byte ^ 0xff, RX_END);
+	ether3_setbuffer(dev, buffer_read, 0);
+	ether3_readbuffer(dev, buffer, TX_END);
+	ether3_setbuffer(dev, buffer_read, RX_START);
+	ether3_readbuffer(dev, buffer + RX_START, RX_LEN);
+
+	for (i = 0; i < RX_END; i++) {
+		if (buffer[i] != byte) {
+			if (max_errors > 0 && bad != buffer[i]) {
+				printk("%s: RAM failed with (%02X instead of %02X) at 0x%04X",
+				       dev->name, buffer[i], byte, i);
+				ret = 2;
+				max_errors--;
+				bad = i;
+			}
+		} else {
+			if (bad != -1) {
+				if (bad != i - 1)
+					printk(" - 0x%04X\n", i - 1);
+				printk("\n");
+				bad = -1;
+			}
+		}
+	}
+	if (bad != -1)
+		printk(" - 0xffff\n");
+	kfree(buffer);
+
+	return ret;
+}
+
+/* ------------------------------------------------------------------------------- */
+
+static int __init
+ether3_init_2(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	int i;
+
+	priv->regs.config1 = CFG1_RECVCOMPSTAT0|CFG1_DMABURST8;
+	priv->regs.config2 = CFG2_CTRLO|CFG2_RECVCRC|CFG2_ERRENCRC;
+	priv->regs.command = 0;
+
+	/*
+	 * Set up our hardware address
+	 */
+	ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
+	for (i = 0; i < 6; i++)
+		ether3_outb(dev->dev_addr[i], REG_BUFWIN);
+
+	if (dev->flags & IFF_PROMISC)
+		priv->regs.config1 |= CFG1_RECVPROMISC;
+	else if (dev->flags & IFF_MULTICAST)
+		priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
+	else
+		priv->regs.config1 |= CFG1_RECVSPECBROAD;
+
+	/*
+	 * There is a problem with the NQ8005 in that it occasionally loses the
+	 * last two bytes.  To get round this problem, we receive the CRC as
+	 * well.  That way, if we do lose the last two, then it doesn't matter.
+	 */
+	ether3_outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
+	ether3_outw((TX_END>>8) - 1, REG_BUFWIN);
+	ether3_outw(priv->rx_head, REG_RECVPTR);
+	ether3_outw(0, REG_TRANSMITPTR);
+	ether3_outw(priv->rx_head >> 8, REG_RECVEND);
+	ether3_outw(priv->regs.config2, REG_CONFIG2);
+	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+	ether3_outw(priv->regs.command, REG_COMMAND);
+
+	i = ether3_ramtest(dev, 0x5A);
+	if(i)
+		return i;
+	i = ether3_ramtest(dev, 0x1E);
+	if(i)
+		return i;
+
+	ether3_setbuffer(dev, buffer_write, 0);
+	ether3_writelong(dev, 0);
+	return 0;
+}
+
+static void
+ether3_init_for_open(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	int i;
+
+	memset(&priv->stats, 0, sizeof(struct net_device_stats));
+
+	/* Reset the chip */
+	ether3_outw(CFG2_RESET, REG_CONFIG2);
+	udelay(4);
+
+	priv->regs.command = 0;
+	ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
+	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
+
+	ether3_outw(priv->regs.config1 | CFG1_BUFSELSTAT0, REG_CONFIG1);
+	for (i = 0; i < 6; i++)
+		ether3_outb(dev->dev_addr[i], REG_BUFWIN);
+
+	priv->tx_head	= 0;
+	priv->tx_tail	= 0;
+	priv->regs.config2 |= CFG2_CTRLO;
+	priv->rx_head	= RX_START;
+
+	ether3_outw(priv->regs.config1 | CFG1_TRANSEND, REG_CONFIG1);
+	ether3_outw((TX_END>>8) - 1, REG_BUFWIN);
+	ether3_outw(priv->rx_head, REG_RECVPTR);
+	ether3_outw(priv->rx_head >> 8, REG_RECVEND);
+	ether3_outw(0, REG_TRANSMITPTR);
+	ether3_outw(priv->regs.config2, REG_CONFIG2);
+	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+
+	ether3_setbuffer(dev, buffer_write, 0);
+	ether3_writelong(dev, 0);
+
+	priv->regs.command = CMD_ENINTRX | CMD_ENINTTX;
+	ether3_outw(priv->regs.command | CMD_RXON, REG_COMMAND);
+}
+
+static inline int
+ether3_probe_bus_8(struct net_device *dev, int val)
+{
+	int write_low, write_high, read_low, read_high;
+
+	write_low = val & 255;
+	write_high = val >> 8;
+
+	printk(KERN_DEBUG "ether3_probe: write8 [%02X:%02X]", write_high, write_low);
+
+	ether3_outb(write_low, REG_RECVPTR);
+	ether3_outb(write_high, REG_RECVPTR + 1);
+
+	read_low = ether3_inb(REG_RECVPTR);
+	read_high = ether3_inb(REG_RECVPTR + 1);
+
+	printk(", read8 [%02X:%02X]\n", read_high, read_low);
+
+	return read_low == write_low && read_high == write_high;
+}
+
+static inline int
+ether3_probe_bus_16(struct net_device *dev, int val)
+{
+	int read_val;
+
+	ether3_outw(val, REG_RECVPTR);
+	read_val = ether3_inw(REG_RECVPTR);
+
+	printk(KERN_DEBUG "ether3_probe: write16 [%04X], read16 [%04X]\n", val, read_val);
+
+	return read_val == val;
+}
+
+/*
+ * Open/initialize the board.  This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+static int
+ether3_open(struct net_device *dev)
+{
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
+			dev->name);
+		return -EINVAL;
+	}
+
+	if (request_irq(dev->irq, ether3_interrupt, 0, "ether3", dev))
+		return -EAGAIN;
+
+	ether3_init_for_open(dev);
+
+	netif_start_queue(dev);
+
+	return 0;
+}
+
+/*
+ * The inverse routine to ether3_open().
+ */
+static int
+ether3_close(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+
+	netif_stop_queue(dev);
+
+	disable_irq(dev->irq);
+
+	ether3_outw(CMD_RXOFF|CMD_TXOFF, REG_COMMAND);
+	priv->regs.command = 0;
+	while (ether3_inw(REG_STATUS) & (STAT_RXON|STAT_TXON));
+	ether3_outb(0x80, REG_CONFIG2 + 1);
+	ether3_outw(0, REG_COMMAND);
+
+	free_irq(dev->irq, dev);
+
+	return 0;
+}
+
+/*
+ * Get the current statistics.	This may be called with the card open or
+ * closed.
+ */
+static struct net_device_stats *ether3_getstats(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	return &priv->stats;
+}
+
+/*
+ * Set or clear promiscuous/multicast mode filter for this adaptor.
+ *
+ * We don't attempt any packet filtering.  The card may have a SEEQ 8004
+ * in which does not have the other ethernet address registers present...
+ */
+static void ether3_setmulticastlist(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+
+	priv->regs.config1 &= ~CFG1_RECVPROMISC;
+
+	if (dev->flags & IFF_PROMISC) {
+		/* promiscuous mode */
+		priv->regs.config1 |= CFG1_RECVPROMISC;
+	} else if (dev->flags & IFF_ALLMULTI) {
+		priv->regs.config1 |= CFG1_RECVSPECBRMULTI;
+	} else
+		priv->regs.config1 |= CFG1_RECVSPECBROAD;
+
+	ether3_outw(priv->regs.config1 | CFG1_LOCBUFMEM, REG_CONFIG1);
+}
+
+static void
+ether3_timeout(struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	unsigned long flags;
+
+	del_timer(&priv->timer);
+
+	local_irq_save(flags);
+	printk(KERN_ERR "%s: transmit timed out, network cable problem?\n", dev->name);
+	printk(KERN_ERR "%s: state: { status=%04X cfg1=%04X cfg2=%04X }\n", dev->name,
+		ether3_inw(REG_STATUS), ether3_inw(REG_CONFIG1), ether3_inw(REG_CONFIG2));
+	printk(KERN_ERR "%s: { rpr=%04X rea=%04X tpr=%04X }\n", dev->name,
+		ether3_inw(REG_RECVPTR), ether3_inw(REG_RECVEND), ether3_inw(REG_TRANSMITPTR));
+	printk(KERN_ERR "%s: tx head=%X tx tail=%X\n", dev->name,
+		priv->tx_head, priv->tx_tail);
+	ether3_setbuffer(dev, buffer_read, priv->tx_tail);
+	printk(KERN_ERR "%s: packet status = %08X\n", dev->name, ether3_readlong(dev));
+	local_irq_restore(flags);
+
+	priv->regs.config2 |= CFG2_CTRLO;
+	priv->stats.tx_errors += 1;
+	ether3_outw(priv->regs.config2, REG_CONFIG2);
+	priv->tx_head = priv->tx_tail = 0;
+
+	netif_wake_queue(dev);
+}
+
+/*
+ * Transmit a packet
+ */
+static int
+ether3_sendpacket(struct sk_buff *skb, struct net_device *dev)
+{
+	struct dev_priv *priv = (struct dev_priv *)dev->priv;
+	unsigned long flags;
+	unsigned int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned int ptr, next_ptr;
+
+	length = (length + 1) & ~1;
+
+	if (priv->broken) {
+		dev_kfree_skb(skb);
+		priv->stats.tx_dropped ++;
+		netif_start_queue(dev);
+		return 0;
+	}
+
+	next_ptr = (priv->tx_head + 1) & 15;
+
+	local_irq_save(flags);
+
+	if (priv->tx_tail == next_ptr) {
+		local_irq_restore(flags);
+		return 1;	/* unable to queue */
+	}
+
+	dev->trans_start = jiffies;
+	ptr		 = 0x600 * priv->tx_head;
+	priv->tx_head	 = next_ptr;
+	next_ptr	*= 0x600;
+
+#define TXHDR_FLAGS (TXHDR_TRANSMIT|TXHDR_CHAINCONTINUE|TXHDR_DATAFOLLOWS|TXHDR_ENSUCCESS)
+
+	ether3_setbuffer(dev, buffer_write, next_ptr);
+	ether3_writelong(dev, 0);
+	ether3_setbuffer(dev, buffer_write, ptr);
+	ether3_writelong(dev, 0);
+	ether3_writebuffer(dev, skb->data, length);
+	ether3_writeword(dev, htons(next_ptr));
+	ether3_writeword(dev, TXHDR_CHAINCONTINUE >> 16);
+	ether3_setbuffer(dev, buffer_write, ptr);
+	ether3_writeword(dev, htons((ptr + length + 4)));
+	ether3_writeword(dev, TXHDR_FLAGS >> 16);
+	ether3_ledon(dev, priv);
+
+	if (!(ether3_inw(REG_STATUS) & STAT_TXON)) {
+		ether3_outw(ptr, REG_TRANSMITPTR);
+		ether3_outw(priv->regs.command | CMD_TXON, REG_COMMAND);
+	}
+
+	next_ptr = (priv->tx_head + 1) & 15;
+	local_irq_restore(flags);
+
+	dev_kfree_skb(skb);
+
+	if (priv->tx_tail == next_ptr)
+		netif_stop_queue(dev);
+
+	return 0;
+}
+
+static irqreturn_t
+ether3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_id;
+	struct dev_priv *priv;
+	unsigned int status, handled = IRQ_NONE;
+
+#if NET_DEBUG > 1
+	if(net_debug & DEBUG_INT)
+		printk("eth3irq: %d ", irq);
+#endif
+
+	priv = (struct dev_priv *)dev->priv;
+
+	status = ether3_inw(REG_STATUS);
+
+	if (status & STAT_INTRX) {
+		ether3_outw(CMD_ACKINTRX | priv->regs.command, REG_COMMAND);
+		ether3_rx(dev, priv, 12);
+		handled = IRQ_HANDLED;
+	}
+
+	if (status & STAT_INTTX) {
+		ether3_outw(CMD_ACKINTTX | priv->regs.command, REG_COMMAND);
+		ether3_tx(dev, priv);
+		handled = IRQ_HANDLED;
+	}
+
+#if NET_DEBUG > 1
+	if(net_debug & DEBUG_INT)
+		printk("done\n");
+#endif
+	return handled;
+}
+
+/*
+ * If we have a good packet(s), get it/them out of the buffers.
+ */
+static int
+ether3_rx(struct net_device *dev, struct dev_priv *priv, unsigned int maxcnt)
+{
+	unsigned int next_ptr = priv->rx_head, received = 0;
+	ether3_ledon(dev, priv);
+
+	do {
+		unsigned int this_ptr, status;
+		unsigned char addrs[16];
+
+		/*
+		 * read the first 16 bytes from the buffer.
+		 * This contains the status bytes etc and ethernet addresses,
+		 * and we also check the source ethernet address to see if
+		 * it originated from us.
+		 */
+		{
+			unsigned int temp_ptr;
+			ether3_setbuffer(dev, buffer_read, next_ptr);
+			temp_ptr = ether3_readword(dev);
+			status = ether3_readword(dev);
+			if ((status & (RXSTAT_DONE | RXHDR_CHAINCONTINUE | RXHDR_RECEIVE)) !=
+				(RXSTAT_DONE | RXHDR_CHAINCONTINUE) || !temp_ptr)
+				break;
+
+			this_ptr = next_ptr + 4;
+			next_ptr = ntohs(temp_ptr);
+		}
+		ether3_setbuffer(dev, buffer_read, this_ptr);
+		ether3_readbuffer(dev, addrs+2, 12);
+
+if (next_ptr < RX_START || next_ptr >= RX_END) {
+ int i;
+ printk("%s: bad next pointer @%04X: ", dev->name, priv->rx_head);
+ printk("%02X %02X %02X %02X ", next_ptr >> 8, next_ptr & 255, status & 255, status >> 8);
+ for (i = 2; i < 14; i++)
+   printk("%02X ", addrs[i]);
+ printk("\n");
+ next_ptr = priv->rx_head;
+ break;
+}
+		/*
+ 		 * ignore our own packets...
+	 	 */
+		if (!(*(unsigned long *)&dev->dev_addr[0] ^ *(unsigned long *)&addrs[2+6]) &&
+		    !(*(unsigned short *)&dev->dev_addr[4] ^ *(unsigned short *)&addrs[2+10])) {
+			maxcnt ++; /* compensate for loopedback packet */
+			ether3_outw(next_ptr >> 8, REG_RECVEND);
+		} else
+		if (!(status & (RXSTAT_OVERSIZE|RXSTAT_CRCERROR|RXSTAT_DRIBBLEERROR|RXSTAT_SHORTPACKET))) {
+			unsigned int length = next_ptr - this_ptr;
+			struct sk_buff *skb;
+
+			if (next_ptr <= this_ptr)
+				length += RX_END - RX_START;
+
+			skb = dev_alloc_skb(length + 2);
+			if (skb) {
+				unsigned char *buf;
+
+				skb->dev = dev;
+				skb_reserve(skb, 2);
+				buf = skb_put(skb, length);
+				ether3_readbuffer(dev, buf + 12, length - 12);
+				ether3_outw(next_ptr >> 8, REG_RECVEND);
+				*(unsigned short *)(buf + 0)	= *(unsigned short *)(addrs + 2);
+				*(unsigned long *)(buf + 2)	= *(unsigned long *)(addrs + 4);
+				*(unsigned long *)(buf + 6)	= *(unsigned long *)(addrs + 8);
+				*(unsigned short *)(buf + 10)	= *(unsigned short *)(addrs + 12);
+				skb->protocol = eth_type_trans(skb, dev);
+				netif_rx(skb);
+				received ++;
+			} else
+				goto dropping;
+		} else {
+			struct net_device_stats *stats = &priv->stats;
+			ether3_outw(next_ptr >> 8, REG_RECVEND);
+			if (status & RXSTAT_OVERSIZE)	  stats->rx_over_errors ++;
+			if (status & RXSTAT_CRCERROR)	  stats->rx_crc_errors ++;
+			if (status & RXSTAT_DRIBBLEERROR) stats->rx_fifo_errors ++;
+			if (status & RXSTAT_SHORTPACKET)  stats->rx_length_errors ++;
+			stats->rx_errors++;
+		}
+	}
+	while (-- maxcnt);
+
+done:
+	priv->stats.rx_packets += received;
+	priv->rx_head = next_ptr;
+	/*
+	 * If rx went off line, then that means that the buffer may be full.  We
+	 * have dropped at least one packet.
+	 */
+	if (!(ether3_inw(REG_STATUS) & STAT_RXON)) {
+		priv->stats.rx_dropped ++;
+    		ether3_outw(next_ptr, REG_RECVPTR);
+		ether3_outw(priv->regs.command | CMD_RXON, REG_COMMAND);
+	}
+
+	return maxcnt;
+
+dropping:{
+	static unsigned long last_warned;
+
+	ether3_outw(next_ptr >> 8, REG_RECVEND);
+	/*
+	 * Don't print this message too many times...
+	 */
+	if (time_after(jiffies, last_warned + 10 * HZ)) {
+		last_warned = jiffies;
+		printk("%s: memory squeeze, dropping packet.\n", dev->name);
+	}
+	priv->stats.rx_dropped ++;
+	goto done;
+	}
+}
+
+/*
+ * Update stats for the transmitted packet(s)
+ */
+static void
+ether3_tx(struct net_device *dev, struct dev_priv *priv)
+{
+	unsigned int tx_tail = priv->tx_tail;
+	int max_work = 14;
+
+	do {
+	    	unsigned long status;
+
+    		/*
+	    	 * Read the packet header
+    		 */
+	    	ether3_setbuffer(dev, buffer_read, tx_tail * 0x600);
+    		status = ether3_readlong(dev);
+
+		/*
+		 * Check to see if this packet has been transmitted
+		 */
+		if ((status & (TXSTAT_DONE | TXHDR_TRANSMIT)) !=
+		    (TXSTAT_DONE | TXHDR_TRANSMIT))
+			break;
+
+		/*
+		 * Update errors
+		 */
+		if (!(status & (TXSTAT_BABBLED | TXSTAT_16COLLISIONS)))
+			priv->stats.tx_packets++;
+		else {
+			priv->stats.tx_errors ++;
+			if (status & TXSTAT_16COLLISIONS) priv->stats.collisions += 16;
+			if (status & TXSTAT_BABBLED) priv->stats.tx_fifo_errors ++;
+		}
+
+		tx_tail = (tx_tail + 1) & 15;
+	} while (--max_work);
+
+	if (priv->tx_tail != tx_tail) {
+		priv->tx_tail = tx_tail;
+		netif_wake_queue(dev);
+	}
+}
+
+static void __init ether3_banner(void)
+{
+	static unsigned version_printed = 0;
+
+	if (net_debug && version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+}
+
+static const char * __init
+ether3_get_dev(struct net_device *dev, struct expansion_card *ec)
+{
+	const char *name = "ether3";
+
+	dev->base_addr = ecard_address(ec, ECARD_MEMC, 0);
+	dev->irq = ec->irq;
+
+	if (ec->cid.manufacturer == MANU_ANT &&
+	    ec->cid.product == PROD_ANT_ETHERB) {
+		dev->base_addr += 0x200;
+		name = "etherb";
+	}
+
+	ec->irqaddr = (volatile unsigned char *)ioaddr(dev->base_addr);
+	ec->irqmask = 0xf0;
+
+	ether3_addr(dev->dev_addr, ec);
+
+	return name;
+}
+
+static int __devinit
+ether3_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct net_device *dev;
+	struct dev_priv *priv;
+	const char *name;
+	int i, bus_type, ret;
+
+	ether3_banner();
+
+	dev = init_etherdev(NULL, sizeof(struct dev_priv));
+	if (!dev) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	SET_MODULE_OWNER(dev);
+
+	name = ether3_get_dev(dev, ec);
+	if (!name) {
+		ret = -ENODEV;
+		goto free;
+	}
+
+	/*
+	 * this will not fail - the nature of the bus ensures this
+	 */
+	if (!request_region(dev->base_addr, 128, dev->name)) {
+		ret = -EBUSY;
+		goto free;
+	}
+
+	priv = (struct dev_priv *) dev->priv;
+	init_timer(&priv->timer);
+
+	/* Reset card...
+	 */
+	ether3_outb(0x80, REG_CONFIG2 + 1);
+	bus_type = BUS_UNKNOWN;
+	udelay(4);
+
+	/* Test using Receive Pointer (16-bit register) to find out
+	 * how the ether3 is connected to the bus...
+	 */
+	if (ether3_probe_bus_8(dev, 0x100) &&
+	    ether3_probe_bus_8(dev, 0x201))
+		bus_type = BUS_8;
+
+	if (bus_type == BUS_UNKNOWN &&
+	    ether3_probe_bus_16(dev, 0x101) &&
+	    ether3_probe_bus_16(dev, 0x201))
+		bus_type = BUS_16;
+
+	switch (bus_type) {
+	case BUS_UNKNOWN:
+		printk(KERN_ERR "%s: unable to identify bus width\n", dev->name);
+		ret = -ENODEV;
+		goto failed;
+
+	case BUS_8:
+		printk(KERN_ERR "%s: %s found, but is an unsupported "
+			"8-bit card\n", dev->name, name);
+		ret = -ENODEV;
+		goto failed;
+
+	default:
+		break;
+	}
+
+	printk("%s: %s in slot %d, ", dev->name, name, ec->slot_no);
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+	if (ether3_init_2(dev)) {
+		ret = -ENODEV;
+		goto failed;
+	}
+
+	dev->open		= ether3_open;
+	dev->stop		= ether3_close;
+	dev->hard_start_xmit	= ether3_sendpacket;
+	dev->get_stats		= ether3_getstats;
+	dev->set_multicast_list	= ether3_setmulticastlist;
+	dev->tx_timeout		= ether3_timeout;
+	dev->watchdog_timeo	= 5 * HZ / 100;
+
+	ecard_set_drvdata(ec, dev);
+	return 0;
+
+failed:
+	release_region(dev->base_addr, 128);
+free:
+	unregister_netdev(dev);
+	kfree(dev);
+out:
+	return ret;
+}
+
+static void __devexit ether3_remove(struct expansion_card *ec)
+{
+	struct net_device *dev = ecard_get_drvdata(ec);
+
+	ecard_set_drvdata(ec, NULL);
+
+	unregister_netdev(dev);
+	release_region(dev->base_addr, 128);
+	kfree(dev);
+}
+
+static const struct ecard_id ether3_ids[] = {
+	{ MANU_ANT2, PROD_ANT_ETHER3 },
+	{ MANU_ANT,  PROD_ANT_ETHER3 },
+	{ MANU_ANT,  PROD_ANT_ETHERB },
+	{ 0xffff, 0xffff }
+};
+
+static struct ecard_driver ether3_driver = {
+	.probe		= ether3_probe,
+	.remove		= __devexit_p(ether3_remove),
+	.id_table	= ether3_ids,
+	.drv = {
+		.name	= "ether3",
+	},
+};
+
+static int __init ether3_init(void)
+{
+	return ecard_register_driver(&ether3_driver);
+}
+
+static void __exit ether3_exit(void)
+{
+	ecard_remove_driver(&ether3_driver);
+}
+
+module_init(ether3_init);
+module_exit(ether3_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/net/arm/ether3.h b/drivers/net/arm/ether3.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/ether3.h	Thu May 15 17:41:33 2003
@@ -0,0 +1,168 @@
+/*
+ *  linux/drivers/acorn/net/ether3.h
+ *
+ *  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.
+ *
+ *  network driver for Acorn/ANT Ether3 cards
+ */
+
+#ifndef _LINUX_ether3_H
+#define _LINUX_ether3_H
+
+/* use 0 for production, 1 for verification, >2 for debug. debug flags: */
+#define DEBUG_TX	 2
+#define DEBUG_RX	 4
+#define DEBUG_INT	 8
+#define DEBUG_IC	16
+#ifndef NET_DEBUG
+#define NET_DEBUG 	0
+#endif
+
+/* Command register definitions & bits */
+#define REG_COMMAND		(dev->base_addr + 0x00)
+#define CMD_ENINTDMA		0x0001
+#define CMD_ENINTRX		0x0002
+#define CMD_ENINTTX		0x0004
+#define CMD_ENINTBUFWIN		0x0008
+#define CMD_ACKINTDMA		0x0010
+#define CMD_ACKINTRX		0x0020
+#define CMD_ACKINTTX		0x0040
+#define CMD_ACKINTBUFWIN	0x0080
+#define CMD_DMAON		0x0100
+#define CMD_RXON		0x0200
+#define CMD_TXON		0x0400
+#define CMD_DMAOFF		0x0800
+#define CMD_RXOFF		0x1000
+#define CMD_TXOFF		0x2000
+#define CMD_FIFOREAD		0x4000
+#define CMD_FIFOWRITE		0x8000
+
+/* status register */
+#define REG_STATUS		(dev->base_addr + 0x00)
+#define STAT_ENINTSTAT		0x0001
+#define STAT_ENINTRX		0x0002
+#define STAT_ENINTTX		0x0004
+#define STAT_ENINTBUFWIN	0x0008
+#define STAT_INTDMA		0x0010
+#define STAT_INTRX		0x0020
+#define STAT_INTTX		0x0040
+#define STAT_INTBUFWIN		0x0080
+#define STAT_DMAON		0x0100
+#define STAT_RXON		0x0200
+#define STAT_TXON		0x0400
+#define STAT_FIFOFULL		0x2000
+#define STAT_FIFOEMPTY		0x4000
+#define STAT_FIFODIR		0x8000
+
+/* configuration register 1 */
+#define REG_CONFIG1		(dev->base_addr + 0x10)
+#define CFG1_BUFSELSTAT0	0x0000
+#define CFG1_BUFSELSTAT1	0x0001
+#define CFG1_BUFSELSTAT2	0x0002
+#define CFG1_BUFSELSTAT3	0x0003
+#define CFG1_BUFSELSTAT4	0x0004
+#define CFG1_BUFSELSTAT5	0x0005
+#define CFG1_ADDRPROM		0x0006
+#define CFG1_TRANSEND		0x0007
+#define CFG1_LOCBUFMEM		0x0008
+#define CFG1_INTVECTOR		0x0009
+#define CFG1_RECVSPECONLY	0x0000
+#define CFG1_RECVSPECBROAD	0x4000
+#define CFG1_RECVSPECBRMULTI	0x8000
+#define CFG1_RECVPROMISC	0xC000
+
+/* The following aren't in 8004 */
+#define CFG1_DMABURSTCONT	0x0000
+#define CFG1_DMABURST800NS	0x0010
+#define CFG1_DMABURST1600NS	0x0020
+#define CFG1_DMABURST3200NS	0x0030
+#define CFG1_DMABURST1		0x0000
+#define CFG1_DMABURST4		0x0040
+#define CFG1_DMABURST8		0x0080
+#define CFG1_DMABURST16		0x00C0
+#define CFG1_RECVCOMPSTAT0	0x0100
+#define CFG1_RECVCOMPSTAT1	0x0200
+#define CFG1_RECVCOMPSTAT2	0x0400
+#define CFG1_RECVCOMPSTAT3	0x0800
+#define CFG1_RECVCOMPSTAT4	0x1000
+#define CFG1_RECVCOMPSTAT5	0x2000
+
+/* configuration register 2 */
+#define REG_CONFIG2		(dev->base_addr + 0x20)
+#define CFG2_BYTESWAP		0x0001
+#define CFG2_ERRENCRC		0x0008
+#define CFG2_ERRENDRIBBLE	0x0010
+#define CFG2_ERRSHORTFRAME	0x0020
+#define CFG2_SLOTSELECT		0x0040
+#define CFG2_PREAMSELECT	0x0080
+#define CFG2_ADDRLENGTH		0x0100
+#define CFG2_RECVCRC		0x0200
+#define CFG2_XMITNOCRC		0x0400
+#define CFG2_LOOPBACK		0x0800
+#define CFG2_CTRLO		0x1000
+#define CFG2_RESET		0x8000
+
+#define REG_RECVEND		(dev->base_addr + 0x30)
+
+#define REG_BUFWIN		(dev->base_addr + 0x40)
+
+#define REG_RECVPTR		(dev->base_addr + 0x50)
+
+#define REG_TRANSMITPTR		(dev->base_addr + 0x60)
+
+#define REG_DMAADDR		(dev->base_addr + 0x70)
+
+/*
+ * Cards transmit/receive headers
+ */
+#define TX_NEXT			(0xffff)
+#define TXHDR_ENBABBLEINT	(1 << 16)
+#define TXHDR_ENCOLLISIONINT	(1 << 17)
+#define TXHDR_EN16COLLISION	(1 << 18)
+#define TXHDR_ENSUCCESS		(1 << 19)
+#define TXHDR_DATAFOLLOWS	(1 << 21)
+#define TXHDR_CHAINCONTINUE	(1 << 22)
+#define TXHDR_TRANSMIT		(1 << 23)
+#define TXSTAT_BABBLED		(1 << 24)
+#define TXSTAT_COLLISION	(1 << 25)
+#define TXSTAT_16COLLISIONS	(1 << 26)
+#define TXSTAT_DONE		(1 << 31)
+
+#define RX_NEXT			(0xffff)
+#define RXHDR_CHAINCONTINUE	(1 << 6)
+#define RXHDR_RECEIVE		(1 << 7)
+#define RXSTAT_OVERSIZE		(1 << 8)
+#define RXSTAT_CRCERROR		(1 << 9)
+#define RXSTAT_DRIBBLEERROR	(1 << 10)
+#define RXSTAT_SHORTPACKET	(1 << 11)
+#define RXSTAT_DONE		(1 << 15)
+
+
+#define TX_START	0x0000
+#define TX_END		0x6000
+#define RX_START	0x6000
+#define RX_LEN		0xA000
+#define RX_END		0x10000
+/* must be a power of 2 and greater than MAX_TX_BUFFERED */
+#define MAX_TXED	16
+#define MAX_TX_BUFFERED	10
+
+struct dev_priv {
+    struct {
+	unsigned int command;
+	unsigned int config1;
+	unsigned int config2;
+    } regs;
+    unsigned char tx_head;		/* buffer nr to insert next packet	 */
+    unsigned char tx_tail;		/* buffer nr of transmitting packet	 */
+    unsigned int rx_head;		/* address to fetch next packet from	 */
+    struct net_device_stats stats;
+    struct timer_list timer;
+    int broken;				/* 0 = ok, 1 = something went wrong	 */
+};
+
+#endif
diff -Nru a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/arm/etherh.c	Sat May 17 06:52:31 2003
@@ -0,0 +1,763 @@
+/*
+ *  linux/drivers/acorn/net/etherh.c
+ *
+ *  Copyright (C) 2000-2002 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.
+ *
+ * NS8390 I-cubed EtherH and ANT EtherM specific driver
+ * Thanks to I-Cubed for information on their cards.
+ * EtherM conversion (C) 1999 Chris Kemp and Tim Watterton
+ * EtherM integration (C) 2000 Aleph One Ltd (Tak-Shing Chan)
+ * EtherM integration re-engineered by Russell King.
+ *
+ * Changelog:
+ *  08-12-1996	RMK	1.00	Created
+ *		RMK	1.03	Added support for EtherLan500 cards
+ *  23-11-1997	RMK	1.04	Added media autodetection
+ *  16-04-1998	RMK	1.05	Improved media autodetection
+ *  10-02-2000	RMK	1.06	Updated for 2.3.43
+ *  13-05-2000	RMK	1.07	Updated for 2.3.99-pre8
+ *  12-10-1999  CK/TEW		EtherM driver first release
+ *  21-12-2000	TTC		EtherH/EtherM integration
+ *  25-12-2000	RMK	1.08	Clean integration of EtherM into this driver.
+ *  03-01-2002	RMK	1.09	Always enable IRQs if we're in the nic slot.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/init.h>
+
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+
+#include "../8390.h"
+
+#define NET_DEBUG  0
+#define DEBUG_INIT 2
+
+static unsigned int net_debug = NET_DEBUG;
+
+struct etherh_priv {
+	struct ei_device eidev;
+	unsigned int	id;
+	unsigned int	ctrl_port;
+	unsigned int	ctrl;
+};
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("EtherH/EtherM driver");
+MODULE_LICENSE("GPL");
+
+static char version[] __initdata =
+	"EtherH/EtherM Driver (c) 2002 Russell King v1.09\n";
+
+#define ETHERH500_DATAPORT	0x200	/* MEMC */
+#define ETHERH500_NS8390	0x000	/* MEMC */
+#define ETHERH500_CTRLPORT	0x200	/* IOC  */
+
+#define ETHERH600_DATAPORT	16	/* MEMC */
+#define ETHERH600_NS8390	0x200	/* MEMC */
+#define ETHERH600_CTRLPORT	0x080	/* MEMC */
+
+#define ETHERH_CP_IE		1
+#define ETHERH_CP_IF		2
+#define ETHERH_CP_HEARTBEAT	2
+
+#define ETHERH_TX_START_PAGE	1
+#define ETHERH_STOP_PAGE	127
+
+/*
+ * These came from CK/TEW
+ */
+#define ETHERM_DATAPORT		0x080	/* MEMC */
+#define ETHERM_NS8390		0x200	/* MEMC */
+#define ETHERM_CTRLPORT		0x08f	/* MEMC */
+
+#define ETHERM_TX_START_PAGE	64
+#define ETHERM_STOP_PAGE	127
+
+/* ------------------------------------------------------------------------ */
+
+static inline void etherh_set_ctrl(struct etherh_priv *eh, unsigned int mask)
+{
+	eh->ctrl |= mask;
+	outb(eh->ctrl, eh->ctrl_port);
+}
+
+static inline void etherh_clr_ctrl(struct etherh_priv *eh, unsigned int mask)
+{
+	eh->ctrl &= ~mask;
+	outb(eh->ctrl, eh->ctrl_port);
+}
+
+static inline unsigned int etherh_get_stat(struct etherh_priv *eh)
+{
+	return inb(eh->ctrl_port);
+}
+
+
+
+
+static void etherh_irq_enable(ecard_t *ec, int irqnr)
+{
+	struct etherh_priv *eh = ec->irq_data;
+
+	etherh_set_ctrl(eh, ETHERH_CP_IE);
+}
+
+static void etherh_irq_disable(ecard_t *ec, int irqnr)
+{
+	struct etherh_priv *eh = ec->irq_data;
+
+	etherh_clr_ctrl(eh, ETHERH_CP_IE);
+}
+
+static expansioncard_ops_t etherh_ops = {
+	.irqenable	= etherh_irq_enable,
+	.irqdisable	= etherh_irq_disable,
+};
+
+
+
+
+static void
+etherh_setif(struct net_device *dev)
+{
+	struct etherh_priv *eh = (struct etherh_priv *)dev->priv;
+	struct ei_device *ei_local = &eh->eidev;
+	unsigned long addr, flags;
+
+	local_irq_save(flags);
+
+	/* set the interface type */
+	switch (eh->id) {
+	case PROD_I3_ETHERLAN600:
+	case PROD_I3_ETHERLAN600A:
+		addr = dev->base_addr + EN0_RCNTHI;
+
+		switch (dev->if_port) {
+		case IF_PORT_10BASE2:
+			outb((inb(addr) & 0xf8) | 1, addr);
+			break;
+		case IF_PORT_10BASET:
+			outb((inb(addr) & 0xf8), addr);
+			break;
+		}
+		break;
+
+	case PROD_I3_ETHERLAN500:
+		switch (dev->if_port) {
+		case IF_PORT_10BASE2:
+			etherh_clr_ctrl(eh, ETHERH_CP_IF);
+			break;
+
+		case IF_PORT_10BASET:
+			etherh_set_ctrl(eh, ETHERH_CP_IF);
+			break;
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	local_irq_restore(flags);
+}
+
+static int
+etherh_getifstat(struct net_device *dev)
+{
+	struct etherh_priv *eh = (struct etherh_priv *)dev->priv;
+	struct ei_device *ei_local = &eh->eidev;
+	int stat = 0;
+
+	switch (eh->id) {
+	case PROD_I3_ETHERLAN600:
+	case PROD_I3_ETHERLAN600A:
+		switch (dev->if_port) {
+		case IF_PORT_10BASE2:
+			stat = 1;
+			break;
+		case IF_PORT_10BASET:
+			stat = inb(dev->base_addr+EN0_RCNTHI) & 4;
+			break;
+		}
+		break;
+
+	case PROD_I3_ETHERLAN500:
+		switch (dev->if_port) {
+		case IF_PORT_10BASE2:
+			stat = 1;
+			break;
+		case IF_PORT_10BASET:
+			stat = etherh_get_stat(eh) & ETHERH_CP_HEARTBEAT;
+			break;
+		}
+		break;
+
+	default:
+		stat = 0;
+		break;
+	}
+
+	return stat != 0;
+}
+
+/*
+ * Configure the interface.  Note that we ignore the other
+ * parts of ifmap, since its mostly meaningless for this driver.
+ */
+static int etherh_set_config(struct net_device *dev, struct ifmap *map)
+{
+	switch (map->port) {
+	case IF_PORT_10BASE2:
+	case IF_PORT_10BASET:
+		/*
+		 * If the user explicitly sets the interface
+		 * media type, turn off automedia detection.
+		 */
+		dev->flags &= ~IFF_AUTOMEDIA;
+		dev->if_port = map->port;
+		break;
+
+	default:
+		return -EINVAL;
+	}
+
+	etherh_setif(dev);
+
+	return 0;
+}
+
+/*
+ * Reset the 8390 (hard reset).  Note that we can't actually do this.
+ */
+static void
+etherh_reset(struct net_device *dev)
+{
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+	outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, dev->base_addr);
+
+	/*
+	 * See if we need to change the interface type.
+	 * Note that we use 'interface_num' as a flag
+	 * to indicate that we need to change the media.
+	 */
+	if (dev->flags & IFF_AUTOMEDIA && ei_local->interface_num) {
+		ei_local->interface_num = 0;
+
+		if (dev->if_port == IF_PORT_10BASET)
+			dev->if_port = IF_PORT_10BASE2;
+		else
+			dev->if_port = IF_PORT_10BASET;
+
+		etherh_setif(dev);
+	}
+}
+
+/*
+ * Write a block of data out to the 8390
+ */
+static void
+etherh_block_output (struct net_device *dev, int count, const unsigned char *buf, int start_page)
+{
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	unsigned int addr, dma_addr;
+	unsigned long dma_start;
+
+	if (ei_local->dmaing) {
+		printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: "
+			" DMAstat %d irqlock %d\n", dev->name,
+			ei_local->dmaing, ei_local->irqlock);
+		return;
+	}
+
+	/*
+	 * Make sure we have a round number of bytes if we're in word mode.
+	 */
+	if (count & 1 && ei_local->word16)
+		count++;
+
+	ei_local->dmaing = 1;
+
+	addr = dev->base_addr;
+	dma_addr = dev->mem_start;
+
+	count = (count + 1) & ~1;
+	outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
+
+	outb (0x42, addr + EN0_RCNTLO);
+	outb (0x00, addr + EN0_RCNTHI);
+	outb (0x42, addr + EN0_RSARLO);
+	outb (0x00, addr + EN0_RSARHI);
+	outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
+
+	udelay (1);
+
+	outb (ENISR_RDC, addr + EN0_ISR);
+	outb (count, addr + EN0_RCNTLO);
+	outb (count >> 8, addr + EN0_RCNTHI);
+	outb (0, addr + EN0_RSARLO);
+	outb (start_page, addr + EN0_RSARHI);
+	outb (E8390_RWRITE | E8390_START, addr + E8390_CMD);
+
+	if (ei_local->word16)
+		outsw (dma_addr, buf, count >> 1);
+	else
+		outsb (dma_addr, buf, count);
+
+	dma_start = jiffies;
+
+	while ((inb (addr + EN0_ISR) & ENISR_RDC) == 0)
+		if (jiffies - dma_start > 2*HZ/100) { /* 20ms */
+			printk(KERN_ERR "%s: timeout waiting for TX RDC\n",
+				dev->name);
+			etherh_reset (dev);
+			NS8390_init (dev, 1);
+			break;
+		}
+
+	outb (ENISR_RDC, addr + EN0_ISR);
+	ei_local->dmaing = 0;
+}
+
+/*
+ * Read a block of data from the 8390
+ */
+static void
+etherh_block_input (struct net_device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	unsigned int addr, dma_addr;
+	unsigned char *buf;
+
+	if (ei_local->dmaing) {
+		printk(KERN_ERR "%s: DMAing conflict in etherh_block_input: "
+			" DMAstat %d irqlock %d\n", dev->name,
+			ei_local->dmaing, ei_local->irqlock);
+		return;
+	}
+
+	ei_local->dmaing = 1;
+
+	addr = dev->base_addr;
+	dma_addr = dev->mem_start;
+
+	buf = skb->data;
+	outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
+	outb (count, addr + EN0_RCNTLO);
+	outb (count >> 8, addr + EN0_RCNTHI);
+	outb (ring_offset, addr + EN0_RSARLO);
+	outb (ring_offset >> 8, addr + EN0_RSARHI);
+	outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
+
+	if (ei_local->word16) {
+		insw (dma_addr, buf, count >> 1);
+		if (count & 1)
+			buf[count - 1] = inb (dma_addr);
+	} else
+		insb (dma_addr, buf, count);
+
+	outb (ENISR_RDC, addr + EN0_ISR);
+	ei_local->dmaing = 0;
+}
+
+/*
+ * Read a header from the 8390
+ */
+static void
+etherh_get_header (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+	unsigned int addr, dma_addr;
+
+	if (ei_local->dmaing) {
+		printk(KERN_ERR "%s: DMAing conflict in etherh_get_header: "
+			" DMAstat %d irqlock %d\n", dev->name,
+			ei_local->dmaing, ei_local->irqlock);
+		return;
+	}
+
+	ei_local->dmaing = 1;
+
+	addr = dev->base_addr;
+	dma_addr = dev->mem_start;
+
+	outb (E8390_NODMA | E8390_PAGE0 | E8390_START, addr + E8390_CMD);
+	outb (sizeof (*hdr), addr + EN0_RCNTLO);
+	outb (0, addr + EN0_RCNTHI);
+	outb (0, addr + EN0_RSARLO);
+	outb (ring_page, addr + EN0_RSARHI);
+	outb (E8390_RREAD | E8390_START, addr + E8390_CMD);
+
+	if (ei_local->word16)
+		insw (dma_addr, hdr, sizeof (*hdr) >> 1);
+	else
+		insb (dma_addr, hdr, sizeof (*hdr));
+
+	outb (ENISR_RDC, addr + EN0_ISR);
+	ei_local->dmaing = 0;
+}
+
+/*
+ * Open/initialize the board.  This is called (in the current kernel)
+ * sometime after booting when the 'ifconfig' program is run.
+ *
+ * This routine should set everything up anew at each open, even
+ * registers that "should" only need to be set once at boot, so that
+ * there is non-reboot way to recover if something goes wrong.
+ */
+static int
+etherh_open(struct net_device *dev)
+{
+	struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+	if (!is_valid_ether_addr(dev->dev_addr)) {
+		printk(KERN_WARNING "%s: invalid ethernet MAC address\n",
+			dev->name);
+		return -EINVAL;
+	}
+
+	if (request_irq(dev->irq, ei_interrupt, 0, dev->name, dev))
+		return -EAGAIN;
+
+	/*
+	 * Make sure that we aren't going to change the
+	 * media type on the next reset - we are about to
+	 * do automedia manually now.
+	 */
+	ei_local->interface_num = 0;
+
+	/*
+	 * If we are doing automedia detection, do it now.
+	 * This is more reliable than the 8390's detection.
+	 */
+	if (dev->flags & IFF_AUTOMEDIA) {
+		dev->if_port = IF_PORT_10BASET;
+		etherh_setif(dev);
+		mdelay(1);
+		if (!etherh_getifstat(dev)) {
+			dev->if_port = IF_PORT_10BASE2;
+			etherh_setif(dev);
+		}
+	} else
+		etherh_setif(dev);
+
+	etherh_reset(dev);
+	ei_open(dev);
+
+	return 0;
+}
+
+/*
+ * The inverse routine to etherh_open().
+ */
+static int
+etherh_close(struct net_device *dev)
+{
+	ei_close (dev);
+	free_irq (dev->irq, dev);
+	return 0;
+}
+
+/*
+ * Initialisation
+ */
+
+static void __init etherh_banner(void)
+{
+	static int version_printed;
+
+	if (net_debug && version_printed++ == 0)
+		printk(KERN_INFO "%s", version);
+}
+
+/*
+ * Read the ethernet address string from the on board rom.
+ * This is an ascii string...
+ */
+static int __init etherh_addr(char *addr, struct expansion_card *ec)
+{
+	struct in_chunk_dir cd;
+	char *s;
+	
+	if (ecard_readchunk(&cd, ec, 0xf5, 0) && (s = strchr(cd.d.string, '('))) {
+		int i;
+		for (i = 0; i < 6; i++) {
+			addr[i] = simple_strtoul(s + 1, &s, 0x10);
+			if (*s != (i == 5? ')' : ':'))
+				break;
+		}
+		if (i == 6)
+			return 0;
+	}
+	return -ENODEV;
+}
+
+/*
+ * Create an ethernet address from the system serial number.
+ */
+static int __init etherm_addr(char *addr)
+{
+	unsigned int serial;
+
+	if (system_serial_low == 0 && system_serial_high == 0)
+		return -ENODEV;
+
+	serial = system_serial_low | system_serial_high;
+
+	addr[0] = 0;
+	addr[1] = 0;
+	addr[2] = 0xa4;
+	addr[3] = 0x10 + (serial >> 24);
+	addr[4] = serial >> 16;
+	addr[5] = serial >> 8;
+	return 0;
+}
+
+static u32 etherh_regoffsets[16];
+static u32 etherm_regoffsets[16];
+
+static int __init
+etherh_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct ei_device *ei_local;
+	struct net_device *dev;
+	struct etherh_priv *eh;
+	const char *dev_type;
+	int i, size, ret;
+
+	etherh_banner();
+
+	dev = init_etherdev(NULL, sizeof(struct etherh_priv));
+	if (!dev) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	/*
+	 * init_etherdev allocs and zeros dev->priv
+	 */
+	eh = dev->priv;
+
+	spin_lock_init(&eh->eidev.page_lock);
+
+	SET_MODULE_OWNER(dev);
+
+	dev->open		= etherh_open;
+	dev->stop		= etherh_close;
+	dev->set_config		= etherh_set_config;
+	dev->irq		= ec->irq;
+	dev->base_addr		= ecard_address(ec, ECARD_MEMC, 0);
+
+	/*
+	 * IRQ and control port handling
+	 */
+	if (ec->irq != 11) {
+		ec->ops		= &etherh_ops;
+		ec->irq_data	= eh;
+	}
+	eh->ctrl		= 0;
+	eh->id			= ec->cid.product;
+
+	switch (ec->cid.product) {
+	case PROD_ANT_ETHERM:
+		etherm_addr(dev->dev_addr);
+		dev->base_addr += ETHERM_NS8390;
+		dev->mem_start  = dev->base_addr + ETHERM_DATAPORT;
+		eh->ctrl_port   = dev->base_addr + ETHERM_CTRLPORT;
+		break;
+
+	case PROD_I3_ETHERLAN500:
+		etherh_addr(dev->dev_addr, ec);
+		dev->base_addr += ETHERH500_NS8390;
+		dev->mem_start  = dev->base_addr + ETHERH500_DATAPORT;
+		eh->ctrl_port   = ecard_address (ec, ECARD_IOC, ECARD_FAST)
+				  + ETHERH500_CTRLPORT;
+		break;
+
+	case PROD_I3_ETHERLAN600:
+	case PROD_I3_ETHERLAN600A:
+		etherh_addr(dev->dev_addr, ec);
+		dev->base_addr += ETHERH600_NS8390;
+		dev->mem_start  = dev->base_addr + ETHERH600_DATAPORT;
+		eh->ctrl_port   = dev->base_addr + ETHERH600_CTRLPORT;
+		break;
+
+	default:
+		printk(KERN_ERR "%s: unknown card type %x\n",
+		       dev->name, ec->cid.product);
+		ret = -ENODEV;
+		goto free;
+	}
+
+	size = 16;
+	if (ec->cid.product == PROD_ANT_ETHERM)
+		size <<= 3;
+
+	if (!request_region(dev->base_addr, size, dev->name)) {
+		ret = -EBUSY;
+		goto free;
+	}
+
+	if (ethdev_init(dev)) {
+		ret = -ENODEV;
+		goto release;
+	}
+
+	/*
+	 * If we're in the NIC slot, make sure the IRQ is enabled
+	 */
+	if (dev->irq == 11)
+		etherh_set_ctrl(eh, ETHERH_CP_IE);
+
+	/*
+	 * Unfortunately, ethdev_init eventually calls
+	 * ether_setup, which re-writes dev->flags.
+	 */
+	switch (ec->cid.product) {
+	case PROD_ANT_ETHERM:
+		dev_type = "ANT EtherM";
+		dev->if_port = IF_PORT_UNKNOWN;
+		break;
+
+	case PROD_I3_ETHERLAN500:
+		dev_type = "i3 EtherH 500";
+		dev->if_port = IF_PORT_UNKNOWN;
+		break;
+
+	case PROD_I3_ETHERLAN600:
+		dev_type = "i3 EtherH 600";
+		dev->flags  |= IFF_PORTSEL | IFF_AUTOMEDIA;
+		dev->if_port = IF_PORT_10BASET;
+		break;
+
+	case PROD_I3_ETHERLAN600A:
+		dev_type = "i3 EtherH 600A";
+		dev->flags  |= IFF_PORTSEL | IFF_AUTOMEDIA;
+		dev->if_port = IF_PORT_10BASET;
+		break;
+
+	default:
+		dev_type = "unknown";
+		break;
+	}
+
+	printk(KERN_INFO "%s: %s in slot %d, ",
+		dev->name, dev_type, ec->slot_no);
+
+	for (i = 0; i < 6; i++)
+		printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
+
+	ei_local = (struct ei_device *) dev->priv;
+	if (ec->cid.product == PROD_ANT_ETHERM) {
+		ei_local->tx_start_page = ETHERM_TX_START_PAGE;
+		ei_local->stop_page     = ETHERM_STOP_PAGE;
+		ei_local->reg_offset    = etherm_regoffsets;
+	} else {
+		ei_local->tx_start_page = ETHERH_TX_START_PAGE;
+		ei_local->stop_page     = ETHERH_STOP_PAGE;
+		ei_local->reg_offset    = etherh_regoffsets;
+	}
+
+	ei_local->name          = dev->name;
+	ei_local->word16        = 1;
+	ei_local->rx_start_page = ei_local->tx_start_page + TX_PAGES;
+	ei_local->reset_8390    = etherh_reset;
+	ei_local->block_input   = etherh_block_input;
+	ei_local->block_output  = etherh_block_output;
+	ei_local->get_8390_hdr  = etherh_get_header;
+	ei_local->interface_num = 0;
+
+	etherh_reset(dev);
+	NS8390_init(dev, 0);
+
+	ecard_set_drvdata(ec, dev);
+
+	return 0;
+
+release:
+	release_region(dev->base_addr, 16);
+free:
+	unregister_netdev(dev);
+	kfree(dev->priv);
+	kfree(dev);
+out:
+	return ret;
+}
+
+static void __devexit etherh_remove(struct expansion_card *ec)
+{
+	struct net_device *dev = ecard_get_drvdata(ec);
+	int size = 16;
+
+	ecard_set_drvdata(ec, NULL);
+
+	unregister_netdev(dev);
+	if (ec->cid.product == PROD_ANT_ETHERM)
+		size <<= 3;
+	release_region(dev->base_addr, size);
+	kfree(dev);
+
+	ec->ops = NULL;
+	kfree(ec->irq_data);
+}
+
+static const struct ecard_id etherh_ids[] = {
+	{ MANU_ANT, PROD_ANT_ETHERM      },
+	{ MANU_I3,  PROD_I3_ETHERLAN500  },
+	{ MANU_I3,  PROD_I3_ETHERLAN600  },
+	{ MANU_I3,  PROD_I3_ETHERLAN600A },
+	{ 0xffff,   0xffff }
+};
+
+static struct ecard_driver etherh_driver = {
+	.probe		= etherh_probe,
+	.remove		= __devexit_p(etherh_remove),
+	.id_table	= etherh_ids,
+	.drv = {
+		.name	= "etherh",
+	},
+};
+
+static int __init etherh_init(void)
+{
+	int i;
+
+	for (i = 0; i < 16; i++) {
+		etherh_regoffsets[i] = i;
+		etherm_regoffsets[i] = i << 3;
+	}
+
+	return ecard_register_driver(&etherh_driver);
+}
+
+static void __exit etherh_exit(void)
+{
+	ecard_remove_driver(&etherh_driver);
+}
+
+module_init(etherh_init);
+module_exit(etherh_exit);
diff -Nru a/drivers/net/bmac.c b/drivers/net/bmac.c
--- a/drivers/net/bmac.c	Thu Feb 13 22:18:41 2003
+++ b/drivers/net/bmac.c	Wed Apr 23 05:03:30 2003
@@ -17,6 +17,7 @@
 #include <linux/timer.h>
 #include <linux/proc_fs.h>
 #include <linux/init.h>
+#include <linux/spinlock.h>
 #include <linux/crc32.h>
 #include <asm/prom.h>
 #include <asm/dbdma.h>
@@ -82,6 +83,7 @@
 	int opened;
 	unsigned short hash_use_count[64];
 	unsigned short hash_table_mask[4];
+	spinlock_t lock;
 	struct net_device *next_bmac;
 };
 
@@ -159,9 +161,9 @@
 static void bmac_init_registers(struct net_device *dev);
 static void bmac_enable_and_reset_chip(struct net_device *dev);
 static int bmac_set_address(struct net_device *dev, void *addr);
-static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs);
-static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
-static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
 static void bmac_set_timeout(struct net_device *dev);
 static void bmac_tx_timeout(unsigned long data);
 static int bmac_proc_info ( char *buffer, char **start, off_t offset, int length);
@@ -485,7 +487,7 @@
 	case PBOOK_SLEEP_NOW:
 		netif_device_detach(dev);
 		/* prolly should wait for dma to finish & turn off the chip */
-		save_flags(flags); cli();
+		spin_lock_irqsave(&bp->lock, flags);
 		if (bp->timeout_active) {
 			del_timer(&bp->tx_timeout);
 			bp->timeout_active = 0;
@@ -494,7 +496,7 @@
 		disable_irq(bp->tx_dma_intr);
 		disable_irq(bp->rx_dma_intr);
 		bp->sleeping = 1;
-		restore_flags(flags);
+		spin_unlock_irqrestore(&bp->lock, flags);
 		if (bp->opened) {
 			volatile struct dbdma_regs *rd = bp->rx_dma;
 			volatile struct dbdma_regs *td = bp->tx_dma;
@@ -539,13 +541,14 @@
 
 static int bmac_set_address(struct net_device *dev, void *addr)
 {
+	struct bmac_data *bp = (struct bmac_data *) dev->priv;
 	unsigned char *p = addr;
 	unsigned short *pWord16;
 	unsigned long flags;
 	int i;
 
 	XXDEBUG(("bmac: enter set_address\n"));
-	save_flags(flags); cli();
+	spin_lock_irqsave(&bp->lock, flags);
 
 	for (i = 0; i < 6; ++i) {
 		dev->dev_addr[i] = p[i];
@@ -556,7 +559,7 @@
 	bmwrite(dev, MADD1, *pWord16++);
 	bmwrite(dev, MADD2, *pWord16);
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
 	XXDEBUG(("bmac: exit set_address\n"));
 	return 0;
 }
@@ -566,8 +569,7 @@
 	struct bmac_data *bp = (struct bmac_data *) dev->priv;
 	unsigned long flags;
 
-	save_flags(flags);
-	cli();
+	spin_lock_irqsave(&bp->lock, flags);
 	if (bp->timeout_active)
 		del_timer(&bp->tx_timeout);
 	bp->tx_timeout.expires = jiffies + TX_TIMEOUT;
@@ -575,7 +577,7 @@
 	bp->tx_timeout.data = (unsigned long) dev;
 	add_timer(&bp->tx_timeout);
 	bp->timeout_active = 1;
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
 }
 
 static void
@@ -703,7 +705,7 @@
 
 static int rxintcount;
 
-static void bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
 	struct bmac_data *bp = (struct bmac_data *) dev->priv;
@@ -715,7 +717,7 @@
 	int last;
 	unsigned long flags;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&bp->lock, flags);
 
 	if (++rxintcount < 10) {
 		XXDEBUG(("bmac_rxdma_intr\n"));
@@ -769,18 +771,18 @@
 		bp->rx_empty = i;
 	}
 
-	restore_flags(flags);
-
 	dbdma_continue(rd);
+	spin_unlock_irqrestore(&bp->lock, flags);
 
 	if (rxintcount < 10) {
 		XXDEBUG(("bmac_rxdma_intr done\n"));
 	}
+	return IRQ_HANDLED;
 }
 
 static int txintcount;
 
-static void bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bmac_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
 	struct bmac_data *bp = (struct bmac_data *) dev->priv;
@@ -788,7 +790,7 @@
 	int stat;
 	unsigned long flags;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&bp->lock, flags);
 
 	if (txintcount++ < 10) {
 		XXDEBUG(("bmac_txdma_intr\n"));
@@ -824,13 +826,14 @@
 			break;
 	}
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
 
 	if (txintcount < 10) {
 		XXDEBUG(("bmac_txdma_intr done->bmac_start\n"));
 	}
 
 	bmac_start(dev);
+	return IRQ_HANDLED;
 }
 
 static struct net_device_stats *bmac_stats(struct net_device *dev)
@@ -1096,7 +1099,7 @@
 
 static int miscintcount;
 
-static void bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t bmac_misc_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = (struct net_device *) dev_id;
 	struct bmac_data *bp = (struct bmac_data *)dev->priv;
@@ -1117,6 +1120,7 @@
 	if (status & TxErrorMask) bp->stats.tx_errors++;
 	if (status & TxUnderrun) bp->stats.tx_fifo_errors++;
 	if (status & TxNormalCollExp) bp->stats.collisions++;
+	return IRQ_HANDLED;
 }
 
 /*
@@ -1249,7 +1253,7 @@
 	struct sk_buff *skb;
 	unsigned char *data;
 
-	save_flags(flags); cli();
+	spin_lock_irqsave(&bp->lock, flags);
 	bmac_enable_and_reset_chip(dev);
 	bmac_init_tx_ring(bp);
 	bmac_init_rx_ring(bp);
@@ -1270,7 +1274,7 @@
 		memcpy(data+6, dev->dev_addr, 6);
 		bmac_transmit_packet(skb, dev);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
 }
 
 static int __init bmac_probe(void)
@@ -1336,6 +1340,7 @@
 	bp = (struct bmac_data *) dev->priv;
 	SET_MODULE_OWNER(dev);
 	bp->node = bmac;
+	spin_lock_init(&bp->lock);
 
 	if (!request_OF_resource(bmac, 0, " (bmac)")) {
 		printk(KERN_ERR "BMAC: can't request IO resource !\n");
@@ -1522,7 +1527,7 @@
 	if (bp->sleeping)
 		return;
 		
-	save_flags(flags); cli();
+	spin_lock_irqsave(&bp->lock, flags);
 	while (1) {
 		i = bp->tx_fill + 1;
 		if (i >= N_TX_RING)
@@ -1534,7 +1539,7 @@
 			break;
 		bmac_transmit_packet(skb, dev);
 	}
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
 }
 
 static int
@@ -1558,7 +1563,7 @@
 	int i;
 
 	XXDEBUG(("bmac: tx_timeout called\n"));
-	save_flags(flags); cli();
+	spin_lock_irqsave(&bp->lock, flags);
 	bp->timeout_active = 0;
 
 	/* update various counters */
@@ -1614,7 +1619,7 @@
 	oldConfig = bmread(dev, TXCFG);		
 	bmwrite(dev, TXCFG, oldConfig | TxMACEnable );
 
-	restore_flags(flags);
+	spin_unlock_irqrestore(&bp->lock, flags);
 }
 
 #if 0
diff -Nru a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c
--- a/drivers/net/cs89x0.c	Sun Apr 20 22:09:47 2003
+++ b/drivers/net/cs89x0.c	Wed May 14 23:44:08 2003
@@ -1630,16 +1630,21 @@
 }
 
 
-static int set_mac_address(struct net_device *dev, void *addr)
+static int set_mac_address(struct net_device *dev, void *p)
 {
 	int i;
+	struct sockaddr *addr = p;
+
 
 	if (netif_running(dev))
 		return -EBUSY;
+
+	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
 	if (net_debug) {
 		printk("%s: Setting MAC address to ", dev->name);
-		for (i = 0; i < 6; i++)
-			printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]);
+		for (i = 0; i < dev->addr_len; i++)
+			printk(" %2.2x", dev->dev_addr[i]);
 		printk(".\n");
 	}
 	/* set the Ethernet address */
diff -Nru a/drivers/net/defxx.c b/drivers/net/defxx.c
--- a/drivers/net/defxx.c	Thu Nov 21 14:06:11 2002
+++ b/drivers/net/defxx.c	Tue May 20 20:02:19 2003
@@ -443,6 +443,7 @@
 	}
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	bp = dev->priv;
 
diff -Nru a/drivers/net/depca.c b/drivers/net/depca.c
--- a/drivers/net/depca.c	Sun Apr 20 23:00:41 2003
+++ b/drivers/net/depca.c	Tue Apr 29 01:27:16 2003
@@ -230,6 +230,7 @@
       			   by acme@conectiva.com.br
       0.54    08-Nov-01	  use library crc32 functions
       			   by Matt_Domsch@dell.com
+      0.55    01-Mar-03   Use EISA/sysfs framework <maz@wild-wind.fr.eu.org>
 
     =========================================================================
 */
@@ -263,6 +264,11 @@
 #include <linux/mca.h>
 #endif
 
+#ifdef CONFIG_EISA
+#include <linux/device.h>
+#include <linux/eisa.h>
+#endif
+
 #include "depca.h"
 
 static char version[] __initdata = "depca.c:v0.53 2001/1/12 davies@maniac.ultranet.com\n";
@@ -328,6 +334,25 @@
 	DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
 } adapter;
 
+#ifdef CONFIG_EISA
+struct eisa_device_id depca_eisa_ids[] = {
+	{ "DEC4220" },
+	{ "" }
+};
+
+static int depca_eisa_probe  (struct device *device);
+static int depca_eisa_remove (struct device *device);
+
+struct eisa_driver depca_eisa_driver = {
+	.id_table = depca_eisa_ids,
+	.driver   = {
+		.name    = "depca",
+		.probe   = depca_eisa_probe,
+		.remove  = __devexit_p (depca_eisa_remove)
+	}
+};
+#endif
+
 /*
 ** Miscellaneous info...
 */
@@ -388,6 +413,8 @@
 	void *rx_buff[NUM_RX_DESC];	/* CPU virt address of sh'd memory buffs  */
 	void *tx_buff[NUM_TX_DESC];	/* CPU virt address of sh'd memory buffs  */
 	void *sh_mem;		/* CPU mapped virt address of device RAM  */
+	u_long mem_start;	/* Bus address of device RAM (before remap) */
+	u_long mem_len;		/* device memory size */
 /* Device address space fields */
 	u_long device_ram_start;	/* Start of RAM in device addr space      */
 /* Offsets used in both address spaces */
@@ -450,10 +477,8 @@
 static void DepcaSignature(char *name, u_long paddr);
 static int DevicePresent(u_long ioaddr);
 static int get_hw_addr(struct net_device *dev);
-static int EISA_signature(char *name, s32 eisa_id);
 static void SetMulticastFilter(struct net_device *dev);
 static void isa_probe(struct net_device *dev, u_long iobase);
-static void eisa_probe(struct net_device *dev, u_long iobase);
 #ifdef CONFIG_MCA
 static void mca_probe(struct net_device *dev, u_long iobase);
 #endif
@@ -503,7 +528,9 @@
 		mca_probe(dev, iobase);
 #endif
 		isa_probe(dev, iobase);
-		eisa_probe(dev, iobase);
+#ifdef CONFIG_EISA
+		eisa_driver_register (&depca_eisa_driver);
+#endif
 
 		if ((tmp == num_depcas) && (iobase != 0) && loading_module) {
 			printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name, iobase);
@@ -530,6 +557,7 @@
 	int i, j, offset, netRAM, mem_len, status = 0;
 	s16 nicsr;
 	u_long mem_start = 0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
+	int is_eisa = ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS);
 
 	STOP_DEPCA;
 
@@ -555,7 +583,7 @@
 
 	if (mca_slot != -1) {
 		printk("%s: %s at 0x%04lx (MCA slot %d)", dev->name, name, ioaddr, mca_slot);
-	} else if ((ioaddr & 0x0fff) == DEPCA_EISA_IO_PORTS) {	/* EISA slot address */
+	} else if (is_eisa) {	/* EISA slot address */
 		printk("%s: %s at 0x%04lx (EISA slot %d)", dev->name, name, ioaddr, (int) ((ioaddr >> 12) & 0x0f));
 	} else {		/* ISA port address */
 		printk("%s: %s at 0x%04lx", dev->name, name, ioaddr);
@@ -600,9 +628,11 @@
 	}
 
 	/* Define the device private memory */
-	dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL);
-	if (dev->priv == NULL)
-		return -ENOMEM;
+	if (!is_eisa) {
+		dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL);
+		if (dev->priv == NULL)
+			return -ENOMEM;
+	}
 	lp = (struct depca_private *) dev->priv;
 	memset((char *) dev->priv, 0, sizeof(struct depca_private));
 	lp->adapter = adapter;
@@ -610,18 +640,23 @@
 	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);
-		goto out_priv;
-	}
 
 	/* Initialisation Block */
-	lp->sh_mem = ioremap(mem_start, mem_len);
+	if (!request_mem_region (mem_start, mem_len, lp->adapter_name)) {
+		printk(KERN_ERR "depca: cannot request ISA memory, aborting\n");
+		goto out_priv;
+	}
+		
 	status = -EIO;
+	lp->sh_mem = ioremap(mem_start, mem_len);
 	if (lp->sh_mem == NULL) {
 		printk(KERN_ERR "depca: cannot remap ISA memory, aborting\n");
-		goto out_region;
+		release_mem_region (mem_start, mem_len);
+		goto out_priv;
 	}
+
+	lp->mem_start = mem_start;
+	lp->mem_len   = mem_len;
 	lp->device_ram_start = mem_start & LA_MASK;
 
 	offset = 0;
@@ -703,7 +738,7 @@
 		status = -ENXIO;
 		if (!irqnum) {
 			printk(" and failed to detect IRQ line.\n");
-			goto out_region;
+			goto out_priv;
 		} else {
 			for (dev->irq = 0, i = 0; (depca_irq[i]) && (!dev->irq); i++)
 				if (irqnum == depca_irq[i]) {
@@ -714,7 +749,7 @@
 			status = -ENXIO;
 			if (!dev->irq) {
 				printk(" but incorrect IRQ line detected.\n");
-				goto out_region;
+				goto out_priv;
 			}
 		}
 #endif				/* MODULE */
@@ -739,13 +774,16 @@
 	dev->mem_start = 0;
 
 	/* Fill in the generic field of the device structure. */
-	ether_setup(dev);
+	if (!is_eisa)
+		ether_setup(dev);
 	return 0;
-      out_region:
-	release_region(ioaddr, DEPCA_TOTAL_SIZE);
       out_priv:
-	kfree(dev->priv);
-	dev->priv = NULL;
+	if (!is_eisa) {
+		kfree(dev->priv);
+		dev->priv = NULL;
+	} else {
+		unregister_netdev (dev);
+	}
 	return status;
 }
 
@@ -1351,31 +1389,35 @@
 			   ** Get everything allocated and initialized...  (almost just
 			   ** like the ISA and EISA probes)
 			 */
+			if (!request_region (iobase, DEPCA_TOTAL_SIZE, "depca")) {
+				if (autoprobed)
+					printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
+				goto next;
+			}
 			if (DevicePresent(iobase) != 0) {
 				/*
 				   ** If the MCA configuration says the card should be here,
 				   ** it really should be here.
 				 */
 				printk(KERN_ERR "%s: MCA reports card at 0x%lx but it is not responding.\n", dev->name, iobase);
+				goto release_next;
 			}
 
-			if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
-				if ((dev = alloc_device(dev, iobase)) != NULL) {
-					dev->irq = irq;
-					if (depca_hw_init(dev, iobase, slot) == 0) {
-						/*
-						   ** Adapter initialized correctly:  Name it in
-						   ** /proc/mca.
-						 */
-						mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter");
-						mca_mark_as_used(slot);
-						num_depcas++;
-					}
-					num_eth++;
-				}
-			} else if (autoprobed) {
-				printk(KERN_WARNING "%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
-			}
+			if (!(dev = alloc_device(dev, iobase)))
+				goto release_next;
+
+			num_eth++;
+			dev->irq = irq;
+			if (depca_hw_init(dev, iobase, slot))
+				goto release_next;
+			
+			/*
+			** Adapter initialized correctly:  Name it in
+			** /proc/mca.
+			*/
+			mca_set_adapter_name(slot, "DE210/212 Ethernet Adapter");
+			mca_mark_as_used(slot);
+			num_depcas++;
 
 			/*
 			   ** If this is a probe by a module, return after setting up the
@@ -1385,9 +1427,15 @@
 				return;
 
 			/*
-			   ** Set up to check the next slot and loop.
+			** Set up to check the next slot and loop.
 			 */
 			slot++;
+			continue;
+
+	release_next:
+			release_region (iobase, DEPCA_TOTAL_SIZE);
+	next:
+			slot++;
 		}
 	}
 
@@ -1418,69 +1466,100 @@
 	}
 
 	for (; (i < maxSlots) && (dev != NULL) && ports[i]; i++) {
-		if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
-			if (DevicePresent(ports[i]) == 0) {
-				if ((dev = alloc_device(dev, ports[i])) != NULL) {
-					if (depca_hw_init(dev, ports[i], -1) == 0) {
-						num_depcas++;
-					}
-					num_eth++;
-				}
-			}
-		} else if (autoprobed) {
-			printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]);
+		if (!request_region (ports[i], DEPCA_TOTAL_SIZE, "depca")) {
+			if (autoprobed)
+				printk("%s: region already allocated at 0x%04x.\n", dev->name, ports[i]);
+			continue;
 		}
+
+		if (DevicePresent(ports[i])) {
+			release_region (ports[i], DEPCA_TOTAL_SIZE);
+			continue;
+		}
+
+		if (!(dev = alloc_device(dev, ports[i]))) {
+			release_region (ports[i], DEPCA_TOTAL_SIZE);
+			continue;
+		}
+
+		num_eth++;
+
+		if (depca_hw_init(dev, ports[i], -1)) {
+			release_region (ports[i], DEPCA_TOTAL_SIZE);
+			continue;
+		}
+
+		num_depcas++;
 	}
 
 	return;
 }
 
 /*
-** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
-** the motherboard. Upto 15 EISA devices are supported.
+** EISA callbacks from sysfs.
 */
-static void __init eisa_probe(struct net_device *dev, u_long ioaddr)
+
+#ifdef CONFIG_EISA
+static int __init depca_eisa_probe (struct device *device)
 {
-	int i, maxSlots;
+	struct eisa_device *edev;
+	struct net_device *dev;
 	u_long iobase;
-	char name[DEPCA_STRLEN];
+	int status = 0;
 
-	if (!ioaddr && autoprobed)
-		return;		/* Been here before ! */
-	if ((ioaddr < 0x400) && (ioaddr > 0))
-		return;		/* ISA Address */
+	edev = to_eisa_device (device);
+	iobase = edev->base_addr + DEPCA_EISA_IO_PORTS;
 
-	if (ioaddr == 0) {	/* Autoprobing */
-		iobase = EISA_SLOT_INC;	/* Get the first slot address */
-		i = 1;
-		maxSlots = MAX_EISA_SLOTS;
-	} else {		/* Probe a specific location */
-		iobase = ioaddr;
-		i = (ioaddr >> 12);
-		maxSlots = i + 1;
+	if (!request_region (iobase, DEPCA_TOTAL_SIZE, "depca")) {
+		status = -EBUSY;
+		goto out;
+	}
+	
+	if (DevicePresent(iobase)) {
+		status = -ENODEV;
+		goto out_release;
 	}
-	if ((iobase & 0x0fff) == 0)
-		iobase += DEPCA_EISA_IO_PORTS;
 
-	for (; (i < maxSlots) && (dev != NULL); i++, iobase += EISA_SLOT_INC) {
-		if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
-			if (EISA_signature(name, EISA_ID)) {
-				if (DevicePresent(iobase) == 0) {
-					if ((dev = alloc_device(dev, iobase)) != NULL) {
-						if (depca_hw_init(dev, iobase, -1) == 0) {
-							num_depcas++;
-						}
-						num_eth++;
-					}
-				}
-			}
-		} else if (autoprobed) {
-			printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
-		}
+	if (!(dev = init_etherdev (NULL, sizeof (struct depca_private)))) {
+		status = -ENOMEM;
+		goto out_release;
 	}
+		
+	eisa_set_drvdata (edev, dev);
 
-	return;
+	if ((status = depca_hw_init(dev, iobase, -1)))
+		goto out_free;
+
+	num_depcas++;
+	return 0;
+
+ out_free:
+	kfree (dev);
+ out_release:
+	release_region (iobase, DEPCA_TOTAL_SIZE);
+ out:
+	return status;
+}
+
+static int __devexit depca_eisa_remove (struct device *device)
+{
+	struct net_device *dev;
+	struct eisa_device *edev;
+	struct depca_private *lp;
+
+	edev = to_eisa_device (device);
+	dev  = eisa_get_drvdata (edev);
+	lp   = dev->priv;
+
+	unregister_netdev (dev);
+	iounmap (lp->sh_mem);
+	release_mem_region (lp->mem_start, lp->mem_len);
+	release_region (dev->base_addr, DEPCA_TOTAL_SIZE);
+	kfree (dev);
+
+	return 0;
 }
+#endif
 
 /*
 ** Search the entire 'eth' device list for a fixed probe. If a match isn't
@@ -1781,40 +1860,6 @@
 	return status;
 }
 
-/*
-** Look for a particular board name in the EISA configuration space
-*/
-static int __init EISA_signature(char *name, s32 eisa_id)
-{
-	u_int i;
-	const char *signatures[] = DEPCA_SIGNATURE;
-	char ManCode[DEPCA_STRLEN];
-	union {
-		s32 ID;
-		char Id[4];
-	} Eisa;
-	int status = 0;
-
-	*name = '\0';
-	Eisa.ID = inl(eisa_id);
-
-	ManCode[0] = (((Eisa.Id[0] >> 2) & 0x1f) + 0x40);
-	ManCode[1] = (((Eisa.Id[1] & 0xe0) >> 5) + ((Eisa.Id[0] & 0x03) << 3) + 0x40);
-	ManCode[2] = (((Eisa.Id[2] >> 4) & 0x0f) + 0x30);
-	ManCode[3] = ((Eisa.Id[2] & 0x0f) + 0x30);
-	ManCode[4] = (((Eisa.Id[3] >> 4) & 0x0f) + 0x30);
-	ManCode[5] = '\0';
-
-	for (i = 0; (*signatures[i] != '\0') && (*name == '\0'); i++) {
-		if (strstr(ManCode, signatures[i]) != NULL) {
-			strcpy(name, ManCode);
-			status = 1;
-		}
-	}
-
-	return status;
-}
-
 static void depca_dbg_open(struct net_device *dev)
 {
 	struct depca_private *lp = (struct depca_private *) dev->priv;
@@ -2067,6 +2112,7 @@
 	unregister_netdev(&thisDepca);
 	if (lp) {
 		iounmap(lp->sh_mem);
+		release_mem_region (lp->mem_start, lp->mem_len);
 #ifdef CONFIG_MCA
 		if (lp->mca_slot != -1)
 			mca_mark_as_unused(lp->mca_slot);
diff -Nru a/drivers/net/dl2k.c b/drivers/net/dl2k.c
--- a/drivers/net/dl2k.c	Sun Apr 20 22:09:47 2003
+++ b/drivers/net/dl2k.c	Tue May 20 20:02:19 2003
@@ -154,6 +154,7 @@
 		goto err_out_res;
 	}
 	SET_MODULE_OWNER (dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 #ifdef MEM_MAPPING
 	ioaddr = pci_resource_start (pdev, 1);
diff -Nru a/drivers/net/e100/e100_main.c b/drivers/net/e100/e100_main.c
--- a/drivers/net/e100/e100_main.c	Sun Apr 20 14:14:29 2003
+++ b/drivers/net/e100/e100_main.c	Tue May 20 20:02:19 2003
@@ -591,6 +591,7 @@
 	bdp->device = dev;
 
 	pci_set_drvdata(pcid, dev);
+	SET_NETDEV_DEV(dev, &pcid->dev);
 
 	if ((rc = e100_alloc_space(bdp)) != 0) {
 		goto err_dev;
diff -Nru a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c
--- a/drivers/net/e1000/e1000_main.c	Sun Apr 27 20:54:15 2003
+++ b/drivers/net/e1000/e1000_main.c	Tue May 20 20:02:19 2003
@@ -391,6 +391,7 @@
 		goto err_alloc_etherdev;
 
 	SET_MODULE_OWNER(netdev);
+	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	pci_set_drvdata(pdev, netdev);
 	adapter = netdev->priv;
diff -Nru a/drivers/net/eepro100.c b/drivers/net/eepro100.c
--- a/drivers/net/eepro100.c	Sun Apr 20 21:26:41 2003
+++ b/drivers/net/eepro100.c	Tue May 20 20:02:19 2003
@@ -678,6 +678,7 @@
 	}
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (dev->mem_start > 0)
 		option = dev->mem_start;
@@ -829,6 +830,7 @@
 	pci_set_power_state(pdev, acpi_idle_state);
 
 	pci_set_drvdata (pdev, dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	dev->irq = pdev->irq;
 
diff -Nru a/drivers/net/epic100.c b/drivers/net/epic100.c
--- a/drivers/net/epic100.c	Sun Apr 20 21:58:27 2003
+++ b/drivers/net/epic100.c	Tue May 20 20:02:19 2003
@@ -409,6 +409,7 @@
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_request_regions(pdev, DRV_NAME))
 		goto err_out_free_netdev;
diff -Nru a/drivers/net/fc/iph5526.c b/drivers/net/fc/iph5526.c
--- a/drivers/net/fc/iph5526.c	Mon Mar 31 15:55:40 2003
+++ b/drivers/net/fc/iph5526.c	Mon Apr 21 17:23:14 2003
@@ -2984,8 +2984,7 @@
 	 */
 	if ((type == ETH_P_ARP) || (status == 0))
 		dev_kfree_skb(skb);
-	else
-		netif_wake_queue(dev);
+	netif_wake_queue(dev);
 	LEAVE("iph5526_send_packet");
 	return 0;
 }
diff -Nru a/drivers/net/fealnx.c b/drivers/net/fealnx.c
--- a/drivers/net/fealnx.c	Sun Apr 20 21:58:27 2003
+++ b/drivers/net/fealnx.c	Tue May 20 20:02:19 2003
@@ -539,6 +539,7 @@
 		goto err_out_unmap;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/* read ethernet id */
 	for (i = 0; i < 6; ++i)
diff -Nru a/drivers/net/hamachi.c b/drivers/net/hamachi.c
--- a/drivers/net/hamachi.c	Sun Apr 20 22:09:47 2003
+++ b/drivers/net/hamachi.c	Tue May 20 20:02:19 2003
@@ -613,6 +613,7 @@
 		goto err_out_iounmap;
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 #ifdef TX_CHECKSUM
 	printk("check that skbcopy in ip_queue_xmit isn't happening\n");
diff -Nru a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
--- a/drivers/net/hamradio/dmascc.c	Sun Apr 27 20:36:19 2003
+++ b/drivers/net/hamradio/dmascc.c	Mon May 19 23:22:51 2003
@@ -324,10 +324,11 @@
 
     /* Unregister devices */
     for (i = 0; i < 2; i++) {
-      if (info->dev[i].name)
+      if (info->dev[i].name) {
 	rtnl_lock();
 	unregister_netdevice(&info->dev[i]);
 	rtnl_unlock();
+      }
     }
 
     /* Reset board */
diff -Nru a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
--- a/drivers/net/hamradio/mkiss.c	Mon Apr 21 20:58:40 2003
+++ b/drivers/net/hamradio/mkiss.c	Wed Apr 23 19:53:14 2003
@@ -347,6 +347,7 @@
 	netif_rx(skb);
 	tmp_ax->dev->last_rx = jiffies;
 	tmp_ax->rx_packets++;
+	tmp_ax->rx_bytes+=count;
 }
 
 /* Encapsulate one AX.25 packet and stuff into a TTY queue. */
@@ -386,6 +387,7 @@
 		ax->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
 		actual = ax->tty->driver->write(ax->tty, 0, ax->xbuff, count);
 		ax->tx_packets++;
+		ax->tx_bytes+=actual;
 		ax->dev->trans_start = jiffies;
 		ax->xleft = count - actual;
 		ax->xhead = ax->xbuff + actual;
@@ -394,6 +396,7 @@
 		ax->mkiss->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
 		actual = ax->mkiss->tty->driver->write(ax->mkiss->tty, 0, ax->mkiss->xbuff, count);
 		ax->tx_packets++;
+		ax->tx_bytes+=actual;
 		ax->mkiss->dev->trans_start = jiffies;
 		ax->mkiss->xleft = count - actual;
 		ax->mkiss->xhead = ax->mkiss->xbuff + actual;
@@ -709,6 +712,8 @@
 
 	stats.rx_packets     = ax->rx_packets;
 	stats.tx_packets     = ax->tx_packets;
+	stats.rx_bytes	     = ax->rx_bytes;
+	stats.tx_bytes       = ax->tx_bytes;
 	stats.rx_dropped     = ax->rx_dropped;
 	stats.tx_dropped     = ax->tx_dropped;
 	stats.tx_errors      = ax->tx_errors;
@@ -936,7 +941,7 @@
 	memcpy(dev->dev_addr,  ax25_test,  AX25_ADDR_LEN);
 
 	/* New-style flags. */
-	dev->flags      = 0;
+	dev->flags      = IFF_BROADCAST | IFF_MULTICAST;
 
 	return 0;
 }
diff -Nru a/drivers/net/hamradio/mkiss.h b/drivers/net/hamradio/mkiss.h
--- a/drivers/net/hamradio/mkiss.h	Tue Feb  5 09:40:01 2002
+++ b/drivers/net/hamradio/mkiss.h	Mon Mar 17 15:42:28 2003
@@ -31,6 +31,8 @@
 	/* SLIP interface statistics. */
 	unsigned long      rx_packets;		/* inbound frames counter	*/
 	unsigned long      tx_packets;		/* outbound frames counter      */
+	unsigned long      rx_bytes;		/* inbound bytes counter        */
+	unsigned long      tx_bytes;		/* outbound bytes counter       */
 	unsigned long      rx_errors;		/* Parity, etc. errors          */
 	unsigned long      tx_errors;		/* Planned stuff                */
 	unsigned long      rx_dropped;		/* No memory for skb            */
diff -Nru a/drivers/net/hp100.c b/drivers/net/hp100.c
--- a/drivers/net/hp100.c	Sun Apr 20 22:41:09 2003
+++ b/drivers/net/hp100.c	Tue May 20 20:02:19 2003
@@ -776,6 +776,7 @@
 	hp100_clear_stats(lp, ioaddr);
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pci_dev->dev);
 	ether_setup(dev);
 
 	/* If busmaster mode is wanted, a dma-capable memory area is needed for
diff -Nru a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c
--- a/drivers/net/ioc3-eth.c	Sun Apr 27 20:36:19 2003
+++ b/drivers/net/ioc3-eth.c	Tue May 20 20:02:19 2003
@@ -1532,6 +1532,8 @@
 		goto out_free;
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
 	ip = dev->priv;
 	ip->dev = dev;
 
diff -Nru a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
--- a/drivers/net/irda/sa1100_ir.c	Sun Jan 12 09:15:55 2003
+++ b/drivers/net/irda/sa1100_ir.c	Mon May 19 23:22:52 2003
@@ -636,13 +636,14 @@
 	sa1100_irda_rx_dma_start(si);
 }
 
-static void sa1100_irda_irq(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sa1100_irda_irq(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct net_device *dev = dev_id;
 	if (IS_FIR(((struct sa1100_irda *)dev->priv)))
 		sa1100_irda_fir_irq(dev);
 	else
 		sa1100_irda_hpsir_irq(dev);
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/drivers/net/irda/sir_dongle.c b/drivers/net/irda/sir_dongle.c
--- a/drivers/net/irda/sir_dongle.c	Mon Dec 30 09:05:21 2002
+++ b/drivers/net/irda/sir_dongle.c	Sat May 17 12:39:13 2003
@@ -66,10 +66,7 @@
 	int err = -EINVAL;
 
 #ifdef CONFIG_KMOD
-	char modname[30];
-
-	sprintf(modname, "irda-dongle-%d", type);
-	request_module(modname);
+	request_module("irda-dongle-%d", type);
 #endif
 
 	if (dev->dongle_drv != NULL)
diff -Nru a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c
--- a/drivers/net/ixgb/ixgb_main.c	Sun Apr 27 21:42:23 2003
+++ b/drivers/net/ixgb/ixgb_main.c	Tue May 20 20:02:19 2003
@@ -333,6 +333,7 @@
 	}
 
 	SET_MODULE_OWNER(netdev);
+	SET_NETDEV_DEV(netdev, &pdev->dev);
 
 	pci_set_drvdata(pdev, netdev);
 	adapter = netdev->priv;
diff -Nru a/drivers/net/mace.c b/drivers/net/mace.c
--- a/drivers/net/mace.c	Wed Feb 12 14:07:11 2003
+++ b/drivers/net/mace.c	Wed Apr 23 15:42:58 2003
@@ -86,9 +86,9 @@
 static void mace_set_multicast(struct net_device *dev);
 static void mace_reset(struct net_device *dev);
 static int mace_set_address(struct net_device *dev, void *addr);
-static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
-static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs);
 static void mace_set_timeout(struct net_device *dev);
 static void mace_tx_timeout(unsigned long data);
 static inline void dbdma_reset(volatile struct dbdma_regs *dma);
@@ -622,7 +622,7 @@
 	    printk(KERN_DEBUG "mace: jabbering transceiver\n");
 }
 
-static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct net_device *dev = (struct net_device *) dev_id;
     struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -765,6 +765,7 @@
 	mace_set_timeout(dev);
     }
     spin_unlock_irqrestore(&mp->lock, flags);
+    return IRQ_HANDLED;
 }
 
 static void mace_tx_timeout(unsigned long data)
@@ -833,11 +834,12 @@
     spin_unlock_irqrestore(&mp->lock, flags);
 }
 
-static void mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_txdma_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
+	return IRQ_HANDLED;
 }
 
-static void mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_rxdma_intr(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct net_device *dev = (struct net_device *) dev_id;
     struct mace_data *mp = (struct mace_data *) dev->priv;
@@ -947,6 +949,7 @@
 	mp->rx_fill = i;
     }
     spin_unlock_irqrestore(&mp->lock, flags);
+    return IRQ_HANDLED;
 }
 
 MODULE_AUTHOR("Paul Mackerras");
diff -Nru a/drivers/net/natsemi.c b/drivers/net/natsemi.c
--- a/drivers/net/natsemi.c	Sun Apr 20 21:58:27 2003
+++ b/drivers/net/natsemi.c	Tue May 20 20:02:19 2003
@@ -762,6 +762,7 @@
 	if (!dev)
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	i = pci_request_regions(pdev, dev->name);
 	if (i) {
diff -Nru a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c
--- a/drivers/net/ne2k-pci.c	Thu Nov 21 14:06:11 2002
+++ b/drivers/net/ne2k-pci.c	Tue May 20 20:02:19 2003
@@ -265,6 +265,7 @@
 		goto err_out_free_res;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	/* Reset card. Who knows what dain-bramaged state it was left in. */
 	{
diff -Nru a/drivers/net/ns83820.c b/drivers/net/ns83820.c
--- a/drivers/net/ns83820.c	Sun Apr 20 21:58:27 2003
+++ b/drivers/net/ns83820.c	Tue May 20 20:26:02 2003
@@ -1586,6 +1586,7 @@
 	dprintk("%s: done %s in %d loops\n", dev->net_dev.name, name, loops);
 }
 
+#ifdef PHY_CODE_IS_FINISHED
 static void ns83820_mii_write_bit(struct ns83820 *dev, int bit)
 {
 	/* drive MDC low */
@@ -1758,6 +1759,7 @@
 		dprintk("version: 0x%04x 0x%04x\n", a, b);
 	}
 }
+#endif
 
 static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id)
 {
@@ -1788,7 +1790,8 @@
 
 	dev->ee.cache = &dev->MEAR_cache;
 	dev->ee.lock = &dev->misc_lock;
-	dev->net_dev.owner = THIS_MODULE;
+	SET_MODULE_OWNER(dev->net_dev);
+	SET_NETDEV_DEV(&dev->net_dev, &pci_dev->dev);
 	dev->net_dev.priv = dev;
 
 	INIT_WORK(&dev->tq_refill, queue_refill, dev);
diff -Nru a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c
--- a/drivers/net/pci-skeleton.c	Sun Apr 27 20:36:19 2003
+++ b/drivers/net/pci-skeleton.c	Tue May 20 20:02:19 2003
@@ -610,6 +610,7 @@
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 	tp = dev->priv;
 
 	/* enable device (incl. PCI PM wakeup), and bus-mastering */
diff -Nru a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c
--- a/drivers/net/pcmcia/3c589_cs.c	Tue Apr 29 15:46:18 2003
+++ b/drivers/net/pcmcia/3c589_cs.c	Sun May  4 14:20:34 2003
@@ -159,7 +159,7 @@
 static int el3_config(struct net_device *dev, struct ifmap *map);
 static int el3_open(struct net_device *dev);
 static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void update_stats(struct net_device *dev);
 static struct net_device_stats *el3_get_stats(struct net_device *dev);
 static int el3_rx(struct net_device *dev);
@@ -816,15 +816,16 @@
 }
 
 /* The EL3 interrupt handler. */
-static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct el3_private *lp = dev_id;
     struct net_device *dev = &lp->dev;
     ioaddr_t ioaddr, status;
-    int i = 0;
+    int i = 0, handled = 1;
     
     if (!netif_device_present(dev))
-	return;
+	return IRQ_NONE;
+
     ioaddr = dev->base_addr;
 
     DEBUG(3, "%s: interrupt, status %4.4x.\n",
@@ -833,9 +834,9 @@
     spin_lock(&lp->lock);    
     while ((status = inw(ioaddr + EL3_STATUS)) &
 	(IntLatch | RxComplete | StatsFull)) {
-	if (!netif_device_present(dev) ||
-	    ((status & 0xe000) != 0x2000)) {
+	if ((status & 0xe000) != 0x2000) {
 	    DEBUG(1, "%s: interrupt from dead card\n", dev->name);
+	    handled = 0;
 	    break;
 	}
 	
@@ -897,7 +898,7 @@
     spin_unlock(&lp->lock);    
     DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
 	  dev->name, inw(ioaddr + EL3_STATUS));
-    return;
+    return IRQ_RETVAL(handled);
 }
 
 static void media_check(unsigned long arg)
diff -Nru a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c
--- a/drivers/net/pcmcia/fmvj18x_cs.c	Tue Apr 29 15:46:18 2003
+++ b/drivers/net/pcmcia/fmvj18x_cs.c	Sun May  4 14:20:34 2003
@@ -107,7 +107,7 @@
 static int fjn_open(struct net_device *dev);
 static int fjn_close(struct net_device *dev);
 static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void fjn_rx(struct net_device *dev);
 static void fjn_reset(struct net_device *dev);
 static struct net_device_stats *fjn_get_stats(struct net_device *dev);
@@ -845,7 +845,7 @@
 
 /*====================================================================*/
 
-static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     local_info_t *lp = dev_id;
     struct net_device *dev = &lp->dev;
@@ -855,7 +855,7 @@
     if (lp == NULL) {
         printk(KERN_NOTICE "fjn_interrupt(): irq %d for "
 	       "unknown device.\n", irq);
-        return;
+        return IRQ_NONE;
     }
     ioaddr = dev->base_addr;
 
@@ -899,6 +899,7 @@
 
     outb(D_TX_INTR, ioaddr + TX_INTR);
     outb(D_RX_INTR, ioaddr + RX_INTR);
+    return IRQ_HANDLED;
 
 } /* fjn_interrupt */
 
diff -Nru a/drivers/net/pcmcia/ibmtr_cs.c b/drivers/net/pcmcia/ibmtr_cs.c
--- a/drivers/net/pcmcia/ibmtr_cs.c	Tue Apr 29 15:46:18 2003
+++ b/drivers/net/pcmcia/ibmtr_cs.c	Sun May  4 14:20:34 2003
@@ -127,7 +127,7 @@
 
 extern int ibmtr_probe(struct net_device *dev);
 extern int trdev_init(struct net_device *dev);
-extern void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+extern irqreturn_t tok_interrupt (int irq, void *dev_id, struct pt_regs *regs);
 
 /*====================================================================*/
 
diff -Nru a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c
--- a/drivers/net/pcmcia/nmclan_cs.c	Tue Apr 29 15:46:18 2003
+++ b/drivers/net/pcmcia/nmclan_cs.c	Sun May  4 14:20:34 2003
@@ -431,7 +431,7 @@
 static int mace_close(struct net_device *dev);
 static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void mace_tx_timeout(struct net_device *dev);
-static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static struct net_device_stats *mace_get_stats(struct net_device *dev);
 static int mace_rx(struct net_device *dev, unsigned char RxCnt);
 static void restore_multicast_list(struct net_device *dev);
@@ -1143,7 +1143,7 @@
 mace_interrupt
 	The interrupt handler.
 ---------------------------------------------------------------------------- */
-static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
   mace_private *lp = (mace_private *)dev_id;
   struct net_device *dev = &lp->dev;
@@ -1154,7 +1154,7 @@
   if (dev == NULL) {
     DEBUG(2, "mace_interrupt(): irq 0x%X for unknown device.\n",
 	  irq);
-    return;
+    return IRQ_NONE;
   }
 
   if (lp->tx_irq_disabled) {
@@ -1169,12 +1169,12 @@
       inb(ioaddr + AM2150_MACE_BASE + MACE_IMR)
     );
     /* WARNING: MACE_IR has been read! */
-    return;
+    return IRQ_NONE;
   }
 
   if (!netif_device_present(dev)) {
     DEBUG(2, "%s: interrupt from dead card\n", dev->name);
-    goto exception;
+    return IRQ_NONE;
   }
 
   do {
@@ -1279,8 +1279,7 @@
 
   } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt));
 
-exception:
-  return;
+  return IRQ_HANDLED;
 } /* mace_interrupt */
 
 /* ----------------------------------------------------------------------------
diff -Nru a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c
--- a/drivers/net/pcmcia/smc91c92_cs.c	Tue Apr 29 15:46:18 2003
+++ b/drivers/net/pcmcia/smc91c92_cs.c	Sun May  4 14:20:34 2003
@@ -293,7 +293,7 @@
 static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static void smc_tx_timeout(struct net_device *dev);
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void smc_rx(struct net_device *dev);
 static struct net_device_stats *smc_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
@@ -1574,16 +1574,18 @@
 
 /*====================================================================*/
 
-static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct smc_private *smc = dev_id;
     struct net_device *dev = &smc->dev;
     ioaddr_t ioaddr;
     u_short saved_bank, saved_pointer, mask, status;
+    unsigned int handled = 1;
     char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */
 
     if (!netif_device_present(dev))
-	return;
+	return IRQ_NONE;
+
     ioaddr = dev->base_addr;
 
     DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
@@ -1596,6 +1598,7 @@
 	   maybe it has been ejected. */
 	DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent"
 	      "/ejected device.\n", dev->name, irq);
+	handled = 0;
 	goto irq_done;
     }
 
@@ -1609,9 +1612,11 @@
 	status = inw(ioaddr + INTERRUPT) & 0xff;
 	DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
 	      status, mask);
-	if ((status & mask) == 0)
+	if ((status & mask) == 0) {
+	    if (bogus_cnt == INTR_WORK)
+		handled = 0;
 	    break;
-	
+	}
 	if (status & IM_RCV_INT) {
 	    /* Got a packet(s). */
 	    smc_rx(dev);
@@ -1683,6 +1688,7 @@
 	readb(smc->base+MEGAHERTZ_ISR);
     }
 #endif
+    return IRQ_RETVAL(handled);
 }
 
 /*====================================================================*/
diff -Nru a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c
--- a/drivers/net/pcmcia/xirc2ps_cs.c	Tue Apr 29 15:46:18 2003
+++ b/drivers/net/pcmcia/xirc2ps_cs.c	Sun May  4 14:20:34 2003
@@ -317,7 +317,7 @@
  * less on other parts of the kernel.
  */
 
-static void xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 
 /*
  * The dev_info variable is the "key" that is used to match up this
@@ -1296,7 +1296,7 @@
 /****************
  * This is the Interrupt service route.
  */
-static void
+static irqreturn_t
 xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
     struct net_device *dev = (struct net_device *)dev_id;
@@ -1305,14 +1305,14 @@
     u_char saved_page;
     unsigned bytes_rcvd;
     unsigned int_status, eth_status, rx_status, tx_status;
-    unsigned rsr, pktlen;
+    unsigned rsr, pktlen, handled = 1;
     ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days
 				  * is this something to worry about?
 				  * -- on a laptop?
 				  */
 
     if (!netif_device_present(dev))
-	return;
+	return IRQ_NONE;
 
     ioaddr = dev->base_addr;
     if (lp->mohawk) { /* must disable the interrupt */
@@ -1330,6 +1330,7 @@
   loop_entry:
     if (int_status == 0xff) { /* card may be ejected */
 	DEBUG(3, "%s: interrupt %d for dead card\n", dev->name, irq);
+	handled = 0;
 	goto leave;
     }
     eth_status = GetByte(XIRCREG_ESR);
@@ -1514,6 +1515,7 @@
      * force an interrupt with this command:
      *	  PutByte(XIRCREG_CR, EnableIntr|ForceIntr);
      */
+    return IRQ_RETVAL(handled);
 } /* xirc2ps_interrupt */
 
 /*====================================================================*/
diff -Nru a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c
--- a/drivers/net/pcnet32.c	Sun Apr 20 21:26:42 2003
+++ b/drivers/net/pcnet32.c	Tue May 20 20:02:19 2003
@@ -638,6 +638,7 @@
 	    release_region(ioaddr, PCNET32_TOTAL_SIZE);
 	    return -ENOMEM;
     }
+    SET_NETDEV_DEV(dev, &pdev->dev);
 
     printk(KERN_INFO PFX "%s at %#3lx,", chipname, ioaddr);
 
@@ -718,6 +719,7 @@
     spin_lock_init(&lp->lock);
     
     SET_MODULE_OWNER(dev);
+    SET_NETDEV_DEV(dev, &pdev->dev);
     dev->priv = lp;
     lp->name = chipname;
     lp->shared_irq = shared;
diff -Nru a/drivers/net/ppp_deflate.c b/drivers/net/ppp_deflate.c
--- a/drivers/net/ppp_deflate.c	Sun May  4 06:10:30 2003
+++ b/drivers/net/ppp_deflate.c	Sun May  4 15:20:44 2003
@@ -88,7 +88,6 @@
 		if (state->strm.workspace)
 			vfree(state->strm.workspace);
 		kfree(state);
-		MOD_DEC_USE_COUNT;
 	}
 }
 
@@ -118,7 +117,6 @@
 	if (state == NULL)
 		return NULL;
 
-	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
 	state->strm.next_in   = NULL;
 	state->w_size         = w_size;
@@ -274,7 +272,6 @@
 		if (state->strm.workspace)
 			kfree(state->strm.workspace);
 		kfree(state);
-		MOD_DEC_USE_COUNT;
 	}
 }
 
@@ -303,7 +300,6 @@
 	if (state == NULL)
 		return NULL;
 
-	MOD_INC_USE_COUNT;
 	memset (state, 0, sizeof (struct ppp_deflate_state));
 	state->w_size         = w_size;
 	state->strm.next_out  = NULL;
diff -Nru a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c
--- a/drivers/net/ppp_generic.c	Sun May  4 06:10:30 2003
+++ b/drivers/net/ppp_generic.c	Mon May 19 23:22:51 2003
@@ -57,7 +57,9 @@
 #define NP_IPV6	1		/* Internet Protocol V6 */
 #define NP_IPX	2		/* IPX protocol */
 #define NP_AT	3		/* Appletalk protocol */
-#define NUM_NP	4		/* Number of NPs. */
+#define NP_MPLS_UC 4		/* MPLS unicast */
+#define NP_MPLS_MC 5		/* MPLS multicast */
+#define NUM_NP	6		/* Number of NPs. */
 
 #define MPHDRLEN	6	/* multilink protocol header length */
 #define MPHDRLEN_SSN	4	/* ditto with short sequence numbers */
@@ -281,6 +283,10 @@
 		return NP_IPX;
 	case PPP_AT:
 		return NP_AT;
+	case PPP_MPLS_UC:
+		return NP_MPLS_UC;
+	case PPP_MPLS_MC:
+		return NP_MPLS_MC;
 	}
 	return -EINVAL;
 }
@@ -291,6 +297,8 @@
 	PPP_IPV6,
 	PPP_IPX,
 	PPP_AT,
+	PPP_MPLS_UC,
+	PPP_MPLS_MC,
 };
 	
 /* Translates an ethertype into an NP index */
@@ -306,6 +314,10 @@
 	case ETH_P_PPPTALK:
 	case ETH_P_ATALK:
 		return NP_AT;
+	case ETH_P_MPLS_UC:
+		return NP_MPLS_UC;
+	case ETH_P_MPLS_MC:
+		return NP_MPLS_MC;
 	}
 	return -1;
 }
@@ -316,6 +328,8 @@
 	ETH_P_IPV6,
 	ETH_P_IPX,
 	ETH_P_PPPTALK,
+	ETH_P_MPLS_UC,
+	ETH_P_MPLS_MC,
 };
 
 /*
@@ -784,11 +798,14 @@
 
 	printk(KERN_INFO "PPP generic driver version " PPP_VERSION "\n");
 	err = register_chrdev(PPP_MAJOR, "ppp", &ppp_device_fops);
+	if (!err) {
+		err = devfs_mk_cdev(MKDEV(PPP_MAJOR, 0),
+				S_IFCHR|S_IRUSR|S_IWUSR, "ppp");
+	}
+
 	if (err)
 		printk(KERN_ERR "failed to register PPP device (%d)\n", err);
-	devfs_register(NULL, "ppp", DEVFS_FL_DEFAULT, PPP_MAJOR, 0,
-		       S_IFCHR | S_IRUSR | S_IWUSR, &ppp_device_fops, NULL);
-	return 0;
+	return err;
 }
 
 /*
@@ -1931,9 +1948,6 @@
 	struct ppp_option_data data;
 	void *state, *ostate;
 	unsigned char ccp_option[CCP_MAX_OPTION_LENGTH];
-#ifdef CONFIG_KMOD
-	char modname[32];
-#endif
 
 	err = -EFAULT;
 	if (copy_from_user(&data, (void *) arg, sizeof(data))
@@ -1948,8 +1962,7 @@
 	cp = find_compressor(ccp_option[0]);
 #ifdef CONFIG_KMOD
 	if (cp == 0) {
-		sprintf(modname, "ppp-compress-%d", ccp_option[0]);
-		request_module(modname);
+		request_module("ppp-compress-%d", ccp_option[0]);
 		cp = find_compressor(ccp_option[0]);
 	}
 #endif /* CONFIG_KMOD */
@@ -2332,8 +2345,10 @@
 	ppp_unlock(ppp);
 	if (dev) {
 		rtnl_lock();
-		dev_close(dev);
+
+		/* This will call dev_close() for us. */
 		unregister_netdevice(dev);
+
 		rtnl_unlock();
 	}
 	cardmap_set(&all_ppp_units, ppp->file.index, NULL);
diff -Nru a/drivers/net/r8169.c b/drivers/net/r8169.c
--- a/drivers/net/r8169.c	Sun Apr 20 22:09:47 2003
+++ b/drivers/net/r8169.c	Tue May 20 20:02:19 2003
@@ -373,6 +373,7 @@
 	}
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 	tp = dev->priv;
 
 	// enable device (incl. PCI PM wakeup and hotplug setup)
diff -Nru a/drivers/net/rclanmtl.h b/drivers/net/rclanmtl.h
--- a/drivers/net/rclanmtl.h	Sun Apr 20 21:26:42 2003
+++ b/drivers/net/rclanmtl.h	Mon Apr 21 17:23:14 2003
@@ -54,10 +54,10 @@
 #include <asm/io.h>
 
 /* Debug stuff. Define for debug output */
-#define RCDEBUG
+#undef RCDEBUG
 
 #ifdef RCDEBUG
-#define dprintk(args...) printk(KERN_DEBUG "(rcpci45 driver:) " args)
+#define dprintk(args...) printk(KERN_DEBUG "rc: " args)
 #else
 #define dprintk(args...) { }
 #endif
diff -Nru a/drivers/net/rcpci45.c b/drivers/net/rcpci45.c
--- a/drivers/net/rcpci45.c	Sun Apr 20 21:26:42 2003
+++ b/drivers/net/rcpci45.c	Tue May 20 20:02:20 2003
@@ -179,6 +179,7 @@
 		goto err_out;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	error = pci_enable_device (pdev);
 	if (error) {
diff -Nru a/drivers/net/rrunner.c b/drivers/net/rrunner.c
--- a/drivers/net/rrunner.c	Sun Apr 27 20:36:19 2003
+++ b/drivers/net/rrunner.c	Tue May 20 20:02:20 2003
@@ -114,6 +114,7 @@
 	rrpriv = (struct rr_private *)dev->priv;
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_request_regions(pdev, "rrunner")) {
 		ret = -EIO;
diff -Nru a/drivers/net/sb1000.c b/drivers/net/sb1000.c
--- a/drivers/net/sb1000.c	Sun Apr 27 20:36:20 2003
+++ b/drivers/net/sb1000.c	Tue May 20 20:02:20 2003
@@ -49,7 +49,7 @@
 #include <linux/skbuff.h>
 #include <linux/delay.h>	/* for udelay() */
 #include <linux/etherdevice.h>
-#include <linux/isapnp.h>
+#include <linux/pnp.h>
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -131,146 +131,119 @@
 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}
+static const struct pnp_device_id sb1000_pnp_ids[] = {
+	{ "GIC1000", 0 },
+	{ "", 0 }
 };
+MODULE_DEVICE_TABLE(pnp, sb1000_pnp_ids);
 
-MODULE_DEVICE_TABLE(isapnp, id_table);
-
-/* probe for SB1000 using Plug-n-Play mechanism */
-int
-sb1000_probe(struct net_device *dev)
+static int
+sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
 {
-
+	struct net_device *dev;
 	unsigned short ioaddr[2], irq;
-	struct pnp_dev *idev=NULL;
 	unsigned int serial_number;
+	int error = -ENODEV;
 	
-	while(1)
-	{
-		/*
-		 *	Find the card
-		 */
-		 
-		idev=pnp_find_dev(NULL, ISAPNP_VENDOR('G','I','C'),
-			ISAPNP_FUNCTION(0x1000), idev);
-			
-		/*
-		 *	No card
-		 */
-		 
-		if(idev==NULL || idev->card == NULL)
-			return -ENODEV;
-			
-		/*
-		 *	Bring it online
-		 */
-		 
-		if (pnp_device_attach(idev) < 0)
-			continue;
-		if (pnp_activate_dev(idev) < 0) {
-		      __again:
-			pnp_device_detach(idev);
-			continue;
-		}
-		
-		/*
-		 *	Ports free ?
-		 */
-		 
-		if(!pnp_port_valid(idev, 0) || !pnp_port_valid(idev, 1) || !pnp_irq_valid(idev, 0))
-			goto __again;
+	if (pnp_device_attach(pdev) < 0)
+		return -ENODEV;
+	if (pnp_activate_dev(pdev) < 0)
+		goto out_detach;
+
+	if (!pnp_port_valid(pdev, 0) || !pnp_port_valid(pdev, 1))
+		goto out_disable;
+	if (!pnp_irq_valid(pdev, 0))
+		goto out_disable;
 		
-		serial_number = idev->card->serial;
+	serial_number = pdev->card->serial;
 		
-		ioaddr[0]=pnp_port_start(idev, 0);
-		ioaddr[1]=pnp_port_start(idev, 0);
+	ioaddr[0] = pnp_port_start(pdev, 0);
+	ioaddr[1] = pnp_port_start(pdev, 0);
 		
-		irq = pnp_irq(idev, 0);
+	irq = pnp_irq(pdev, 0);
 
-		/* check I/O base and IRQ */
-		if (dev->base_addr != 0 && dev->base_addr != ioaddr[0])
-			goto __again;
-		if (dev->mem_start != 0 && dev->mem_start != ioaddr[1])
-			goto __again;
-		if (dev->irq != 0 && dev->irq != irq)
-			goto __again;
-			
-		/*
-		 *	Ok set it up.
-		 */
-		if (!request_region(ioaddr[0], 16, dev->name))
-			goto __again;
-		if (!request_region(ioaddr[1], 16, dev->name)) {
-			release_region(ioaddr[0], 16);
-			goto __again;
-		}
+	if (!request_region(ioaddr[0], 16, dev->name))
+		goto out_disable;
+	if (!request_region(ioaddr[1], 16, dev->name))
+		goto out_release_region0;
 		 
-		dev->base_addr = ioaddr[0];
-		/* mem_start holds the second I/O address */
-		dev->mem_start = ioaddr[1];
-		dev->irq = irq;
-
-		if (sb1000_debug > 0)
-			printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), "
-				"S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr,
-				dev->mem_start, serial_number, dev->irq);
-
-		dev = init_etherdev(dev, 0);
-		if (!dev) {
-			pnp_device_detach(idev);
-			release_region(ioaddr[1], 16);
-			release_region(ioaddr[0], 16);
-			return -ENOMEM;
-		}
-		SET_MODULE_OWNER(dev);
-
-		/* Make up a SB1000-specific-data structure. */
-		dev->priv = kmalloc(sizeof(struct sb1000_private), GFP_KERNEL);
-		if (dev->priv == NULL)
-			return -ENOMEM;
-		memset(dev->priv, 0, sizeof(struct sb1000_private));
-
-		if (sb1000_debug > 0)
-			printk(KERN_NOTICE "%s", version);
-
-		/* The SB1000-specific entries in the device structure. */
-		dev->open = sb1000_open;
-		dev->do_ioctl = sb1000_dev_ioctl;
-		dev->hard_start_xmit = sb1000_start_xmit;
-		dev->stop = sb1000_close;
-		dev->get_stats = sb1000_stats;
-
-		/* Fill in the generic fields of the device structure. */
-		dev->change_mtu		= NULL;
-		dev->hard_header	= NULL;
-		dev->rebuild_header 	= NULL;
-		dev->set_mac_address 	= NULL;
-		dev->header_cache_update= NULL;
-
-		dev->type		= ARPHRD_ETHER;
-		dev->hard_header_len 	= 0;
-		dev->mtu		= 1500;
-		dev->addr_len		= ETH_ALEN;
-		/* hardware address is 0:0:serial_number */
-		dev->dev_addr[0] = 0;
-		dev->dev_addr[1] = 0;
-		dev->dev_addr[2] = serial_number >> 24 & 0xff;
-		dev->dev_addr[3] = serial_number >> 16 & 0xff;
-		dev->dev_addr[4] = serial_number >>  8 & 0xff;
-		dev->dev_addr[5] = serial_number >>  0 & 0xff;
-		dev->tx_queue_len	= 0;
-	
-		/* New-style flags. */
-		dev->flags		= IFF_POINTOPOINT|IFF_NOARP;
+	dev->base_addr = ioaddr[0];
+	/* mem_start holds the second I/O address */
+	dev->mem_start = ioaddr[1];
+	dev->irq = irq;
 
-		/* Lock resources */
+	if (sb1000_debug > 0)
+		printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), "
+			"S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr,
+			dev->mem_start, serial_number, dev->irq);
+
+	dev = alloc_etherdev(sizeof(struct sb1000_private));
+	if (!dev) {
+		error = -ENOMEM;
+		goto out_release_regions;
+	}
+
+	/*
+	 * The SB1000 is an rx-only cable modem device.  The uplink is a modem
+	 * and we do not want to arp on it.
+	 */
+	dev->flags = IFF_POINTOPOINT|IFF_NOARP;
+
+	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
+
+	if (sb1000_debug > 0)
+		printk(KERN_NOTICE "%s", version);
+
+	/* The SB1000-specific entries in the device structure. */
+	dev->open		= sb1000_open;
+	dev->do_ioctl		= sb1000_dev_ioctl;
+	dev->hard_start_xmit	= sb1000_start_xmit;
+	dev->stop		= sb1000_close;
+	dev->get_stats		= sb1000_stats;
+
+	/* hardware address is 0:0:serial_number */
+	dev->dev_addr[2]	= serial_number >> 24 & 0xff;
+	dev->dev_addr[3]	= serial_number >> 16 & 0xff;
+	dev->dev_addr[4]	= serial_number >>  8 & 0xff;
+	dev->dev_addr[5]	= serial_number >>  0 & 0xff;
+
+	pnp_set_drvdata(pdev, dev);
+
+	error = register_netdev(dev);
+	if (error)
+		goto out_unregister;
+	return 0;
 
-		return 0;
-	}
-}
+ out_unregister:
+	unregister_netdev(dev);
+ out_release_regions:
+	release_region(ioaddr[1], 16);
+ out_release_region0:
+	release_region(ioaddr[0], 16);
+ out_disable:
+	pnp_disable_dev(pdev);
+ out_detach:
+	pnp_device_detach(pdev);
+	return error;
+}
+
+static void
+sb1000_remove_one(struct pnp_dev *pdev)
+{
+	struct net_device *dev = pnp_get_drvdata(pdev);
+
+	unregister_netdev(dev);
+	release_region(dev->base_addr, 16);
+	release_region(dev->mem_start, 16);
+}
+
+static struct pnp_driver sb1000_driver = {
+	.name		= "sb1000",
+	.id_table	= sb1000_pnp_ids,
+	.probe		= sb1000_probe_one,
+	.remove		= sb1000_remove_one,
+};
 
 
 /*
@@ -1207,60 +1180,21 @@
 	return 0;
 }
 
-#ifdef MODULE
 MODULE_AUTHOR("Franco Venturi <fventuri@mediaone.net>");
 MODULE_DESCRIPTION("General Instruments SB1000 driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(io, "1-2i");
-MODULE_PARM(irq, "i");
-MODULE_PARM_DESC(io, "SB1000 I/O base addresses");
-MODULE_PARM_DESC(irq, "SB1000 IRQ number");
-
-static struct net_device dev_sb1000;
-static int io[2];
-static int irq;
-
-int
-init_module(void)
+static int __init
+sb1000_init(void)
 {
-	int i;
-	for (i = 0; i < 100; i++) {
-		sprintf(dev_sb1000.name, "cm%d", i);
-		if (dev_get(dev_sb1000.name) == 0) break;
-	}
-	if (i == 100) {
-		printk(KERN_ERR "sb1000: can't register any device cm<n>\n");
-		return -ENFILE;
-	}
-	dev_sb1000.init = sb1000_probe;
-	dev_sb1000.base_addr = io[0];
-	/* mem_start holds the second I/O address */
-	dev_sb1000.mem_start = io[1];
-	dev_sb1000.irq = irq;
-	if (register_netdev(&dev_sb1000) != 0) {
-		printk(KERN_ERR "sb1000: failed to register device (io: %03x,%03x   "
-			"irq: %d)\n", io[0], io[1], irq);
-		return -EIO;
-	}
-	return 0;
+	return pnp_register_driver(&sb1000_driver);
 }
 
-void cleanup_module(void)
+static void __exit
+sb1000_exit(void)
 {
-	unregister_netdev(&dev_sb1000);
-	release_region(dev_sb1000.base_addr, 16);
-	release_region(dev_sb1000.mem_start, 16);
-	kfree(dev_sb1000.priv);
-	dev_sb1000.priv = NULL;
+	pnp_unregister_driver(&sb1000_driver);
 }
-#endif /* MODULE */
-
-/*
- * Local variables:
- *  compile-command: "gcc -D__KERNEL__ -DMODULE -Wall -Wstrict-prototypes -O -m486 -c sb1000.c"
- *  version-control: t
- *  tab-width: 4
- *  c-basic-offset: 4
- * End:
- */
+
+module_init(sb1000_init);
+module_exit(sb1000_exit);
diff -Nru a/drivers/net/setup.c b/drivers/net/setup.c
--- a/drivers/net/setup.c	Mon Feb 17 15:39:52 2003
+++ b/drivers/net/setup.c	Mon May 19 23:57:38 2003
@@ -9,30 +9,17 @@
 #include <linux/init.h>
 #include <linux/netlink.h>
 
-extern int slip_init_ctrl_dev(void);
-extern int x25_asy_init_ctrl_dev(void);
-  
 extern int dmascc_init(void);
 
 extern int arcnet_init(void); 
 extern int scc_enet_init(void); 
 extern int fec_enet_init(void); 
-extern int dlci_setup(void); 
 extern int sdla_setup(void); 
 extern int sdla_c_setup(void); 
-extern int comx_init(void);
 extern int lmc_setup(void);
 
 extern int madgemc_probe(void);
 
-/* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */
-#define __PAD6 "\0\0\0\0\0\0\0\0\0"
-#define __PAD5 __PAD6 "\0"
-#define __PAD4 __PAD5 "\0"
-#define __PAD3 __PAD4 "\0"
-#define __PAD2 __PAD3 "\0"
-
-
 /*
  *	Devices in this list must do new style probing. That is they must
  *	allocate their own device objects and do their own bus scans.
@@ -52,9 +39,6 @@
 #if defined(CONFIG_DMASCC)
 	{dmascc_init, 0},
 #endif	
-#if defined(CONFIG_DLCI)
-	{dlci_setup, 0},
-#endif
 #if defined(CONFIG_SDLA)
 	{sdla_c_setup, 0},
 #endif
@@ -67,10 +51,6 @@
 #if defined(CONFIG_FEC_ENET)
         {fec_enet_init, 0},
 #endif
-#if defined(CONFIG_COMX)
-	{comx_init, 0},
-#endif
-	 
 #if defined(CONFIG_LANMEDIA)
 	{lmc_setup, 0},
 #endif
@@ -91,7 +71,7 @@
  *	into them.
  */
  
-static void __init network_probe(void)
+void __init net_device_init(void)
 {
 	struct net_probe *p = pci_probes;
 
@@ -100,48 +80,4 @@
 		p->status = p->probe();
 		p++;
 	}
-}
-
-
-/*
- *	Initialise the line discipline drivers
- */
- 
-static void __init network_ldisc_init(void)
-{
-#if defined(CONFIG_SLIP)
-	slip_init_ctrl_dev();
-#endif
-#if defined(CONFIG_X25_ASY)
-	x25_asy_init_ctrl_dev();
-#endif
-}
-
-
-static void __init special_device_init(void)
-{
-#ifdef CONFIG_NET_SB1000
-	extern int sb1000_probe(struct net_device *dev);
-
-	static struct net_device sb1000_dev = {
-		.name = "cm0" __PAD3,
-		.init = sb1000_probe,
-	};
-	register_netdev(&sb1000_dev);
-#endif
-}
-
-/*
- *	Initialise network devices
- */
- 
-void __init net_device_init(void)
-{
-	/* Devices supporting the new probing API */
-	network_probe();
-	/* Line disciplines */
-	network_ldisc_init();
-	/* Special devices */
-	special_device_init();
-	/* That kicks off the legacy init functions */
 }
diff -Nru a/drivers/net/sis900.c b/drivers/net/sis900.c
--- a/drivers/net/sis900.c	Sun Apr 20 21:26:42 2003
+++ b/drivers/net/sis900.c	Tue May 20 20:02:20 2003
@@ -397,6 +397,7 @@
 	if (!net_dev)
 		return -ENOMEM;
 	SET_MODULE_OWNER(net_dev);
+	SET_NETDEV_DEV(net_dev, &pci_dev->dev);
 
 	/* We do a request_region() to register /proc/ioports info. */
 	ioaddr = pci_resource_start(pci_dev, 0);	
diff -Nru a/drivers/net/sk98lin/skge.c b/drivers/net/sk98lin/skge.c
--- a/drivers/net/sk98lin/skge.c	Sun Apr 20 23:39:12 2003
+++ b/drivers/net/sk98lin/skge.c	Tue May 20 20:02:20 2003
@@ -348,12 +348,12 @@
 static int	SkGeIocMib(DEV_NET*, unsigned int, int);
 
 
-/*Extern */
+static const char SK_Root_Dir_entry[] = "sk98lin";
+static struct proc_dir_entry *pSkRootDir;
 
-extern struct proc_dir_entry *pSkRootDir;
 
 //extern struct proc_dir_entry Our_Proc_Dir;
-extern int proc_read(char *buffer, char **buffer_location,
+extern int sk_proc_read(char *buffer, char **buffer_location,
 	off_t offset, int buffer_length, int *eof, void *data);
 
 
@@ -376,17 +376,6 @@
 static uintptr_t RxQueueAddr[SK_MAX_MACS] = {0x400, 0x480};
 
 
-
-void proc_fill_inode(struct inode *inode, int fill)
-{
-	if (fill)
-		MOD_INC_USE_COUNT;
-	else
-		MOD_DEC_USE_COUNT;
-}
-
-
-
 /*****************************************************************************
  *
  * 	skge_probe - find all SK-98xx adapters
@@ -471,6 +460,7 @@
 		dev->irq = pdev->irq;
 
 		SET_MODULE_OWNER(dev);
+		SET_NETDEV_DEV(dev, &pdev->dev);
 		dev->open =		&SkGeOpen;
 		dev->stop =		&SkGeClose;
 		dev->hard_start_xmit =	&SkGeXmit;
@@ -481,20 +471,20 @@
 		dev->change_mtu =	&SkGeChangeMtu;
 
 		if(!proc_root_initialized) {
-			pSkRootDir = create_proc_entry("sk98lin",
+			pSkRootDir = create_proc_entry(SK_Root_Dir_entry,
 				S_IFDIR | S_IWUSR | S_IRUGO | S_IXUGO, proc_net);
 			pSkRootDir->owner = THIS_MODULE;
-
 			proc_root_initialized = 1;
 		}
 
 		pProcFile = create_proc_entry(dev->name, 
 			S_IFREG | 0444, pSkRootDir);
-		pProcFile->read_proc = proc_read;
+ 		pProcFile->read_proc = sk_proc_read;
 		pProcFile->write_proc = NULL;
 		pProcFile->nlink = 1;
 		pProcFile->size = sizeof(dev->name+1);
 		pProcFile->data = (void*)pProcFile;
+		pProcFile->owner = THIS_MODULE;
 
 		/*
 		 * Dummy value.
@@ -571,11 +561,12 @@
 
 			pProcFile = create_proc_entry(dev->name, 
 				S_IFREG | 0444, pSkRootDir);
-			pProcFile->read_proc = proc_read;
+			pProcFile->read_proc = sk_proc_read;
 			pProcFile->write_proc = NULL;
 			pProcFile->nlink = 1;
 			pProcFile->size = sizeof(dev->name+1);
 			pProcFile->data = (void*)pProcFile;
+			pProcFile->owner = THIS_MODULE;
 
 			memcpy((caddr_t) &dev->dev_addr,
 			(caddr_t) &pAC->Addr.Net[1].CurrentMacAddress, 6);
diff -Nru a/drivers/net/sk98lin/skproc.c b/drivers/net/sk98lin/skproc.c
--- a/drivers/net/sk98lin/skproc.c	Mon Feb  4 23:45:07 2002
+++ b/drivers/net/sk98lin/skproc.c	Thu May  8 09:41:49 2003
@@ -54,7 +54,6 @@
 //#define SPECIAL	32		/* 0x */
 #define LARGE	64
 
-extern void proc_fill_inode(struct inode *inode, int fill);
 extern char * SkNumber(char * str, long long num, int base, int size, 
 				int precision ,int type);
 int proc_read(char *buffer,
@@ -64,19 +63,8 @@
 				int *eof,
 				void *data);
 
-static const char SK_Root_Dir_entry[] = "sk98lin";
-extern struct net_device *sk98lin_root_dev;
-
-
-struct proc_dir_entry pSkRootDir = { 
-	0,
-	sizeof(SK_Root_Dir_entry)-1,
-	(const char*)SK_Root_Dir_entry,
-	S_IFDIR | S_IRUGO,
-	2, 0, 0, 0, NULL,
-	NULL
-};
 
+extern struct net_device *sk98lin_root_dev;
 
 /*****************************************************************************
  *
@@ -90,7 +78,7 @@
  * Returns: buffer with statistic data
  *	
  */
-int proc_read(char *buffer,
+int sk_proc_read(char *buffer,
 char **buffer_location,
 off_t offset,
 int buffer_length,
diff -Nru a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c
--- a/drivers/net/skfp/skfddi.c	Sun Apr 27 20:36:20 2003
+++ b/drivers/net/skfp/skfddi.c	Thu May  8 17:40:17 2003
@@ -539,6 +539,8 @@
 	dev->header_cache_update = NULL;	/* not supported */
 	dev->change_mtu = NULL;	/* set in fddi_setup() */
 
+	SET_MODULE_OWNER(dev);
+
 	/* Initialize remaining device structure information */
 	fddi_setup(dev);
 }				// init_device
@@ -791,8 +793,6 @@
 	smt_online(smc, 1);
 	STI_FBI();
 
-	MOD_INC_USE_COUNT;
-
 	/* Clear local multicast address tables */
 	mac_clear_multicast(smc);
 
@@ -853,8 +853,6 @@
 		bp->QueueSkb++;
 		dev_kfree_skb(skb);
 	}
-
-	MOD_DEC_USE_COUNT;
 
 	return (0);
 }				// skfp_close
diff -Nru a/drivers/net/slip.c b/drivers/net/slip.c
--- a/drivers/net/slip.c	Mon Apr 21 20:58:43 2003
+++ b/drivers/net/slip.c	Mon May 19 23:22:51 2003
@@ -81,11 +81,7 @@
 #include <net/slhc_vj.h>
 #endif
 
-#ifdef MODULE
-#define SLIP_VERSION    "0.8.4-NET3.019-NEWTTY-MODULAR"
-#else
-#define	SLIP_VERSION	"0.8.4-NET3.019-NEWTTY"
-#endif
+#define SLIP_VERSION	"0.8.4-NET3.019-NEWTTY"
 
 
 typedef struct slip_ctrl {
@@ -98,8 +94,6 @@
 MODULE_PARM(slip_maxdev, "i");
 MODULE_PARM_DESC(slip_maxdev, "Maximum number of slip devices");
 
-static struct tty_ldisc	sl_ldisc;
-
 static int slip_esc(unsigned char *p, unsigned char *d, int len);
 static void slip_unesc(struct slip *sl, unsigned char c);
 #ifdef CONFIG_SLIP_MODE_SLIP6
@@ -1309,13 +1303,24 @@
 #endif
 /* VSV changes end */
 
-/* Initialize SLIP control device -- register SLIP line discipline */
+static struct tty_ldisc	sl_ldisc = {
+	.owner 		= THIS_MODULE,
+	.magic 		= TTY_LDISC_MAGIC,
+	.name 		= "slip",
+	.open 		= slip_open,
+	.close	 	= slip_close,
+	.ioctl		= slip_ioctl,
+	.receive_buf	= slip_receive_buf,
+	.receive_room	= slip_receive_room,
+	.write_wakeup	= slip_write_wakeup,
+};
 
-int __init slip_init_ctrl_dev(void)
+static int __init slip_init(void)
 {
 	int status;
 
-	if (slip_maxdev < 4) slip_maxdev = 4; /* Sanity */
+	if (slip_maxdev < 4)
+		slip_maxdev = 4; /* Sanity */
 
 	printk(KERN_INFO "SLIP: version %s (dynamic channels, max=%d)"
 #ifdef CONFIG_SLIP_MODE_SLIP6
@@ -1323,16 +1328,15 @@
 #endif
 	       ".\n",
 	       SLIP_VERSION, slip_maxdev );
-#if defined(SL_INCLUDE_CSLIP) && !defined(MODULE)
+#if defined(SL_INCLUDE_CSLIP)
 	printk(KERN_INFO "CSLIP: code copyright 1989 Regents of the University of California.\n");
 #endif
 #ifdef CONFIG_SLIP_SMART
 	printk(KERN_INFO "SLIP linefill/keepalive option.\n");
 #endif
 
-	slip_ctrls = (slip_ctrl_t **) kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL);
-	if (slip_ctrls == NULL)
-	{
+	slip_ctrls = kmalloc(sizeof(void*)*slip_maxdev, GFP_KERNEL);
+	if (!slip_ctrls) {
 		printk(KERN_ERR "SLIP: Can't allocate slip_ctrls[] array!  Uaargh! (-> No SLIP available)\n");
 		return -ENOMEM;
 	}
@@ -1347,28 +1351,7 @@
 	return status;
 }
 
-static struct tty_ldisc	sl_ldisc =
-{
-	.owner 		=	THIS_MODULE,
-	.magic 		= 	TTY_LDISC_MAGIC,
-	.name 		= 	"slip",
-	.open 		= 	slip_open,
-	.close	 	= 	slip_close,
-	.ioctl		=	slip_ioctl,
-	.receive_buf	=	slip_receive_buf,
-	.receive_room	=	slip_receive_room,
-	.write_wakeup	=	slip_write_wakeup,
-};
-
-#ifdef MODULE
-
-int init_module(void)
-{
-	return slip_init_ctrl_dev();
-}
-
-void
-cleanup_module(void)
+static void __exit slip_exit(void)
 {
 	int i;
 
@@ -1425,7 +1408,9 @@
 		printk(KERN_ERR "SLIP: can't unregister line discipline (err = %d)\n", i);
 	}
 }
-#endif /* MODULE */
+
+module_init(slip_init);
+module_exit(slip_exit);
 
 #ifdef CONFIG_SLIP_SMART
 /*
diff -Nru a/drivers/net/slip.h b/drivers/net/slip.h
--- a/drivers/net/slip.h	Mon Apr 21 20:58:43 2003
+++ b/drivers/net/slip.h	Thu May  8 09:47:21 2003
@@ -116,10 +116,6 @@
 #endif  
 };
 
-
-
 #define SLIP_MAGIC 0x5302
-
-extern int slip_init(struct net_device *dev);
 
 #endif	/* _LINUX_SLIP.H */
diff -Nru a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c
--- a/drivers/net/smc-mca.c	Sat Dec  7 11:19:12 2002
+++ b/drivers/net/smc-mca.c	Tue May 20 20:02:20 2003
@@ -207,6 +207,7 @@
 		return -ENODEV;
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, gen_dev);
 
 	if((i = register_netdev(dev)) != 0)
 		return i;
diff -Nru a/drivers/net/starfire.c b/drivers/net/starfire.c
--- a/drivers/net/starfire.c	Sun Apr 20 21:58:27 2003
+++ b/drivers/net/starfire.c	Tue May 20 20:02:20 2003
@@ -876,6 +876,7 @@
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	irq = pdev->irq;
 
diff -Nru a/drivers/net/sundance.c b/drivers/net/sundance.c
--- a/drivers/net/sundance.c	Fri Apr 25 20:32:05 2003
+++ b/drivers/net/sundance.c	Tue May 20 20:02:20 2003
@@ -548,6 +548,7 @@
 	if (!dev)
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_request_regions(pdev, DRV_NAME))
 		goto err_out_netdev;
diff -Nru a/drivers/net/sungem.c b/drivers/net/sungem.c
--- a/drivers/net/sungem.c	Mon Apr 21 00:00:25 2003
+++ b/drivers/net/sungem.c	Tue May 20 20:02:20 2003
@@ -1,4 +1,4 @@
-/* $Id: sungem.c,v 1.49 2002/01/23 15:40:45 davem Exp $
+/* $Id: sungem.c,v 1.44.2.22 2002/03/13 01:18:12 davem Exp $
  * sungem.c: Sun GEM ethernet driver.
  *
  * Copyright (C) 2000, 2001, 2002 David S. Miller (davem@redhat.com)
@@ -10,13 +10,8 @@
  *  - Get rid of all those nasty mdelay's and replace them
  * with schedule_timeout.
  *  - Implement WOL
- *  - Currently, forced Gb mode is only supported on bcm54xx
- *    PHY for which I use the SPD2 bit of the control register.
- *    On m1011 PHY, I can't force as I don't have the specs, but
- *    I can at least detect gigabit with autoneg.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
@@ -60,12 +55,20 @@
 #include <asm/pmac_feature.h>
 #endif
 
+#include "sungem_phy.h"
 #include "sungem.h"
 
+/* Stripping FCS is causing problems, disabled for now */
+#undef STRIP_FCS
+
 #define DEFAULT_MSG	(NETIF_MSG_DRV		| \
 			 NETIF_MSG_PROBE	| \
 			 NETIF_MSG_LINK)
 
+#define ADVERTISE_MASK	(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
+			 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
+			 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
+
 #define DRV_NAME	"sungem"
 #define DRV_VERSION	"0.97"
 #define DRV_RELDATE	"3/20/02"
@@ -78,24 +81,6 @@
 MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
 MODULE_LICENSE("GPL");
 
-MODULE_PARM(gem_debug, "i");
-MODULE_PARM_DESC(gem_debug, "bitmapped message enable number");
-MODULE_PARM(link_mode, "i");
-MODULE_PARM_DESC(link_mode, "default link mode");
-
-int gem_debug = -1;
-static int link_mode;
-
-static u16 link_modes[] __devinitdata = {
-	BMCR_ANENABLE,			/* 0 : autoneg */
-	0,				/* 1 : 10bt half duplex */
-	BMCR_SPEED100,			/* 2 : 100bt half duplex */
-	BMCR_SPD2, /* bcm54xx only */   /* 3 : 1000bt half duplex */
-	BMCR_FULLDPLX,			/* 4 : 10bt full duplex */
-	BMCR_SPEED100|BMCR_FULLDPLX,	/* 5 : 100bt full duplex */
-	BMCR_SPD2|BMCR_FULLDPLX		/* 6 : 1000bt full duplex */
-};
-
 #define GEM_MODULE_NAME	"gem"
 #define PFX GEM_MODULE_NAME ": "
 
@@ -116,12 +101,14 @@
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMACP,
 	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+	{ PCI_VENDOR_ID_APPLE, PCI_DEVICE_ID_APPLE_UNI_N_GMAC2,
+	  PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
 	{0, }
 };
 
 MODULE_DEVICE_TABLE(pci, gem_pci_tbl);
 
-static u16 __phy_read(struct gem *gp, int reg, int phy_addr)
+static u16 __phy_read(struct gem *gp, int phy_addr, int reg)
 {
 	u32 cmd;
 	int limit = 10000;
@@ -147,12 +134,18 @@
 	return cmd & MIF_FRAME_DATA;
 }
 
+static inline int _phy_read(struct net_device *dev, int mii_id, int reg)
+{
+	struct gem *gp = dev->priv;
+	return __phy_read(gp, mii_id, reg);
+}
+
 static inline u16 phy_read(struct gem *gp, int reg)
 {
-	return __phy_read(gp, reg, gp->mii_phy_addr);
+	return __phy_read(gp, gp->mii_phy_addr, reg);
 }
 
-static void __phy_write(struct gem *gp, int reg, u16 val, int phy_addr)
+static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val)
 {
 	u32 cmd;
 	int limit = 10000;
@@ -174,9 +167,15 @@
 	}
 }
 
+static inline void _phy_write(struct net_device *dev, int mii_id, int reg, int val)
+{
+	struct gem *gp = dev->priv;
+	__phy_write(gp, mii_id, reg, val & 0xffff);
+}
+
 static inline void phy_write(struct gem *gp, int reg, u16 val)
 {
-	__phy_write(gp, reg, val, gp->mii_phy_addr);
+	__phy_write(gp, gp->mii_phy_addr, reg, val);
 }
 
 static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits)
@@ -225,10 +224,11 @@
 	if (pcs_miistat & PCS_MIISTAT_LS) {
 		printk(KERN_INFO "%s: PCS link is now up.\n",
 		       dev->name);
+		netif_carrier_on(gp->dev);
 	} else {
 		printk(KERN_INFO "%s: PCS link is now down.\n",
 		       dev->name);
-
+		netif_carrier_off(gp->dev);
 		/* If this happens and the link timer is not running,
 		 * reset so we re-negotiate.
 		 */
@@ -1006,7 +1006,7 @@
 	} while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST));
 
 	if (limit <= 0)
-		printk(KERN_ERR "gem: SW reset is ghetto.\n");
+		printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name);
 }
 
 /* Must be invoked under gp->lock. */
@@ -1033,136 +1033,118 @@
 
 }
 
-/* Link modes of the BCM5400 PHY */
-static int phy_BCM5400_link_table[8][3] = {
-	{ 0, 0, 0 },	/* No link */
-	{ 0, 0, 0 },	/* 10BT Half Duplex */
-	{ 1, 0, 0 },	/* 10BT Full Duplex */
-	{ 0, 1, 0 },	/* 100BT Half Duplex */
-	{ 0, 1, 0 },	/* 100BT Half Duplex */
-	{ 1, 1, 0 },	/* 100BT Full Duplex*/
-	{ 1, 0, 1 },	/* 1000BT */
-	{ 1, 0, 1 },	/* 1000BT */
-};
 
 /* Must be invoked under gp->lock. */
+// XXX dbl check what that function should do when called on PCS PHY
 static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
 {
-	u16 ctl;
+	u32 advertise, features;
+	int autoneg;
+	int speed;
+	int duplex;
+
+	if (gp->phy_type != phy_mii_mdio0 &&
+     	    gp->phy_type != phy_mii_mdio1)
+     	    	goto non_mii;
+
+	/* Setup advertise */
+	if (found_mii_phy(gp))
+		features = gp->phy_mii.def->features;
+	else
+		features = 0;
+
+	advertise = features & ADVERTISE_MASK;
+	if (gp->phy_mii.advertising != 0)
+		advertise &= gp->phy_mii.advertising;
+
+	autoneg = gp->want_autoneg;
+	speed = gp->phy_mii.speed;
+	duplex = gp->phy_mii.duplex;
 	
 	/* Setup link parameters */
 	if (!ep)
 		goto start_aneg;
 	if (ep->autoneg == AUTONEG_ENABLE) {
-		/* TODO: parse ep->advertising */
-		gp->link_advertise |= (ADVERTISE_10HALF | ADVERTISE_10FULL);
-		gp->link_advertise |= (ADVERTISE_100HALF | ADVERTISE_100FULL);
-		/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
-		gp->link_cntl = BMCR_ANENABLE;
+		advertise = ep->advertising;
+		autoneg = 1;
 	} else {
-		gp->link_cntl = 0;
-		if (ep->speed == SPEED_100)
-			gp->link_cntl |= BMCR_SPEED100;
-		else if (ep->speed == SPEED_1000 && gp->gigabit_capable)
-			/* Hrm... check if this is right... */
-			gp->link_cntl |= BMCR_SPD2;
-		if (ep->duplex == DUPLEX_FULL)
-			gp->link_cntl |= BMCR_FULLDPLX;
+		autoneg = 0;
+		speed = ep->speed;
+		duplex = ep->duplex;
 	}
 
 start_aneg:
-	if (!gp->hw_running)
+	/* Sanitize settings based on PHY capabilities */
+	if ((features & SUPPORTED_Autoneg) == 0)
+		autoneg = 0;
+	if (speed == SPEED_1000 &&
+	    !(features & (SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)))
+		speed = SPEED_100;
+	if (speed == SPEED_100 &&
+	    !(features & (SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full)))
+		speed = SPEED_10;
+	if (duplex == DUPLEX_FULL &&
+	    !(features & (SUPPORTED_1000baseT_Full |
+	    		  SUPPORTED_100baseT_Full |
+	    		  SUPPORTED_10baseT_Full)))
+	    	duplex = DUPLEX_HALF;
+	if (speed == 0)
+		speed = SPEED_10;
+	
+	/* If HW is down, we don't try to actually setup the PHY, we
+	 * just store the settings
+	 */
+	if (!gp->hw_running) {
+		gp->phy_mii.autoneg = gp->want_autoneg = autoneg;
+		gp->phy_mii.speed = speed;
+		gp->phy_mii.duplex = duplex;
 		return;
+	}
 
 	/* Configure PHY & start aneg */
-	ctl = phy_read(gp, MII_BMCR);
-	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
-	ctl |= gp->link_cntl;
-	if (ctl & BMCR_ANENABLE) {
-		ctl |= BMCR_ANRESTART;
+	gp->want_autoneg = autoneg;
+	if (autoneg) {
+		if (found_mii_phy(gp))
+			gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, advertise);
 		gp->lstate = link_aneg;
 	} else {
+		if (found_mii_phy(gp))
+			gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, speed, duplex);
 		gp->lstate = link_force_ok;
 	}
-	phy_write(gp, MII_BMCR, ctl);
 
+non_mii:
 	gp->timer_ticks = 0;
 	mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
 }
 
-/* Must be invoked under gp->lock. */
-static void gem_read_mii_link_mode(struct gem *gp, int *fd, int *spd, int *pause)
-{
-	u32 val;
-
-	*fd = 0;
-	*spd = 10;
-	*pause = 0;
-	
-	if (gp->phy_mod == phymod_bcm5400 ||
-	    gp->phy_mod == phymod_bcm5401 ||
-	    gp->phy_mod == phymod_bcm5411) {
-		int link_mode;	
-
-	    	val = phy_read(gp, MII_BCM5400_AUXSTATUS);
-		link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
-			     MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
-		*fd = phy_BCM5400_link_table[link_mode][0];
-		*spd = phy_BCM5400_link_table[link_mode][2] ?
-			1000 :
-			(phy_BCM5400_link_table[link_mode][1] ? 100 : 10);
-		val = phy_read(gp, MII_LPA);
-		if (val & LPA_PAUSE)
-			*pause = 1;
-	} else {
-		val = phy_read(gp, MII_LPA);
-
-		if (val & (LPA_10FULL | LPA_100FULL))
-			*fd = 1;
-		if (val & (LPA_100FULL | LPA_100HALF))
-			*spd = 100;
-
-		if (gp->phy_mod == phymod_m1011) {
-			val = phy_read(gp, 0x0a);
-			if (val & 0xc00)
-				*spd = 1000;
-			if (val & 0x800)
-				*fd = 1;
-		}
-	}
-}
-
 /* A link-up condition has occurred, initialize and enable the
  * rest of the chip.
  *
  * Must be invoked under gp->lock.
  */
-static void gem_set_link_modes(struct gem *gp)
+static int gem_set_link_modes(struct gem *gp)
 {
 	u32 val;
 	int full_duplex, speed, pause;
 
 	full_duplex = 0;
-	speed = 10;
+	speed = SPEED_10;
 	pause = 0;
 
-	if (gp->phy_type == phy_mii_mdio0 ||
-	    gp->phy_type == phy_mii_mdio1) {
-		val = phy_read(gp, MII_BMCR);
-		if (val & BMCR_ANENABLE)
-			gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
-		else {
-			if (val & BMCR_FULLDPLX)
-				full_duplex = 1;
-			if (val & BMCR_SPEED100)
-				speed = 100;
-		}
-	} else {
+	if (found_mii_phy(gp)) {
+	    	if (gp->phy_mii.def->ops->read_link(&gp->phy_mii))
+	    		return 1;
+		full_duplex = (gp->phy_mii.duplex == DUPLEX_FULL);
+		speed = gp->phy_mii.speed;
+		pause = gp->phy_mii.pause;
+	} else if (gp->phy_type == phy_serialink ||
+	    	   gp->phy_type == phy_serdes) {
 		u32 pcs_lpa = readl(gp->regs + PCS_MIILP);
 
 		if (pcs_lpa & PCS_MIIADV_FD)
 			full_duplex = 1;
-		speed = 1000;
+		speed = SPEED_1000;
 	}
 
 	if (netif_msg_link(gp))
@@ -1186,7 +1168,7 @@
 		val |= MAC_XIFCFG_FLED;
 	}
 
-	if (speed == 1000)
+	if (speed == SPEED_1000)
 		val |= (MAC_XIFCFG_GMII);
 
 	writel(val, gp->regs + MAC_XIFCFG);
@@ -1194,7 +1176,7 @@
 	/* If gigabit and half-duplex, enable carrier extension
 	 * mode.  Else, disable it.
 	 */
-	if (speed == 1000 && !full_duplex) {
+	if (speed == SPEED_1000 && !full_duplex) {
 		val = readl(gp->regs + MAC_TXCFG);
 		writel(val | MAC_TXCFG_TCE, gp->regs + MAC_TXCFG);
 
@@ -1242,50 +1224,51 @@
 	writel(val, gp->regs + MAC_MCCFG);
 
 	gem_start_dma(gp);
+
+	return 0;
 }
 
 /* Must be invoked under gp->lock. */
 static int gem_mdio_link_not_up(struct gem *gp)
 {
-	u16 val;
-	
-	if (gp->lstate == link_force_ret) {
+	switch (gp->lstate) {
+	case link_force_ret:
 		if (netif_msg_link(gp))
 			printk(KERN_INFO "%s: Autoneg failed again, keeping"
 				" forced mode\n", gp->dev->name);
-		phy_write(gp, MII_BMCR, gp->link_fcntl);
+		gp->phy_mii.def->ops->setup_forced(&gp->phy_mii,
+			gp->last_forced_speed, DUPLEX_HALF);
 		gp->timer_ticks = 5;
 		gp->lstate = link_force_ok;
-	} else if (gp->lstate == link_aneg) {
-		val = phy_read(gp, MII_BMCR);
-
+		return 0;
+	case link_aneg:
 		if (netif_msg_link(gp))
 			printk(KERN_INFO "%s: switching to forced 100bt\n",
 				gp->dev->name);
 		/* Try forced modes. */
-		val &= ~(BMCR_ANRESTART | BMCR_ANENABLE);
-		val &= ~(BMCR_FULLDPLX);
-		val |= BMCR_SPEED100;
-		phy_write(gp, MII_BMCR, val);
+		gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_100,
+			DUPLEX_HALF);
 		gp->timer_ticks = 5;
 		gp->lstate = link_force_try;
-	} else {
+		return 0;
+	case link_force_try:
 		/* Downgrade from 100 to 10 Mbps if necessary.
 		 * If already at 10Mbps, warn user about the
 		 * situation every 10 ticks.
 		 */
-		val = phy_read(gp, MII_BMCR);
-		if (val & BMCR_SPEED100) {
-			val &= ~BMCR_SPEED100;
-			phy_write(gp, MII_BMCR, val);
+		if (gp->phy_mii.speed == SPEED_100) {
+			gp->phy_mii.def->ops->setup_forced(&gp->phy_mii, SPEED_10,
+				DUPLEX_HALF);
 			gp->timer_ticks = 5;
 			if (netif_msg_link(gp))
 				printk(KERN_INFO "%s: switching to forced 10bt\n",
 					gp->dev->name);
+			return 0;
 		} else
 			return 1;
+	default:
+		return 0;
 	}
-	return 0;
 }
 
 static void gem_init_rings(struct gem *);
@@ -1325,7 +1308,8 @@
 static void gem_link_timer(unsigned long data)
 {
 	struct gem *gp = (struct gem *) data;
-
+	int restart_aneg = 0;
+		
 	if (!gp->hw_running)
 		return;
 
@@ -1337,62 +1321,8 @@
 	if (gp->reset_task_pending)
 		goto restart;
 	    	
-	if (gp->phy_type == phy_mii_mdio0 ||
-	    gp->phy_type == phy_mii_mdio1) {
-		u16 val = phy_read(gp, MII_BMSR);
-		u16 cntl = phy_read(gp, MII_BMCR);
-		int up;
-
-		/* When using autoneg, we really wait for ANEGCOMPLETE or we may
-		 * get a "transcient" incorrect link state
-		 */
-		if (cntl & BMCR_ANENABLE)
-			up = (val & (BMSR_ANEGCOMPLETE | BMSR_LSTATUS)) == (BMSR_ANEGCOMPLETE | BMSR_LSTATUS);
-		else
-			up = (val & BMSR_LSTATUS) != 0;
-		if (up) {
-			/* Ok, here we got a link. If we had it due to a forced
-			 * fallback, and we were configured for autoneg, we do
-			 * retry a short autoneg pass. If you know your hub is
-			 * broken, use ethtool ;)
-			 */
-			if (gp->lstate == link_force_try && (gp->link_cntl & BMCR_ANENABLE)) {
-				gp->lstate = link_force_ret;
-				gp->link_fcntl = phy_read(gp, MII_BMCR);
-				gp->timer_ticks = 5;
-				if (netif_msg_link(gp))
-					printk(KERN_INFO "%s: Got link after fallback, retrying"
-						" autoneg once...\n", gp->dev->name);
-				phy_write(gp, MII_BMCR,
-					  gp->link_fcntl | BMCR_ANENABLE | BMCR_ANRESTART);
-			} else if (gp->lstate != link_up) {
-				gp->lstate = link_up;
-				if (gp->opened)
-					gem_set_link_modes(gp);
-			}
-		} else {
-			int restart = 0;
-
-			/* If the link was previously up, we restart the
-			 * whole process
-			 */
-			if (gp->lstate == link_up) {
-				gp->lstate = link_down;
-				if (netif_msg_link(gp))
-					printk(KERN_INFO "%s: Link down\n",
-						gp->dev->name);
-				gp->reset_task_pending = 2;
-				schedule_work(&gp->reset_task);
-				restart = 1;
-			} else if (++gp->timer_ticks > 10)
-				restart = gem_mdio_link_not_up(gp);
-
-			if (restart) {
-				gem_begin_auto_negotiation(gp, NULL);
-				goto out_unlock;
-			}
-		}
-	} else {
+	if (gp->phy_type == phy_serialink ||
+	    gp->phy_type == phy_serdes) {
 		u32 val = readl(gp->regs + PCS_MIISTAT);
 
 		if (!(val & PCS_MIISTAT_LS))
@@ -1400,11 +1330,56 @@
 
 		if ((val & PCS_MIISTAT_LS) != 0) {
 			gp->lstate = link_up;
+			netif_carrier_on(gp->dev);
 			if (gp->opened)
-				gem_set_link_modes(gp);
+				(void)gem_set_link_modes(gp);
 		}
+		goto restart;
+	}
+	if (found_mii_phy(gp) && gp->phy_mii.def->ops->poll_link(&gp->phy_mii)) {
+		/* Ok, here we got a link. If we had it due to a forced
+		 * fallback, and we were configured for autoneg, we do
+		 * retry a short autoneg pass. If you know your hub is
+		 * broken, use ethtool ;)
+		 */
+		if (gp->lstate == link_force_try && gp->want_autoneg) {
+			gp->lstate = link_force_ret;
+			gp->last_forced_speed = gp->phy_mii.speed;
+			gp->timer_ticks = 5;
+			if (netif_msg_link(gp))
+				printk(KERN_INFO "%s: Got link after fallback, retrying"
+					" autoneg once...\n", gp->dev->name);
+			gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, gp->phy_mii.advertising);
+		} else if (gp->lstate != link_up) {
+			gp->lstate = link_up;
+			netif_carrier_on(gp->dev);
+			if (gp->opened && gem_set_link_modes(gp))
+				restart_aneg = 1;
+		}
+	} else {
+		/* If the link was previously up, we restart the
+		 * whole process
+		 */
+		if (gp->lstate == link_up) {
+			gp->lstate = link_down;
+			if (netif_msg_link(gp))
+				printk(KERN_INFO "%s: Link down\n",
+					gp->dev->name);
+			netif_carrier_off(gp->dev);
+			gp->reset_task_pending = 2;
+			schedule_work(&gp->reset_task);
+			restart_aneg = 1;
+		} else if (++gp->timer_ticks > 10) {
+			if (found_mii_phy(gp))
+				restart_aneg = gem_mdio_link_not_up(gp);
+			else
+				restart_aneg = 1;
+		}
+	}
+	if (restart_aneg) {
+		gem_begin_auto_negotiation(gp, NULL);
+		goto out_unlock;
 	}
-
 restart:
 	mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
 out_unlock:
@@ -1507,150 +1482,10 @@
 }
 
 /* Must be invoked under gp->lock. */
-static int gem_reset_one_mii_phy(struct gem *gp, int phy_addr)
-{
-	u16 val;
-	int limit = 10000;
-	
-	val = __phy_read(gp, MII_BMCR, phy_addr);
-	val &= ~BMCR_ISOLATE;
-	val |= BMCR_RESET;
-	__phy_write(gp, MII_BMCR, val, phy_addr);
-
-	udelay(100);
-
-	while (limit--) {
-		val = __phy_read(gp, MII_BMCR, phy_addr);
-		if ((val & BMCR_RESET) == 0)
-			break;
-		udelay(10);
-	}
-	if ((val & BMCR_ISOLATE) && limit > 0)
-		__phy_write(gp, MII_BMCR, val & ~BMCR_ISOLATE, phy_addr);
-	
-	return (limit <= 0);
-}
-
-/* Must be invoked under gp->lock. */
-static void gem_init_bcm5201_phy(struct gem *gp)
-{
-	u16 data;
-
-	data = phy_read(gp, MII_BCM5201_MULTIPHY);
-	data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
-	phy_write(gp, MII_BCM5201_MULTIPHY, data);
-}
-
-/* Must be invoked under gp->lock. */
-static void gem_init_bcm5400_phy(struct gem *gp)
-{
-	u16 data;
-
-	/* Configure for gigabit full duplex */
-	data = phy_read(gp, MII_BCM5400_AUXCONTROL);
-	data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
-	phy_write(gp, MII_BCM5400_AUXCONTROL, data);
-	
-	data = phy_read(gp, MII_BCM5400_GB_CONTROL);
-	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
-	
-	mdelay(10);
-
-	/* Reset and configure cascaded 10/100 PHY */
-	gem_reset_one_mii_phy(gp, 0x1f);
-	
-	data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f);
-	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
-	__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
-
-	data = phy_read(gp, MII_BCM5400_AUXCONTROL);
-	data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
-	phy_write(gp, MII_BCM5400_AUXCONTROL, data);
-}
-
-/* Must be invoked under gp->lock. */
-static void gem_init_bcm5401_phy(struct gem *gp)
-{
-	u16 data;
-	int rev;
-
-	rev = phy_read(gp, MII_PHYSID2) & 0x000f;
-	if (rev == 0 || rev == 3) {
-		/* Some revisions of 5401 appear to need this
-		 * initialisation sequence to disable, according
-		 * to OF, "tap power management"
-		 * 
-		 * WARNING ! OF and Darwin don't agree on the
-		 * register addresses. OF seem to interpret the
-		 * register numbers below as decimal
-		 *
-		 * Note: This should (and does) match tg3_init_5401phy_dsp
-		 *       in the tg3.c driver. -DaveM
-		 */
-		phy_write(gp, 0x18, 0x0c20);
-		phy_write(gp, 0x17, 0x0012);
-		phy_write(gp, 0x15, 0x1804);
-		phy_write(gp, 0x17, 0x0013);
-		phy_write(gp, 0x15, 0x1204);
-		phy_write(gp, 0x17, 0x8006);
-		phy_write(gp, 0x15, 0x0132);
-		phy_write(gp, 0x17, 0x8006);
-		phy_write(gp, 0x15, 0x0232);
-		phy_write(gp, 0x17, 0x201f);
-		phy_write(gp, 0x15, 0x0a20);
-	}
-	
-	/* Configure for gigabit full duplex */
-	data = phy_read(gp, MII_BCM5400_GB_CONTROL);
-	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
-
-	mdelay(1);
-
-	/* Reset and configure cascaded 10/100 PHY */
-	gem_reset_one_mii_phy(gp, 0x1f);
-	
-	data = __phy_read(gp, MII_BCM5201_MULTIPHY, 0x1f);
-	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
-	__phy_write(gp, MII_BCM5201_MULTIPHY, data, 0x1f);
-}
-
-/* Must be invoked under gp->lock. */
-static void gem_init_bcm5411_phy(struct gem *gp)
-{
-	u16 data;
-
-	/* Here's some more Apple black magic to setup
-	 * some voltage stuffs.
-	 */
-	phy_write(gp, 0x1c, 0x8c23);
-	phy_write(gp, 0x1c, 0x8ca3);
-	phy_write(gp, 0x1c, 0x8c23);
-
-	/* Here, Apple seems to want to reset it, do
-	 * it as well
-	 */
-	phy_write(gp, MII_BMCR, BMCR_RESET);
-
-	/* Start autoneg */
-	phy_write(gp, MII_BMCR,
-		  (BMCR_ANENABLE | BMCR_FULLDPLX |
-		   BMCR_ANRESTART | BMCR_SPD2));
-
-	data = phy_read(gp, MII_BCM5400_GB_CONTROL);
-	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
-	phy_write(gp, MII_BCM5400_GB_CONTROL, data);
-}
-
-/* Must be invoked under gp->lock. */
 static void gem_init_phy(struct gem *gp)
 {
 	u32 mifcfg;
-
-	if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201)
-		phy_write(gp, MII_BCM5201_INTERRUPT, 0);
-
+	
 	/* Revert MIF CFG setting done on stop_phy */
 	mifcfg = readl(gp->regs + MIF_CFG);
 	mifcfg &= ~MIF_CFG_BBMODE;
@@ -1658,19 +1493,37 @@
 	
 #ifdef CONFIG_ALL_PPC
 	if (gp->pdev->vendor == PCI_VENDOR_ID_APPLE) {
-		int i;
+		int i, j;
 
+		/* Those delay sucks, the HW seem to love them though, I'll
+		 * serisouly consider breaking some locks here to be able
+		 * to schedule instead
+		 */
 		pmac_call_feature(PMAC_FTR_GMAC_PHY_RESET, gp->of_node, 0, 0);
-		for (i = 0; i < 32; i++) {
-			gp->mii_phy_addr = i;
-			if (phy_read(gp, MII_BMCR) != 0xffff)
+		mdelay(10);
+		for (j = 0; j < 3; j++) {
+			/* Some PHYs used by apple have problem getting back to us,
+			 * we _know_ it's actually at addr 0, that's a hack, but
+			 * it helps to do that reset now. I suspect some motherboards
+			 * don't wire the PHY reset line properly, thus the PHY doesn't
+			 * come back with the above pmac_call_feature.
+			 */
+			gp->mii_phy_addr = 0;
+			phy_write(gp, MII_BMCR, BMCR_RESET);
+			/* We should probably break some locks here and schedule... */
+			mdelay(10);
+			for (i = 0; i < 32; i++) {
+				gp->mii_phy_addr = i;
+				if (phy_read(gp, MII_BMCR) != 0xffff)
+					break;
+			}
+			if (i == 32) {
+				printk(KERN_WARNING "%s: GMAC PHY not responding !\n",
+				       gp->dev->name);
+				gp->mii_phy_addr = 0;
+			} else
 				break;
 		}
-		if (i == 32) {
-			printk(KERN_WARNING "%s: GMAC PHY not responding !\n",
-			       gp->dev->name);
-			return;
-		}
 	}
 #endif /* CONFIG_ALL_PPC */
 
@@ -1693,79 +1546,12 @@
 
 	if (gp->phy_type == phy_mii_mdio0 ||
 	    gp->phy_type == phy_mii_mdio1) {
-		u32 phy_id;
-		u16 val;
-	
-		/* Take PHY out of isloate mode and reset it. */
-		gem_reset_one_mii_phy(gp, gp->mii_phy_addr);
-
-		phy_id = (phy_read(gp, MII_PHYSID1) << 16 | phy_read(gp, MII_PHYSID2))
-			 	& 0xfffffff0;
-		printk(KERN_INFO "%s: MII PHY ID: %x ", gp->dev->name, phy_id);
-		switch(phy_id) {
-		case 0x406210:
-			gp->phy_mod = phymod_bcm5201;
-			gem_init_bcm5201_phy(gp);
-			printk("BCM 5201\n");
-			break;
-
-		case 0x4061e0:
-			printk("BCM 5221\n");
-			gp->phy_mod = phymod_bcm5221;
-			break;
-
-		case 0x206040:
-			printk("BCM 5400\n");
-			gp->phy_mod = phymod_bcm5400;
-			gem_init_bcm5400_phy(gp);
-			gp->gigabit_capable = 1;
-			break;
-
-		case 0x206050:
-			printk("BCM 5401\n");
-			gp->phy_mod = phymod_bcm5401;
-			gem_init_bcm5401_phy(gp);
-			gp->gigabit_capable = 1;
-			break;
+	    	// XXX check for errors
+		mii_phy_probe(&gp->phy_mii, gp->mii_phy_addr);
 
-		case 0x206070:
-			printk("BCM 5411\n");
-			gp->phy_mod = phymod_bcm5411;
-			gem_init_bcm5411_phy(gp);
-			gp->gigabit_capable = 1;
-			break;
-		case 0x1410c60:
-			printk("M1011 (Marvel ?)\n");
-			gp->phy_mod = phymod_m1011;
-			gp->gigabit_capable = 1;
-			break;
-
-		case 0x18074c0:
-			printk("Lucent\n");
-			gp->phy_mod = phymod_generic;
-			break;
-
-		case 0x437420:
-			printk("Enable Semiconductor\n");
-			gp->phy_mod = phymod_generic;
-			break;
-
-		default:
-			printk("Unknown (Using generic mode)\n");
-			gp->phy_mod = phymod_generic;
-			break;
-		};
-
-		/* Init advertisement and enable autonegotiation. */
-		val = phy_read(gp, MII_BMCR);
-		val &= ~BMCR_ANENABLE;
-		phy_write(gp, MII_BMCR, val);
-		udelay(10);
-		
-		phy_write(gp, MII_ADVERTISE,
-			  phy_read(gp, MII_ADVERTISE) |
-			  (ADVERTISE_10HALF | ADVERTISE_10FULL |
-			   ADVERTISE_100HALF | ADVERTISE_100FULL));
+		/* Init PHY */
+		if (gp->phy_mii.def && gp->phy_mii.def->ops->init)
+			gp->phy_mii.def->ops->init(&gp->phy_mii);
 	} else {
 		u32 val;
 		int limit;
@@ -1822,13 +1608,7 @@
 		else
 			val |= PCS_SCTRL_LOOP;
 		writel(val, gp->regs + PCS_SCTRL);
-		gp->gigabit_capable = 1;
 	}
-
-	/* BMCR_SPD2 is a broadcom 54xx specific thing afaik */
-	if (gp->phy_mod != phymod_bcm5400 && gp->phy_mod != phymod_bcm5401 &&
-	    gp->phy_mod != phymod_bcm5411)
-	    	gp->link_cntl &= ~BMCR_SPD2;
 }
 
 /* Must be invoked under gp->lock. */
@@ -1917,9 +1697,7 @@
 {
 	unsigned char *e = &gp->dev->dev_addr[0];
 
-	if (gp->pdev->vendor == PCI_VENDOR_ID_SUN &&
-	    gp->pdev->device == PCI_DEVICE_ID_SUN_GEM)
-		writel(0x1bf0, gp->regs + MAC_SNDPAUSE);
+	writel(0x1bf0, gp->regs + MAC_SNDPAUSE);
 
 	writel(0x00, gp->regs + MAC_IPG0);
 	writel(0x08, gp->regs + MAC_IPG1);
@@ -1956,7 +1734,9 @@
 	writel(0, gp->regs + MAC_AF0MSK);
 
 	gp->mac_rx_cfg = gem_setup_multicast(gp);
-
+#ifdef STRIP_FCS
+	gp->mac_rx_cfg |= MAC_RXCFG_SFCS;
+#endif
 	writel(0, gp->regs + MAC_NCOLL);
 	writel(0, gp->regs + MAC_FASUCC);
 	writel(0, gp->regs + MAC_ECOLL);
@@ -2132,12 +1912,15 @@
 		/* Default aneg parameters */
 		gp->timer_ticks = 0;
 		gp->lstate = link_down;
+		netif_carrier_off(gp->dev);
 
 		/* Can I advertise gigabit here ? I'd need BCM PHY docs... */
 		gem_begin_auto_negotiation(gp, NULL);
 	} else {
-		if (gp->lstate == link_up)
+		if (gp->lstate == link_up) {
+			netif_carrier_on(gp->dev);
 			gem_set_link_modes(gp);
+		}
 	}
 }
 
@@ -2187,9 +1970,6 @@
 {
 	u32 mifcfg;
 
-	if (!gp->wake_on_lan && gp->phy_mod == phymod_bcm5201)
-		phy_write(gp, MII_BCM5201_INTERRUPT, 0);
-
 	/* Make sure we aren't polling PHY status change. We
 	 * don't currently use that feature though
 	 */
@@ -2197,9 +1977,6 @@
 	mifcfg &= ~MIF_CFG_POLL;
 	writel(mifcfg, gp->regs + MIF_CFG);
 
-	/* Here's a strange hack used by both MacOS 9 and X */
-	phy_write(gp, MII_LPA, phy_read(gp, MII_LPA));
-
 	if (gp->wake_on_lan) {
 		/* Setup wake-on-lan */
 	} else
@@ -2213,21 +1990,12 @@
 		gem_stop(gp);
 		writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST);
 		writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST);
-		if (gp->phy_mod == phymod_bcm5400 || gp->phy_mod == phymod_bcm5401 ||
-		    gp->phy_mod == phymod_bcm5411) {
-#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
-			phy_write(gp, MII_BMCR, BMCR_PDOWN);
-#endif
-		} else if (gp->phy_mod == phymod_bcm5201 || gp->phy_mod == phymod_bcm5221) {
-#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
-			u16 val = phy_read(gp, MII_BCM5201_AUXMODE2)
-			phy_write(gp, MII_BCM5201_AUXMODE2,
-				  val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
-#endif				
-			phy_write(gp, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
-		} else if (gp->phy_mod == phymod_m1011)
-			phy_write(gp, MII_BMCR, BMCR_PDOWN);
+	}
+
+	if (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend)
+		gp->phy_mii.def->ops->suspend(&gp->phy_mii, 0 /* wake on lan options */);
 
+	if (!gp->wake_on_lan) {
 		/* According to Apple, we must set the MDIO pins to this begnign
 		 * state or we may 1) eat more current, 2) damage some PHYs
 		 */
@@ -2529,7 +2297,11 @@
 	netif_stop_queue(dev);
 
 	rxcfg = readl(gp->regs + MAC_RXCFG);
-	gp->mac_rx_cfg = rxcfg_new = gem_setup_multicast(gp);
+	rxcfg_new = gem_setup_multicast(gp);
+#ifdef STRIP_FCS
+	rxcfg_new |= MAC_RXCFG_SFCS;
+#endif
+	gp->mac_rx_cfg = rxcfg_new;
 	
 	writel(rxcfg & ~MAC_RXCFG_ENAB, gp->regs + MAC_RXCFG);
 	while (readl(gp->regs + MAC_RXCFG) & MAC_RXCFG_ENAB) {
@@ -2554,8 +2326,6 @@
 static int gem_ethtool_ioctl(struct net_device *dev, void *ep_user)
 {
 	struct gem *gp = dev->priv;
-	u16 bmcr;
-	int full_duplex, speed, pause;
 	struct ethtool_cmd ecmd;
 
 	if (copy_from_user(&ecmd, ep_user, sizeof(ecmd)))
@@ -2578,41 +2348,36 @@
 	}
 
 	case ETHTOOL_GSET:
-		ecmd.supported =
+		if (gp->phy_type == phy_mii_mdio0 ||
+	     	    gp->phy_type == phy_mii_mdio1) {
+	     	    	if (gp->phy_mii.def)
+	     	    		ecmd.supported = gp->phy_mii.def->features;
+	     	    	else
+	     	    		ecmd.supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full;
+
+			/* XXX hardcoded stuff for now */
+			ecmd.port = PORT_MII;
+			ecmd.transceiver = XCVR_EXTERNAL;
+			ecmd.phy_address = 0; /* XXX fixed PHYAD */
+
+			/* Return current PHY settings */
+			spin_lock_irq(&gp->lock);
+			ecmd.autoneg = gp->want_autoneg;
+			ecmd.speed = gp->phy_mii.speed;
+			ecmd.duplex = gp->phy_mii.duplex;			
+			ecmd.advertising = gp->phy_mii.advertising;
+			/* If we started with a forced mode, we don't have a default
+			 * advertise set, we need to return something sensible so
+			 * userland can re-enable autoneg properly */
+			if (ecmd.advertising == 0)
+				ecmd.advertising = ecmd.supported;
+			spin_unlock_irq(&gp->lock);
+		} else { // XXX PCS ?
+	     	    ecmd.supported =
 			(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
 			 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
-			 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
-
-		if (gp->gigabit_capable)
-			ecmd.supported |=
-				(SUPPORTED_1000baseT_Half |
-				 SUPPORTED_1000baseT_Full);
-
-		/* XXX hardcoded stuff for now */
-		ecmd.port = PORT_MII;
-		ecmd.transceiver = XCVR_EXTERNAL;
-		ecmd.phy_address = 0; /* XXX fixed PHYAD */
-
-		/* Record PHY settings if HW is on. */
-		spin_lock_irq(&gp->lock);
-		if (gp->hw_running) {
-			bmcr = phy_read(gp, MII_BMCR);
-			gem_read_mii_link_mode(gp, &full_duplex, &speed, &pause);
-		} else
-			bmcr = 0;
-		spin_unlock_irq(&gp->lock);
-		if (bmcr & BMCR_ANENABLE) {
-			ecmd.autoneg = AUTONEG_ENABLE;
-			ecmd.speed = speed == 10 ? SPEED_10 : (speed == 1000 ? SPEED_1000 : SPEED_100);
-			ecmd.duplex = full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
-		} else {
-			ecmd.autoneg = AUTONEG_DISABLE;
-			ecmd.speed =
-				(bmcr & BMCR_SPEED100) ?
-				SPEED_100 : SPEED_10;
-			ecmd.duplex =
-				(bmcr & BMCR_FULLDPLX) ?
-				DUPLEX_FULL : DUPLEX_HALF;
+			 SUPPORTED_Autoneg);
+		    ecmd.advertising = ecmd.supported;
 		}
 		if (copy_to_user(ep_user, &ecmd, sizeof(ecmd)))
 			return -EFAULT;
@@ -2627,13 +2392,18 @@
 		    ecmd.autoneg != AUTONEG_DISABLE)
 			return -EINVAL;
 
+		if (ecmd.autoneg == AUTONEG_ENABLE &&
+		    ecmd.advertising == 0)
+		    	return -EINVAL;
+
 		if (ecmd.autoneg == AUTONEG_DISABLE &&
-		    ((ecmd.speed != SPEED_100 &&
+		    ((ecmd.speed != SPEED_1000 &&
+		      ecmd.speed != SPEED_100 &&
 		      ecmd.speed != SPEED_10) ||
 		     (ecmd.duplex != DUPLEX_HALF &&
 		      ecmd.duplex != DUPLEX_FULL)))
 			return -EINVAL;
-
+	      
 		/* Apply settings and restart link process. */
 		spin_lock_irq(&gp->lock);
 		gem_begin_auto_negotiation(gp, &ecmd);
@@ -2642,7 +2412,7 @@
 		return 0;
 
 	case ETHTOOL_NWAY_RST:
-		if ((gp->link_cntl & BMCR_ANENABLE) == 0)
+		if (!gp->want_autoneg)
 			return -EINVAL;
 
 		/* Restart link process. */
@@ -2746,15 +2516,21 @@
 		/* Fallthrough... */
 
 	case SIOCGMIIREG:		/* Read MII PHY register. */
-		data->val_out = __phy_read(gp, data->reg_num & 0x1f, data->phy_id & 0x1f);
-		rc = 0;
+		if (!gp->hw_running)
+			rc = -EIO;
+		else {
+			data->val_out = __phy_read(gp, data->phy_id & 0x1f, data->reg_num & 0x1f);
+			rc = 0;
+		}
 		break;
 
 	case SIOCSMIIREG:		/* Write MII PHY register. */
-		if (!capable(CAP_NET_ADMIN)) {
+		if (!capable(CAP_NET_ADMIN))
 			rc = -EPERM;
-		} else {
-			__phy_write(gp, data->reg_num & 0x1f, data->val_in, data->phy_id & 0x1f);
+		else if (!gp->hw_running)
+			rc = -EIO;
+		else {
+			__phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f, data->val_in);
 			rc = 0;
 		}
 		break;
@@ -2856,8 +2632,7 @@
 		printk(KERN_ERR "%s: can't get mac-address\n", dev->name);
 		return -1;
 	}
-#warning MAX_ADDR_LEN is now 32 bytes instead of 8, please fix this as appropriate
-	memcpy(dev->dev_addr, addr, MAX_ADDR_LEN);
+	memcpy(dev->dev_addr, addr, 6);
 #else
 	get_gem_mac_nonobp(gp->pdev, gp->dev->dev_addr);
 #endif
@@ -2928,6 +2703,7 @@
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	gp = dev->priv;
 
@@ -2941,7 +2717,7 @@
 	dev->base_addr = (long) pdev;
 	gp->dev = dev;
 
-	gp->msg_enable = (gem_debug < 0 ? DEFAULT_MSG : gem_debug);
+	gp->msg_enable = DEFAULT_MSG;
 
 	spin_lock_init(&gp->lock);
 	init_MUTEX(&gp->pm_sem);
@@ -2957,13 +2733,9 @@
 	INIT_WORK(&gp->pm_task, gem_pm_task, gp);
 	INIT_WORK(&gp->reset_task, gem_reset_task, gp);
 	
-	/* Default link parameters */
-	if (link_mode >= 0 && link_mode <= 6)
-		gp->link_cntl = link_modes[link_mode];
-	else
-		gp->link_cntl = BMCR_ANENABLE;
 	gp->lstate = link_down;
 	gp->timer_ticks = 0;
+	netif_carrier_off(dev);
 
 	gp->regs = (unsigned long) ioremap(gemreg_base, gemreg_len);
 	if (gp->regs == 0UL) {
@@ -2984,15 +2756,17 @@
 	gem_stop(gp);
 	spin_unlock_irq(&gp->lock);
 
+	/* Fill up the mii_phy structure (even if we won't use it) */
+	gp->phy_mii.dev = dev;
+	gp->phy_mii.mdio_read = _phy_read;
+	gp->phy_mii.mdio_write = _phy_write;
+
+	/* By default, we start with autoneg */
+	gp->want_autoneg = 1;
+	
 	if (gem_check_invariants(gp))
 		goto err_out_iounmap;
 
-	spin_lock_irq(&gp->lock);
-	gp->hw_running = 1;
-	gem_init_phy(gp);
-	gem_begin_auto_negotiation(gp, NULL);
-	spin_unlock_irq(&gp->lock);
-
 	/* It is guaranteed that the returned buffer will be at least
 	 * PAGE_SIZE aligned.
 	 */
@@ -3019,11 +2793,22 @@
 
 	printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet ",
 	       dev->name);
-
 	for (i = 0; i < 6; i++)
 		printk("%2.2x%c", dev->dev_addr[i],
 		       i == 5 ? ' ' : ':');
 	printk("\n");
+
+	/* Detect & init PHY, start autoneg */
+	spin_lock_irq(&gp->lock);
+	gp->hw_running = 1;
+	gem_init_phy(gp);
+	gem_begin_auto_negotiation(gp, NULL);
+	spin_unlock_irq(&gp->lock);
+
+	if (gp->phy_type == phy_mii_mdio0 ||
+     	    gp->phy_type == phy_mii_mdio1)
+		printk(KERN_INFO "%s: Found %s PHY\n", dev->name, 
+			gp->phy_mii.def ? gp->phy_mii.def->name : "no");
 
 	pci_set_drvdata(pdev, dev);
 
diff -Nru a/drivers/net/sungem.h b/drivers/net/sungem.h
--- a/drivers/net/sungem.h	Tue Feb 25 09:17:53 2003
+++ b/drivers/net/sungem.h	Mon May 19 23:38:39 2003
@@ -1,4 +1,4 @@
-/* $Id: sungem.h,v 1.12 2002/01/23 15:40:45 davem Exp $
+/* $Id: sungem.h,v 1.10.2.4 2002/03/11 08:54:48 davem Exp $
  * sungem.h: Definitions for Sun GEM ethernet driver.
  *
  * Copyright (C) 2000 David S. Miller (davem@redhat.com)
@@ -936,16 +936,6 @@
 	phy_serdes,
 };
 
-enum gem_phy_model {
-	phymod_generic,
-	phymod_bcm5201,
-	phymod_bcm5221,
-	phymod_bcm5400,
-	phymod_bcm5401,
-	phymod_bcm5411,
-	phymod_m1011,
-};
-
 enum link_state {
 	link_down = 0,	/* No link, will retry */
 	link_aneg,	/* Autoneg in progress */
@@ -980,26 +970,25 @@
 	struct net_device_stats net_stats;
 
 	enum gem_phy_type	phy_type;
-	enum gem_phy_model	phy_mod;
+	struct mii_phy		phy_mii;
+	
 	int			tx_fifo_sz;
 	int			rx_fifo_sz;
 	int			rx_pause_off;
 	int			rx_pause_on;
 	int			mii_phy_addr;
-	int			gigabit_capable;
 
 	u32			mac_rx_cfg;
 	u32			swrst_base;
 
 	/* Autoneg & PHY control */
-	int			link_cntl;
-	int			link_advertise;
-	int			link_fcntl;
+	int			want_autoneg;
+	int			last_forced_speed;
 	enum link_state		lstate;
 	struct timer_list	link_timer;
 	int			timer_ticks;
 	int			wake_on_lan;
-	struct work_struct			reset_task;
+	struct work_struct	reset_task;
 	volatile int		reset_task_pending;
 	
 	/* Diagnostic counters and state. */
@@ -1014,6 +1003,9 @@
 #endif
 };
 
+#define found_mii_phy(gp) ((gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) \
+				&& gp->phy_mii.def && gp->phy_mii.def->ops)
+			
 #define ALIGNED_RX_SKB_ADDR(addr) \
         ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr))
 static __inline__ struct sk_buff *gem_alloc_skb(int size, int gfp_flags)
diff -Nru a/drivers/net/sungem_phy.c b/drivers/net/sungem_phy.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/sungem_phy.c	Mon May 19 23:38:25 2003
@@ -0,0 +1,838 @@
+/*
+ * PHY drivers for the sungem ethernet driver.
+ * 
+ * This file could be shared with other drivers.
+ * 
+ * (c) 2002, Benjamin Herrenscmidt (benh@kernel.crashing.org)
+ *
+ * TODO:
+ *  - Implement WOL
+ *  - Add support for PHYs that provide an IRQ line
+ *  - Eventually moved the entire polling state machine in
+ *    there (out of the eth driver), so that it can easily be
+ *    skipped on PHYs that implement it in hardware.
+ *  - On LXT971 & BCM5201, Apple uses some chip specific regs
+ *    to read the link status. Figure out why and if it makes
+ *    sense to do the same (magic aneg ?)
+ *  - Apple has some additional power management code for some
+ *    Broadcom PHYs that they "hide" from the OpenSource version
+ *    of darwin, still need to reverse engineer that
+ */
+
+#include <linux/config.h>
+
+#include <linux/module.h>
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/mii.h>
+#include <linux/ethtool.h>
+#include <linux/delay.h>
+
+#include "sungem_phy.h"
+
+/* Link modes of the BCM5400 PHY */
+static int phy_BCM5400_link_table[8][3] = {
+	{ 0, 0, 0 },	/* No link */
+	{ 0, 0, 0 },	/* 10BT Half Duplex */
+	{ 1, 0, 0 },	/* 10BT Full Duplex */
+	{ 0, 1, 0 },	/* 100BT Half Duplex */
+	{ 0, 1, 0 },	/* 100BT Half Duplex */
+	{ 1, 1, 0 },	/* 100BT Full Duplex*/
+	{ 1, 0, 1 },	/* 1000BT */
+	{ 1, 0, 1 },	/* 1000BT */
+};
+
+static inline int __phy_read(struct mii_phy* phy, int id, int reg)
+{
+	return phy->mdio_read(phy->dev, id, reg);
+}
+
+static inline void __phy_write(struct mii_phy* phy, int id, int reg, int val)
+{
+	phy->mdio_write(phy->dev, id, reg, val);
+}
+
+static inline int phy_read(struct mii_phy* phy, int reg)
+{
+	return phy->mdio_read(phy->dev, phy->mii_id, reg);
+}
+
+static inline void phy_write(struct mii_phy* phy, int reg, int val)
+{
+	phy->mdio_write(phy->dev, phy->mii_id, reg, val);
+}
+
+static int reset_one_mii_phy(struct mii_phy* phy, int phy_id)
+{
+	u16 val;
+	int limit = 10000;
+	
+	val = __phy_read(phy, phy_id, MII_BMCR);
+	val &= ~BMCR_ISOLATE;
+	val |= BMCR_RESET;
+	__phy_write(phy, phy_id, MII_BMCR, val);
+
+	udelay(100);
+
+	while (limit--) {
+		val = __phy_read(phy, phy_id, MII_BMCR);
+		if ((val & BMCR_RESET) == 0)
+			break;
+		udelay(10);
+	}
+	if ((val & BMCR_ISOLATE) && limit > 0)
+		__phy_write(phy, phy_id, MII_BMCR, val & ~BMCR_ISOLATE);
+	
+	return (limit <= 0);
+}
+
+static int bcm5201_init(struct mii_phy* phy)
+{
+	u16 data;
+
+	data = phy_read(phy, MII_BCM5201_MULTIPHY);
+	data &= ~MII_BCM5201_MULTIPHY_SUPERISOLATE;
+	phy_write(phy, MII_BCM5201_MULTIPHY, data);
+
+	return 0;
+}
+
+static int bcm5201_suspend(struct mii_phy* phy, int wol_options)
+{
+	if (!wol_options)
+		phy_write(phy, MII_BCM5201_INTERRUPT, 0);
+
+	/* Here's a strange hack used by both MacOS 9 and X */
+	phy_write(phy, MII_LPA, phy_read(phy, MII_LPA));
+	
+	if (!wol_options) {
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+		u16 val = phy_read(phy, MII_BCM5201_AUXMODE2)
+		phy_write(phy, MII_BCM5201_AUXMODE2,
+			  val & ~MII_BCM5201_AUXMODE2_LOWPOWER);
+#endif			
+		phy_write(phy, MII_BCM5201_MULTIPHY, MII_BCM5201_MULTIPHY_SUPERISOLATE);
+	}
+
+	return 0;
+}
+
+static int bcm5221_init(struct mii_phy* phy)
+{
+	u16 data;
+
+	data = phy_read(phy, MII_BCM5221_TEST);
+	phy_write(phy, MII_BCM5221_TEST,
+		data | MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+	data = phy_read(phy, MII_BCM5221_SHDOW_AUX_STAT2);
+	phy_write(phy, MII_BCM5221_SHDOW_AUX_STAT2,
+		data | MII_BCM5221_SHDOW_AUX_STAT2_APD);
+
+	data = phy_read(phy, MII_BCM5221_SHDOW_AUX_MODE4);
+	phy_write(phy, MII_BCM5221_SHDOW_AUX_MODE4,
+		data | MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR);
+
+	data = phy_read(phy, MII_BCM5221_TEST);
+	phy_write(phy, MII_BCM5221_TEST,
+		data & ~MII_BCM5221_TEST_ENABLE_SHADOWS);
+
+	return 0;
+}
+
+static int bcm5400_init(struct mii_phy* phy)
+{
+	u16 data;
+
+	/* Configure for gigabit full duplex */
+	data = phy_read(phy, MII_BCM5400_AUXCONTROL);
+	data |= MII_BCM5400_AUXCONTROL_PWR10BASET;
+	phy_write(phy, MII_BCM5400_AUXCONTROL, data);
+	
+	data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+	
+	mdelay(10);
+
+	/* Reset and configure cascaded 10/100 PHY */
+	(void)reset_one_mii_phy(phy, 0x1f);
+	
+	data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+	__phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+
+	data = phy_read(phy, MII_BCM5400_AUXCONTROL);
+	data &= ~MII_BCM5400_AUXCONTROL_PWR10BASET;
+	phy_write(phy, MII_BCM5400_AUXCONTROL, data);
+
+	return 0;
+}
+
+static int bcm5400_suspend(struct mii_phy* phy, int wol_options)
+{
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+	phy_write(phy, MII_BMCR, BMCR_PDOWN);
+#endif
+	return 0;
+}
+
+static int bcm5401_init(struct mii_phy* phy)
+{
+	u16 data;
+	int rev;
+
+	rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+	if (rev == 0 || rev == 3) {
+		/* Some revisions of 5401 appear to need this
+		 * initialisation sequence to disable, according
+		 * to OF, "tap power management"
+		 * 
+		 * WARNING ! OF and Darwin don't agree on the
+		 * register addresses. OF seem to interpret the
+		 * register numbers below as decimal
+		 *
+		 * Note: This should (and does) match tg3_init_5401phy_dsp
+		 *       in the tg3.c driver. -DaveM
+		 */
+		phy_write(phy, 0x18, 0x0c20);
+		phy_write(phy, 0x17, 0x0012);
+		phy_write(phy, 0x15, 0x1804);
+		phy_write(phy, 0x17, 0x0013);
+		phy_write(phy, 0x15, 0x1204);
+		phy_write(phy, 0x17, 0x8006);
+		phy_write(phy, 0x15, 0x0132);
+		phy_write(phy, 0x17, 0x8006);
+		phy_write(phy, 0x15, 0x0232);
+		phy_write(phy, 0x17, 0x201f);
+		phy_write(phy, 0x15, 0x0a20);
+	}
+	
+	/* Configure for gigabit full duplex */
+	data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+
+	mdelay(10);
+
+	/* Reset and configure cascaded 10/100 PHY */
+	(void)reset_one_mii_phy(phy, 0x1f);
+	
+	data = __phy_read(phy, 0x1f, MII_BCM5201_MULTIPHY);
+	data |= MII_BCM5201_MULTIPHY_SERIALMODE;
+	__phy_write(phy, 0x1f, MII_BCM5201_MULTIPHY, data);
+
+	return 0;
+}
+
+static int bcm5401_suspend(struct mii_phy* phy, int wol_options)
+{
+#if 0 /* Commented out in Darwin... someone has those dawn docs ? */
+	phy_write(phy, MII_BMCR, BMCR_PDOWN);
+#endif
+	return 0;
+}
+
+static int bcm5411_init(struct mii_phy* phy)
+{
+	u16 data;
+
+	/* Here's some more Apple black magic to setup
+	 * some voltage stuffs.
+	 */
+	phy_write(phy, 0x1c, 0x8c23);
+	phy_write(phy, 0x1c, 0x8ca3);
+	phy_write(phy, 0x1c, 0x8c23);
+
+	/* Here, Apple seems to want to reset it, do
+	 * it as well
+	 */
+	phy_write(phy, MII_BMCR, BMCR_RESET);
+	phy_write(phy, MII_BMCR, 0x1340);
+
+	data = phy_read(phy, MII_BCM5400_GB_CONTROL);
+	data |= MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP;
+	phy_write(phy, MII_BCM5400_GB_CONTROL, data);
+
+	mdelay(10);
+
+	/* Reset and configure cascaded 10/100 PHY */
+	(void)reset_one_mii_phy(phy, 0x1f);
+	
+	return 0;
+}
+
+static int bcm5411_suspend(struct mii_phy* phy, int wol_options)
+{
+	phy_write(phy, MII_BMCR, BMCR_PDOWN);
+
+	return 0;
+}
+
+static int bcm5421_init(struct mii_phy* phy)
+{
+	u16 data;
+	int rev;
+
+	rev = phy_read(phy, MII_PHYSID2) & 0x000f;
+	if (rev == 0) {
+		/* This is borrowed from MacOS
+		 */
+		phy_write(phy, 0x18, 0x1007);
+		data = phy_read(phy, 0x18);
+		phy_write(phy, 0x18, data | 0x0400);
+		phy_write(phy, 0x18, 0x0007);
+		data = phy_read(phy, 0x18);
+		phy_write(phy, 0x18, data | 0x0800);
+		phy_write(phy, 0x17, 0x000a);
+		data = phy_read(phy, 0x15);
+		phy_write(phy, 0x15, data | 0x0200);
+	}
+#if 0
+	/* This has to be verified before I enable it */
+	/* Enable automatic low-power */
+	phy_write(phy, 0x1c, 0x9002);
+	phy_write(phy, 0x1c, 0xa821);
+	phy_write(phy, 0x1c, 0x941d);
+#endif
+	return 0;
+}
+
+static int bcm54xx_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+	u16 ctl, adv;
+	
+	phy->autoneg = 1;
+	phy->speed = SPEED_10;
+	phy->duplex = DUPLEX_HALF;
+	phy->pause = 0;
+	phy->advertising = advertise;
+
+	/* Setup standard advertise */
+	adv = phy_read(phy, MII_ADVERTISE);
+	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+	if (advertise & ADVERTISED_10baseT_Half)
+		adv |= ADVERTISE_10HALF;
+	if (advertise & ADVERTISED_10baseT_Full)
+		adv |= ADVERTISE_10FULL;
+	if (advertise & ADVERTISED_100baseT_Half)
+		adv |= ADVERTISE_100HALF;
+	if (advertise & ADVERTISED_100baseT_Full)
+		adv |= ADVERTISE_100FULL;
+	phy_write(phy, MII_ADVERTISE, adv);
+
+	/* Setup 1000BT advertise */
+	adv = phy_read(phy, MII_1000BASETCONTROL);
+	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP|MII_1000BASETCONTROL_HALFDUPLEXCAP);
+	if (advertise & SUPPORTED_1000baseT_Half)
+		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
+	if (advertise & SUPPORTED_1000baseT_Full)
+		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
+	phy_write(phy, MII_1000BASETCONTROL, adv);
+
+	/* Start/Restart aneg */
+	ctl = phy_read(phy, MII_BMCR);
+	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+	phy_write(phy, MII_BMCR, ctl);
+
+	return 0;
+}
+
+static int bcm54xx_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+	u16 ctl;
+	
+	phy->autoneg = 0;
+	phy->speed = speed;
+	phy->duplex = fd;
+	phy->pause = 0;
+
+	ctl = phy_read(phy, MII_BMCR);
+	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
+
+	/* First reset the PHY */
+	phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+
+	/* Select speed & duplex */
+	switch(speed) {
+	case SPEED_10:
+		break;
+	case SPEED_100:
+		ctl |= BMCR_SPEED100;
+		break;
+	case SPEED_1000:
+		ctl |= BMCR_SPD2;
+	}
+	if (fd == DUPLEX_FULL)
+		ctl |= BMCR_FULLDPLX;
+
+	// XXX Should we set the sungem to GII now on 1000BT ?
+	
+	phy_write(phy, MII_BMCR, ctl);
+
+	return 0;
+}
+
+static int bcm54xx_read_link(struct mii_phy *phy)
+{
+	int link_mode;	
+	u16 val;
+	
+	if (phy->autoneg) {
+	    	val = phy_read(phy, MII_BCM5400_AUXSTATUS);
+		link_mode = ((val & MII_BCM5400_AUXSTATUS_LINKMODE_MASK) >>
+			     MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT);
+		phy->duplex = phy_BCM5400_link_table[link_mode][0] ? DUPLEX_FULL : DUPLEX_HALF;
+		phy->speed = phy_BCM5400_link_table[link_mode][2] ?
+				SPEED_1000 :
+				(phy_BCM5400_link_table[link_mode][1] ? SPEED_100 : SPEED_10);
+		val = phy_read(phy, MII_LPA);
+		phy->pause = ((val & LPA_PAUSE) != 0);
+	}
+	/* On non-aneg, we assume what we put in BMCR is the speed,
+	 * though magic-aneg shouldn't prevent this case from occurring
+	 */
+
+	return 0;
+}
+
+static int marvell_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+	u16 ctl, adv;
+	
+	phy->autoneg = 1;
+	phy->speed = SPEED_10;
+	phy->duplex = DUPLEX_HALF;
+	phy->pause = 0;
+	phy->advertising = advertise;
+
+	/* Setup standard advertise */
+	adv = phy_read(phy, MII_ADVERTISE);
+	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+	if (advertise & ADVERTISED_10baseT_Half)
+		adv |= ADVERTISE_10HALF;
+	if (advertise & ADVERTISED_10baseT_Full)
+		adv |= ADVERTISE_10FULL;
+	if (advertise & ADVERTISED_100baseT_Half)
+		adv |= ADVERTISE_100HALF;
+	if (advertise & ADVERTISED_100baseT_Full)
+		adv |= ADVERTISE_100FULL;
+	phy_write(phy, MII_ADVERTISE, adv);
+
+	/* Setup 1000BT advertise & enable crossover detect
+	 * XXX How do we advertise 1000BT ? Darwin source is
+	 * confusing here, they read from specific control and
+	 * write to control... Someone has specs for those
+	 * beasts ?
+	 */
+	adv = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
+	adv |= MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX;
+	adv &= ~(MII_1000BASETCONTROL_FULLDUPLEXCAP |
+			MII_1000BASETCONTROL_HALFDUPLEXCAP);
+	if (advertise & SUPPORTED_1000baseT_Half)
+		adv |= MII_1000BASETCONTROL_HALFDUPLEXCAP;
+	if (advertise & SUPPORTED_1000baseT_Full)
+		adv |= MII_1000BASETCONTROL_FULLDUPLEXCAP;
+	phy_write(phy, MII_1000BASETCONTROL, adv);
+
+	/* Start/Restart aneg */
+	ctl = phy_read(phy, MII_BMCR);
+	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+	phy_write(phy, MII_BMCR, ctl);
+
+	return 0;
+}
+
+static int marvell_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+	u16 ctl, ctl2;
+	
+	phy->autoneg = 0;
+	phy->speed = speed;
+	phy->duplex = fd;
+	phy->pause = 0;
+
+	ctl = phy_read(phy, MII_BMCR);
+	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_SPD2|BMCR_ANENABLE);
+	ctl |= BMCR_RESET;
+
+	/* Select speed & duplex */
+	switch(speed) {
+	case SPEED_10:
+		break;
+	case SPEED_100:
+		ctl |= BMCR_SPEED100;
+		break;
+	/* I'm not sure about the one below, again, Darwin source is
+	 * quite confusing and I lack chip specs
+	 */
+	case SPEED_1000:
+		ctl |= BMCR_SPD2;
+	}
+	if (fd == DUPLEX_FULL)
+		ctl |= BMCR_FULLDPLX;
+
+	/* Disable crossover. Again, the way Apple does it is strange,
+	 * though I don't assume they are wrong ;)
+	 */
+	ctl2 = phy_read(phy, MII_M1011_PHY_SPEC_CONTROL);
+	ctl2 &= ~(MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX |
+		MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX |
+		MII_1000BASETCONTROL_FULLDUPLEXCAP |
+		MII_1000BASETCONTROL_HALFDUPLEXCAP);
+	if (speed == SPEED_1000)
+		ctl2 |= (fd == DUPLEX_FULL) ?
+			MII_1000BASETCONTROL_FULLDUPLEXCAP :
+			MII_1000BASETCONTROL_HALFDUPLEXCAP;
+	phy_write(phy, MII_1000BASETCONTROL, ctl2);
+
+	// XXX Should we set the sungem to GII now on 1000BT ?
+	
+	phy_write(phy, MII_BMCR, ctl);
+
+	return 0;
+}
+
+static int marvell_read_link(struct mii_phy *phy)
+{
+	u16 status;
+
+	if (phy->autoneg) {
+		status = phy_read(phy, MII_M1011_PHY_SPEC_STATUS);
+		if ((status & MII_M1011_PHY_SPEC_STATUS_RESOLVED) == 0)
+			return -EAGAIN;
+		if (status & MII_M1011_PHY_SPEC_STATUS_1000)
+			phy->speed = SPEED_1000;
+		else if (status & MII_M1011_PHY_SPEC_STATUS_100)
+			phy->speed = SPEED_100;
+		else
+			phy->speed = SPEED_10;
+		if (status & MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX)
+			phy->duplex = DUPLEX_FULL;
+		else
+			phy->duplex = DUPLEX_HALF;
+		phy->pause = 0; /* XXX Check against spec ! */
+	}
+	/* On non-aneg, we assume what we put in BMCR is the speed,
+	 * though magic-aneg shouldn't prevent this case from occurring
+	 */
+
+	return 0;
+}
+
+static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise)
+{
+	u16 ctl, adv;
+	
+	phy->autoneg = 1;
+	phy->speed = SPEED_10;
+	phy->duplex = DUPLEX_HALF;
+	phy->pause = 0;
+	phy->advertising = advertise;
+
+	/* Setup standard advertise */
+	adv = phy_read(phy, MII_ADVERTISE);
+	adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
+	if (advertise & ADVERTISED_10baseT_Half)
+		adv |= ADVERTISE_10HALF;
+	if (advertise & ADVERTISED_10baseT_Full)
+		adv |= ADVERTISE_10FULL;
+	if (advertise & ADVERTISED_100baseT_Half)
+		adv |= ADVERTISE_100HALF;
+	if (advertise & ADVERTISED_100baseT_Full)
+		adv |= ADVERTISE_100FULL;
+	phy_write(phy, MII_ADVERTISE, adv);
+
+	/* Start/Restart aneg */
+	ctl = phy_read(phy, MII_BMCR);
+	ctl |= (BMCR_ANENABLE | BMCR_ANRESTART);
+	phy_write(phy, MII_BMCR, ctl);
+
+	return 0;
+}
+
+static int genmii_setup_forced(struct mii_phy *phy, int speed, int fd)
+{
+	u16 ctl;
+	
+	phy->autoneg = 0;
+	phy->speed = speed;
+	phy->duplex = fd;
+	phy->pause = 0;
+
+	ctl = phy_read(phy, MII_BMCR);
+	ctl &= ~(BMCR_FULLDPLX|BMCR_SPEED100|BMCR_ANENABLE);
+
+	/* First reset the PHY */
+	phy_write(phy, MII_BMCR, ctl | BMCR_RESET);
+
+	/* Select speed & duplex */
+	switch(speed) {
+	case SPEED_10:
+		break;
+	case SPEED_100:
+		ctl |= BMCR_SPEED100;
+		break;
+	case SPEED_1000:
+	default:
+		return -EINVAL;
+	}
+	if (fd == DUPLEX_FULL)
+		ctl |= BMCR_FULLDPLX;
+	phy_write(phy, MII_BMCR, ctl);
+
+	return 0;
+}
+
+static int genmii_poll_link(struct mii_phy *phy)
+{
+	u16 status;
+	
+	(void)phy_read(phy, MII_BMSR);
+	status = phy_read(phy, MII_BMSR);
+	if ((status & BMSR_LSTATUS) == 0)
+		return 0;
+	if (phy->autoneg && !(status & BMSR_ANEGCOMPLETE))
+		return 0;
+	return 1;
+}
+
+static int genmii_read_link(struct mii_phy *phy)
+{
+	u16 lpa;
+
+	if (phy->autoneg) {
+		lpa = phy_read(phy, MII_LPA);
+
+		if (lpa & (LPA_10FULL | LPA_100FULL))
+			phy->duplex = DUPLEX_FULL;
+		else
+			phy->duplex = DUPLEX_HALF;
+		if (lpa & (LPA_100FULL | LPA_100HALF))
+			phy->speed = SPEED_100;
+		else
+			phy->speed = SPEED_10;
+		phy->pause = 0;
+	}
+	/* On non-aneg, we assume what we put in BMCR is the speed,
+	 * though magic-aneg shouldn't prevent this case from occurring
+	 */
+
+	 return 0;
+}
+
+
+#define MII_BASIC_FEATURES	(SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | \
+				 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | \
+				 SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII)
+#define MII_GBIT_FEATURES	(MII_BASIC_FEATURES | \
+				 SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full)
+
+/* Broadcom BCM 5201 */
+static struct mii_phy_ops bcm5201_phy_ops = {
+	init:		bcm5201_init,
+	suspend:	bcm5201_suspend,
+	setup_aneg:	genmii_setup_aneg,
+	setup_forced:	genmii_setup_forced,
+	poll_link:	genmii_poll_link,
+	read_link:	genmii_read_link,
+};
+
+static struct mii_phy_def bcm5201_phy_def = {
+	phy_id:		0x00406210,
+	phy_id_mask:	0xfffffff0,
+	name:		"BCM5201",
+	features:	MII_BASIC_FEATURES,
+	magic_aneg:	0,
+	ops:		&bcm5201_phy_ops
+};
+
+/* Broadcom BCM 5221 */
+static struct mii_phy_ops bcm5221_phy_ops = {
+	suspend:	bcm5201_suspend,
+	init:		bcm5221_init,
+	setup_aneg:	genmii_setup_aneg,
+	setup_forced:	genmii_setup_forced,
+	poll_link:	genmii_poll_link,
+	read_link:	genmii_read_link,
+};
+
+static struct mii_phy_def bcm5221_phy_def = {
+	phy_id:		0x004061e0,
+	phy_id_mask:	0xfffffff0,
+	name:		"BCM5221",
+	features:	MII_BASIC_FEATURES,
+	magic_aneg:	0,
+	ops:		&bcm5221_phy_ops
+};
+
+/* Broadcom BCM 5400 */
+static struct mii_phy_ops bcm5400_phy_ops = {
+	init:		bcm5400_init,
+	suspend:	bcm5400_suspend,
+	setup_aneg:	bcm54xx_setup_aneg,
+	setup_forced:	bcm54xx_setup_forced,
+	poll_link:	genmii_poll_link,
+	read_link:	bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5400_phy_def = {
+	phy_id:		0x00206040,
+	phy_id_mask:	0xfffffff0,
+	name:		"BCM5400",
+	features:	MII_GBIT_FEATURES,
+	magic_aneg:	1,
+	ops:		&bcm5400_phy_ops
+};
+
+/* Broadcom BCM 5401 */
+static struct mii_phy_ops bcm5401_phy_ops = {
+	init:		bcm5401_init,
+	suspend:	bcm5401_suspend,
+	setup_aneg:	bcm54xx_setup_aneg,
+	setup_forced:	bcm54xx_setup_forced,
+	poll_link:	genmii_poll_link,
+	read_link:	bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5401_phy_def = {
+	phy_id:		0x00206050,
+	phy_id_mask:	0xfffffff0,
+	name:		"BCM5401",
+	features:	MII_GBIT_FEATURES,
+	magic_aneg:	1,
+	ops:		&bcm5401_phy_ops
+};
+
+/* Broadcom BCM 5411 */
+static struct mii_phy_ops bcm5411_phy_ops = {
+	init:		bcm5411_init,
+	suspend:	bcm5411_suspend,
+	setup_aneg:	bcm54xx_setup_aneg,
+	setup_forced:	bcm54xx_setup_forced,
+	poll_link:	genmii_poll_link,
+	read_link:	bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5411_phy_def = {
+	phy_id:		0x00206070,
+	phy_id_mask:	0xfffffff0,
+	name:		"BCM5411",
+	features:	MII_GBIT_FEATURES,
+	magic_aneg:	1,
+	ops:		&bcm5411_phy_ops
+};
+
+/* Broadcom BCM 5421 */
+static struct mii_phy_ops bcm5421_phy_ops = {
+	init:		bcm5421_init,
+	suspend:	bcm5411_suspend,
+	setup_aneg:	bcm54xx_setup_aneg,
+	setup_forced:	bcm54xx_setup_forced,
+	poll_link:	genmii_poll_link,
+	read_link:	bcm54xx_read_link,
+};
+
+static struct mii_phy_def bcm5421_phy_def = {
+	phy_id:		0x002060e0,
+	phy_id_mask:	0xfffffff0,
+	name:		"BCM5421",
+	features:	MII_GBIT_FEATURES,
+	magic_aneg:	1,
+	ops:		&bcm5421_phy_ops
+};
+
+/* Marvell 88E1101 (Apple seem to deal with 2 different revs,
+ * I masked out the 8 last bits to get both, but some specs
+ * would be useful here) --BenH.
+ */
+static struct mii_phy_ops marvell_phy_ops = {
+	setup_aneg:	marvell_setup_aneg,
+	setup_forced:	marvell_setup_forced,
+	poll_link:	genmii_poll_link,
+	read_link:	marvell_read_link
+};
+
+static struct mii_phy_def marvell_phy_def = {
+	phy_id:		0x01410c00,
+	phy_id_mask:	0xffffff00,
+	name:		"Marvell 88E1101",
+	features:	MII_GBIT_FEATURES,
+	magic_aneg:	1,
+	ops:		&marvell_phy_ops
+};
+
+/* Generic implementation for most 10/100 PHYs */
+static struct mii_phy_ops generic_phy_ops = {
+	setup_aneg:	genmii_setup_aneg,
+	setup_forced:	genmii_setup_forced,
+	poll_link:	genmii_poll_link,
+	read_link:	genmii_read_link
+};
+
+static struct mii_phy_def genmii_phy_def = {
+	phy_id:		0x00000000,
+	phy_id_mask:	0x00000000,
+	name:		"Generic MII",
+	features:	MII_BASIC_FEATURES,
+	magic_aneg:	0,
+	ops:		&generic_phy_ops
+};
+
+static struct mii_phy_def* mii_phy_table[] = {
+	&bcm5201_phy_def,
+	&bcm5221_phy_def,
+	&bcm5400_phy_def,
+	&bcm5401_phy_def,
+	&bcm5411_phy_def,
+	&bcm5421_phy_def,
+	&marvell_phy_def,
+	&genmii_phy_def,
+	NULL
+};
+
+int mii_phy_probe(struct mii_phy *phy, int mii_id)
+{
+	int rc;
+	u32 id;
+	struct mii_phy_def* def;
+	int i;
+
+	/* We do not reset the mii_phy structure as the driver
+	 * may re-probe the PHY regulary
+	 */
+	phy->mii_id = mii_id;
+	
+	/* Take PHY out of isloate mode and reset it. */
+	rc = reset_one_mii_phy(phy, mii_id);
+	if (rc)
+		goto fail;
+
+	/* Read ID and find matching entry */	
+	id = (phy_read(phy, MII_PHYSID1) << 16 | phy_read(phy, MII_PHYSID2))
+			 	& 0xfffffff0;
+	for (i=0; (def = mii_phy_table[i]) != NULL; i++)
+		if ((id & def->phy_id_mask) == def->phy_id)
+			break;
+	/* Should never be NULL (we have a generic entry), but... */
+	if (def == NULL)
+		goto fail;
+
+	phy->def = def;
+	
+	return 0;
+fail:
+	phy->speed = 0;
+	phy->duplex = 0;
+	phy->pause = 0;
+	phy->advertising = 0;
+	return -ENODEV;
+}
+
+EXPORT_SYMBOL(mii_phy_probe);
+MODULE_LICENSE("GPL");
+
diff -Nru a/drivers/net/sungem_phy.h b/drivers/net/sungem_phy.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/net/sungem_phy.h	Mon May 19 23:38:26 2003
@@ -0,0 +1,116 @@
+#ifndef __SUNGEM_PHY_H__
+#define __SUNGEM_PHY_H__
+
+struct mii_phy;
+
+/* Operations supported by any kind of PHY */
+struct mii_phy_ops
+{
+	int		(*init)(struct mii_phy *phy);
+	int		(*suspend)(struct mii_phy *phy, int wol_options);
+	int		(*setup_aneg)(struct mii_phy *phy, u32 advertise);
+	int		(*setup_forced)(struct mii_phy *phy, int speed, int fd);
+	int		(*poll_link)(struct mii_phy *phy);
+	int		(*read_link)(struct mii_phy *phy);
+};
+
+/* Structure used to statically define an mii/gii based PHY */
+struct mii_phy_def
+{
+	u32				phy_id;		/* Concatenated ID1 << 16 | ID2 */
+	u32				phy_id_mask;	/* Significant bits */
+	u32				features;	/* Ethtool SUPPORTED_* defines */
+	int				magic_aneg;	/* Autoneg does all speed test for us */
+	const char*			name;
+	const struct mii_phy_ops*	ops;
+};
+
+/* An instance of a PHY, partially borrowed from mii_if_info */
+struct mii_phy
+{
+	struct mii_phy_def*	def;
+	int			advertising;
+	int			mii_id;
+
+	/* 1: autoneg enabled, 0: disabled */
+	int			autoneg;
+
+	/* forced speed & duplex (no autoneg)
+	 * partner speed & duplex & pause (autoneg)
+	 */
+	int			speed;
+	int			duplex;
+	int			pause;
+
+	/* Provided by host chip */
+	struct net_device*	dev;
+	int (*mdio_read) (struct net_device *dev, int mii_id, int reg);
+	void (*mdio_write) (struct net_device *dev, int mii_id, int reg, int val);
+};
+
+/* Pass in a struct mii_phy with dev, mdio_read and mdio_write
+ * filled, the remaining fields will be filled on return
+ */
+extern int mii_phy_probe(struct mii_phy *phy, int mii_id);
+
+
+/* MII definitions missing from mii.h */
+
+#define BMCR_SPD2	0x0040		/* Gigabit enable (bcm54xx)	*/
+#define LPA_PAUSE	0x0400
+
+/* More PHY registers (model specific) */
+
+/* MII BCM5201 MULTIPHY interrupt register */
+#define MII_BCM5201_INTERRUPT			0x1A
+#define MII_BCM5201_INTERRUPT_INTENABLE		0x4000
+
+#define MII_BCM5201_AUXMODE2			0x1B
+#define MII_BCM5201_AUXMODE2_LOWPOWER		0x0008
+
+#define MII_BCM5201_MULTIPHY                    0x1E
+
+/* MII BCM5201 MULTIPHY register bits */
+#define MII_BCM5201_MULTIPHY_SERIALMODE         0x0002
+#define MII_BCM5201_MULTIPHY_SUPERISOLATE       0x0008
+
+/* MII BCM5221 Additional registers */
+#define MII_BCM5221_TEST			0x1f
+#define MII_BCM5221_TEST_ENABLE_SHADOWS		0x0080
+#define MII_BCM5221_SHDOW_AUX_STAT2		0x1b
+#define MII_BCM5221_SHDOW_AUX_STAT2_APD		0x0020
+#define MII_BCM5221_SHDOW_AUX_MODE4		0x1a
+#define MII_BCM5221_SHDOW_AUX_MODE4_CLKLOPWR	0x0004
+
+/* MII BCM5400 1000-BASET Control register */
+#define MII_BCM5400_GB_CONTROL			0x09
+#define MII_BCM5400_GB_CONTROL_FULLDUPLEXCAP	0x0200
+
+/* MII BCM5400 AUXCONTROL register */
+#define MII_BCM5400_AUXCONTROL                  0x18
+#define MII_BCM5400_AUXCONTROL_PWR10BASET       0x0004
+
+/* MII BCM5400 AUXSTATUS register */
+#define MII_BCM5400_AUXSTATUS                   0x19
+#define MII_BCM5400_AUXSTATUS_LINKMODE_MASK     0x0700
+#define MII_BCM5400_AUXSTATUS_LINKMODE_SHIFT    8  
+
+/* 1000BT control (Marvell & BCM54xx at least) */
+#define MII_1000BASETCONTROL			0x09
+#define MII_1000BASETCONTROL_FULLDUPLEXCAP	0x0200
+#define MII_1000BASETCONTROL_HALFDUPLEXCAP	0x0100
+
+/* Marvell 88E1011 PHY control */
+#define MII_M1011_PHY_SPEC_CONTROL		0x10
+#define MII_M1011_PHY_SPEC_CONTROL_MANUAL_MDIX	0x20
+#define MII_M1011_PHY_SPEC_CONTROL_AUTO_MDIX	0x40
+
+/* Marvell 88E1011 PHY status */
+#define MII_M1011_PHY_SPEC_STATUS		0x11
+#define MII_M1011_PHY_SPEC_STATUS_1000		0x8000
+#define MII_M1011_PHY_SPEC_STATUS_100		0x4000
+#define MII_M1011_PHY_SPEC_STATUS_SPD_MASK	0xc000
+#define MII_M1011_PHY_SPEC_STATUS_FULLDUPLEX	0x2000
+#define MII_M1011_PHY_SPEC_STATUS_RESOLVED	0x0800
+
+#endif /* __SUNGEM_PHY_H__ */
diff -Nru a/drivers/net/sunhme.c b/drivers/net/sunhme.c
--- a/drivers/net/sunhme.c	Mon Apr 21 00:00:25 2003
+++ b/drivers/net/sunhme.c	Tue May 20 20:02:20 2003
@@ -3025,6 +3025,7 @@
 	if (!dev)
 		goto err_out;
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (hme_version_printed++ == 0)
 		printk(KERN_INFO "%s", version);
@@ -3092,8 +3093,12 @@
 
 #ifdef __sparc__
 	hp->hm_revision = prom_getintdefault(node, "hm-rev", 0xff);
-	if (hp->hm_revision == 0xff)
-		hp->hm_revision = 0xa0;
+	if (hp->hm_revision == 0xff) {
+		unsigned char prev;
+
+		pci_read_config_byte(pdev, PCI_REVISION_ID, &prev);
+		hp->hm_revision = 0xc0 | (prev & 0x0f);
+	}
 #else
 	/* works with this on non-sparc hosts */
 	hp->hm_revision = 0x20;
@@ -3102,7 +3107,7 @@
 	/* Now enable the feature flags we can. */
 	if (hp->hm_revision == 0x20 || hp->hm_revision == 0x21)
 		hp->happy_flags = HFLAG_20_21;
-	else if (hp->hm_revision != 0xa0)
+	else if (hp->hm_revision != 0xa0 && hp->hm_revision != 0xc0)
 		hp->happy_flags = HFLAG_NOT_A0;
 
 	if (qp != NULL)
diff -Nru a/drivers/net/tg3.c b/drivers/net/tg3.c
--- a/drivers/net/tg3.c	Wed Apr 23 20:02:11 2003
+++ b/drivers/net/tg3.c	Tue May 20 20:02:20 2003
@@ -6764,6 +6764,7 @@
 	}
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_using_dac)
 		dev->features |= NETIF_F_HIGHDMA;
diff -Nru a/drivers/net/tlan.c b/drivers/net/tlan.c
--- a/drivers/net/tlan.c	Sun Apr 20 21:26:42 2003
+++ b/drivers/net/tlan.c	Tue May 20 20:02:20 2003
@@ -521,6 +521,7 @@
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 	
 	priv = dev->priv;
 
diff -Nru a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c
--- a/drivers/net/tulip/de2104x.c	Sun Apr 20 22:41:09 2003
+++ b/drivers/net/tulip/de2104x.c	Tue May 20 20:02:20 2003
@@ -2006,6 +2006,7 @@
 		return -ENOMEM;
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 	dev->open = de_open;
 	dev->stop = de_close;
 	dev->set_multicast_list = de_set_rx_mode;
diff -Nru a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c
--- a/drivers/net/tulip/de4x5.c	Sun Apr 20 22:41:09 2003
+++ b/drivers/net/tulip/de4x5.c	Tue May 20 20:02:20 2003
@@ -1350,6 +1350,7 @@
     
     /* The DE4X5-specific entries in the device structure. */
     SET_MODULE_OWNER(dev);
+    SET_NETDEV_DEV(dev, &pdev->dev);
     dev->open = &de4x5_open;
     dev->hard_start_xmit = &de4x5_queue_pkt;
     dev->stop = &de4x5_close;
diff -Nru a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c
--- a/drivers/net/tulip/dmfe.c	Sun Apr 20 23:00:42 2003
+++ b/drivers/net/tulip/dmfe.c	Tue May 20 20:02:20 2003
@@ -348,6 +348,7 @@
 	if (dev == NULL)
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_set_dma_mask(pdev, 0xffffffff)) {
 		printk(KERN_WARNING DRV_NAME ": 32-bit PCI DMA not available.\n");
diff -Nru a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c
--- a/drivers/net/tulip/tulip_core.c	Sun Apr  6 14:00:36 2003
+++ b/drivers/net/tulip/tulip_core.c	Tue May 20 20:02:20 2003
@@ -223,6 +223,7 @@
 	{ 0x1626, 0x8410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x1737, 0xAB09, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
 	{ 0x17B3, 0xAB08, PCI_ANY_ID, PCI_ANY_ID, 0, 0, COMET },
+ 	{ 0x10b9, 0x5261, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DM910X },	/* ALi 1563 integrated ethernet */
 	{ } /* terminate list */
 };
 MODULE_DEVICE_TABLE(pci, tulip_pci_tbl);
@@ -1325,12 +1326,14 @@
 		csr0 &= ~0xfff10000; /* zero reserved bits 31:20, 16 */
 
 	/* DM9102A has troubles with MRM & clear reserved bits 24:22, 20, 16, 7:1 */
-	if (pdev->vendor == 0x1282 && pdev->device == 0x9102)
+	if ((pdev->vendor == 0x1282 && pdev->device == 0x9102)
+		|| (pdev->vendor == 0x10b9 && pdev->device == 0x5261))
 		csr0 &= ~0x01f100ff;
 
 #if defined(__sparc__)
         /* DM9102A needs 32-dword alignment/burst length on sparc - chip bug? */
-        if (pdev->vendor == 0x1282 && pdev->device == 0x9102)
+	if ((pdev->vendor == 0x1282 && pdev->device == 0x9102)
+		|| (pdev->vendor == 0x10b9 && pdev->device == 0x5261))
                 csr0 = (csr0 & ~0xff00) | 0xe000;
 #endif
 
@@ -1357,6 +1360,7 @@
 	}
 
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 	if (pci_resource_len (pdev, 0) < tulip_tbl[chip_idx].io_size) {
 		printk (KERN_ERR PFX "%s: I/O region (0x%lx@0x%lx) too small, "
 			"aborting\n", pdev->slot_name,
diff -Nru a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c
--- a/drivers/net/tulip/winbond-840.c	Sun Apr 20 23:00:42 2003
+++ b/drivers/net/tulip/winbond-840.c	Tue May 20 20:02:20 2003
@@ -423,6 +423,7 @@
 	if (!dev)
 		return -ENOMEM;
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	if (pci_request_regions(pdev, DRV_NAME))
 		goto err_out_netdev;
diff -Nru a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c
--- a/drivers/net/tulip/xircom_cb.c	Sun Apr 20 23:39:12 2003
+++ b/drivers/net/tulip/xircom_cb.c	Tue May 20 20:02:20 2003
@@ -276,6 +276,7 @@
 		return -ENODEV;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 	printk(KERN_INFO "%s: Xircom cardbus revision %i at irq %i \n", dev->name, chip_rev, pdev->irq);
 
 	private->dev = dev;
diff -Nru a/drivers/net/tulip/xircom_tulip_cb.c b/drivers/net/tulip/xircom_tulip_cb.c
--- a/drivers/net/tulip/xircom_tulip_cb.c	Sun Apr 20 23:39:12 2003
+++ b/drivers/net/tulip/xircom_tulip_cb.c	Tue May 20 20:02:20 2003
@@ -560,6 +560,7 @@
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	dev->base_addr = ioaddr;
 	dev->irq = pdev->irq;
diff -Nru a/drivers/net/tun.c b/drivers/net/tun.c
--- a/drivers/net/tun.c	Mon Apr 14 00:12:11 2003
+++ b/drivers/net/tun.c	Mon May 19 23:22:51 2003
@@ -379,7 +379,7 @@
 		tun->owner = -1;
 		tun->dev.init = tun_net_init;
 		tun->dev.priv = tun;
-		tun->dev.owner = THIS_MODULE;
+		SET_MODULE_OWNER(&tun->dev);
 
 		err = -EINVAL;
 
diff -Nru a/drivers/net/typhoon.c b/drivers/net/typhoon.c
--- a/drivers/net/typhoon.c	Fri Apr 25 21:01:33 2003
+++ b/drivers/net/typhoon.c	Tue May 20 20:02:20 2003
@@ -2266,6 +2266,7 @@
 		goto error_out;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	err = pci_enable_device(pdev);
 	if(err < 0) {
diff -Nru a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c
--- a/drivers/net/via-rhine.c	Fri Apr 25 19:57:40 2003
+++ b/drivers/net/via-rhine.c	Tue May 20 20:02:20 2003
@@ -660,6 +660,7 @@
 		goto err_out;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 	
 	if (pci_request_regions(pdev, shortname))
 		goto err_out_free_netdev;
diff -Nru a/drivers/net/wan/comx-hw-comx.c b/drivers/net/wan/comx-hw-comx.c
--- a/drivers/net/wan/comx-hw-comx.c	Sun Apr 27 20:36:20 2003
+++ b/drivers/net/wan/comx-hw-comx.c	Mon May 19 23:57:38 2003
@@ -1427,24 +1427,20 @@
 	NULL
 };
 
-#ifdef MODULE
-#define comx_hw_comx_init init_module
-#endif
-
-int __init comx_hw_comx_init(void)
+static int __init comx_hw_comx_init(void)
 {
 	comx_register_hardware(&comx_hw);
 	comx_register_hardware(&cmx_hw);
 	comx_register_hardware(&hicomx_hw);
-	memset(memory_used, 0, sizeof(memory_used));
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit comx_hw_comx_exit(void)
 {
 	comx_unregister_hardware("comx");
 	comx_unregister_hardware("cmx");
 	comx_unregister_hardware("hicomx");
 }
-#endif
+
+module_init(comx_hw_comx_init);
+module_exit(comx_hw_comx_exit);
diff -Nru a/drivers/net/wan/comx-hw-locomx.c b/drivers/net/wan/comx-hw-locomx.c
--- a/drivers/net/wan/comx-hw-locomx.c	Thu Nov 21 14:06:12 2002
+++ b/drivers/net/wan/comx-hw-locomx.c	Mon May 19 23:57:38 2003
@@ -479,20 +479,16 @@
 	NULL
 };
 	
-#ifdef MODULE
-#define comx_hw_locomx_init init_module
-#endif
-
-int __init comx_hw_locomx_init(void)
+static int __init comx_hw_locomx_init(void)
 {
 	comx_register_hardware(&locomx_hw);
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit comx_hw_locomx_exit(void)
 {
 	comx_unregister_hardware("locomx");
-	return;
 }
-#endif
+
+module_init(comx_hw_locomx_init);
+module_exit(comx_hw_locomx_exit);
diff -Nru a/drivers/net/wan/comx-hw-mixcom.c b/drivers/net/wan/comx-hw-mixcom.c
--- a/drivers/net/wan/comx-hw-mixcom.c	Sun Apr 27 20:36:20 2003
+++ b/drivers/net/wan/comx-hw-mixcom.c	Mon May 19 23:57:38 2003
@@ -944,21 +944,15 @@
 	NULL
 };
 	
-/* Module management */
-
-#ifdef MODULE
-#define comx_hw_mixcom_init init_module
-#endif
-
-int __init comx_hw_mixcom_init(void)
+static int __init comx_hw_mixcom_init(void)
 {
-	return(comx_register_hardware(&mixcomhw));
+	return comx_register_hardware(&mixcomhw);
 }
 
-#ifdef MODULE
-void
-cleanup_module(void)
+static void __exit comx_hw_mixcom_exit(void)
 {
 	comx_unregister_hardware("mixcom");
 }
-#endif
+
+module_init(comx_hw_mixcom_init);
+module_exit(comx_hw_mixcom_exit);
diff -Nru a/drivers/net/wan/comx-proto-fr.c b/drivers/net/wan/comx-proto-fr.c
--- a/drivers/net/wan/comx-proto-fr.c	Thu Nov 21 14:06:12 2002
+++ b/drivers/net/wan/comx-proto-fr.c	Mon May 19 23:57:38 2003
@@ -988,11 +988,7 @@
 	.hw_dump	= dlci_dump, 
 };
 
-#ifdef MODULE
-#define comx_proto_fr_init init_module
-#endif
-
-int __init comx_proto_fr_init(void)
+static int __init comx_proto_fr_init(void)
 {
 	int ret; 
 
@@ -1005,12 +1001,12 @@
 	return comx_register_protocol(&fr_slave_protocol);
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit comx_proto_fr_exit(void)
 {
 	comx_unregister_hardware(fr_dlci.name);
 	comx_unregister_protocol(fr_master_protocol.name);
 	comx_unregister_protocol(fr_slave_protocol.name);
 }
-#endif /* MODULE */
 
+module_init(comx_proto_fr_init);
+module_exit(comx_proto_fr_exit);
diff -Nru a/drivers/net/wan/comx-proto-lapb.c b/drivers/net/wan/comx-proto-lapb.c
--- a/drivers/net/wan/comx-proto-lapb.c	Mon Feb  4 23:45:17 2002
+++ b/drivers/net/wan/comx-proto-lapb.c	Mon May 19 23:57:38 2003
@@ -523,7 +523,7 @@
 	NULL 
 };
 
-int __init comx_proto_lapb_init(void)
+static int __init comx_proto_lapb_init(void)
 {
 	int ret;
 
@@ -539,9 +539,7 @@
 	comx_unregister_protocol(comx25_protocol.name);
 }
 
-#ifdef MODULE
 module_init(comx_proto_lapb_init);
-#endif
 module_exit(comx_proto_lapb_exit);
 
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/net/wan/comx-proto-ppp.c b/drivers/net/wan/comx-proto-ppp.c
--- a/drivers/net/wan/comx-proto-ppp.c	Wed May 22 11:16:37 2002
+++ b/drivers/net/wan/comx-proto-ppp.c	Mon May 19 23:57:38 2003
@@ -247,26 +247,24 @@
 	NULL 
 };
 
-
-#ifdef MODULE
-#define comx_proto_ppp_init init_module
-#endif
-
-int __init comx_proto_ppp_init(void)
+static int __init comx_proto_ppp_init(void)
 {
 	int ret;
 
-	if(0!=(ret=comx_register_protocol(&hdlc_protocol))) {
-		return ret;
+	ret = comx_register_protocol(&hdlc_protocol);
+	if (!ret) {
+		ret = comx_register_protocol(&syncppp_protocol);
+		if (ret)
+			comx_unregister_protocol(hdlc_protocol.name);
 	}
-	return comx_register_protocol(&syncppp_protocol);
+	return ret;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit comx_proto_ppp_exit(void)
 {
 	comx_unregister_protocol(syncppp_protocol.name);
 	comx_unregister_protocol(hdlc_protocol.name);
 }
-#endif /* MODULE */
 
+module_init(comx_proto_ppp_init);
+module_exit(comx_proto_ppp_exit);
diff -Nru a/drivers/net/wan/comx.c b/drivers/net/wan/comx.c
--- a/drivers/net/wan/comx.c	Sat Aug  3 10:51:42 2002
+++ b/drivers/net/wan/comx.c	Mon May 19 23:57:38 2003
@@ -81,15 +81,6 @@
 MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");
 MODULE_LICENSE("GPL");
 
-extern int comx_hw_comx_init(void);
-extern int comx_hw_locomx_init(void);
-extern int comx_hw_mixcom_init(void);
-extern int comx_proto_hdlc_init(void);
-extern int comx_proto_ppp_init(void);
-extern int comx_proto_syncppp_init(void);
-extern int comx_proto_lapb_init(void);
-extern int comx_proto_fr_init(void);
-
 static struct comx_hardware *comx_channels = NULL;
 static struct comx_protocol *comx_lines = NULL;
 
@@ -613,7 +604,6 @@
 	char *page;
 	struct comx_hardware *hw = comx_channels;
 	struct comx_protocol *line = comx_lines;
-	char str[30];
 	int ret=0;
 
 	if (count > PAGE_SIZE) {
@@ -691,8 +681,7 @@
 		}
 #ifdef CONFIG_KMOD
 		if(!hw && comx_strcasecmp(HWNAME_NONE,page) != 0){
-			sprintf(str,"comx-hw-%s",page);
-			request_module(str);
+			request_module("comx-hw-%s",page);
 		}		
 		hw=comx_channels;
 		while (hw) {
@@ -734,8 +723,7 @@
 		}
 #ifdef CONFIG_KMOD
 		if(!line && comx_strcasecmp(PROTONAME_NONE, page) != 0) {
-			sprintf(str,"comx-proto-%s",page);
-			request_module(str);
+			request_module("comx-proto-%s",page);
 		}		
 		line=comx_lines;
 		while (line) {
@@ -1081,11 +1069,7 @@
 	return -1;
 }
 
-#ifdef MODULE
-#define comx_init init_module
-#endif
-
-int __init comx_init(void)
+static int __init comx_init(void)
 {
 	struct proc_dir_entry *new_file;
 
@@ -1118,42 +1102,18 @@
 
 	printk(KERN_INFO "COMX: driver version %s (C) 1995-1999 ITConsult-Pro Co. <info@itc.hu>\n", 
 		VERSION);
-
-#ifndef MODULE
-#ifdef CONFIG_COMX_HW_COMX
-	comx_hw_comx_init();
-#endif
-#ifdef CONFIG_COMX_HW_LOCOMX
-	comx_hw_locomx_init();
-#endif
-#ifdef CONFIG_COMX_HW_MIXCOM
-	comx_hw_mixcom_init();
-#endif
-#ifdef CONFIG_COMX_PROTO_HDLC
-	comx_proto_hdlc_init();
-#endif
-#ifdef CONFIG_COMX_PROTO_PPP
-	comx_proto_ppp_init();
-#endif
-#ifdef CONFIG_COMX_PROTO_LAPB
-	comx_proto_lapb_init();
-#endif
-#ifdef CONFIG_COMX_PROTO_FR
-	comx_proto_fr_init();
-#endif
-#endif
-
 	return 0;
 }
 
-#ifdef MODULE
-void cleanup_module(void)
+static void __exit comx_exit(void)
 {
 	remove_proc_entry(FILENAME_HARDWARELIST, comx_root_dir);
 	remove_proc_entry(FILENAME_PROTOCOLLIST, comx_root_dir);
 	remove_proc_entry(comx_root_dir->name, &proc_root);
 }
-#endif
+
+module_init(comx_init);
+module_exit(comx_exit);
 
 EXPORT_SYMBOL(comx_register_hardware);
 EXPORT_SYMBOL(comx_unregister_hardware);
diff -Nru a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c
--- a/drivers/net/wan/cosa.c	Sun Apr 27 20:36:21 2003
+++ b/drivers/net/wan/cosa.c	Wed May  7 08:47:30 2003
@@ -392,12 +392,9 @@
 	}
 	devfs_mk_dir("cosa");
 	for (i=0; i<nr_cards; i++) {
-		char name[16];
-		sprintf(name, "cosa/%d", i);
-		devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-			       cosa_major, i,
-			       S_IFCHR | S_IRUSR | S_IWUSR,
-			       &cosa_fops, NULL);
+		devfs_mk_cdev(MKDEV(cosa_major, i),
+				S_IFCHR|S_IRUSR|S_IWUSR,
+				"cosa/%d", i);
 	}
 	return 0;
 }
diff -Nru a/drivers/net/wan/cycx_drv.c b/drivers/net/wan/cycx_drv.c
--- a/drivers/net/wan/cycx_drv.c	Mon Oct  7 07:39:27 2002
+++ b/drivers/net/wan/cycx_drv.c	Thu May 15 19:33:21 2003
@@ -6,7 +6,7 @@
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
 *
 * Based on sdladrv.c by Gene Kozin <genek@compuserve.com>
 *
@@ -66,15 +66,9 @@
 MODULE_DESCRIPTION("Cyclom 2x Sync Card Driver");
 MODULE_LICENSE("GPL");
 
-
-/* Function Prototypes */
-/* Module entry points. These are called by the OS and must be public. */
-int init_module(void);
-void cleanup_module(void);
-
 /* Hardware-specific functions */
-static int load_cyc2x(cycxhw_t *hw, cfm_t *cfm, u32 len);
-static void cycx_bootcfg(cycxhw_t *hw);
+static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len);
+static void cycx_bootcfg(struct cycx_hw *hw);
 
 static int reset_cyc2x(u32 addr);
 static int detect_cyc2x(u32 addr);
@@ -86,27 +80,19 @@
 
 #define wait_cyc(addr) cycx_exec(addr + CMD_OFFSET)
 
-#define cyc2x_readb(b) readb(b)
-#define cyc2x_readw(b) readw(b)
-#define cyc2x_writeb(b, addr) writeb(b, addr)
-#define cyc2x_writew(w, addr) writew(w, addr)
-#define cyc2x_memcpy_toio(addr, buf, len) memcpy_toio((addr), buf, len)
-#define cyc2x_memcpy_fromio(buf, addr, len) memcpy_fromio(buf, (addr), len)
-
 /* Global Data */
 
 /* private data */
 static char modname[] = "cycx_drv";
 static char fullname[] = "Cyclom 2X Support Module";
-static char copyright[] = "(c) 1998-2000 Arnaldo Carvalho de Melo "
+static char copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
 			  "<acme@conectiva.com.br>";
 
 /* Hardware configuration options.
  * These are arrays of configuration options used by verification routines.
  * The first element of each array is its size (i.e. number of options).
  */
-static u32 cyc2x_dpmbase_options[] =
-{
+static u32 cyc2x_dpmbase_options[] = {
 	20,
 	0xA0000, 0xA4000, 0xA8000, 0xAC000, 0xB0000, 0xB4000, 0xB8000,
 	0xBC000, 0xC0000, 0xC4000, 0xC8000, 0xCC000, 0xD0000, 0xD4000,
@@ -149,7 +135,7 @@
  * Return:	0	ok.
  *		< 0	error */
 EXPORT_SYMBOL(cycx_setup);
-int cycx_setup(cycxhw_t *hw, void *cfm, u32 len)
+int cycx_setup(struct cycx_hw *hw, void *cfm, u32 len)
 {
 	unsigned long dpmbase = hw->dpmbase;
 	int err;
@@ -158,7 +144,7 @@
 	if (!get_option_index(cycx_2x_irq_options, hw->irq)) {
 		printk(KERN_ERR "%s: IRQ %d is illegal!\n", modname, hw->irq);
 		return -EINVAL;
-	} 
+	}
 
 	/* Setup adapter dual-port memory window and test memory */
 	if (!hw->dpmbase) {
@@ -190,10 +176,10 @@
 		cycx_down(hw);         /* shutdown adapter */
 
 	return err;
-} 
+}
 
 EXPORT_SYMBOL(cycx_down);
-int cycx_down(cycxhw_t *hw)
+int cycx_down(struct cycx_hw *hw)
 {
 	iounmap((u32 *)hw->dpmbase);
 
@@ -202,16 +188,16 @@
 
 /* Enable interrupt generation.  */
 EXPORT_SYMBOL(cycx_inten);
-void cycx_inten(cycxhw_t *hw)
+void cycx_inten(struct cycx_hw *hw)
 {
-	cyc2x_writeb(0, hw->dpmbase);
+	writeb(0, hw->dpmbase);
 }
 
 /* Generate an interrupt to adapter's CPU. */
 EXPORT_SYMBOL(cycx_intr);
-void cycx_intr(cycxhw_t *hw)
+void cycx_intr(struct cycx_hw *hw)
 {
-	cyc2x_writew(0, hw->dpmbase + GEN_CYCX_INTR);
+	writew(0, hw->dpmbase + GEN_CYCX_INTR);
 }
 
 /* Execute Adapter Command.
@@ -223,9 +209,9 @@
 	u16 i = 0;
 	/* wait till addr content is zeroed */
 
-	while (cyc2x_readw(addr)) {
+	while (readw(addr)) {
 		udelay(1000);
-		
+
 		if (++i > 50)
 			return -1;
 	}
@@ -236,12 +222,12 @@
 /* Read absolute adapter memory.
  * Transfer data from adapter's memory to data buffer. */
 EXPORT_SYMBOL(cycx_peek);
-int cycx_peek(cycxhw_t *hw, u32 addr, void *buf, u32 len)
+int cycx_peek(struct cycx_hw *hw, u32 addr, void *buf, u32 len)
 {
 	if (len == 1)
-		*(u8*)buf = cyc2x_readb(hw->dpmbase + addr);
+		*(u8*)buf = readb(hw->dpmbase + addr);
 	else
-		cyc2x_memcpy_fromio(buf, hw->dpmbase + addr, len);
+		memcpy_fromio(buf, hw->dpmbase + addr, len);
 
 	return 0;
 }
@@ -249,12 +235,12 @@
 /* Write Absolute Adapter Memory.
  * Transfer data from data buffer to adapter's memory. */
 EXPORT_SYMBOL(cycx_poke);
-int cycx_poke(cycxhw_t *hw, u32 addr, void *buf, u32 len)
+int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len)
 {
 	if (len == 1)
-		cyc2x_writeb(*(u8*)buf, hw->dpmbase + addr);
+		writeb(*(u8*)buf, hw->dpmbase + addr);
 	else
-		cyc2x_memcpy_toio(hw->dpmbase + addr, buf, len);
+		memcpy_toio(hw->dpmbase + addr, buf, len);
 
 	return 0;
 }
@@ -269,10 +255,10 @@
 	int tries = 0;
 
 	for (; tries < 3 ; tries++) {
-		cyc2x_writew(TEST_PATTERN, addr + 0x10);
+		writew(TEST_PATTERN, addr + 0x10);
 
-		if (cyc2x_readw(addr + 0x10) == TEST_PATTERN)
-			if (cyc2x_readw(addr + 0x10) == TEST_PATTERN)
+		if (readw(addr + 0x10) == TEST_PATTERN)
+			if (readw(addr + 0x10) == TEST_PATTERN)
 				return 1;
 
 		delay_cycx(1);
@@ -289,7 +275,7 @@
 
 	for (i = 0 ; i < cnt ; i++) {
 /*		for (j = 0 ; j < 50 ; j++); Delay - FIXME busy waiting... */
-		cyc2x_writeb(*buffer++, pt_code++);
+		writeb(*buffer++, pt_code++);
 	}
 }
 
@@ -298,8 +284,8 @@
  * o wait for reset code to copy it to right portion of memory */
 static int buffer_load(u32 addr, u8 *buffer, u32 cnt)
 {
-	cyc2x_memcpy_toio(addr + DATA_OFFSET, buffer, cnt);
-	cyc2x_writew(GEN_BOOT_DAT, addr + CMD_OFFSET);
+	memcpy_toio(addr + DATA_OFFSET, buffer, cnt);
+	writew(GEN_BOOT_DAT, addr + CMD_OFFSET);
 
 	return wait_cyc(addr);
 }
@@ -308,30 +294,30 @@
 static void cycx_start(u32 addr)
 {
 	/* put in 0x30 offset the jump instruction to the code entry point */
-	cyc2x_writeb(0xea, addr + 0x30);
-	cyc2x_writeb(0x00, addr + 0x31);
-	cyc2x_writeb(0xc4, addr + 0x32);
-	cyc2x_writeb(0x00, addr + 0x33);
-	cyc2x_writeb(0x00, addr + 0x34);
+	writeb(0xea, addr + 0x30);
+	writeb(0x00, addr + 0x31);
+	writeb(0xc4, addr + 0x32);
+	writeb(0x00, addr + 0x33);
+	writeb(0x00, addr + 0x34);
 
 	/* cmd to start executing code */
-	cyc2x_writew(GEN_START, addr + CMD_OFFSET);
-}         
+	writew(GEN_START, addr + CMD_OFFSET);
+}
 
 /* Load and boot reset code. */
 static void cycx_reset_boot(u32 addr, u8 *code, u32 len)
 {
 	u32 pt_start = addr + START_OFFSET;
 
-        cyc2x_writeb(0xea, pt_start++); /* jmp to f000:3f00 */
-        cyc2x_writeb(0x00, pt_start++);
-        cyc2x_writeb(0xfc, pt_start++);
-        cyc2x_writeb(0x00, pt_start++);
-        cyc2x_writeb(0xf0, pt_start);
+	writeb(0xea, pt_start++); /* jmp to f000:3f00 */
+	writeb(0x00, pt_start++);
+	writeb(0xfc, pt_start++);
+	writeb(0x00, pt_start++);
+	writeb(0xf0, pt_start);
 	reset_load(addr, code, len);
 
 	/* 80186 was in hold, go */
-	cyc2x_writeb(0, addr + START_CPU);
+	writeb(0, addr + START_CPU);
 	delay_cycx(1);
 }
 
@@ -342,22 +328,22 @@
 	u32 i;
 
 	/* boot buffer lenght */
-	cyc2x_writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
-	cyc2x_writew(GEN_DEFPAR, pt_boot_cmd);
+	writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
+	writew(GEN_DEFPAR, pt_boot_cmd);
 
 	if (wait_cyc(addr) < 0)
 		return -1;
 
-	cyc2x_writew(0, pt_boot_cmd + sizeof(u16));
-	cyc2x_writew(0x4000, pt_boot_cmd + 2 * sizeof(u16));
-	cyc2x_writew(GEN_SET_SEG, pt_boot_cmd);
+	writew(0, pt_boot_cmd + sizeof(u16));
+	writew(0x4000, pt_boot_cmd + 2 * sizeof(u16));
+	writew(GEN_SET_SEG, pt_boot_cmd);
 
 	if (wait_cyc(addr) < 0)
 		return -1;
 
 	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
 		if (buffer_load(addr, code + i,
-				MIN(CFM_LOAD_BUFSZ, (len - i))) < 0) {
+				min_t(u32, CFM_LOAD_BUFSZ, (len - i))) < 0) {
 			printk(KERN_ERR "%s: Error !!\n", modname);
 			return -1;
 		}
@@ -373,21 +359,22 @@
 	u32 i;
 
 	/* boot buffer lenght */
-	cyc2x_writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
-	cyc2x_writew(GEN_DEFPAR, pt_boot_cmd);
+	writew(CFM_LOAD_BUFSZ, pt_boot_cmd + sizeof(u16));
+	writew(GEN_DEFPAR, pt_boot_cmd);
 
 	if (wait_cyc(addr) < 0)
 		return -1;
 
-	cyc2x_writew(0x0000, pt_boot_cmd + sizeof(u16));
-	cyc2x_writew(0xc400, pt_boot_cmd + 2 * sizeof(u16));
-	cyc2x_writew(GEN_SET_SEG, pt_boot_cmd);
+	writew(0x0000, pt_boot_cmd + sizeof(u16));
+	writew(0xc400, pt_boot_cmd + 2 * sizeof(u16));
+	writew(GEN_SET_SEG, pt_boot_cmd);
 
 	if (wait_cyc(addr) < 0)
 		return -1;
 
 	for (i = 0 ; i < len ; i += CFM_LOAD_BUFSZ)
-		if (buffer_load(addr, code + i,MIN(CFM_LOAD_BUFSZ,(len - i)))) {
+		if (buffer_load(addr, code + i,
+				min_t(u32, CFM_LOAD_BUFSZ, (len - i)))) {
 			printk(KERN_ERR "%s: Error !!\n", modname);
 			return -1;
 		}
@@ -395,13 +382,13 @@
 	return 0;
 }
 
-/* Load adapter from the memory image of the CYCX firmware module. 
+/* Load adapter from the memory image of the CYCX firmware module.
  * o verify firmware integrity and compatibility
  * o start adapter up */
-static int load_cyc2x(cycxhw_t *hw, cfm_t *cfm, u32 len)
+static int load_cyc2x(struct cycx_hw *hw, struct cycx_firmware *cfm, u32 len)
 {
 	int i, j;
-	cycx_header_t *img_hdr;
+	struct cycx_fw_header *img_hdr;
 	u8 *reset_image,
 	   *data_image,
 	   *code_image;
@@ -430,37 +417,39 @@
 	}
 
 	/* Verify firmware module length and checksum */
-	cksum = checksum((u8*)&cfm->info, sizeof(cfm_info_t) +
-					      cfm->info.codesize);
+	cksum = checksum((u8*)&cfm->info, sizeof(struct cycx_fw_info) +
+					  cfm->info.codesize);
 /*
-        FIXME cfm->info.codesize is off by 2
-	if (((len - sizeof(cfm_t) - 1) != cfm->info.codesize) ||
+	FIXME cfm->info.codesize is off by 2
+	if (((len - sizeof(struct cycx_firmware) - 1) != cfm->info.codesize) ||
 */
 	if (cksum != cfm->checksum) {
 		printk(KERN_ERR "%s:%s: firmware corrupted!\n",
 				modname, __FUNCTION__);
 		printk(KERN_ERR " cdsize = 0x%x (expected 0x%lx)\n",
-				len - sizeof(cfm_t) - 1, cfm->info.codesize);
-                printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n",
+				len - sizeof(struct cycx_firmware) - 1,
+				cfm->info.codesize);
+		printk(KERN_ERR " chksum = 0x%x (expected 0x%x)\n",
 				cksum, cfm->checksum);
 		return -EINVAL;
 	}
 
 	/* If everything is ok, set reset, data and code pointers */
 
-	img_hdr = (cycx_header_t*)(((u8*)cfm) + sizeof(cfm_t) - 1);
+	img_hdr = (struct cycx_fw_header *)(((u8 *)cfm) +
+					    sizeof(struct cycx_firmware) - 1);
 #ifdef FIRMWARE_DEBUG
 	printk(KERN_INFO "%s:%s: image sizes\n", __FUNCTION__, modname);
 	printk(KERN_INFO " reset=%lu\n", img_hdr->reset_size);
 	printk(KERN_INFO "  data=%lu\n", img_hdr->data_size);
 	printk(KERN_INFO "  code=%lu\n", img_hdr->code_size);
 #endif
-	reset_image = ((u8 *)img_hdr) + sizeof(cycx_header_t);
+	reset_image = ((u8 *)img_hdr) + sizeof(struct cycx_fw_header);
 	data_image = reset_image + img_hdr->reset_size;
 	code_image = data_image + img_hdr->data_size;
 
 	/*---- Start load ----*/
-        /* Announce */
+	/* Announce */
 	printk(KERN_INFO "%s: loading firmware %s (ID=%u)...\n", modname,
 			 cfm->descr[0] ? cfm->descr : "unknown firmware",
 			 cfm->info.codeid);
@@ -474,13 +463,13 @@
 		}
 
 		/* Load reset.bin */
-                cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size);
+		cycx_reset_boot(hw->dpmbase, reset_image, img_hdr->reset_size);
 		/* reset is waiting for boot */
-		cyc2x_writew(GEN_POWER_ON, pt_cycld);
+		writew(GEN_POWER_ON, pt_cycld);
 		delay_cycx(1);
 
 		for (j = 0 ; j < 3 ; j++)
-			if (!cyc2x_readw(pt_cycld))
+			if (!readw(pt_cycld))
 				goto reset_loaded;
 			else
 				delay_cycx(1);
@@ -514,7 +503,7 @@
 	printk(KERN_INFO "%s: firmware loaded!\n", modname);
 
 	/* enable interrupts */
-        cycx_inten(hw);
+	cycx_inten(hw);
 
 	return 0;
 }
@@ -525,10 +514,10 @@
    - As of now, only static buffers are available to the user.
      So, the bit VD_RXDIRC must be set in 'valid'. That means that user
      wants to use the static transmission and reception buffers. */
-static void cycx_bootcfg(cycxhw_t *hw)
+static void cycx_bootcfg(struct cycx_hw *hw)
 {
 	/* use fixed buffers */
-	cyc2x_writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET); 
+	writeb(FIXED_BUFFERS, hw->dpmbase + CONF_OFFSET);
 }
 
 /* Detect Cyclom 2x adapter.
@@ -561,9 +550,9 @@
 /* Reset adapter's CPU. */
 static int reset_cyc2x(u32 addr)
 {
-	cyc2x_writeb(0, addr + RST_ENABLE);
+	writeb(0, addr + RST_ENABLE);
 	delay_cycx(2);
-	cyc2x_writeb(0, addr + RST_DISABLE);
+	writeb(0, addr + RST_DISABLE);
 	delay_cycx(2);
 
 	return memory_exists(addr);
@@ -573,7 +562,7 @@
 static void delay_cycx(int sec)
 {
 	set_current_state(TASK_INTERRUPTIBLE);
-	schedule_timeout(sec*HZ);
+	schedule_timeout(sec * HZ);
 }
 
 /* Calculate 16-bit CRC using CCITT polynomial. */
diff -Nru a/drivers/net/wan/cycx_main.c b/drivers/net/wan/cycx_main.c
--- a/drivers/net/wan/cycx_main.c	Sun Apr 27 20:36:21 2003
+++ b/drivers/net/wan/cycx_main.c	Tue May 20 07:19:38 2003
@@ -3,7 +3,7 @@
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998-2001 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
 *
 * Based on sdlamain.c by Gene Kozin <genek@compuserve.com> &
 *			 Jaspreet Singh	<jaspreet@sangoma.com>
@@ -13,6 +13,10 @@
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 * ============================================================================
+* Please look at the bitkeeper changelog (or any other scm tool that ends up
+* importing bitkeeper changelog or that replaces bitkeeper in the future as
+* main tool for linux development).
+* 
 * 2001/05/09	acme		Fix MODULE_DESC for debug, .bss nitpicks,
 * 				some cleanups
 * 2000/07/13	acme		remove useless #ifdef MODULE and crap
@@ -46,11 +50,8 @@
 #include <linux/ioport.h>	/* request_region(), release_region() */
 #include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/cyclomx.h>	/* cyclomx common user API definitions */
-#include <asm/uaccess.h>	/* kernel <-> user copy */
 #include <linux/init.h>         /* __init (when not using as a module) */
 
-/* Debug */
-
 unsigned int cycx_debug;
 
 MODULE_AUTHOR("Arnaldo Carvalho de Melo");
@@ -61,33 +62,32 @@
 
 /* Defines & Macros */
 
-#define	DRV_VERSION	0		/* version number */
-#define	DRV_RELEASE	10		/* release (minor version) number */
-#define	MAX_CARDS	1		/* max number of adapters */
+#define	CYCX_DRV_VERSION	0	/* version number */
+#define	CYCX_DRV_RELEASE	11	/* release (minor version) number */
+#define	CYCX_MAX_CARDS		1	/* max number of adapters */
 
-#define	CONFIG_CYCLOMX_CARDS 1
+#define	CONFIG_CYCX_CARDS 1
 
 /* Function Prototypes */
 
 /* WAN link driver entry points */
-static int setup (wan_device_t *wandev, wandev_conf_t *conf);
-static int shutdown (wan_device_t *wandev);
-static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg);
+static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf);
+static int cycx_wan_shutdown(struct wan_device *wandev);
 
 /* Miscellaneous functions */
-static irqreturn_t cycx_isr (int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t cycx_isr(int irq, void *dev_id, struct pt_regs *regs);
 
 /* Global Data
  * Note: All data must be explicitly initialized!!!
  */
 
 /* private data */
-static char drvname[]	= "cyclomx";
-static char fullname[]	= "CYCLOM 2X(tm) Sync Card Driver";
-static char copyright[] = "(c) 1998-2001 Arnaldo Carvalho de Melo "
+static char cycx_drvname[] = "cyclomx";
+static char cycx_fullname[] = "CYCLOM 2X(tm) Sync Card Driver";
+static char cycx_copyright[] = "(c) 1998-2003 Arnaldo Carvalho de Melo "
 			  "<acme@conectiva.com.br>";
-static int ncards = CONFIG_CYCLOMX_CARDS;
-static cycx_t *card_array;	/* adapter data space */
+static int cycx_ncards = CONFIG_CYCX_CARDS;
+static struct cycx_device *cycx_card_array;	/* adapter data space */
 
 /* Kernel Loadable Module Entry Points */
 
@@ -103,51 +103,52 @@
  *		< 0	error.
  * Context:	process
  */
-int __init cyclomx_init (void)
+int __init cycx_init(void)
 {
 	int cnt, err = -ENOMEM;
 
 	printk(KERN_INFO "%s v%u.%u %s\n",
-		fullname, DRV_VERSION, DRV_RELEASE, copyright);
+		cycx_fullname, CYCX_DRV_VERSION, CYCX_DRV_RELEASE,
+		cycx_copyright);
 
 	/* Verify number of cards and allocate adapter data space */
-	ncards = min_t(int, ncards, MAX_CARDS);
-	ncards = max_t(int, ncards, 1);
-	card_array = kmalloc(sizeof(cycx_t) * ncards, GFP_KERNEL);
-	if (!card_array)
+	cycx_ncards = min_t(int, cycx_ncards, CYCX_MAX_CARDS);
+	cycx_ncards = max_t(int, cycx_ncards, 1);
+	cycx_card_array = kmalloc(sizeof(struct cycx_device) * cycx_ncards,
+				  GFP_KERNEL);
+	if (!cycx_card_array)
 		goto out;
 
-	memset(card_array, 0, sizeof(cycx_t) * ncards);
+	memset(cycx_card_array, 0, sizeof(struct cycx_device) * cycx_ncards);
 
 	/* Register adapters with WAN router */
-	for (cnt = 0; cnt < ncards; ++cnt) {
-		cycx_t *card = &card_array[cnt];
-		wan_device_t *wandev = &card->wandev;
+	for (cnt = 0; cnt < cycx_ncards; ++cnt) {
+		struct cycx_device *card = &cycx_card_array[cnt];
+		struct wan_device *wandev = &card->wandev;
 
-		sprintf(card->devname, "%s%d", drvname, cnt + 1);
+		sprintf(card->devname, "%s%d", cycx_drvname, cnt + 1);
 		wandev->magic    = ROUTER_MAGIC;
 		wandev->name     = card->devname;
 		wandev->private  = card;
-		wandev->setup    = setup;
-		wandev->shutdown = shutdown;
-		wandev->ioctl    = ioctl;
+		wandev->setup    = cycx_wan_setup;
+		wandev->shutdown = cycx_wan_shutdown;
 		err = register_wan_device(wandev);
 
 		if (err) {
 			printk(KERN_ERR "%s: %s registration failed with "
 					"error %d!\n",
-					drvname, card->devname, err);
+					cycx_drvname, card->devname, err);
 			break;
 		}
 	}
 
 	err = -ENODEV;
 	if (!cnt) {
-		kfree(card_array);
+		kfree(cycx_card_array);
 		goto out;
 	}
 	err = 0;
-	ncards = cnt;	/* adjust actual number of cards */
+	cycx_ncards = cnt;	/* adjust actual number of cards */
 out:	return err;
 }
 
@@ -156,16 +157,16 @@
  * o unregister all adapters from the WAN router
  * o release all remaining system resources
  */
-static void __exit cyclomx_cleanup (void)
+static void __exit cycx_exit(void)
 {
 	int i = 0;
 
-	for (; i < ncards; ++i) {
-		cycx_t *card = &card_array[i];
+	for (; i < cycx_ncards; ++i) {
+		struct cycx_device *card = &cycx_card_array[i];
 		unregister_wan_device(card->devname);
 	}
 
-	kfree(card_array);
+	kfree(cycx_card_array);
 }
 
 /* WAN Device Driver Entry Points */
@@ -181,23 +182,23 @@
  * configuration structure is in kernel memory (including extended data, if
  * any).
  */
-static int setup (wan_device_t *wandev, wandev_conf_t *conf)
+static int cycx_wan_setup(struct wan_device *wandev, wandev_conf_t *conf)
 {
-	int err = -EFAULT;
-	cycx_t *card;
+	int rc = -EFAULT;
+	struct cycx_device *card;
 	int irq;
 
 	/* Sanity checks */
-	
+
 	if (!wandev || !wandev->private || !conf)
 		goto out;
 
 	card = wandev->private;
-	err = -EBUSY;
+	rc = -EBUSY;
 	if (wandev->state != WAN_UNCONFIGURED)
 		goto out;
 
-	err = -EINVAL;
+	rc = -EINVAL;
 	if (!conf->data_size || !conf->data) {
 		printk(KERN_ERR "%s: firmware not found in configuration "
 				"data!\n", wandev->name);
@@ -220,7 +221,7 @@
 	}
 
 	/* Configure hardware, load firmware, etc. */
-	memset(&card->hw, 0, sizeof(cycxhw_t));
+	memset(&card->hw, 0, sizeof(card->hw));
 	card->hw.irq	 = irq;
 	card->hw.dpmbase = conf->maddr;
 	card->hw.dpmsize = CYCX_WINDOWSIZE;
@@ -228,8 +229,8 @@
 	card->lock	 = SPIN_LOCK_UNLOCKED;
 	init_waitqueue_head(&card->wait_stats);
 
-	err = cycx_setup(&card->hw, conf->data, conf->data_size);
-	if (err)
+	rc = cycx_setup(&card->hw, conf->data, conf->data_size);
+	if (rc)
 		goto out_irq;
 
 	/* Initialize WAN device data space */
@@ -243,40 +244,41 @@
 	/* Protocol-specific initialization */
 	switch (card->hw.fwid) {
 #ifdef CONFIG_CYCLOMX_X25
-		case CFID_X25_2X:
-			err = cyx_init(card, conf);
-			break;
+	case CFID_X25_2X:
+		rc = cycx_x25_wan_init(card, conf);
+		break;
 #endif
-		default:
-			printk(KERN_ERR "%s: this firmware is not supported!\n",
-					wandev->name);
-			err = -EINVAL;
+	default:
+		printk(KERN_ERR "%s: this firmware is not supported!\n",
+				wandev->name);
+		rc = -EINVAL;
 	}
 
-	if (err) {
+	if (rc) {
 		cycx_down(&card->hw);
 		goto out_irq;
 	}
 
-	err = 0;
-out:	return err;
+	rc = 0;
+out:
+	return rc;
 out_irq:
 	free_irq(irq, card);
 	goto out;
 }
 
 /*
- * Shut down WAN link driver. 
+ * Shut down WAN link driver.
  * o shut down adapter hardware
  * o release system resources.
  *
  * This function is called by the router when device is being unregistered or
  * when it handles ROUTER_DOWN IOCTL.
  */
-static int shutdown (wan_device_t *wandev)
+static int cycx_wan_shutdown(struct wan_device *wandev)
 {
 	int ret = -EFAULT;
-	cycx_t *card;
+	struct cycx_device *card;
 
 	/* sanity checks */
 	if (!wandev || !wandev->private)
@@ -295,30 +297,15 @@
 out:	return ret;
 }
 
-/*
- * Driver I/O control. 
- * o verify arguments
- * o perform requested action
- *
- * This function is called when router handles one of the reserved user
- * IOCTLs.  Note that 'arg' still points to user address space.
- *
- * no reserved ioctls for the cyclom 2x up to now
- */
-static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg)
-{
-	return -EINVAL;
-}
-
 /* Miscellaneous */
 /*
  * Cyclom 2X Interrupt Service Routine.
  * o acknowledge Cyclom 2X hardware interrupt.
  * o call protocol-specific interrupt service routine, if any.
  */
-static irqreturn_t cycx_isr (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t cycx_isr(int irq, void *dev_id, struct pt_regs *regs)
 {
-	cycx_t *card = (cycx_t *)dev_id;
+	struct cycx_device *card = (struct cycx_device *)dev_id;
 
 	if (!card || card->wandev.state == WAN_UNCONFIGURED)
 		goto out;
@@ -332,35 +319,12 @@
 	if (card->isr)
 		card->isr(card);
 	return IRQ_HANDLED;
-out:	return IRQ_NONE;
-}
-
-/*
- * This routine is called by the protocol-specific modules when network
- * interface is being open.  The only reason we need this, is because we
- * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
- * defined more than once into the same kernel module.
- */
-void cyclomx_mod_inc_use_count (cycx_t *card)
-{
-	++card->open_cnt;
-	MOD_INC_USE_COUNT;
-}
-
-/*
- * This routine is called by the protocol-specific modules when network
- * interface is being closed.  The only reason we need this, is because we
- * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's
- * defined more than once into the same kernel module.
- */
-void cyclomx_mod_dec_use_count (cycx_t *card)
-{
-	--card->open_cnt;
-	MOD_DEC_USE_COUNT;
+out:
+	return IRQ_NONE;
 }
 
 /* Set WAN device state.  */
-void cyclomx_set_state (cycx_t *card, int state)
+void cycx_set_state(struct cycx_device *card, int state)
 {
 	unsigned long flags;
 	char *string_state = NULL;
@@ -369,15 +333,13 @@
 
 	if (card->wandev.state != state) {
 		switch (state) {
-			case WAN_CONNECTED:
-				string_state = "connected!";
-				break;
-
-			case WAN_DISCONNECTED:
-				string_state = "disconnected!";
-				break;
+		case WAN_CONNECTED:
+			string_state = "connected!";
+			break;
+		case WAN_DISCONNECTED:
+			string_state = "disconnected!";
+			break;
 		}
-
 		printk(KERN_INFO "%s: link %s\n", card->devname, string_state);
 		card->wandev.state = state;
 	}
@@ -386,5 +348,5 @@
 	spin_unlock_irqrestore(&card->lock, flags);
 }
 
-module_init(cyclomx_init);
-module_exit(cyclomx_cleanup);
+module_init(cycx_init);
+module_exit(cycx_exit);
diff -Nru a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c
--- a/drivers/net/wan/cycx_x25.c	Thu Apr 24 05:17:37 2003
+++ b/drivers/net/wan/cycx_x25.c	Tue May 20 07:19:38 2003
@@ -3,7 +3,7 @@
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998-2001 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
 *
 * Based on sdla_x25.c by Gene Kozin <genek@compuserve.com>
 *
@@ -79,25 +79,28 @@
 #define CYCLOMX_X25_DEBUG 1
 
 #include <linux/version.h>
-#include <linux/kernel.h>	/* printk(), and other useful stuff */
-#include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
+#include <linux/if_arp.h>       /* ARPHRD_HWX25 */
+#include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/module.h>	/* SET_MODULE_OWNER */
 #include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/slab.h>		/* kmalloc(), kfree() */
+#include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/wanrouter.h>	/* WAN router definitions */
+
 #include <asm/byteorder.h>	/* htons(), etc. */
-#include <linux/if_arp.h>       /* ARPHRD_HWX25 */
+
 #include <linux/cyclomx.h>	/* Cyclom 2X common user API definitions */
 #include <linux/cycx_x25.h>	/* X.25 firmware API definitions */
 
 /* Defines & Macros */
-#define MAX_CMD_RETRY	5
-#define X25_CHAN_MTU	2048	/* unfragmented logical channel MTU */
+#define CYCX_X25_MAX_CMD_RETRY 5
+#define CYCX_X25_CHAN_MTU 2048	/* unfragmented logical channel MTU */
 
 /* Data Structures */
 /* This is an extension of the 'struct net_device' we create for each network
    interface to keep the rest of X.25 channel-specific data. */
-typedef struct x25_channel {
+struct cycx_x25_channel {
 	/* This member must be first. */
 	struct net_device *slave;	/* WAN slave */
 
@@ -114,80 +117,95 @@
 	u8 drop_sequence;		/* mark sequence for dropping */
 	u32 idle_tmout;			/* sec, before disconnecting */
 	struct sk_buff *rx_skb;		/* receive socket buffer */
-	cycx_t *card;			/* -> owner */
+	struct cycx_device *card;	/* -> owner */
 	struct net_device_stats ifstats;/* interface statistics */
-} x25_channel_t;
+};
 
 /* Function Prototypes */
 /* WAN link driver entry points. These are called by the WAN router module. */
-static int update (wan_device_t *wandev),
-	   new_if (wan_device_t *wandev, struct net_device *dev,
-		   wanif_conf_t *conf),
-	   del_if (wan_device_t *wandev, struct net_device *dev);
+static int cycx_wan_update(struct wan_device *wandev),
+	   cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
+			   wanif_conf_t *conf),
+	   cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev);
 
 /* Network device interface */
-static int if_init (struct net_device *dev),
-	   if_open (struct net_device *dev),
-	   if_close (struct net_device *dev),
-	   if_header (struct sk_buff *skb, struct net_device *dev,
-		      u16 type, void *daddr, void *saddr, unsigned len),
-	   if_rebuild_hdr (struct sk_buff *skb),
-	   if_send (struct sk_buff *skb, struct net_device *dev);
+static int cycx_netdevice_init(struct net_device *dev),
+	   cycx_netdevice_open(struct net_device *dev),
+	   cycx_netdevice_stop(struct net_device *dev),
+	   cycx_netdevice_hard_header(struct sk_buff *skb,
+				     struct net_device *dev, u16 type,
+				     void *daddr, void *saddr, unsigned len),
+	   cycx_netdevice_rebuild_header(struct sk_buff *skb),
+	   cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
+					  struct net_device *dev);
 
-static struct net_device_stats * if_stats (struct net_device *dev);
+static struct net_device_stats *
+			cycx_netdevice_get_stats(struct net_device *dev);
 
 /* Interrupt handlers */
-static void cyx_isr (cycx_t *card),
-	    tx_intr (cycx_t *card, TX25Cmd *cmd),
-	    rx_intr (cycx_t *card, TX25Cmd *cmd),
-	    log_intr (cycx_t *card, TX25Cmd *cmd),
-	    stat_intr (cycx_t *card, TX25Cmd *cmd),
-	    connect_confirm_intr (cycx_t *card, TX25Cmd *cmd),
-	    disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd),
-	    connect_intr (cycx_t *card, TX25Cmd *cmd),
-	    disconnect_intr (cycx_t *card, TX25Cmd *cmd),
-	    spur_intr (cycx_t *card, TX25Cmd *cmd);
+static void cycx_x25_irq_handler(struct cycx_device *card),
+	    cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd),
+	    cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd),
+	    cycx_x25_irq_log(struct cycx_device *card,
+			     struct cycx_x25_cmd *cmd),
+	    cycx_x25_irq_stat(struct cycx_device *card,
+			      struct cycx_x25_cmd *cmd),
+	    cycx_x25_irq_connect_confirm(struct cycx_device *card,
+					 struct cycx_x25_cmd *cmd),
+	    cycx_x25_irq_disconnect_confirm(struct cycx_device *card,
+					    struct cycx_x25_cmd *cmd),
+	    cycx_x25_irq_connect(struct cycx_device *card,
+				 struct cycx_x25_cmd *cmd),
+	    cycx_x25_irq_disconnect(struct cycx_device *card,
+				    struct cycx_x25_cmd *cmd),
+	    cycx_x25_irq_spurious(struct cycx_device *card,
+				  struct cycx_x25_cmd *cmd);
 
 /* X.25 firmware interface functions */
-static int x25_configure (cycx_t *card, TX25Config *conf),
-	   x25_get_stats (cycx_t *card),
-	   x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len,
-		     void *buf),
-	   x25_connect_response (cycx_t *card, x25_channel_t *chan),
-	   x25_disconnect_response (cycx_t *card, u8 link, u8 lcn);
+static int cycx_x25_configure(struct cycx_device *card,
+			      struct cycx_x25_config *conf),
+	   cycx_x25_get_stats(struct cycx_device *card),
+	   cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm,
+			 int len, void *buf),
+	   cycx_x25_connect_response(struct cycx_device *card,
+				struct cycx_x25_channel *chan),
+	   cycx_x25_disconnect_response(struct cycx_device *card, u8 link,
+			   		u8 lcn);
 
 /* channel functions */
-static int chan_connect (struct net_device *dev),
-    	   chan_send (struct net_device *dev, struct sk_buff *skb);
+static int cycx_x25_chan_connect(struct net_device *dev),
+	   cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb);
 
-static void chan_disconnect (struct net_device *dev),
-	    chan_x25_send_event(struct net_device *dev, u8 event);
+static void cycx_x25_chan_disconnect(struct net_device *dev),
+	    cycx_x25_chan_send_event(struct net_device *dev, u8 event);
 
 /* Miscellaneous functions */
-static void set_chan_state (struct net_device *dev, u8 state),
-	    chan_timer (unsigned long d);
+static void cycx_x25_set_chan_state(struct net_device *dev, u8 state),
+	    cycx_x25_chan_timer(unsigned long d);
 
-static void nibble_to_byte (u8 *s, u8 *d, u8 len, u8 nibble),
-	    reset_timer (struct net_device *dev);
+static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble),
+	    reset_timer(struct net_device *dev);
 
-static u8 bps_to_speed_code (u32 bps);
-static u8 log2 (u32 n);
+static u8 bps_to_speed_code(u32 bps);
+static u8 log2(u32 n);
 
-static unsigned dec_to_uint (u8 *str, int len);
+static unsigned dec_to_uint(u8 *str, int len);
 
-static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn);
-static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte);
+static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev,
+						  s16 lcn);
+static struct net_device *
+	cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte);
 
 #ifdef CYCLOMX_X25_DEBUG
 static void hex_dump(char *msg, unsigned char *p, int len);
-static void x25_dump_config(TX25Config *conf);
-static void x25_dump_stats(TX25Stats *stats);
-static void x25_dump_devs(wan_device_t *wandev);
+static void cycx_x25_dump_config(struct cycx_x25_config *conf);
+static void cycx_x25_dump_stats(struct cycx_x25_stats *stats);
+static void cycx_x25_dump_devs(struct wan_device *wandev);
 #else
 #define hex_dump(msg, p, len)
-#define x25_dump_config(conf)
-#define x25_dump_stats(stats)
-#define x25_dump_devs(wandev)
+#define cycx_x25_dump_config(conf)
+#define cycx_x25_dump_stats(stats)
+#define cycx_x25_dump_devs(wandev)
 #endif
 /* Public Functions */
 
@@ -200,9 +218,9 @@
  *
  * Return:	0	o.k.
  *		< 0	failure.  */
-int cyx_init (cycx_t *card, wandev_conf_t *conf)
+int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf)
 {
-	TX25Config cfg;
+	struct cycx_x25_config cfg;
 
 	/* Verify configuration ID */
 	if (conf->config_id != WANCONFIG_X25) {
@@ -256,7 +274,7 @@
 		cfg.remaddr = 3; /* DTE */
 	}
 
-        if (conf->interface == WANOPT_RS232)
+	if (conf->interface == WANOPT_RS232)
 	        cfg.flags = 0;      /* FIXME just reset the 2nd bit */
 
 	if (conf->u.x25.hi_pvc) {
@@ -298,7 +316,7 @@
 		cfg.n2 = min_t(unsigned int, conf->u.x25.n2, 30);
 
 	/* initialize adapter */
-	if (x25_configure(card, &cfg))
+	if (cycx_x25_configure(card, &cfg))
 		return -EIO;
 
 	/* Initialize protocol-specific fields of adapter data space */
@@ -306,11 +324,11 @@
 	card->wandev.interface	= conf->interface;
 	card->wandev.clocking	= conf->clocking;
 	card->wandev.station	= conf->station;
-	card->isr		= cyx_isr;
+	card->isr		= cycx_x25_irq_handler;
 	card->exec		= NULL;
-	card->wandev.update	= update;
-	card->wandev.new_if	= new_if;
-	card->wandev.del_if	= del_if;
+	card->wandev.update	= cycx_wan_update;
+	card->wandev.new_if	= cycx_wan_new_if;
+	card->wandev.del_if	= cycx_wan_del_if;
 	card->wandev.state	= WAN_DISCONNECTED;
 
 	return 0;
@@ -318,7 +336,7 @@
 
 /* WAN Device Driver Entry Points */
 /* Update device status & statistics. */
-static int update (wan_device_t *wandev)
+static int cycx_wan_update(struct wan_device *wandev)
 {
 	/* sanity checks */
 	if (!wandev || !wandev->private)
@@ -327,7 +345,7 @@
 	if (wandev->state == WAN_UNCONFIGURED)
 		return -ENODEV;
 
-	x25_get_stats(wandev->private);
+	cycx_x25_get_stats(wandev->private);
 
 	return 0;
 }
@@ -342,23 +360,25 @@
  *
  * Return:	0	o.k.
  *		< 0	failure (channel will not be created) */
-static int new_if (wan_device_t *wandev, struct net_device *dev,
-		   wanif_conf_t *conf)
+static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev,
+			   wanif_conf_t *conf)
 {
-	cycx_t *card = wandev->private;
-	x25_channel_t *chan;
+	struct cycx_device *card = wandev->private;
+	struct cycx_x25_channel *chan;
 	int err = 0;
 
 	if (!conf->name[0] || strlen(conf->name) > WAN_IFNAME_SZ) {
-		printk(KERN_INFO "%s: invalid interface name!\n",card->devname);
+		printk(KERN_INFO "%s: invalid interface name!\n",
+		       card->devname);
 		return -EINVAL;
 	}
 
 	/* allocate and initialize private data */
-	if ((chan = kmalloc(sizeof(x25_channel_t), GFP_KERNEL)) == NULL)
+	chan = kmalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL);
+	if (!chan)
 		return -ENOMEM;
 
-	memset(chan, 0, sizeof(x25_channel_t));
+	memset(chan, 0, sizeof(*chan));
 	strcpy(chan->name, conf->name);
 	chan->card = card;
 	chan->link = conf->port;
@@ -385,19 +405,19 @@
 				}
 			}
 
-                	strncpy(chan->local_addr, conf->local_addr,
+			strncpy(chan->local_addr, conf->local_addr,
 				WAN_ADDRESS_SZ);
 		}
 
-                chan->svc = 1;
-                strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
+		chan->svc = 1;
+		strncpy(chan->addr, &conf->addr[1], WAN_ADDRESS_SZ);
 		init_timer(&chan->timer);
-		chan->timer.function = chan_timer;
-		chan->timer.data = (unsigned long)dev;
+		chan->timer.function	= cycx_x25_chan_timer;
+		chan->timer.data	= (unsigned long)dev;
 
-                /* Set channel timeouts (default if not specified) */
-                chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
-        } else if (is_digit(conf->addr[0])) {	/* PVC */
+		/* Set channel timeouts (default if not specified) */
+		chan->idle_tmout = conf->idle_timeout ? conf->idle_timeout : 90;
+	} else if (is_digit(conf->addr[0])) {	/* PVC */
 		s16 lcn = dec_to_uint(conf->addr, 0);
 
 		if (lcn >= card->u.x.lo_pvc && lcn <= card->u.x.hi_pvc)
@@ -424,17 +444,17 @@
 
 	/* prepare network device data space for registration */
 	strcpy(dev->name, chan->name);
-	dev->init = if_init;
+	dev->init = cycx_netdevice_init;
 	dev->priv = chan;
 
 	return 0;
 }
 
 /* Delete logical channel. */
-static int del_if (wan_device_t *wandev, struct net_device *dev)
+static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev)
 {
 	if (dev->priv) {
-		x25_channel_t *chan = dev->priv;
+		struct cycx_x25_channel *chan = dev->priv;
 
 		if (chan->svc) {
 			if (chan->local_addr)
@@ -457,42 +477,44 @@
  * This routine is called only once for each interface, during Linux network
  * interface registration.  Returning anything but zero will fail interface
  * registration. */
-static int if_init (struct net_device *dev)
+static int cycx_netdevice_init(struct net_device *dev)
 {
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
-	wan_device_t *wandev = &card->wandev;
+	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_device *card = chan->card;
+	struct wan_device *wandev = &card->wandev;
 
 	/* Initialize device driver entry points */
-	dev->open = if_open;
-	dev->stop = if_close;
-	dev->hard_header = if_header;
-	dev->rebuild_header = if_rebuild_hdr;
-	dev->hard_start_xmit = if_send;
-	dev->get_stats = if_stats;
+	dev->open		= cycx_netdevice_open;
+	dev->stop		= cycx_netdevice_stop;
+	dev->hard_header	= cycx_netdevice_hard_header;
+	dev->rebuild_header	= cycx_netdevice_rebuild_header;
+	dev->hard_start_xmit	= cycx_netdevice_hard_start_xmit;
+	dev->get_stats		= cycx_netdevice_get_stats;
 
 	/* Initialize media-specific parameters */
-	dev->mtu = X25_CHAN_MTU;
-	dev->type = ARPHRD_HWX25;	/* ARP h/w type */
-	dev->hard_header_len = 0;	/* media header length */
-	dev->addr_len = 0;		/* hardware address length */
+	dev->mtu		= CYCX_X25_CHAN_MTU;
+	dev->type		= ARPHRD_HWX25;	/* ARP h/w type */
+	dev->hard_header_len	= 0;		/* media header length */
+	dev->addr_len		= 0;		/* hardware address length */
 
 	if (!chan->svc)
 		*(u16*)dev->dev_addr = htons(chan->lcn);
 
 	/* Initialize hardware parameters (just for reference) */
-	dev->irq = wandev->irq;
-	dev->dma = wandev->dma;
-	dev->base_addr = wandev->ioport;
-	dev->mem_start = (unsigned long)wandev->maddr;
-	dev->mem_end = (unsigned long)(wandev->maddr + wandev->msize - 1);
-	dev->flags |= IFF_NOARP;
-
-        /* Set transmit buffer queue length */
-        dev->tx_queue_len = 10;
+	dev->irq		= wandev->irq;
+	dev->dma		= wandev->dma;
+	dev->base_addr		= wandev->ioport;
+	dev->mem_start		= (unsigned long)wandev->maddr;
+	dev->mem_end		= (unsigned long)(wandev->maddr +
+						  wandev->msize - 1);
+	dev->flags		|= IFF_NOARP;
+
+	/* Set transmit buffer queue length */
+	dev->tx_queue_len	= 10;
+	SET_MODULE_OWNER(dev);
 
 	/* Initialize socket buffers */
-	set_chan_state(dev, WAN_DISCONNECTED);
+	cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
 
 	return 0;
 }
@@ -502,34 +524,26 @@
  * o if link is disconnected then initiate connection
  *
  * Return 0 if O.k. or errno.  */
-static int if_open (struct net_device *dev)
+static int cycx_netdevice_open(struct net_device *dev)
 {
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
-
 	if (netif_running(dev))
-		return -EBUSY; /* only one open is allowed */ 
+		return -EBUSY; /* only one open is allowed */
 
 	netif_start_queue(dev);
-	cyclomx_mod_inc_use_count(card);
-
 	return 0;
 }
 
 /* Close network interface.
  * o reset flags.
  * o if there's no more open channels then disconnect physical link. */
-static int if_close (struct net_device *dev)
+static int cycx_netdevice_stop(struct net_device *dev)
 {
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
+	struct cycx_x25_channel *chan = dev->priv;
 
 	netif_stop_queue(dev);
-	
+
 	if (chan->state == WAN_CONNECTED || chan->state == WAN_CONNECTING)
-		chan_disconnect(dev);
-		
-	cyclomx_mod_dec_use_count(card);
+		cycx_x25_chan_disconnect(dev);
 
 	return 0;
 }
@@ -542,8 +556,9 @@
  * set skb->protocol to 0 and discard packet later.
  *
  * Return:	media header length. */
-static int if_header (struct sk_buff *skb, struct net_device *dev,
-		      u16 type, void *daddr, void *saddr, unsigned len)
+static int cycx_netdevice_hard_header(struct sk_buff *skb,
+				      struct net_device *dev, u16 type,
+				      void *daddr, void *saddr, unsigned len)
 {
 	skb->protocol = type;
 
@@ -553,7 +568,7 @@
 /* * Re-build media header.
  * Return:	1	physical address resolved.
  *		0	physical address not resolved */
-static int if_rebuild_hdr (struct sk_buff *skb)
+static int cycx_netdevice_rebuild_header(struct sk_buff *skb)
 {
 	return 1;
 }
@@ -573,66 +588,67 @@
  *    bottom half" (with interrupts enabled).
  * 2. Setting tbusy flag will inhibit further transmit requests from the
  *    protocol stack and can be used for flow control with protocol layer. */
-static int if_send (struct sk_buff *skb, struct net_device *dev)
+static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb,
+					  struct net_device *dev)
 {
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
+	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_device *card = chan->card;
 
 	if (!chan->svc)
 		chan->protocol = skb->protocol;
 
 	if (card->wandev.state != WAN_CONNECTED)
 		++chan->ifstats.tx_dropped;
-        else if (chan->svc && chan->protocol &&
+	else if (chan->svc && chan->protocol &&
 		 chan->protocol != skb->protocol) {
-                printk(KERN_INFO
-                        "%s: unsupported Ethertype 0x%04X on interface %s!\n",
-                        card->devname, skb->protocol, dev->name);
-                ++chan->ifstats.tx_errors;
-        } else if (chan->protocol == ETH_P_IP) {
+		printk(KERN_INFO
+		       "%s: unsupported Ethertype 0x%04X on interface %s!\n",
+		       card->devname, skb->protocol, dev->name);
+		++chan->ifstats.tx_errors;
+	} else if (chan->protocol == ETH_P_IP) {
 		switch (chan->state) {
-			case WAN_DISCONNECTED:
-				if (chan_connect(dev)) {
-					netif_stop_queue(dev);
-					return -EBUSY;
-				}
-				/* fall thru */
-			case WAN_CONNECTED:
-				reset_timer(dev);
-				dev->trans_start = jiffies;
+		case WAN_DISCONNECTED:
+			if (cycx_x25_chan_connect(dev)) {
 				netif_stop_queue(dev);
+				return -EBUSY;
+			}
+			/* fall thru */
+		case WAN_CONNECTED:
+			reset_timer(dev);
+			dev->trans_start = jiffies;
+			netif_stop_queue(dev);
 
-				if (chan_send(dev, skb))
-					return -EBUSY;
+			if (cycx_x25_chan_send(dev, skb))
+				return -EBUSY;
 
-				break;
-			default:
-				++chan->ifstats.tx_dropped;	
-				++card->wandev.stats.tx_dropped;
-		} 
+			break;
+		default:
+			++chan->ifstats.tx_dropped;
+			++card->wandev.stats.tx_dropped;
+	}
 	} else { /* chan->protocol == ETH_P_X25 */
 		switch (skb->data[0]) {
-			case 0: break;
-			case 1: /* Connect request */
-				chan_connect(dev);
-				goto free_packet;
-		        case 2: /* Disconnect request */
-				chan_disconnect(dev);
-				goto free_packet;
-		        default:
-				printk(KERN_INFO
-				       "%s: unknown %d x25-iface request on %s!\n",
-                       			card->devname, skb->data[0], dev->name);
-               			++chan->ifstats.tx_errors;
-				goto free_packet;
+		case 0: break;
+		case 1: /* Connect request */
+			cycx_x25_chan_connect(dev);
+			goto free_packet;
+		case 2: /* Disconnect request */
+			cycx_x25_chan_disconnect(dev);
+			goto free_packet;
+	        default:
+			printk(KERN_INFO
+			       "%s: unknown %d x25-iface request on %s!\n",
+			       card->devname, skb->data[0], dev->name);
+			++chan->ifstats.tx_errors;
+			goto free_packet;
 		}
 
 		skb_pull(skb, 1); /* Remove control byte */
 		reset_timer(dev);
 		dev->trans_start = jiffies;
 		netif_stop_queue(dev);
-		
-		if (chan_send(dev, skb)) {
+
+		if (cycx_x25_chan_send(dev, skb)) {
 			/* prepare for future retransmissions */
 			skb_push(skb, 1);
 			return -EBUSY;
@@ -647,18 +663,18 @@
 
 /* Get Ethernet-style interface statistics.
  * Return a pointer to struct net_device_stats */
-static struct net_device_stats *if_stats (struct net_device *dev)
+static struct net_device_stats *cycx_netdevice_get_stats(struct net_device *dev)
 {
-        x25_channel_t *chan = dev->priv;
+	struct cycx_x25_channel *chan = dev->priv;
 
 	return chan ? &chan->ifstats : NULL;
 }
 
 /* Interrupt Handlers */
 /* X.25 Interrupt Service Routine. */
-static void cyx_isr (cycx_t *card)
+static void cycx_x25_irq_handler(struct cycx_device *card)
 {
-	TX25Cmd cmd;
+	struct cycx_x25_cmd cmd;
 	u16 z = 0;
 
 	card->in_isr = 1;
@@ -666,38 +682,39 @@
 	cycx_peek(&card->hw, X25_RXMBOX_OFFS, &cmd, sizeof(cmd));
 
 	switch (cmd.command) {
-		case X25_DATA_INDICATION:
-			rx_intr(card, &cmd);
-			break;
-		case X25_ACK_FROM_VC:
-			tx_intr(card, &cmd);
-			break;
-		case X25_LOG: 
-			log_intr(card, &cmd);
-			break;
-		case X25_STATISTIC: 
-			stat_intr(card, &cmd);
-			break;
-		case X25_CONNECT_CONFIRM:
-			connect_confirm_intr(card, &cmd);
-			break;
-		case X25_CONNECT_INDICATION:
-			connect_intr(card, &cmd);
-			break;
-		case X25_DISCONNECT_INDICATION:
-			disconnect_intr(card, &cmd);
-			break;
-		case X25_DISCONNECT_CONFIRM:
-			disconnect_confirm_intr(card, &cmd);
-			break;
-		case X25_LINE_ON:
-			cyclomx_set_state(card, WAN_CONNECTED);
-			break;
-		case X25_LINE_OFF:
-			cyclomx_set_state(card, WAN_DISCONNECTED);
-			break;
-		default: 
-			spur_intr(card, &cmd); /* unwanted interrupt */
+	case X25_DATA_INDICATION:
+		cycx_x25_irq_rx(card, &cmd);
+		break;
+	case X25_ACK_FROM_VC:
+		cycx_x25_irq_tx(card, &cmd);
+		break;
+	case X25_LOG:
+		cycx_x25_irq_log(card, &cmd);
+		break;
+	case X25_STATISTIC:
+		cycx_x25_irq_stat(card, &cmd);
+		break;
+	case X25_CONNECT_CONFIRM:
+		cycx_x25_irq_connect_confirm(card, &cmd);
+		break;
+	case X25_CONNECT_INDICATION:
+		cycx_x25_irq_connect(card, &cmd);
+		break;
+	case X25_DISCONNECT_INDICATION:
+		cycx_x25_irq_disconnect(card, &cmd);
+		break;
+	case X25_DISCONNECT_CONFIRM:
+		cycx_x25_irq_disconnect_confirm(card, &cmd);
+		break;
+	case X25_LINE_ON:
+		cycx_set_state(card, WAN_CONNECTED);
+		break;
+	case X25_LINE_OFF:
+		cycx_set_state(card, WAN_DISCONNECTED);
+		break;
+	default:
+		cycx_x25_irq_spurious(card, &cmd);
+		break;
 	}
 
 	cycx_poke(&card->hw, 0, &z, sizeof(z));
@@ -708,16 +725,17 @@
 /* Transmit interrupt handler.
  *	o Release socket buffer
  *	o Clear 'tbusy' flag */
-static void tx_intr (cycx_t *card, TX25Cmd *cmd)
+static void cycx_x25_irq_tx(struct cycx_device *card, struct cycx_x25_cmd *cmd)
 {
 	struct net_device *dev;
-	wan_device_t *wandev = &card->wandev;
+	struct wan_device *wandev = &card->wandev;
 	u8 lcn;
 
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
 
 	/* unbusy device and then dev_tint(); */
-	if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
+	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
+	if (dev) {
 		card->buff_int_mode_unbusy = 1;
 		netif_wake_queue(dev);
 	} else
@@ -730,7 +748,7 @@
  * RFC1356.
  * o map logical channel number to network interface.
  * o allocate socket buffer or append received packet to the existing one.
- * o if M-bit is reset (i.e. it's the last packet in a sequence) then 
+ * o if M-bit is reset (i.e. it's the last packet in a sequence) then
  *   decapsulate packet and pass socket buffer to the protocol stack.
  *
  * Notes:
@@ -739,11 +757,11 @@
  *    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. */
-static void rx_intr (cycx_t *card, TX25Cmd *cmd)
+static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd)
 {
-	wan_device_t *wandev = &card->wandev;
+	struct wan_device *wandev = &card->wandev;
 	struct net_device *dev;
-	x25_channel_t *chan;
+	struct cycx_x25_channel *chan;
 	struct sk_buff *skb;
 	u8 bitm, lcn;
 	int pktlen = cmd->len - 5;
@@ -752,7 +770,8 @@
 	cycx_peek(&card->hw, cmd->buf + 4, &bitm, sizeof(bitm));
 	bitm &= 0x10;
 
-	if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {
+	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
+	if (!dev) {
 		/* Invalid channel, discard packet */
 		printk(KERN_INFO "%s: receiving on orphaned LCN %d!\n",
 				 card->devname, lcn);
@@ -785,7 +804,7 @@
 
 		if (chan->protocol == ETH_P_X25) /* X.25 socket layer control */
 			/* 0 = data packet (dev_alloc_skb zeroed skb->data) */
-			skb_put(skb, 1); 
+			skb_put(skb, 1);
 
 		skb->dev = dev;
 		skb->protocol = htons(chan->protocol);
@@ -823,11 +842,12 @@
 }
 
 /* Connect interrupt handler. */
-static void connect_intr (cycx_t *card, TX25Cmd *cmd)
+static void cycx_x25_irq_connect(struct cycx_device *card,
+				 struct cycx_x25_cmd *cmd)
 {
-	wan_device_t *wandev = &card->wandev;
+	struct wan_device *wandev = &card->wandev;
 	struct net_device *dev = NULL;
-	x25_channel_t *chan;
+	struct cycx_x25_channel *chan;
 	u8 d[32],
 	   loc[24],
 	   rem[24];
@@ -848,10 +868,11 @@
 	if (sizerem)
 		nibble_to_byte(d + (sizeloc >> 1), rem, sizerem, sizeloc & 1);
 
-	dprintk(1, KERN_INFO "connect_intr:lcn=%d, local=%s, remote=%s\n",
-			  lcn, loc, rem);
+	dprintk(1, KERN_INFO "%s:lcn=%d, local=%s, remote=%s\n",
+			  __FUNCTION__, lcn, loc, rem);
 
-	if ((dev = get_dev_by_dte_addr(wandev, rem)) == NULL) {
+	dev = cycx_x25_get_dev_by_dte_addr(wandev, rem);
+	if (!dev) {
 		/* Invalid channel, discard packet */
 		printk(KERN_INFO "%s: connect not expected: remote %s!\n",
 				 card->devname, rem);
@@ -860,24 +881,26 @@
 
 	chan = dev->priv;
 	chan->lcn = lcn;
-	x25_connect_response(card, chan);
-	set_chan_state(dev, WAN_CONNECTED);
+	cycx_x25_connect_response(card, chan);
+	cycx_x25_set_chan_state(dev, WAN_CONNECTED);
 }
 
 /* Connect confirm interrupt handler. */
-static void connect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
+static void cycx_x25_irq_connect_confirm(struct cycx_device *card,
+					 struct cycx_x25_cmd *cmd)
 {
-	wan_device_t *wandev = &card->wandev;
+	struct wan_device *wandev = &card->wandev;
 	struct net_device *dev;
-	x25_channel_t *chan;
+	struct cycx_x25_channel *chan;
 	u8 lcn, key;
 
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
 	cycx_peek(&card->hw, cmd->buf + 1, &key, sizeof(key));
-	dprintk(1, KERN_INFO "%s: connect_confirm_intr:lcn=%d, key=%d\n",
-			  card->devname, lcn, key);
+	dprintk(1, KERN_INFO "%s: %s:lcn=%d, key=%d\n",
+			  card->devname, __FUNCTION__, lcn, key);
 
-	if ((dev = get_dev_by_lcn(wandev, -key)) == NULL) {
+	dev = cycx_x25_get_dev_by_lcn(wandev, -key);
+	if (!dev) {
 		/* Invalid channel, discard packet */
 		clear_bit(--key, (void*)&card->u.x.connection_keys);
 		printk(KERN_INFO "%s: connect confirm not expected: lcn %d, "
@@ -888,50 +911,54 @@
 	clear_bit(--key, (void*)&card->u.x.connection_keys);
 	chan = dev->priv;
 	chan->lcn = lcn;
-	set_chan_state(dev, WAN_CONNECTED);
+	cycx_x25_set_chan_state(dev, WAN_CONNECTED);
 }
 
 /* Disconnect confirm interrupt handler. */
-static void disconnect_confirm_intr (cycx_t *card, TX25Cmd *cmd)
+static void cycx_x25_irq_disconnect_confirm(struct cycx_device *card,
+					    struct cycx_x25_cmd *cmd)
 {
-	wan_device_t *wandev = &card->wandev;
+	struct wan_device *wandev = &card->wandev;
 	struct net_device *dev;
 	u8 lcn;
 
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	dprintk(1, KERN_INFO "%s: disconnect_confirm_intr:lcn=%d\n",
-			  card->devname, lcn);
-	if ((dev = get_dev_by_lcn(wandev, lcn)) == NULL) {
+	dprintk(1, KERN_INFO "%s: %s:lcn=%d\n",
+			  card->devname, __FUNCTION__, lcn);
+	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
+	if (!dev) {
 		/* Invalid channel, discard packet */
 		printk(KERN_INFO "%s:disconnect confirm not expected!:lcn %d\n",
 				 card->devname, lcn);
 		return;
 	}
 
-	set_chan_state(dev, WAN_DISCONNECTED);
+	cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
 }
 
 /* disconnect interrupt handler. */
-static void disconnect_intr (cycx_t *card, TX25Cmd *cmd)
+static void cycx_x25_irq_disconnect(struct cycx_device *card,
+				    struct cycx_x25_cmd *cmd)
 {
-	wan_device_t *wandev = &card->wandev;
+	struct wan_device *wandev = &card->wandev;
 	struct net_device *dev;
 	u8 lcn;
 
 	cycx_peek(&card->hw, cmd->buf, &lcn, sizeof(lcn));
-	dprintk(1, KERN_INFO "disconnect_intr:lcn=%d\n", lcn);
+	dprintk(1, KERN_INFO "%s:lcn=%d\n", __FUNCTION__, lcn);
 
-	if ((dev = get_dev_by_lcn(wandev, lcn)) != NULL) {
-		x25_channel_t *chan = dev->priv;
+	dev = cycx_x25_get_dev_by_lcn(wandev, lcn);
+	if (dev) {
+		struct cycx_x25_channel *chan = dev->priv;
 
-		x25_disconnect_response(card, chan->link, lcn);
-		set_chan_state(dev, WAN_DISCONNECTED);
+		cycx_x25_disconnect_response(card, chan->link, lcn);
+		cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
 	} else
-		x25_disconnect_response(card, 0, lcn);
+		cycx_x25_disconnect_response(card, 0, lcn);
 }
 
 /* LOG interrupt handler. */
-static void log_intr (cycx_t *card, TX25Cmd *cmd)
+static void cycx_x25_irq_log(struct cycx_device *card, struct cycx_x25_cmd *cmd)
 {
 #if CYCLOMX_X25_DEBUG
 	char bf[20];
@@ -947,7 +974,7 @@
 	cycx_peek(&card->hw, cmd->buf + 10 + toread, &code, 1);
 	cycx_peek(&card->hw, cmd->buf + 10 + toread + 1, &routine, 1);
 
-	printk(KERN_INFO "cyx_isr: X25_LOG (0x4500) indic.:\n");
+	printk(KERN_INFO "cycx_x25_irq_handler: X25_LOG (0x4500) indic.:\n");
 	printk(KERN_INFO "cmd->buf=0x%X\n", cmd->buf);
 	printk(KERN_INFO "Log message code=0x%X\n", msg_code);
 	printk(KERN_INFO "Link=%d\n", link);
@@ -959,20 +986,22 @@
 }
 
 /* STATISTIC interrupt handler. */
-static void stat_intr (cycx_t *card, TX25Cmd *cmd)
+static void cycx_x25_irq_stat(struct cycx_device *card,
+			      struct cycx_x25_cmd *cmd)
 {
 	cycx_peek(&card->hw, cmd->buf, &card->u.x.stats,
 		  sizeof(card->u.x.stats));
-	hex_dump("stat_intr", (unsigned char*)&card->u.x.stats,
+	hex_dump("cycx_x25_irq_stat", (unsigned char*)&card->u.x.stats,
 		 sizeof(card->u.x.stats));
-	x25_dump_stats(&card->u.x.stats);
+	cycx_x25_dump_stats(&card->u.x.stats);
 	wake_up_interruptible(&card->wait_stats);
 }
 
 /* Spurious interrupt handler.
  * o print a warning
  * If number of spurious interrupts exceeded some limit, then ??? */
-static void spur_intr (cycx_t *card, TX25Cmd *cmd)
+static void cycx_x25_irq_spurious(struct cycx_device *card,
+				  struct cycx_x25_cmd *cmd)
 {
 	printk(KERN_INFO "%s: spurious interrupt (0x%X)!\n",
 			 card->devname, cmd->command);
@@ -997,13 +1026,13 @@
 
 /* Cyclom 2X Firmware-Specific Functions */
 /* Exec X.25 command. */
-static int x25_exec (cycx_t *card, int command, int link,
-		     void *d1, int len1, void *d2, int len2)
+static int x25_exec(struct cycx_device *card, int command, int link,
+		    void *d1, int len1, void *d2, int len2)
 {
-	TX25Cmd c;
+	struct cycx_x25_cmd c;
 	unsigned long flags;
 	u32 addr = 0x1200 + 0x2E0 * link + 0x1E2;
-	u8 retry = MAX_CMD_RETRY;
+	u8 retry = CYCX_X25_MAX_CMD_RETRY;
 	int err = 0;
 
 	c.command = command;
@@ -1045,14 +1074,15 @@
 }
 
 /* Configure adapter. */
-static int x25_configure (cycx_t *card, TX25Config *conf)
+static int cycx_x25_configure(struct cycx_device *card,
+			      struct cycx_x25_config *conf)
 {
 	struct {
 		u16 nlinks;
-		TX25Config conf[2];
+		struct cycx_x25_config conf[2];
 	} x25_cmd_conf;
 
-	memset (&x25_cmd_conf, 0, sizeof(x25_cmd_conf));
+	memset(&x25_cmd_conf, 0, sizeof(x25_cmd_conf));
 	x25_cmd_conf.nlinks = 2;
 	x25_cmd_conf.conf[0] = *conf;
 	/* FIXME: we need to find a way in the wanrouter framework
@@ -1066,15 +1096,15 @@
 	x25_cmd_conf.conf[1].clock = 8;
 	x25_cmd_conf.conf[1].flags = 0; /* default = RS232 */
 
-	x25_dump_config(&x25_cmd_conf.conf[0]);
-	x25_dump_config(&x25_cmd_conf.conf[1]);
+	cycx_x25_dump_config(&x25_cmd_conf.conf[0]);
+	cycx_x25_dump_config(&x25_cmd_conf.conf[1]);
 
 	return x25_exec(card, X25_CONFIG, 0,
 			&x25_cmd_conf, sizeof(x25_cmd_conf), NULL, 0);
 }
 
 /* Get protocol statistics. */
-static int x25_get_stats (cycx_t *card)
+static int cycx_x25_get_stats(struct cycx_device *card)
 {
 	/* the firmware expects 20 in the size field!!!
 	   thanks to Daniela */
@@ -1102,7 +1132,7 @@
 	card->wandev.stats.collisions = 0; /* not available from fw */
 	card->wandev.stats.tx_errors = 0; /* not available from fw */
 
-	x25_dump_devs(&card->wandev);
+	cycx_x25_dump_devs(&card->wandev);
 
 	return 0;
 }
@@ -1110,27 +1140,27 @@
 /* return the number of nibbles */
 static int byte_to_nibble(u8 *s, u8 *d, char *nibble)
 {
-        int i = 0;
+	int i = 0;
+
+	if (*nibble && *s) {
+		d[i] |= *s++ - '0';
+		*nibble = 0;
+		++i;
+	}
 
-        if (*nibble && *s) {
-                d[i] |= *s++ - '0';
-                *nibble = 0;
-                ++i;
-        }
-
-        while (*s) {
-                d[i] = (*s - '0') << 4;
-                if (*(s + 1))
+	while (*s) {
+		d[i] = (*s - '0') << 4;
+		if (*(s + 1))
 			d[i] |= *(s + 1) - '0';
-                else {
-                        *nibble = 1;
-                        break;
-                }
-                ++i;
-                s += 2;
-        }
+		else {
+			*nibble = 1;
+			break;
+		}
+		++i;
+		s += 2;
+	}
 
-        return i;
+	return i;
 }
 
 static void nibble_to_byte(u8 *s, u8 *d, u8 len, u8 nibble)
@@ -1147,7 +1177,7 @@
 			*d++ = '0' + (*s & 0x0F);
 			--len;
 		} else break;
-		
+
 		++s;
 	}
 
@@ -1155,7 +1185,8 @@
 }
 
 /* Place X.25 call. */
-static int x25_place_call (cycx_t *card, x25_channel_t *chan)
+static int x25_place_call(struct cycx_device *card,
+			  struct cycx_x25_channel *chan)
 {
 	int err = 0,
 	    len;
@@ -1190,18 +1221,19 @@
 
 	d[5] = mylen << 4 | remotelen;
 	d[6 + len + 1] = 0xCC; /* TCP/IP over X.25, thanks to Daniela :) */
-	
+
 	if ((err = x25_exec(card, X25_CONNECT_REQUEST, chan->link,
 			    &d, 7 + len + 1, NULL, 0)) != 0)
 		clear_bit(--key, (void*)&card->u.x.connection_keys);
 	else
-                chan->lcn = -key;
+		chan->lcn = -key;
 
-        return err;
+	return err;
 }
 
 /* Place X.25 CONNECT RESPONSE. */
-static int x25_connect_response (cycx_t *card, x25_channel_t *chan)
+static int cycx_x25_connect_response(struct cycx_device *card,
+				     struct cycx_x25_channel *chan)
 {
 	u8 d[8];
 
@@ -1215,7 +1247,8 @@
 }
 
 /* Place X.25 DISCONNECT RESPONSE.  */
-static int x25_disconnect_response (cycx_t *card, u8 link, u8 lcn)
+static int cycx_x25_disconnect_response(struct cycx_device *card, u8 link,
+					u8 lcn)
 {
 	char d[5];
 
@@ -1228,7 +1261,8 @@
 }
 
 /* Clear X.25 call.  */
-static int x25_clear_call (cycx_t *card, u8 link, u8 lcn, u8 cause, u8 diagn)
+static int x25_clear_call(struct cycx_device *card, u8 link, u8 lcn, u8 cause,
+			  u8 diagn)
 {
 	u8 d[7];
 
@@ -1243,9 +1277,10 @@
 }
 
 /* Send X.25 data packet. */
-static int x25_send (cycx_t *card, u8 link, u8 lcn, u8 bitm, int len, void *buf)
+static int cycx_x25_send(struct cycx_device *card, u8 link, u8 lcn, u8 bitm,
+			 int len, void *buf)
 {
-	u8 d[] = "?\xFF\x10??"; 
+	u8 d[] = "?\xFF\x10??";
 
 	d[0] = d[3] = lcn;
 	d[4] = bitm;
@@ -1255,29 +1290,31 @@
 
 /* Miscellaneous */
 /* Find network device by its channel number.  */
-static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn)
+static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev,
+						  s16 lcn)
 {
 	struct net_device *dev = wandev->dev;
-	x25_channel_t *chan;
+	struct cycx_x25_channel *chan;
 
 	while (dev) {
-		chan = (x25_channel_t*)dev->priv;
+		chan = (struct cycx_x25_channel*)dev->priv;
 
 		if (chan->lcn == lcn)
 			break;
 		dev = chan->slave;
-	}	
+	}
 	return dev;
 }
 
 /* Find network device by its remote dte address. */
-static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte)
+static struct net_device *
+	cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte)
 {
 	struct net_device *dev = wandev->dev;
-	x25_channel_t *chan;
+	struct cycx_x25_channel *chan;
 
 	while (dev) {
-		chan = (x25_channel_t*)dev->priv;
+		chan = (struct cycx_x25_channel*)dev->priv;
 
 		if (!strcmp(chan->addr, dte))
 			break;
@@ -1293,60 +1330,60 @@
  * Return:	0	connected
  *		>0	connection in progress
  *		<0	failure */
-static int chan_connect (struct net_device *dev)
+static int cycx_x25_chan_connect(struct net_device *dev)
 {
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
+	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_device *card = chan->card;
 
 	if (chan->svc) {
-                if (!chan->addr[0])
+		if (!chan->addr[0])
 			return -EINVAL; /* no destination address */
 
-                dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n",
+		dprintk(1, KERN_INFO "%s: placing X.25 call to %s...\n",
 				  card->devname, chan->addr);
 
-                if (x25_place_call(card, chan))
+		if (x25_place_call(card, chan))
 			return -EIO;
 
-                set_chan_state(dev, WAN_CONNECTING);
-                return 1;
-        } else 
-		set_chan_state(dev, WAN_CONNECTED);
+		cycx_x25_set_chan_state(dev, WAN_CONNECTING);
+		return 1;
+	} else
+		cycx_x25_set_chan_state(dev, WAN_CONNECTED);
 
 	return 0;
 }
 
 /* Disconnect logical channel.
  * o if SVC then clear X.25 call */
-static void chan_disconnect (struct net_device *dev)
+static void cycx_x25_chan_disconnect(struct net_device *dev)
 {
-	x25_channel_t *chan = dev->priv;
+	struct cycx_x25_channel *chan = dev->priv;
 
 	if (chan->svc) {
 		x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0);
-		set_chan_state(dev, WAN_DISCONNECTING);
+		cycx_x25_set_chan_state(dev, WAN_DISCONNECTING);
 	} else
-		set_chan_state(dev, WAN_DISCONNECTED);
+		cycx_x25_set_chan_state(dev, WAN_DISCONNECTED);
 }
 
 /* Called by kernel timer */
-static void chan_timer (unsigned long d)
+static void cycx_x25_chan_timer(unsigned long d)
 {
 	struct net_device *dev = (struct net_device *)d;
-	x25_channel_t *chan = dev->priv;
-	
+	struct cycx_x25_channel *chan = dev->priv;
+
 	if (chan->state == WAN_CONNECTED)
-		chan_disconnect(dev);
+		cycx_x25_chan_disconnect(dev);
 	else
-		printk(KERN_ERR "%s: chan_timer for svc (%s) not connected!\n",
-				chan->card->devname, dev->name);
+		printk(KERN_ERR "%s: %s for svc (%s) not connected!\n",
+				chan->card->devname, __FUNCTION__, dev->name);
 }
 
 /* Set logical channel state. */
-static void set_chan_state (struct net_device *dev, u8 state)
+static void cycx_x25_set_chan_state(struct net_device *dev, u8 state)
 {
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
+	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_device *card = chan->card;
 	unsigned long flags;
 	char *string_state = NULL;
 
@@ -1355,43 +1392,40 @@
 	if (chan->state != state) {
 		if (chan->svc && chan->state == WAN_CONNECTED)
 			del_timer(&chan->timer);
-	
+
 		switch (state) {
-			case WAN_CONNECTED:
-				string_state = "connected!";
-				*(u16*)dev->dev_addr = htons(chan->lcn);
-				netif_wake_queue(dev);
-				reset_timer(dev);
-
-				if (chan->protocol == ETH_P_X25)
-					chan_x25_send_event(dev, 1);
-
-				break;
-
-			case WAN_CONNECTING:
-				string_state = "connecting...";
-				break;
-
-			case WAN_DISCONNECTING:
-				string_state = "disconnecting...";
-				break;
-
-			case WAN_DISCONNECTED:
-				string_state = "disconnected!";
-				
-				if (chan->svc) {
-					*(unsigned short*)dev->dev_addr = 0;
-					chan->lcn = 0;
-                                }
+		case WAN_CONNECTED:
+			string_state = "connected!";
+			*(u16*)dev->dev_addr = htons(chan->lcn);
+			netif_wake_queue(dev);
+			reset_timer(dev);
+
+			if (chan->protocol == ETH_P_X25)
+				cycx_x25_chan_send_event(dev, 1);
 
-				if (chan->protocol == ETH_P_X25)
-					chan_x25_send_event(dev, 2);
+			break;
+		case WAN_CONNECTING:
+			string_state = "connecting...";
+			break;
+		case WAN_DISCONNECTING:
+			string_state = "disconnecting...";
+			break;
+		case WAN_DISCONNECTED:
+			string_state = "disconnected!";
 
-				netif_wake_queue(dev);
-				break;
+			if (chan->svc) {
+				*(unsigned short*)dev->dev_addr = 0;
+				chan->lcn = 0;
+			}
+
+			if (chan->protocol == ETH_P_X25)
+				cycx_x25_chan_send_event(dev, 2);
+
+			netif_wake_queue(dev);
+			break;
 		}
 
-		printk (KERN_INFO "%s: interface %s %s\n", card->devname,
+		printk(KERN_INFO "%s: interface %s %s\n", card->devname,
 				  dev->name, string_state);
 		chan->state = state;
 	}
@@ -1412,10 +1446,10 @@
  *    the packet into 'complete sequence' using M-bit.
  * 2. When transmission is complete, an event notification should be issued
  *    to the router.  */
-static int chan_send (struct net_device *dev, struct sk_buff *skb)
+static int cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb)
 {
-	x25_channel_t *chan = dev->priv;
-	cycx_t *card = chan->card;
+	struct cycx_x25_channel *chan = dev->priv;
+	struct cycx_device *card = chan->card;
 	int bitm = 0;		/* final packet */
 	unsigned len = skb->len;
 
@@ -1424,9 +1458,9 @@
 		bitm = 0x10;		/* set M-bit (more data) */
 	}
 
-	if (x25_send(card, chan->link, chan->lcn, bitm, len, skb->data))
+	if (cycx_x25_send(card, chan->link, chan->lcn, bitm, len, skb->data))
 		return 1;
-		
+
 	if (bitm) {
 		skb_pull(skb, len);
 		return 1;
@@ -1440,30 +1474,30 @@
 
 /* Send event (connection, disconnection, etc) to X.25 socket layer */
 
-static void chan_x25_send_event(struct net_device *dev, u8 event)
+static void cycx_x25_chan_send_event(struct net_device *dev, u8 event)
 {
-        struct sk_buff *skb;
-        unsigned char *ptr;
+	struct sk_buff *skb;
+	unsigned char *ptr;
 
-        if ((skb = dev_alloc_skb(1)) == NULL) {
-                printk(KERN_ERR "%s: out of memory\n", __FUNCTION__);
-                return;
-        }
+	if ((skb = dev_alloc_skb(1)) == NULL) {
+		printk(KERN_ERR "%s: out of memory\n", __FUNCTION__);
+		return;
+	}
 
-        ptr  = skb_put(skb, 1);
-        *ptr = event;
+	ptr  = skb_put(skb, 1);
+	*ptr = event;
 
-        skb->dev = dev;
-        skb->protocol = htons(ETH_P_X25);
-        skb->mac.raw = skb->data;
-        skb->pkt_type = PACKET_HOST;
+	skb->dev = dev;
+	skb->protocol = htons(ETH_P_X25);
+	skb->mac.raw = skb->data;
+	skb->pkt_type = PACKET_HOST;
 
-        netif_rx(skb);
+	netif_rx(skb);
 	dev->last_rx = jiffies;		/* timestamp */
 }
 
 /* Convert line speed in bps to a number used by cyclom 2x code. */
-static u8 bps_to_speed_code (u32 bps)
+static u8 bps_to_speed_code(u32 bps)
 {
 	u8 number = 0; /* defaults to the lowest (1200) speed ;> */
 
@@ -1480,24 +1514,24 @@
 }
 
 /* log base 2 */
-static u8 log2 (u32 n)
+static u8 log2(u32 n)
 {
-        u8 log = 0;
+	u8 log = 0;
 
-        if (!n)
+	if (!n)
 		return 0;
 
-        while (n > 1) {
-                n >>= 1;
-                ++log;
-        }
+	while (n > 1) {
+		n >>= 1;
+		++log;
+	}
 
-        return log;
+	return log;
 }
 
 /* Convert decimal string to unsigned integer.
  * If len != 0 then only 'len' characters of the string are converted. */
-static unsigned dec_to_uint (u8 *str, int len)
+static unsigned dec_to_uint(u8 *str, int len)
 {
 	unsigned val = 0;
 
@@ -1512,13 +1546,13 @@
 
 static void reset_timer(struct net_device *dev)
 {
-	x25_channel_t *chan = dev->priv;
+	struct cycx_x25_channel *chan = dev->priv;
 
 	if (chan->svc)
 		mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ);
 }
 #ifdef CYCLOMX_X25_DEBUG
-static void x25_dump_config(TX25Config *conf)
+static void cycx_x25_dump_config(struct cycx_x25_config *conf)
 {
 	printk(KERN_INFO "X.25 configuration\n");
 	printk(KERN_INFO "-----------------\n");
@@ -1540,7 +1574,7 @@
 	printk(KERN_INFO "flags=0x%x\n", conf->flags);
 }
 
-static void x25_dump_stats(TX25Stats *stats)
+static void cycx_x25_dump_stats(struct cycx_x25_stats *stats)
 {
 	printk(KERN_INFO "X.25 statistics\n");
 	printk(KERN_INFO "--------------\n");
@@ -1556,7 +1590,7 @@
 	printk(KERN_INFO "rx_aborts=%d\n", stats->rx_aborts);
 }
 
-static void x25_dump_devs(wan_device_t *wandev)
+static void cycx_x25_dump_devs(struct wan_device *wandev)
 {
 	struct net_device *dev = wandev->dev;
 
@@ -1565,7 +1599,7 @@
 	printk(KERN_INFO "---------------------------------------\n");
 
 	while(dev) {
-		x25_channel_t *chan = dev->priv;
+		struct cycx_x25_channel *chan = dev->priv;
 
 		printk(KERN_INFO "%-5.5s %-15.15s   %d     ETH_P_%s\n",
 				 chan->name, chan->addr, netif_queue_stopped(dev),
diff -Nru a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c
--- a/drivers/net/wan/dlci.c	Mon Feb 24 12:51:23 2003
+++ b/drivers/net/wan/dlci.c	Thu May  8 18:29:19 2003
@@ -37,6 +37,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
+#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/init.h>
@@ -577,9 +578,10 @@
 	return(0);
 }
 
-int __init dlci_setup(void)
+int __init init_dlci(void)
 {
 	int i;
+	dlci_ioctl_set(dlci_ioctl);
 
 	printk("%s.\n", version);
 	
@@ -589,25 +591,16 @@
 	for(i=0;i<sizeof(basename) / sizeof(char *);i++)
 		basename[i] = NULL;
 
-	return(0);
+	return 0;
 }
 
-#ifdef MODULE
-
-extern int (*dlci_ioctl_hook)(unsigned int, void *);
-
-int init_module(void)
+void __exit dlci_exit(void)
 {
-	dlci_ioctl_hook = dlci_ioctl;
-
-	return(dlci_setup());
+	dlci_ioctl_set(NULL);
 }
 
-void cleanup_module(void)
-{
-	dlci_ioctl_hook = NULL;
-}
-#endif /* MODULE */
+module_init(init_dlci);
+module_exit(dlci_exit);
 
 MODULE_AUTHOR("Mike McLagan");
 MODULE_DESCRIPTION("Frame Relay DLCI layer");
diff -Nru a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c
--- a/drivers/net/wan/sdla.c	Sun Apr 27 20:36:21 2003
+++ b/drivers/net/wan/sdla.c	Sun May 18 08:18:07 2003
@@ -1636,9 +1636,10 @@
 	dev->change_mtu		= sdla_change_mtu;
 
 	dev->type		= 0xFFFF;
-	dev->hard_header_len = 0;
+	dev->hard_header_len	= 0;
 	dev->addr_len		= 0;
 	dev->mtu		= SDLA_MAX_MTU;
+	SET_MODULE_OWNER(dev);
 
 	flp->activate		= sdla_activate;
 	flp->deactivate		= sdla_deactivate;
diff -Nru a/drivers/net/wan/sdla_chdlc.c b/drivers/net/wan/sdla_chdlc.c
--- a/drivers/net/wan/sdla_chdlc.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/net/wan/sdla_chdlc.c	Mon May 19 23:52:15 2003
@@ -186,21 +186,22 @@
 
 /****** Function Prototypes *************************************************/
 /* WAN link driver entry points. These are called by the WAN router module. */
-static int update (wan_device_t* wandev);
-static int new_if (wan_device_t* wandev, netdevice_t* dev,
-	wanif_conf_t* conf);
+static int update(struct wan_device* wandev);
+static int new_if(struct wan_device* wandev, struct net_device* dev,
+		  wanif_conf_t* conf);
 
 /* Network device interface */
-static int if_init   (netdevice_t* dev);
-static int if_open   (netdevice_t* dev);
-static int if_close  (netdevice_t* dev);
-static int if_header (struct sk_buff* skb, netdevice_t* dev,
-	unsigned short type, void* daddr, void* saddr, unsigned len);
+static int if_init(struct net_device* dev);
+static int if_open(struct net_device* dev);
+static int if_close(struct net_device* dev);
+static int if_header(struct sk_buff* skb, struct net_device* dev,
+		     unsigned short type, void* daddr, void* saddr,
+		     unsigned len);
 
 static int if_rebuild_hdr (struct sk_buff *skb);
-static struct net_device_stats* if_stats (netdevice_t* dev);
+static struct net_device_stats* if_stats(struct net_device* dev);
   
-static int if_send (struct sk_buff* skb, netdevice_t* dev);
+static int if_send(struct sk_buff* skb, struct net_device* dev);
 
 /* CHDLC Firmware interface functions */
 static int chdlc_configure 	(sdla_t* card, void* data);
@@ -214,7 +215,7 @@
 
 
 static int chdlc_disable_comm_shutdown (sdla_t *card);
-static void if_tx_timeout (netdevice_t *dev);
+static void if_tx_timeout(struct net_device *dev);
 
 /* Miscellaneous CHDLC Functions */
 static int set_chdlc_config (sdla_t* card);
@@ -230,8 +231,8 @@
 static int config_chdlc (sdla_t *card);
 static void disable_comm (sdla_t *card);
 
-static void trigger_chdlc_poll (netdevice_t *);
-static void chdlc_poll (netdevice_t *);
+static void trigger_chdlc_poll(struct net_device *dev);
+static void chdlc_poll(struct net_device *dev);
 static void chdlc_poll_delay (unsigned long dev_ptr);
 
 
@@ -245,20 +246,20 @@
 static void timer_intr(sdla_t *);
 
 /* Bottom half handlers */
-static void chdlc_work (netdevice_t *);
-static int chdlc_work_cleanup (netdevice_t *);
-static int bh_enqueue (netdevice_t *, struct sk_buff *);
+static void chdlc_work(struct net_device *dev);
+static int chdlc_work_cleanup(struct net_device *dev);
+static int bh_enqueue(struct net_device *dev, struct sk_buff *skb);
 
 /* Miscellaneous functions */
-static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev,
+static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev,
 				struct sk_buff *skb);
 static int reply_udp( unsigned char *data, unsigned int mbox_len );
 static int intr_test( sdla_t* card);
 static int udp_pkt_type( struct sk_buff *skb , sdla_t* card);
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, netdevice_t* dev,
+                                struct sk_buff *skb, struct net_device* dev,
                                 chdlc_private_area_t* chdlc_priv_area);
-static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,  
+static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,  
 				chdlc_private_area_t* chdlc_priv_area);
 static unsigned short calc_checksum (char *, int);
 static void s508_lock (sdla_t *card, unsigned long *smp_flags);
@@ -598,10 +599,10 @@
  * as to minimize the time that we are inside the interrupt handler.
  *
  */
-static int update (wan_device_t* wandev)
+static int update(struct wan_device* wandev)
 {
 	sdla_t* card = wandev->private;
- 	netdevice_t* dev;
+ 	struct net_device* dev;
         volatile chdlc_private_area_t* chdlc_priv_area;
         SHARED_MEMORY_INFO_STRUCT *flags;
 	unsigned long timeout;
@@ -666,7 +667,8 @@
  * Return:	0	o.k.
  *		< 0	failure (channel will not be created)
  */
-static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf)
+static int new_if(struct wan_device* wandev, struct net_device* dev,
+		  wanif_conf_t* conf)
 {
 	sdla_t* card = wandev->private;
 	chdlc_private_area_t* chdlc_priv_area;
@@ -897,11 +899,11 @@
  * interface registration.  Returning anything but zero will fail interface
  * registration.
  */
-static int if_init (netdevice_t* dev)
-	{
+static int if_init(struct net_device* dev)
+{
 	chdlc_private_area_t* chdlc_priv_area = dev->priv;
 	sdla_t* card = chdlc_priv_area->card;
-	wan_device_t* wandev = &card->wandev;
+	struct wan_device* wandev = &card->wandev;
 
 	/* Initialize device driver entry points */
 	dev->open		= &if_open;
@@ -912,7 +914,6 @@
 	dev->get_stats		= &if_stats;
 	dev->tx_timeout		= &if_tx_timeout;
 	dev->watchdog_timeo	= TX_TIMEOUT;
-
 	
 	/* Initialize media-specific parameters */
 	dev->flags		|= IFF_POINTOPOINT;
@@ -949,6 +950,7 @@
          * by stack.
 	 */
         dev->tx_queue_len = 100;
+	SET_MODULE_OWNER(dev);
    
 	return 0;
 }
@@ -960,7 +962,7 @@
  *
  * Return 0 if O.k. or errno.
  */
-static int if_open (netdevice_t* dev)
+static int if_open(struct net_device* dev)
 {
 	chdlc_private_area_t* chdlc_priv_area = dev->priv;
 	sdla_t* card = chdlc_priv_area->card;
@@ -1013,7 +1015,7 @@
  * o if this is the last close, then disable communications and interrupts.
  * o reset flags.
  */
-static int if_close (netdevice_t* dev)
+static int if_close(struct net_device* dev)
 {
 	chdlc_private_area_t* chdlc_priv_area = dev->priv;
 	sdla_t* card = chdlc_priv_area->card;
@@ -1069,7 +1071,7 @@
 		card->tty=NULL;
 		tty_card_map[card->tty_minor]=NULL;
 		state = &rs_table[card->tty_minor];
-		memset(state,0,sizeof(state));
+		memset(state, 0, sizeof(*state));
 	}
 	return;
 }
@@ -1084,8 +1086,9 @@
  *
  * Return:	media header length.
  */
-static int if_header (struct sk_buff* skb, netdevice_t* dev,
-	unsigned short type, void* daddr, void* saddr, unsigned len)
+static int if_header(struct sk_buff* skb, struct net_device* dev,
+		     unsigned short type, void* daddr, void* saddr,
+		     unsigned len)
 {
 	skb->protocol = htons(type);
 
@@ -1096,7 +1099,7 @@
 /*============================================================================
  * Handle transmit timeout event from netif watchdog
  */
-static void if_tx_timeout (netdevice_t *dev)
+static void if_tx_timeout(struct net_device *dev)
 {
     	chdlc_private_area_t* chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -1144,7 +1147,7 @@
  * 2. Setting tbusy flag will inhibit further transmit requests from the
  *    protocol stack and can be used for flow control with protocol layer.
  */
-static int if_send (struct sk_buff* skb, netdevice_t* dev)
+static int if_send(struct sk_buff* skb, struct net_device* dev)
 {
 	chdlc_private_area_t *chdlc_priv_area = dev->priv;
 	sdla_t *card = chdlc_priv_area->card;
@@ -1278,7 +1281,7 @@
  * multicast source IP address.
  */
 
-static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
+static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
 				struct sk_buff *skb)
 {
 	u32 src_ip_addr;
@@ -1421,7 +1424,7 @@
  * Get ethernet-style interface statistics.
  * Return a pointer to struct enet_statistics.
  */
-static struct net_device_stats* if_stats (netdevice_t* dev)
+static struct net_device_stats* if_stats(struct net_device* dev)
 {
 	sdla_t *my_card;
 	chdlc_private_area_t* chdlc_priv_area;
@@ -1710,7 +1713,7 @@
  *       PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE
  *       DOING */
 
-static void chdlc_work (netdevice_t * dev)
+static void chdlc_work(struct net_device * dev)
 {
 	chdlc_private_area_t* chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -1751,7 +1754,7 @@
 	return;
 }
 
-static int chdlc_work_cleanup (netdevice_t *dev)
+static int chdlc_work_cleanup(struct net_device *dev)
 {
 	chdlc_private_area_t* chan = dev->priv;
 
@@ -1769,7 +1772,7 @@
 
 
 
-static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb)
+static int bh_enqueue(struct net_device *dev, struct sk_buff *skb)
 {
 	/* Check for full */
 	chdlc_private_area_t* chan = dev->priv;
@@ -1804,7 +1807,7 @@
  */
 static void wpc_isr (sdla_t* card)
 {
-	netdevice_t* dev;
+	struct net_device* dev;
 	SHARED_MEMORY_INFO_STRUCT* flags = NULL;
 	int i;
 	sdla_t *my_card;
@@ -1931,7 +1934,7 @@
  */
 static void rx_intr (sdla_t* card)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	chdlc_private_area_t *chdlc_priv_area;
 	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
 	CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb;
@@ -2083,7 +2086,7 @@
  */
 void timer_intr(sdla_t *card)
 {
-        netdevice_t* dev;
+        struct net_device* dev;
         chdlc_private_area_t* chdlc_priv_area = NULL;
         SHARED_MEMORY_INFO_STRUCT* flags = NULL;
 
@@ -2172,7 +2175,7 @@
 		cfg.IP_netmask		= 0;
 		
 	}else if (card->wandev.dev){
-		netdevice_t * dev = card->wandev.dev;
+		struct net_device *dev = card->wandev.dev;
 		chdlc_private_area_t *chdlc_priv_area = dev->priv;
 		
                 struct in_device *in_dev = dev->ip_ptr;
@@ -2402,7 +2405,7 @@
 
 static int configure_ip (sdla_t* card)
 {
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
         chdlc_private_area_t *chdlc_priv_area;
         char err;
 
@@ -2449,7 +2452,7 @@
 
 static int unconfigure_ip (sdla_t* card)
 {
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	chdlc_private_area_t *chdlc_priv_area;
 
 	if (!dev)
@@ -2477,7 +2480,7 @@
 
 static void process_route (sdla_t *card)
 {
-        netdevice_t *dev = card->wandev.dev;
+        struct net_device *dev = card->wandev.dev;
         unsigned char port_num;
         chdlc_private_area_t *chdlc_priv_area = NULL;
 	u32 local_IP_addr = 0;
@@ -2658,8 +2661,8 @@
  */
 
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, netdevice_t* dev,
-                                chdlc_private_area_t* chdlc_priv_area )
+			      struct sk_buff *skb, struct net_device* dev,
+			      chdlc_private_area_t* chdlc_priv_area)
 {
 	int udp_pkt_stored = 0;
 
@@ -2686,7 +2689,7 @@
  * Process UDP management packet.
  */
 
-static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,
+static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,
 				chdlc_private_area_t* chdlc_priv_area ) 
 {
 	unsigned char *buf;
@@ -3263,7 +3266,7 @@
 
                 card->wandev.state = card->u.c.state = state;
 		if (card->wandev.dev){
-			netdevice_t *dev = card->wandev.dev;
+			struct net_device *dev = card->wandev.dev;
 			chdlc_private_area_t *chdlc_priv_area = dev->priv;
 			chdlc_priv_area->common.state = state;
 		}
@@ -3293,7 +3296,7 @@
 
 static int config_chdlc (sdla_t *card)
 {
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	chdlc_private_area_t *chdlc_priv_area = dev->priv;
 	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
 
@@ -3417,7 +3420,7 @@
  *      the chldc_poll routine.  
  */
 
-static void chdlc_poll (netdevice_t *dev)
+static void chdlc_poll(struct net_device *dev)
 {
 	chdlc_private_area_t *chdlc_priv_area;
 	sdla_t *card;
@@ -3567,7 +3570,7 @@
  *      a polling routine.
  *
  */	
-static void trigger_chdlc_poll (netdevice_t *dev)
+static void trigger_chdlc_poll(struct net_device *dev)
 {
 	chdlc_private_area_t *chdlc_priv_area;
 	sdla_t *card;
@@ -3592,7 +3595,7 @@
 
 static void chdlc_poll_delay (unsigned long dev_ptr)
 {
-	netdevice_t *dev = (netdevice_t *)dev_ptr;
+	struct net_device *dev = (struct net_device *)dev_ptr;
 	trigger_chdlc_poll(dev);
 }
 
diff -Nru a/drivers/net/wan/sdla_fr.c b/drivers/net/wan/sdla_fr.c
--- a/drivers/net/wan/sdla_fr.c	Thu Mar  6 09:25:30 2003
+++ b/drivers/net/wan/sdla_fr.c	Sun May 18 08:18:07 2003
@@ -323,27 +323,28 @@
 /****** Function Prototypes *************************************************/
 
 /* WAN link driver entry points. These are called by the WAN router module. */
-static int update(wan_device_t *wandev);
-static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf);
-static int del_if(wan_device_t *wandev, netdevice_t *dev);
+static int update(struct wan_device *wandev);
+static int new_if(struct wan_device *wandev, struct net_device *dev,
+		  wanif_conf_t *conf);
+static int del_if(struct wan_device *wandev, struct net_device *dev);
 static void disable_comm (sdla_t *card);
 
 /* WANPIPE-specific entry points */
 static int wpf_exec(struct sdla *card, void *u_cmd, void *u_data);
 
 /* Network device interface */
-static int if_init(netdevice_t *dev);
-static int if_open(netdevice_t *dev);
-static int if_close(netdevice_t *dev);
+static int if_init(struct net_device *dev);
+static int if_open(struct net_device *dev);
+static int if_close(struct net_device *dev);
 
-static void if_tx_timeout (netdevice_t *dev);
+static void if_tx_timeout(struct net_device *dev);
 
 static int if_rebuild_hdr (struct sk_buff *skb);
 
-static int if_send(struct sk_buff *skb, netdevice_t *dev);
-static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
+static int if_send(struct sk_buff *skb, struct net_device *dev);
+static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
                                 struct sk_buff *skb);
-static struct net_device_stats *if_stats(netdevice_t *dev);
+static struct net_device_stats *if_stats(struct net_device *dev);
 
 /* Interrupt handlers */
 static void fr_isr(sdla_t *card);
@@ -382,9 +383,9 @@
 static int fr_dlci_change(sdla_t *card, fr_mbox_t *mbox);
 
 /* Miscellaneous functions */
-static int update_chan_state(netdevice_t *dev);
-static void set_chan_state(netdevice_t *dev, int state);
-static netdevice_t *find_channel(sdla_t *card, unsigned dlci);
+static int update_chan_state(struct net_device *dev);
+static void set_chan_state(struct net_device *dev, int state);
+static struct net_device *find_channel(sdla_t *card, unsigned dlci);
 static int is_tx_ready(sdla_t *card, fr_channel_t *chan);
 static unsigned int dec_to_uint(unsigned char *str, int len);
 static int reply_udp( unsigned char *data, unsigned int mbox_len );
@@ -393,22 +394,23 @@
 static void init_chan_statistics( fr_channel_t* chan );
 static void init_global_statistics( sdla_t* card );
 static void read_DLCI_IB_mapping( sdla_t* card, fr_channel_t* chan );
-static int setup_for_delayed_transmit(netdevice_t* dev, struct sk_buff *skb);
+static int setup_for_delayed_transmit(struct net_device* dev,
+				      struct sk_buff *skb);
 
-netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *);
-static int check_tx_status(sdla_t *, netdevice_t *);
+struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev);
+static int check_tx_status(sdla_t *card, struct net_device *dev);
 
 /* Frame Relay Socket API */
 static void trigger_fr_bh (fr_channel_t *);
-static void fr_bh (netdevice_t *);
-static int fr_bh_cleanup (netdevice_t *);
-static int bh_enqueue (netdevice_t *, struct sk_buff *);
-
-static void trigger_fr_poll (netdevice_t *);
-static void fr_poll (netdevice_t *);
-//static void add_gateway (netdevice_t *);
+static void fr_bh(struct net_device *dev);
+static int fr_bh_cleanup(struct net_device *dev);
+static int bh_enqueue(struct net_device *dev, struct sk_buff *skb);
+
+static void trigger_fr_poll(struct net_device *dev);
+static void fr_poll(struct net_device *dev);
+//static void add_gateway(struct net_device *dev);
 
-static void trigger_unconfig_fr (netdevice_t *dev);
+static void trigger_unconfig_fr(struct net_device *dev);
 static void unconfig_fr (sdla_t *);
 
 static void trigger_config_fr (sdla_t *);
@@ -416,11 +418,11 @@
 
 
 /* Inverse ARP and Dynamic routing functions */
-int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t *dev);
+int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device *dev);
 int is_arp(void *buf);
-int send_inarp_request(sdla_t *card, netdevice_t *dev);
+int send_inarp_request(sdla_t *card, struct net_device *dev);
 
-static void trigger_fr_arp (netdevice_t *);
+static void trigger_fr_arp(struct net_device *dev);
 static void fr_arp (unsigned long data);
 
 
@@ -442,7 +444,8 @@
 void 	s508_s514_lock(sdla_t *card, unsigned long *smp_flags);
 
 unsigned short calc_checksum (char *, int);
-static int setup_fr_header(struct sk_buff** skb, netdevice_t* dev, char op_mode);
+static int setup_fr_header(struct sk_buff** skb,
+			   struct net_device* dev, char op_mode);
 
 
 /****** Public Functions ****************************************************/
@@ -746,7 +749,7 @@
 /*============================================================================
  * Update device status & statistics.
  */
-static int update (wan_device_t* wandev)
+static int update(struct wan_device* wandev)
 {
 	volatile sdla_t* card;
 	unsigned long timeout;
@@ -791,7 +794,8 @@
  * Return:	0	o.k.
  *		< 0	failure (channel will not be created)
  */
-static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf)
+static int new_if(struct wan_device* wandev, struct net_device* dev,
+		  wanif_conf_t* conf)
 {
 	sdla_t* card = wandev->private;
 	fr_channel_t* chan;
@@ -1020,7 +1024,7 @@
 /*============================================================================
  * Delete logical channel.
  */
-static int del_if (wan_device_t* wandev, netdevice_t* dev)
+static int del_if(struct wan_device* wandev, struct net_device* dev)
 {
 	fr_channel_t* chan = dev->priv;
 	unsigned long smp_flags=0;
@@ -1116,11 +1120,11 @@
  * interface registration.  Returning anything but zero will fail interface
  * registration.
  */
-static int if_init (netdevice_t* dev)
+static int if_init(struct net_device* dev)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
-	wan_device_t* wandev = &card->wandev;
+	struct wan_device* wandev = &card->wandev;
 
 	/* Initialize device driver entry points */
 	dev->open		= &if_open;
@@ -1183,6 +1187,7 @@
 	dev->base_addr	= wandev->ioport;
 	dev->mem_start	= wandev->maddr;
 	dev->mem_end	= wandev->maddr + wandev->msize - 1;
+	SET_MODULE_OWNER(dev);
 
 	return 0;
 }
@@ -1194,7 +1199,7 @@
  *
  * Return 0 if O.k. or errno.
  */
-static int if_open (netdevice_t* dev)
+static int if_open(struct net_device* dev)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -1236,7 +1241,7 @@
  * o if this is the last open, then disable communications and interrupts.
  * o reset flags.
  */
-static int if_close (netdevice_t* dev)
+static int if_close(struct net_device* dev)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -1259,8 +1264,7 @@
  */
 static int if_rebuild_hdr (struct sk_buff* skb)
 {
-
-	netdevice_t *dev = skb->dev;
+	struct net_device *dev = skb->dev;
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 
@@ -1272,7 +1276,7 @@
 /*============================================================================
  * Handle transmit timeout event from netif watchdog
  */
-static void if_tx_timeout (netdevice_t *dev)
+static void if_tx_timeout(struct net_device *dev)
 {
     	fr_channel_t* chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -1315,7 +1319,7 @@
  *    will inhibit further transmit requests from the protocol stack 
  *    and can be used for flow control with protocol layer.
  */
-static int if_send (struct sk_buff* skb, netdevice_t* dev)
+static int if_send(struct sk_buff* skb, struct net_device* dev)
 {
     	fr_channel_t* chan = dev->priv;
     	sdla_t* card = chan->card;
@@ -1562,7 +1566,8 @@
  * Setup so that a frame can be transmitted on the occurrence of a transmit
  * interrupt.
  */
-static int setup_for_delayed_transmit (netdevice_t* dev, struct sk_buff *skb)
+static int setup_for_delayed_transmit(struct net_device* dev,
+				      struct sk_buff *skb)
 {
         fr_channel_t* chan = dev->priv;
         sdla_t* card = chan->card;
@@ -1614,7 +1619,7 @@
  * Return 0 if not broadcast/multicast address, otherwise return 1.
  */
 
-static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
+static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
                                 struct sk_buff *skb)
 {
         u32 src_ip_addr;
@@ -1826,7 +1831,7 @@
  * Get ethernet-style interface statistics.
  * Return a pointer to struct enet_statistics.
  */
-static struct net_device_stats *if_stats(netdevice_t *dev)
+static struct net_device_stats *if_stats(struct net_device *dev)
 {
 	fr_channel_t* chan = dev->priv;
 	
@@ -1952,7 +1957,7 @@
 	fr_channel_t* chan;
 	char *ptr = &flags->iflag;
 	struct sk_buff* skb;
-	netdevice_t* dev;
+	struct net_device* dev;
 	void* buf;
 	unsigned dlci, len, offs, len_incl_hdr;
 	int i, udp_type;	
@@ -2223,7 +2228,7 @@
 {
         fr508_flags_t* flags = card->flags;
         fr_tx_buf_ctl_t* bctl;
-        netdevice_t* dev;
+        struct net_device* dev;
         fr_channel_t* chan;
 
         if(card->hw.type == SDLA_S514){
@@ -2352,9 +2357,10 @@
 	/* Update the channel state call.  This is call is
          * triggered by if_send() function */
 	if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_UPDATE_STATE){
-		netdevice_t *dev;
+		struct net_device *dev;
 		if (card->wandev.state == WAN_CONNECTED){
-			for (dev=card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)){
+			for (dev = card->wandev.dev; dev;
+			     dev = *((struct net_device **)dev->priv)){
 				fr_channel_t *chan = dev->priv;	
 				if (chan->common.state != WAN_CONNECTED){
 					update_chan_state(dev);
@@ -2380,7 +2386,7 @@
 	/* Transmit ARP packets */
 	if (card->u.f.timer_int_enabled & TMR_INT_ENABLED_ARP){
 		int i=0;
-		netdevice_t *dev;
+		struct net_device *dev;
 
 		if (card->u.f.arp_dev == NULL)
 			card->u.f.arp_dev = card->wandev.dev;
@@ -2584,7 +2590,7 @@
  *	This function is called by fr_poll() polling funtion.
  */
 
-static void process_route (netdevice_t *dev)
+static void process_route(struct net_device *dev)
 {
 	fr_channel_t *chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -2985,7 +2991,7 @@
 
 static unsigned int fr_send_hdr (sdla_t*card, int dlci, unsigned int offset)
 {
-	netdevice_t *dev = find_channel(card,dlci);	
+	struct net_device *dev = find_channel(card,dlci);	
 	fr_channel_t *chan;
 
 	if (!dev || !(chan=dev->priv))
@@ -3088,12 +3094,12 @@
 		case FRRES_MODEM_FAILURE:
 			return fr_modem_failure(card, mbox);
 
-		case FRRES_CHANNEL_DOWN:
-			{
-			netdevice_t *dev;
+		case FRRES_CHANNEL_DOWN: {
+			struct net_device *dev;
 
 			/* Remove all routes from associated DLCI's */
-			for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) {
+			for (dev = card->wandev.dev; dev;
+			     dev = *((struct net_device **)dev->priv)) {
 				fr_channel_t *chan = dev->priv;
 				if (chan->route_flag == ROUTE_ADDED) {
 					chan->route_flag = REMOVE_ROUTE;
@@ -3114,13 +3120,13 @@
 			return 1;
 			}
 
-		case FRRES_CHANNEL_UP:
-			{
-			netdevice_t *dev;
+		case FRRES_CHANNEL_UP: {
+			struct net_device *dev;
 
 			/* FIXME: Only startup devices that are on the list */
 			
-			for (dev = card->wandev.dev; dev; dev = *((netdevice_t **)dev->priv)) {
+			for (dev = card->wandev.dev; dev;
+			     dev = *((struct net_device **)dev->priv)) {
 				
 				set_chan_state(dev,WAN_CONNECTED);
 			}
@@ -3194,13 +3200,13 @@
 	dlci_status_t* status = (void*)mbox->data;
 	int cnt = mbox->cmd.length / sizeof(dlci_status_t);
 	fr_channel_t *chan;
-	netdevice_t* dev2;
+	struct net_device* dev2;
 	
 
 	for (; cnt; --cnt, ++status) {
 
 		unsigned short dlci= status->dlci;
-		netdevice_t* dev = find_channel(card, dlci);
+		struct net_device* dev = find_channel(card, dlci);
 		
 		if (dev == NULL){
 			printk(KERN_INFO 
@@ -3259,7 +3265,8 @@
 		}
 	}
 	
-	for (dev2 =card->wandev.dev; dev2; dev2 = *((netdevice_t **)dev2->priv)){
+	for (dev2 = card->wandev.dev; dev2;
+	     dev2 = *((struct net_device **)dev2->priv)){
 		
 		chan = dev2->priv;
 	
@@ -3315,7 +3322,7 @@
 /*============================================================================
  * Update channel state. 
  */
-static int update_chan_state (netdevice_t* dev)
+static int update_chan_state(struct net_device* dev)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -3361,7 +3368,7 @@
 /*============================================================================
  * Set channel state.
  */
-static void set_chan_state (netdevice_t* dev, int state)
+static void set_chan_state(struct net_device* dev, int state)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -3414,7 +3421,7 @@
  * NOTE: del_if() functions updates this array, it uses
  *       the spin locks to avoid corruption.
  */
-static netdevice_t* find_channel (sdla_t* card, unsigned dlci)
+static struct net_device* find_channel(sdla_t* card, unsigned dlci)
 {
 	if(dlci > HIGHEST_VALID_DLCI)
 		return NULL;
@@ -3471,7 +3478,7 @@
 {
         int udp_pkt_stored = 0;
 	
-	netdevice_t *dev=find_channel(card,dlci);
+	struct net_device *dev = find_channel(card, dlci);
 	fr_channel_t *chan;
 	
 	if (!dev || !(chan=dev->priv))
@@ -3517,7 +3524,7 @@
 	int err;
 	struct timeval tv;
 	int udp_mgmt_req_valid = 1;
-        netdevice_t* dev;
+        struct net_device* dev;
         fr_channel_t* chan;
         fr_udp_pkt_t *fr_udp_pkt;
 	unsigned short num_trc_els;
@@ -3918,7 +3925,7 @@
  * Send Inverse ARP Request
  */
 
-int send_inarp_request(sdla_t *card, netdevice_t *dev)
+int send_inarp_request(sdla_t *card, struct net_device *dev)
 {
 	int err=0;
 
@@ -3995,7 +4002,7 @@
  * Process ARP Packet Type
  */
 
-int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, netdevice_t* dev)
+int process_ARP(arphdr_1490_t *ArpPacket, sdla_t *card, struct net_device* dev)
 {
 
 
@@ -4152,7 +4159,7 @@
  *      at a later date.
  */	
 
-static void trigger_fr_arp (netdevice_t *dev)
+static void trigger_fr_arp(struct net_device *dev)
 {
 	fr_channel_t* chan = dev->priv;
 
@@ -4173,7 +4180,7 @@
 
 static void fr_arp (unsigned long data)
 {
-	netdevice_t *dev = (netdevice_t *)data;
+	struct net_device *dev = (struct net_device *)data;
 	fr_channel_t *chan = dev->priv;
 	volatile sdla_t *card = chan->card;
 	fr508_flags_t* flags = card->flags;
@@ -4365,7 +4372,7 @@
  *
  */
 
-static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb)
+static int bh_enqueue(struct net_device *dev, struct sk_buff *skb)
 {
 	/* Check for full */
 	fr_channel_t* chan = dev->priv;
@@ -4438,7 +4445,7 @@
  *
  */	
 
-static void fr_bh (netdevice_t * dev)
+static void fr_bh(struct net_device * dev)
 {
 	fr_channel_t* chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -4485,7 +4492,7 @@
 	return;
 }
 
-static int fr_bh_cleanup (netdevice_t *dev)
+static int fr_bh_cleanup(struct net_device *dev)
 {
 	fr_channel_t* chan = dev->priv;
 
@@ -4519,7 +4526,7 @@
  *      a polling routine.
  *
  */	
-static void trigger_fr_poll (netdevice_t *dev)
+static void trigger_fr_poll(struct net_device *dev)
 {
 	fr_channel_t* chan = dev->priv;
 	schedule_task(&chan->fr_poll_task);
@@ -4549,7 +4556,7 @@
  *      the fr_poll routine.  
  */
 
-static void fr_poll (netdevice_t *dev)
+static void fr_poll(struct net_device *dev)
 {
 
 	fr_channel_t* chan;
@@ -4636,7 +4643,7 @@
  *      an interrupt.
  */
 
-static int check_tx_status(sdla_t *card, netdevice_t *dev)
+static int check_tx_status(sdla_t *card, struct net_device *dev)
 {
 
 	if (card->hw.type == SDLA_S514){
@@ -4666,14 +4673,13 @@
  *
  */
 
-netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev)
+struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev)
 {
 	if (card->wandev.new_if_cnt != 1){
-		if (*((netdevice_t **)dev->priv) == NULL){
+		if (!*((struct net_device **)dev->priv))
 			return card->wandev.dev;
-		}else{
-			return *((netdevice_t **)dev->priv);
-		}
+		else
+			return *((struct net_device **)dev->priv);
 	}
 	return dev;
 }
@@ -4723,10 +4729,11 @@
 
 static void config_fr (sdla_t *card)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	fr_channel_t *chan;
 
-	for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){
+	for (dev = card->wandev.dev; dev;
+	     dev = *((struct net_device **)dev->priv)) {
 	
 		if ((chan=dev->priv) == NULL)
 			continue;
@@ -4795,7 +4802,7 @@
  *
  */
 
-static void trigger_unconfig_fr (netdevice_t *dev)
+static void trigger_unconfig_fr(struct net_device *dev)
 {
 	fr_channel_t *chan = dev->priv;
 	volatile sdla_t *card = chan->card;
@@ -4847,10 +4854,11 @@
 
 static void unconfig_fr (sdla_t *card)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	fr_channel_t *chan;
 
-	for (dev=card->wandev.dev; dev; dev=*((netdevice_t **)dev->priv)){
+	for (dev = card->wandev.dev; dev;
+	     dev = *((struct net_device **)dev->priv)){
 	
 		if ((chan=dev->priv) == NULL)
 			continue;
@@ -4869,7 +4877,8 @@
 	}
 }
 
-static int setup_fr_header(struct sk_buff ** skb_orig, netdevice_t* dev, char op_mode)
+static int setup_fr_header(struct sk_buff **skb_orig, struct net_device* dev,
+			   char op_mode)
 {
 	struct sk_buff *skb = *skb_orig;
 	fr_channel_t *chan=dev->priv;
@@ -4927,7 +4936,7 @@
 	fr_conf_t *conf=NULL;
 	unsigned short dlci_num = chan->dlci;
 	int dlci_offset=0;
-	netdevice_t *dev=NULL;
+	struct net_device *dev = NULL;
 	
 	mbox->cmd.command = FR_READ_CONFIG;
 	mbox->cmd.length = 0;
@@ -4939,9 +4948,9 @@
 		return 0;
 	}
 
-	for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+	for (dev = card->wandev.dev; dev;
+	     dev=*((struct net_device **)dev->priv))
 		set_chan_state(dev,WAN_DISCONNECTED);
-	}
 	
 	printk(KERN_INFO "DLCI %i Not configured, configuring\n",dlci_num);
 	
@@ -4969,7 +4978,8 @@
 	conf = (fr_conf_t *)mbox->data;
 
 	dlci_offset=0;
-	for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+	for (dev = card->wandev.dev; dev;
+	     dev = *((struct net_device **)dev->priv)) {
 		fr_channel_t *chan_tmp = dev->priv;
 		conf->dlci[dlci_offset] = chan_tmp->dlci;		
 		dlci_offset++;
@@ -5003,7 +5013,8 @@
 
 	printk(KERN_INFO "Enabling Communications \n");
 
-	for (dev=card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+	for (dev = card->wandev.dev; dev;
+	     dev = *((struct net_device **)dev->priv)) {
 		fr_channel_t *chan_tmp = dev->priv;
 		fr_init_dlci(card,chan_tmp);
 		fr_add_dlci(card, chan_tmp->dlci);
diff -Nru a/drivers/net/wan/sdla_ft1.c b/drivers/net/wan/sdla_ft1.c
--- a/drivers/net/wan/sdla_ft1.c	Sun Feb 16 16:22:42 2003
+++ b/drivers/net/wan/sdla_ft1.c	Thu May 15 14:42:07 2003
@@ -70,7 +70,7 @@
 
 typedef struct chdlc_private_area
 {
-	netdevice_t 	*slave;
+	struct net_device *slave;
 	sdla_t		*card;
 	int 		TracingEnabled;		/* For enabling Tracing */
 	unsigned long 	curr_trace_addr;	/* Used for Tracing */
diff -Nru a/drivers/net/wan/sdla_ppp.c b/drivers/net/wan/sdla_ppp.c
--- a/drivers/net/wan/sdla_ppp.c	Thu Mar  6 09:25:30 2003
+++ b/drivers/net/wan/sdla_ppp.c	Sun May 18 08:18:07 2003
@@ -168,7 +168,7 @@
   
 typedef struct ppp_private_area
 {
-	netdevice_t *slave;
+	struct net_device *slave;
 	sdla_t* card;	
 	unsigned long router_start_time;	/*router start time in sec */
 	unsigned long tick_counter;		/*used for 5 second counter*/
@@ -231,25 +231,27 @@
 /****** Function Prototypes *************************************************/
 
 /* WAN link driver entry points. These are called by the WAN router module. */
-static int update(wan_device_t *wandev);
-static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf);
-static int del_if(wan_device_t *wandev, netdevice_t *dev);
+static int update(struct wan_device *wandev);
+static int new_if(struct wan_device *wandev, struct net_device *dev,
+		  wanif_conf_t *conf);
+static int del_if(struct wan_device *wandev, struct net_device *dev);
 
 /* WANPIPE-specific entry points */
 static int wpp_exec (struct sdla *card, void *u_cmd, void *u_data);
 
 /* Network device interface */
-static int if_init(netdevice_t *dev);
-static int if_open(netdevice_t *dev);
-static int if_close(netdevice_t *dev);
-static int if_header(struct sk_buff *skb, netdevice_t *dev, unsigned short type, 
+static int if_init(struct net_device *dev);
+static int if_open(struct net_device *dev);
+static int if_close(struct net_device *dev);
+static int if_header(struct sk_buff *skb, struct net_device *dev,
+		     unsigned short type, 
 		     void *daddr, void *saddr, unsigned len);
 
-static void if_tx_timeout (netdevice_t *dev);
+static void if_tx_timeout(struct net_device *dev);
 
 static int if_rebuild_hdr(struct sk_buff *skb);
-static struct net_device_stats *if_stats(netdevice_t *dev);
-static int if_send(struct sk_buff *skb, netdevice_t *dev);
+static struct net_device_stats *if_stats(struct net_device *dev);
+static int if_send(struct sk_buff *skb, struct net_device *dev);
 
 
 /* PPP firmware interface functions */
@@ -278,10 +280,10 @@
 static int read_info( sdla_t *card );
 static int read_connection_info (sdla_t *card);
 static void remove_route( sdla_t *card );
-static int config508(netdevice_t *dev, sdla_t *card);
+static int config508(struct net_device *dev, sdla_t *card);
 static void show_disc_cause(sdla_t * card, unsigned cause);
 static int reply_udp( unsigned char *data, unsigned int mbox_len );
-static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, 
+static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, 
 				ppp_private_area_t *ppp_priv_area);
 static void init_ppp_tx_rx_buff( sdla_t *card );
 static int intr_test( sdla_t *card );
@@ -290,12 +292,12 @@
 static void init_global_statistics( sdla_t *card );
 static int tokenize(char *str, char **tokens);
 static char* strstrip(char *str, char *s);
-static int chk_bcast_mcast_addr(sdla_t* card, netdevice_t* dev,
+static int chk_bcast_mcast_addr(sdla_t* card, struct net_device* dev,
 				struct sk_buff *skb);
 
 static int config_ppp (sdla_t *);
-static void ppp_poll(netdevice_t *);
-static void trigger_ppp_poll(netdevice_t *);
+static void ppp_poll(struct net_device *dev);
+static void trigger_ppp_poll(struct net_device *dev);
 static void ppp_poll_delay (unsigned long dev_ptr);
 
 
@@ -315,7 +317,7 @@
 static void s508_unlock (sdla_t *card, unsigned long *smp_flags);
 
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, netdevice_t* dev,
+                                struct sk_buff *skb, struct net_device* dev,
                                 ppp_private_area_t* ppp_priv_area );
 static unsigned short calc_checksum (char *data, int len);
 static void disable_comm (sdla_t *card);
@@ -444,10 +446,10 @@
 /*============================================================================
  * Update device status & statistics.
  */
-static int update(wan_device_t *wandev)
+static int update(struct wan_device *wandev)
 {
 	sdla_t* card = wandev->private;
- 	netdevice_t* dev;
+ 	struct net_device* dev;
         volatile ppp_private_area_t *ppp_priv_area;
 	ppp_flags_t *flags = card->flags;
 	unsigned long timeout;
@@ -504,7 +506,8 @@
  * Return:	0	o.k.
  *		< 0	failure (channel will not be created)
  */
-static int new_if(wan_device_t *wandev, netdevice_t *dev, wanif_conf_t *conf)
+static int new_if(struct wan_device *wandev, struct net_device *dev,
+		  wanif_conf_t *conf)
 {
 	sdla_t *card = wandev->private;
 	ppp_private_area_t *ppp_priv_area;
@@ -622,7 +625,7 @@
 /*============================================================================
  * Delete logical channel.
  */
-static int del_if(wan_device_t *wandev, netdevice_t *dev)
+static int del_if(struct wan_device *wandev, struct net_device *dev)
 {
 	return 0;
 }
@@ -681,11 +684,11 @@
  * interface registration.  Returning anything but zero will fail interface
  * registration.
  */
-static int if_init(netdevice_t *dev)
+static int if_init(struct net_device *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
-	wan_device_t *wandev = &card->wandev;
+	struct wan_device *wandev = &card->wandev;
 
 	/* Initialize device driver entry points */
 	dev->open		= &if_open;
@@ -719,6 +722,7 @@
 
         /* Set transmit buffer queue length */
         dev->tx_queue_len = 100;
+	SET_MODULE_OWNER(dev);
    
 	return 0;
 }
@@ -730,7 +734,7 @@
  *
  * Return 0 if O.k. or errno.
  */
-static int if_open (netdevice_t *dev)
+static int if_open(struct net_device *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
@@ -769,7 +773,7 @@
  * o if this is the last open, then disable communications and interrupts.
  * o reset flags.
  */
-static int if_close(netdevice_t *dev)
+static int if_close(struct net_device *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
@@ -790,7 +794,7 @@
  *
  * Return:	media header length.
  */
-static int if_header(struct sk_buff *skb, netdevice_t *dev,
+static int if_header(struct sk_buff *skb, struct net_device *dev,
 	unsigned short type, void *daddr, void *saddr, unsigned len)
 {
 	switch (type)
@@ -815,7 +819,7 @@
  */
 static int if_rebuild_hdr (struct sk_buff *skb)
 {
-	netdevice_t *dev = skb->dev;
+	struct net_device *dev = skb->dev;
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
 
@@ -827,7 +831,7 @@
 /*============================================================================
  * Handle transmit timeout event from netif watchdog
  */
-static void if_tx_timeout (netdevice_t *dev)
+static void if_tx_timeout(struct net_device *dev)
 {
     	ppp_private_area_t* chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -865,7 +869,7 @@
  * 2. Setting tbusy flag will inhibit further transmit requests from the
  *    protocol stack and can be used for flow control with protocol layer.
  */
-static int if_send (struct sk_buff *skb, netdevice_t *dev)
+static int if_send (struct sk_buff *skb, struct net_device *dev)
 {
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	sdla_t *card = ppp_priv_area->card;
@@ -995,7 +999,7 @@
  */
 
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, netdevice_t* dev,
+                                struct sk_buff *skb, struct net_device* dev,
                                 ppp_private_area_t* ppp_priv_area )
 {
 	int udp_pkt_stored = 0;
@@ -1189,7 +1193,7 @@
  * Get ethernet-style interface statistics.
  * Return a pointer to struct net_device_stats.
  */
-static struct net_device_stats *if_stats(netdevice_t *dev)
+static struct net_device_stats *if_stats(struct net_device *dev)
 {
 
 	ppp_private_area_t *ppp_priv_area = dev->priv;
@@ -1569,7 +1573,7 @@
 {
 	ppp_flags_t *flags = card->flags;
 	char *ptr = &flags->iflag;
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	int i;
 
 	card->in_isr = 1;
@@ -1649,7 +1653,7 @@
 static void rx_intr(sdla_t *card)
 {
 	ppp_buf_ctl_t *rxbuf = card->rxmb;
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	ppp_private_area_t *ppp_priv_area;
 	struct sk_buff *skb;
 	unsigned len;
@@ -1789,7 +1793,7 @@
 void event_intr (sdla_t *card)
 {
 
- 	netdevice_t* dev = card->wandev.dev;
+ 	struct net_device* dev = card->wandev.dev;
         ppp_private_area_t* ppp_priv_area = dev->priv;
 	volatile ppp_flags_t *flags = card->flags;
 
@@ -1908,7 +1912,7 @@
 void timer_intr (sdla_t *card)
 {
 
-        netdevice_t* dev = card->wandev.dev;
+        struct net_device* dev = card->wandev.dev;
         ppp_private_area_t* ppp_priv_area = dev->priv;
 	ppp_flags_t *flags = card->flags;
 
@@ -2105,7 +2109,7 @@
 static void process_route (sdla_t *card)
 {
 	ppp_flags_t *flags = card->flags;
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	
 	if ((card->u.p.ip_mode == WANOPT_PPP_PEER) &&
@@ -2147,7 +2151,7 @@
  */
 static void retrigger_comm(sdla_t *card)
 {
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 
 	if (dev && ((jiffies - card->state_tick) > HOLD_DOWN_TIME)) {
 
@@ -2164,7 +2168,7 @@
 /*============================================================================
  * Configure S508 adapter.
  */
-static int config508(netdevice_t *dev, sdla_t *card)
+static int config508(struct net_device *dev, sdla_t *card)
 {
 	ppp508_conf_t cfg;
 	struct in_device *in_dev = dev->ip_ptr;
@@ -2336,7 +2340,7 @@
 /*=============================================================================
  * Process UDP call of type PTPIPEAB.
  */
-static void process_udp_mgmt_pkt(sdla_t *card, netdevice_t *dev, 
+static void process_udp_mgmt_pkt(sdla_t *card, struct net_device *dev, 
 				 ppp_private_area_t *ppp_priv_area ) 
 {
 	unsigned char buf2[5];
@@ -2847,7 +2851,7 @@
  */
 static int read_info( sdla_t *card )
 {
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	int err;
 
@@ -2896,7 +2900,7 @@
 static void remove_route( sdla_t *card )
 {
 
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	long ip_addr;
 	int err;
 
@@ -3022,7 +3026,7 @@
  * multicast source IP address.
  */
 
-static int chk_bcast_mcast_addr(sdla_t *card, netdevice_t* dev,
+static int chk_bcast_mcast_addr(sdla_t *card, struct net_device* dev,
 				struct sk_buff *skb)
 {
 	u32 src_ip_addr;
@@ -3073,7 +3077,7 @@
 static int read_connection_info (sdla_t *card)
 {
 	ppp_mbox_t *mb = card->mbox;
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 	ppp508_connect_info_t *ppp508_connect_info;
 	int err;
@@ -3122,7 +3126,7 @@
 static int config_ppp (sdla_t *card)
 {
 
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	ppp_flags_t *flags = card->flags;
 	ppp_private_area_t *ppp_priv_area = dev->priv;
 
@@ -3230,7 +3234,7 @@
  *      trigger_ppp_poll() function is used to kick
  *      the ppp_poll routine.  
  */
-static void ppp_poll (netdevice_t *dev)
+static void ppp_poll(struct net_device *dev)
 {
 	ppp_private_area_t *ppp_priv_area; 	
 	sdla_t *card;
@@ -3375,7 +3379,7 @@
  *
  */	
 
-static void trigger_ppp_poll (netdevice_t *dev)
+static void trigger_ppp_poll(struct net_device *dev)
 {
 	ppp_private_area_t *ppp_priv_area;
 	if ((ppp_priv_area=dev->priv) != NULL){ 	
@@ -3397,7 +3401,7 @@
 
 static void ppp_poll_delay (unsigned long dev_ptr)
 {
-	netdevice_t *dev = (netdevice_t *)dev_ptr;
+	struct net_device *dev = (struct net_device *)dev_ptr;
 	trigger_ppp_poll(dev);
 }
 
diff -Nru a/drivers/net/wan/sdla_x25.c b/drivers/net/wan/sdla_x25.c
--- a/drivers/net/wan/sdla_x25.c	Thu Mar  6 09:25:30 2003
+++ b/drivers/net/wan/sdla_x25.c	Sun May 18 08:18:07 2003
@@ -241,7 +241,7 @@
  *	
  * Assumptions:
  *
- * Description:	This is an extention of the 'netdevice_t' 
+ * Description:	This is an extention of the struct net_device
  *              we create for each network interface to keep 
  *              the rest of X.25 channel-specific data. 
  *
@@ -271,7 +271,7 @@
 	atomic_t  bh_buff_used;
 
 	sdla_t* card;			/* -> owner */
-	netdevice_t *dev;		/* -> bound devce */
+	struct net_device *dev;		/* -> bound devce */
 
 	int ch_idx;
 	unsigned char enable_IPX;
@@ -330,10 +330,10 @@
  * WAN link driver entry points. These are 
  * called by the WAN router module.
  */
-static int update (wan_device_t* wandev);
-static int new_if (wan_device_t* wandev, netdevice_t* dev,
-	wanif_conf_t* conf);
-static int del_if (wan_device_t* wandev, netdevice_t* dev);
+static int update(struct wan_device* wandev);
+static int new_if(struct wan_device* wandev, struct net_device* dev,
+		  wanif_conf_t* conf);
+static int del_if(struct wan_device* wandev, struct net_device* dev);
 static void disable_comm (sdla_t* card);
 static void disable_comm_shutdown(sdla_t *card);
 
@@ -343,24 +343,24 @@
  *	WANPIPE-specific entry points 
  */
 static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data);
-static void x25api_bh (netdevice_t *);
-static int x25api_bh_cleanup (netdevice_t *);
-static int bh_enqueue (netdevice_t *, struct sk_buff *);
+static void x25api_bh(struct net_device *dev);
+static int x25api_bh_cleanup(struct net_device *dev);
+static int bh_enqueue(struct net_device *dev, struct sk_buff *skb);
 
 
 /*=================================================  
  * 	Network device interface 
  */
-static int if_init   (netdevice_t* dev);
-static int if_open   (netdevice_t* dev);
-static int if_close  (netdevice_t* dev);
-static int if_header (struct sk_buff* skb, netdevice_t* dev,
+static int if_init(struct net_device* dev);
+static int if_open(struct net_device* dev);
+static int if_close(struct net_device* dev);
+static int if_header(struct sk_buff* skb, struct net_device* dev,
 	unsigned short type, void* daddr, void* saddr, unsigned len);
 static int if_rebuild_hdr (struct sk_buff* skb);
-static int if_send (struct sk_buff* skb, netdevice_t* dev);
-static struct net_device_stats *if_stats (netdevice_t* dev);
+static int if_send(struct sk_buff* skb, struct net_device* dev);
+static struct net_device_stats *if_stats(struct net_device* dev);
 
-static void if_tx_timeout (netdevice_t *dev);
+static void if_tx_timeout(struct net_device *dev);
 
 /*=================================================  
  * 	Interrupt handlers 
@@ -373,8 +373,9 @@
 static void spur_intr	(sdla_t *);
 static void timer_intr  (sdla_t *);
 
-static int tx_intr_send(sdla_t *, netdevice_t *);
-static netdevice_t * move_dev_to_next (sdla_t *, netdevice_t *);
+static int tx_intr_send(sdla_t *card, struct net_device *dev);
+static struct net_device *move_dev_to_next(sdla_t *card,
+					   struct net_device *dev);
 
 /*=================================================  
  *	Background polling routines 
@@ -425,35 +426,41 @@
  */
 static int connect (sdla_t* card);
 static int disconnect (sdla_t* card);
-static netdevice_t* get_dev_by_lcn(wan_device_t* wandev, unsigned lcn);
-static int chan_connect (netdevice_t* dev);
-static int chan_disc (netdevice_t* dev);
-static void set_chan_state (netdevice_t* dev, int state);
-static int chan_send (netdevice_t* , void* , unsigned, unsigned char);
+static struct net_device* get_dev_by_lcn(struct wan_device* wandev,
+					 unsigned lcn);
+static int chan_connect(struct net_device* dev);
+static int chan_disc(struct net_device* dev);
+static void set_chan_state(struct net_device* dev, int state);
+static int chan_send(struct net_device *dev, void* buff, unsigned data_len,
+		     unsigned char tx_intr);
 static unsigned char bps_to_speed_code (unsigned long bps);
 static unsigned int dec_to_uint (unsigned char* str, int len);
 static unsigned int hex_to_uint (unsigned char*, int);
 static void parse_call_info (unsigned char*, x25_call_info_t*);
-static netdevice_t * find_channel(sdla_t *, unsigned);
-static void bind_lcn_to_dev (sdla_t *, netdevice_t *,unsigned);
-static void setup_for_delayed_transmit (netdevice_t*, void*, unsigned);
+static struct net_device *find_channel(sdla_t *card, unsigned lcn);
+static void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn);
+static void setup_for_delayed_transmit(struct net_device *dev,
+				       void *buf, unsigned len);
 
 
 /*=================================================  
  *      X25 API Functions 
  */
-static int wanpipe_pull_data_in_skb (sdla_t *, netdevice_t *, struct sk_buff **);
+static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev,
+				    struct sk_buff **);
 static void timer_intr_exec(sdla_t *, unsigned char);
-static int execute_delayed_cmd (sdla_t*, netdevice_t *, mbox_cmd_t *,char);
+static int execute_delayed_cmd(sdla_t *card, struct net_device *dev,
+			       mbox_cmd_t *usr_cmd, char bad_cmd);
 static int api_incoming_call (sdla_t*, TX25Mbox *, int);
 static int alloc_and_init_skb_buf (sdla_t *,struct sk_buff **, int);
-static void send_delayed_cmd_result(sdla_t *, netdevice_t *dev, TX25Mbox*);
+static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev,
+				    TX25Mbox* mbox);
 static int clear_confirm_event (sdla_t *, TX25Mbox*);
-static void send_oob_msg (sdla_t *, netdevice_t *, TX25Mbox *);
+static void send_oob_msg (sdla_t *card, struct net_device *dev, TX25Mbox *mbox);
 static int timer_intr_cmd_exec(sdla_t *card);
 static void api_oob_event (sdla_t *card,TX25Mbox *mbox);
-static int check_bad_command (sdla_t *, netdevice_t *);
-static int channel_disconnect (sdla_t*, netdevice_t *);
+static int check_bad_command(sdla_t *card, struct net_device *dev);
+static int channel_disconnect(sdla_t* card, struct net_device *dev);
 static void hdlc_link_down (sdla_t*);
 
 /*=================================================
@@ -464,7 +471,9 @@
 static int reply_udp( unsigned char *, unsigned int); 
 static void init_x25_channel_struct( x25_channel_t *);
 static void init_global_statistics( sdla_t *);
-static int store_udp_mgmt_pkt(int, char, sdla_t*, netdevice_t *, struct sk_buff *, int);
+static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t *card,
+			      struct net_device *dev,
+			      struct sk_buff *skb, int lcn);
 static unsigned short calc_checksum (char *, int);
 
 
@@ -830,7 +839,7 @@
  * 		<0	Failed (or busy).
  */
 
-static int update (wan_device_t* wandev)
+static int update(struct wan_device* wandev)
 {
 	volatile sdla_t* card;
 	TX25Status* status;
@@ -895,7 +904,8 @@
  * Return: 	0 	Ok
  *		<0 	Failed (channel will not be created)
  */
-static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf)
+static int new_if(struct wan_device* wandev, struct net_device* dev,
+		  wanif_conf_t* conf)
 {
 	sdla_t* card = wandev->private;
 	x25_channel_t* chan;
@@ -1029,7 +1039,7 @@
 
 //FIXME Del IF Should be taken out now.
 
-static int del_if (wan_device_t* wandev, netdevice_t* dev)
+static int del_if(struct wan_device* wandev, struct net_device* dev)
 {
 	return 0;
 }
@@ -1095,11 +1105,11 @@
  *
  * Return: 	0 	Ok : Void function.
  */
-static int if_init (netdevice_t* dev)
+static int if_init(struct net_device* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
-	wan_device_t* wandev = &card->wandev;
+	struct wan_device* wandev = &card->wandev;
 
 	/* Initialize device driver entry points */
 	dev->open		= &if_open;
@@ -1138,6 +1148,7 @@
 
         /* Set transmit buffer queue length */
         dev->tx_queue_len = 100;
+	SET_MODULE_OWNER(dev);
 
 	/* FIXME Why are we doing this */
 	set_chan_state(dev, WAN_DISCONNECTED);
@@ -1167,7 +1178,7 @@
  * 		<0 	Failur: Interface will not come up.
  */
 
-static int if_open (netdevice_t* dev)
+static int if_open(struct net_device* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -1260,7 +1271,7 @@
  * Return: 	0 	Ok
  * 		<0 	Failure: Interface will not exit properly.
  */
-static int if_close (netdevice_t* dev)
+static int if_close(struct net_device* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -1318,8 +1329,9 @@
  * 	Return:		media header length.
  *======================================================================*/
 
-static int if_header (struct sk_buff* skb, netdevice_t* dev,
-	unsigned short type, void* daddr, void* saddr, unsigned len)
+static int if_header(struct sk_buff* skb, struct net_device* dev,
+		     unsigned short type, void* daddr, void* saddr,
+		     unsigned len)
 {
 	x25_channel_t* chan = dev->priv;
 	int hdr_len = dev->hard_header_len;
@@ -1344,7 +1356,7 @@
 
 static int if_rebuild_hdr (struct sk_buff* skb)
 {
-	netdevice_t *dev = skb->dev; 
+	struct net_device *dev = skb->dev; 
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
 
@@ -1357,7 +1369,7 @@
 /*============================================================================
  * Handle transmit timeout event from netif watchdog
  */
-static void if_tx_timeout (netdevice_t *dev)
+static void if_tx_timeout(struct net_device *dev)
 {
     	x25_channel_t* chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -1394,7 +1406,7 @@
  *
  *========================================================================*/
 
-static int if_send (struct sk_buff* skb, netdevice_t* dev)
+static int if_send(struct sk_buff* skb, struct net_device* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -1527,8 +1539,8 @@
  * interrupt.
  *===========================================================================*/
 
-static void setup_for_delayed_transmit (netdevice_t* dev, void* buf,
-	unsigned len)
+static void setup_for_delayed_transmit(struct net_device* dev, void* buf,
+				       unsigned len)
 {
         x25_channel_t* chan = dev->priv;
         sdla_t* card = chan->card;
@@ -1579,7 +1591,7 @@
  * 	Return a pointer to struct enet_statistics.
  *
  *==============================================================*/
-static struct net_device_stats *if_stats (netdevice_t* dev)
+static struct net_device_stats *if_stats(struct net_device* dev)
 {
 	x25_channel_t *chan = dev->priv;
 
@@ -1675,7 +1687,7 @@
 {
 	TX25Mbox* rxmb = card->rxmb;
 	unsigned lcn = rxmb->cmd.lcn;
-	netdevice_t* dev = find_channel(card,lcn);
+	struct net_device* dev = find_channel(card,lcn);
 	x25_channel_t* chan;
 	struct sk_buff* skb=NULL;
 
@@ -1773,7 +1785,8 @@
 }
 
 
-static int wanpipe_pull_data_in_skb (sdla_t *card, netdevice_t *dev, struct sk_buff **skb)
+static int wanpipe_pull_data_in_skb(sdla_t *card, struct net_device *dev,
+				    struct sk_buff **skb)
 {
 	void *bufptr;
 	TX25Mbox* rxmb = card->rxmb;
@@ -1883,7 +1896,7 @@
 
 static void tx_intr (sdla_t* card)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	TX25Status* status = card->flags;
 	unsigned char more_to_tx=0;
 	x25_channel_t *chan=NULL;
@@ -1977,14 +1990,13 @@
  *===============================================================*/
 
 
-netdevice_t * move_dev_to_next (sdla_t *card, netdevice_t *dev)
+struct net_device *move_dev_to_next(sdla_t *card, struct net_device *dev)
 {
 	if (card->u.x.no_dev != 1){
-		if (*((netdevice_t**)dev->priv) == NULL){
+		if (!*((struct net_device **)dev->priv))
 			return card->wandev.dev;
-		}else{
-			return *((netdevice_t**)dev->priv);
-		}
+		else
+			return *((struct net_device **)dev->priv);
 	}
 	return dev;
 }
@@ -1995,7 +2007,7 @@
  *
  *===============================================================*/
 
-static int tx_intr_send(sdla_t *card, netdevice_t *dev)
+static int tx_intr_send(sdla_t *card, struct net_device *dev)
 {
 	x25_channel_t* chan = dev->priv; 
 
@@ -2058,7 +2070,7 @@
 
 	}else if (card->u.x.timer_int_enabled & TMR_INT_ENABLED_POLL_ACTIVE) {
 
-		netdevice_t *dev = card->u.x.poll_device;
+		struct net_device *dev = card->u.x.poll_device;
 		x25_channel_t *chan = NULL;
 
 		if (!dev){
@@ -2079,7 +2091,7 @@
 
 		wanpipe_set_state(card, WAN_CONNECTED);
 		if (card->u.x.LAPB_hdlc){
-			netdevice_t *dev = card->wandev.dev;
+			struct net_device *dev = card->wandev.dev;
 			set_chan_state(dev,WAN_CONNECTED);
 			send_delayed_cmd_result(card,dev,card->mbox);	
 		}
@@ -2135,7 +2147,7 @@
 
 	TX25Mbox* mbox = card->mbox;
 	TX25ModemStatus *modem_status;
-	netdevice_t *dev;
+	struct net_device *dev;
 	x25_channel_t *chan;
 	int err;
 
@@ -2164,7 +2176,8 @@
 				mbox->cmd.result = 0x08;
 
 				/* Send a OOB to all connected sockets */
-				for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){
+				for (dev = card->wandev.dev; dev;
+				     dev = *((struct net_device**)dev->priv)) {
 					chan=dev->priv;
 					if (chan->common.usedby == API){
 						send_oob_msg(card,dev,mbox);				
@@ -2294,7 +2307,7 @@
 
 static void poll_disconnected (sdla_t* card)
 {
-	netdevice_t *dev; 
+	struct net_device *dev; 
 	x25_channel_t *chan;
 	TX25Status* status = card->flags;
 
@@ -2331,10 +2344,11 @@
 
 static void poll_active (sdla_t* card)
 {
-	netdevice_t* dev;
+	struct net_device* dev;
 	TX25Status* status = card->flags;
 
-	for (dev = card->wandev.dev; dev; dev = *((netdevice_t**)dev->priv)){
+	for (dev = card->wandev.dev; dev;
+	     dev = *((struct net_device **)dev->priv)){
 		x25_channel_t* chan = dev->priv;
 
 		/* If SVC has been idle long enough, close virtual circuit */
@@ -3101,9 +3115,9 @@
 
 static int incoming_call (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
 {
-	wan_device_t* wandev = &card->wandev;
+	struct wan_device* wandev = &card->wandev;
 	int new_lcn = mb->cmd.lcn;
-	netdevice_t* dev = get_dev_by_lcn(wandev, new_lcn);
+	struct net_device* dev = get_dev_by_lcn(wandev, new_lcn);
 	x25_channel_t* chan = NULL;
 	int accept = 0;		/* set to '1' if o.k. to accept call */
 	unsigned int user_data;
@@ -3155,7 +3169,7 @@
 	user_data = hex_to_uint(info->user,2);
 
 	/* Find available channel */
-	for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)){
+	for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) {
 		chan = dev->priv;
 
 		if (chan->common.usedby == API)
@@ -3252,7 +3266,7 @@
 static int call_accepted (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
 {
 	unsigned new_lcn = mb->cmd.lcn;
-	netdevice_t* dev = find_channel(card, new_lcn);
+	struct net_device* dev = find_channel(card, new_lcn);
 	x25_channel_t* chan;
 
 	if (dev == NULL){
@@ -3292,7 +3306,7 @@
 static int call_cleared (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
 {
 	unsigned new_lcn = mb->cmd.lcn;
-	netdevice_t* dev = find_channel(card, new_lcn);
+	struct net_device* dev = find_channel(card, new_lcn);
 	x25_channel_t *chan;
 	unsigned char old_state;
 
@@ -3336,8 +3350,8 @@
 
 static int restart_event (sdla_t* card, int cmd, int lcn, TX25Mbox* mb)
 {
-	wan_device_t* wandev = &card->wandev;
-	netdevice_t* dev;
+	struct wan_device* wandev = &card->wandev;
+	struct net_device* dev;
 	x25_channel_t *chan;
 	unsigned char old_state;
 
@@ -3346,7 +3360,7 @@
 		card->devname, mb->cmd.cause, mb->cmd.diagn);
 
 	/* down all logical channels */
-	for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv)){
+	for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv)) {
 		chan=dev->priv;
 		old_state = chan->common.state;
 
@@ -3377,7 +3391,7 @@
 
 	if (mb->cmd.pktType == 0x05)	/* call request time out */
 	{
-		netdevice_t* dev = find_channel(card,new_lcn);
+		struct net_device* dev = find_channel(card,new_lcn);
 
 		printk(KERN_INFO "%s: X.25 call timed timeout on LCN %d!\n",
 			card->devname, new_lcn);
@@ -3447,11 +3461,12 @@
  * Find network device by its channel number.
  */
 
-static netdevice_t* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
+static struct net_device* get_dev_by_lcn(struct wan_device* wandev,
+					 unsigned lcn)
 {
-	netdevice_t* dev;
+	struct net_device* dev;
 
-	for (dev = wandev->dev; dev; dev = *((netdevice_t**)dev->priv))
+	for (dev = wandev->dev; dev; dev = *((struct net_device **)dev->priv))
 		if (((x25_channel_t*)dev->priv)->common.lcn == lcn) 
 			break;
 	return dev;
@@ -3467,7 +3482,7 @@
  *			<0	failure
  */
 
-static int chan_connect (netdevice_t* dev)
+static int chan_connect(struct net_device* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -3500,7 +3515,7 @@
  * 	o if SVC then clear X.25 call
  */
 
-static int chan_disc (netdevice_t* dev)
+static int chan_disc(struct net_device* dev)
 {
 	x25_channel_t* chan = dev->priv;
 
@@ -3523,7 +3538,7 @@
  * 	Set logical channel state.
  */
 
-static void set_chan_state (netdevice_t* dev, int state)
+static void set_chan_state(struct net_device* dev, int state)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -3613,7 +3628,8 @@
  *    	to the router.
  */
 
-static int chan_send (netdevice_t* dev, void* buff, unsigned data_len, unsigned char tx_intr)
+static int chan_send(struct net_device* dev, void* buff, unsigned data_len,
+		     unsigned char tx_intr)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -4080,7 +4096,7 @@
  *===============================================================*/
 
 
-netdevice_t * find_channel(sdla_t *card, unsigned lcn)
+struct net_device *find_channel(sdla_t *card, unsigned lcn)
 {
 	if (card->u.x.LAPB_hdlc){
 
@@ -4127,7 +4143,7 @@
 	}
 }
 
-void bind_lcn_to_dev (sdla_t *card, netdevice_t *dev,unsigned lcn)
+void bind_lcn_to_dev(sdla_t *card, struct net_device *dev, unsigned lcn)
 {
 	x25_channel_t *chan = dev->priv;
 
@@ -4154,7 +4170,7 @@
  *
  *==============================================================*/
 
-static void x25api_bh (netdevice_t * dev)
+static void x25api_bh(struct net_device* dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t* card = chan->card;
@@ -4230,7 +4246,7 @@
  *
  *==============================================================*/
 
-static int x25api_bh_cleanup (netdevice_t *dev)
+static int x25api_bh_cleanup(struct net_device *dev)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -4269,7 +4285,7 @@
  *
  *==============================================================*/
 
-static int bh_enqueue (netdevice_t *dev, struct sk_buff *skb)
+static int bh_enqueue(struct net_device *dev, struct sk_buff *skb)
 {
 	x25_channel_t* chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -4309,7 +4325,7 @@
 
 static int timer_intr_cmd_exec (sdla_t* card)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	unsigned char more_to_exec=0;
 	volatile x25_channel_t *chan=NULL;
 	int i=0,bad_cmd=0,err=0;	
@@ -4436,7 +4452,8 @@
  *
  *===============================================================*/
 
-static int execute_delayed_cmd (sdla_t* card, netdevice_t *dev, mbox_cmd_t *usr_cmd,char bad_cmd)
+static int execute_delayed_cmd(sdla_t* card, struct net_device *dev,
+			       mbox_cmd_t *usr_cmd, char bad_cmd)
 {
 	TX25Mbox* mbox = card->mbox;
 	int err;
@@ -4669,7 +4686,8 @@
  *      the result to a waiting sock. 
  *
  *===============================================================*/
-static void send_delayed_cmd_result(sdla_t *card, netdevice_t *dev, TX25Mbox* mbox)
+static void send_delayed_cmd_result(sdla_t *card, struct net_device *dev,
+				    TX25Mbox* mbox)
 {
 	x25_channel_t *chan = dev->priv;
 	mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox;
@@ -4724,7 +4742,7 @@
 
 static int clear_confirm_event (sdla_t *card, TX25Mbox* mb)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	x25_channel_t *chan;
 	unsigned char old_state;	
 
@@ -4772,7 +4790,7 @@
  *
  *===============================================================*/
 
-static void send_oob_msg (sdla_t *card, netdevice_t *dev, TX25Mbox *mbox)
+static void send_oob_msg(sdla_t *card, struct net_device *dev, TX25Mbox *mbox)
 {
 	x25_channel_t *chan = dev->priv;
 	mbox_cmd_t *usr_cmd = (mbox_cmd_t *)chan->common.mbox;
@@ -4870,7 +4888,7 @@
 
 static void api_oob_event (sdla_t *card,TX25Mbox *mbox)
 {
-	netdevice_t *dev = find_channel(card,mbox->cmd.lcn);
+	struct net_device *dev = find_channel(card, mbox->cmd.lcn);
 	x25_channel_t *chan;
 
 	if (!dev)
@@ -4886,7 +4904,7 @@
 
 
 
-static int channel_disconnect (sdla_t* card, netdevice_t *dev)
+static int channel_disconnect(sdla_t* card, struct net_device *dev)
 {
 
 	int err;
@@ -4960,7 +4978,7 @@
 	
 }
 
-static int check_bad_command (sdla_t* card, netdevice_t *dev)
+static int check_bad_command(sdla_t* card, struct net_device *dev)
 {
 	x25_channel_t *chan = dev->priv;
 	int bad_cmd = 0;
@@ -5013,7 +5031,7 @@
 	TX25Mbox       *mbox = card->mbox;
 	int            err;
 	int            udp_mgmt_req_valid = 1;
-	netdevice_t  *dev;
+	struct net_device *dev;
         x25_channel_t  *chan;
 	unsigned short lcn;
 	struct timeval tv;
@@ -5337,7 +5355,8 @@
  */
 
 static int store_udp_mgmt_pkt(int udp_type, char udp_pkt_src, sdla_t* card,
-                                netdevice_t *dev, struct sk_buff *skb, int lcn)
+			      struct net_device *dev, struct sk_buff *skb,
+			      int lcn)
 {
         int udp_pkt_stored = 0;
 
diff -Nru a/drivers/net/wan/sdlamain.c b/drivers/net/wan/sdlamain.c
--- a/drivers/net/wan/sdlamain.c	Sun Apr 27 20:36:21 2003
+++ b/drivers/net/wan/sdlamain.c	Thu May 15 14:42:07 2003
@@ -64,8 +64,6 @@
 #include <linux/sdlapci.h>
 #include <linux/if_wanpipe_common.h>
 
-#define netdevice_t struct net_device
-
 #include <asm/uaccess.h>	/* kernel <-> user copy */
 #include <linux/inetdevice.h>
 
@@ -184,9 +182,9 @@
 void cleanup_module (void);
 
 /* WAN link driver entry points */
-static int setup    (wan_device_t* wandev, wandev_conf_t* conf);
-static int shutdown (wan_device_t* wandev);
-static int ioctl    (wan_device_t* wandev, unsigned cmd, unsigned long arg);
+static int setup(struct wan_device* wandev, wandev_conf_t* conf);
+static int shutdown(struct wan_device* wandev);
+static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg);
 
 /* IOCTL handlers */
 static int ioctl_dump	(sdla_t* card, sdla_dump_t* u_dump);
@@ -279,7 +277,7 @@
 	/* Register adapters with WAN router */
 	for (cnt = 0; cnt < ncards; ++ cnt) {
 		sdla_t* card = &card_array[cnt];
-		wan_device_t* wandev = &card->wandev;
+		struct wan_device* wandev = &card->wandev;
 
 		card->next = NULL;
 		sprintf(card->devname, "%s%d", drvname, cnt + 1);
@@ -352,7 +350,7 @@
  * any).
  */
  
-static int setup (wan_device_t* wandev, wandev_conf_t* conf)
+static int setup(struct wan_device* wandev, wandev_conf_t* conf)
 {
 	sdla_t* card;
 	int err = 0;
@@ -779,7 +777,7 @@
  * This function is called by the router when device is being unregistered or
  * when it handles ROUTER_DOWN IOCTL.
  */
-static int shutdown (wan_device_t* wandev)
+static int shutdown(struct wan_device* wandev)
 {
 	sdla_t *card;
 	int err=0;
@@ -888,7 +886,7 @@
  * This function is called when router handles one of the reserved user
  * IOCTLs.  Note that 'arg' stil points to user address space.
  */
-static int ioctl (wan_device_t* wandev, unsigned cmd, unsigned long arg)
+static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg)
 {
 	sdla_t* card;
 	int err;
@@ -1255,7 +1253,7 @@
 	}
 } 
 
-void wakeup_sk_bh (netdevice_t *dev)
+void wakeup_sk_bh(struct net_device *dev)
 {
 	wanpipe_common_t *chan = dev->priv;
 
@@ -1268,7 +1266,7 @@
 	}
 }
 
-int change_dev_flags (netdevice_t *dev, unsigned flags)
+int change_dev_flags(struct net_device *dev, unsigned flags)
 {
 	struct ifreq if_info;
 	mm_segment_t fs = get_fs();
@@ -1285,7 +1283,7 @@
 	return err;
 }
 
-unsigned long get_ip_address (netdevice_t *dev, int option)
+unsigned long get_ip_address(struct net_device *dev, int option)
 {
 	
 	struct in_ifaddr *ifaddr;
@@ -1323,7 +1321,7 @@
 	return 0;
 }	
 
-void add_gateway(sdla_t *card, netdevice_t *dev)
+void add_gateway(sdla_t *card, struct net_device *dev)
 {
 	mm_segment_t oldfs;
 	struct rtentry route;
diff -Nru a/drivers/net/wan/wanpipe_multppp.c b/drivers/net/wan/wanpipe_multppp.c
--- a/drivers/net/wan/wanpipe_multppp.c	Thu Mar  6 09:25:30 2003
+++ b/drivers/net/wan/wanpipe_multppp.c	Thu May 15 14:42:07 2003
@@ -130,19 +130,19 @@
 
 /****** Function Prototypes *************************************************/
 /* WAN link driver entry points. These are called by the WAN router module. */
-static int update (wan_device_t* wandev);
-static int new_if (wan_device_t* wandev, netdevice_t* dev,
-	wanif_conf_t* conf);
-static int del_if (wan_device_t* wandev, netdevice_t* dev);
+static int update(struct wan_device* wandev);
+static int new_if(struct wan_device* wandev, struct net_device* dev,
+		  wanif_conf_t* conf);
+static int del_if(struct wan_device* wandev, struct net_device* dev);
 
 /* Network device interface */
-static int if_init   (netdevice_t* dev);
-static int if_open   (netdevice_t* dev);
-static int if_close  (netdevice_t* dev);
-static int if_send (struct sk_buff* skb, netdevice_t* dev);
-static struct net_device_stats* if_stats (netdevice_t* dev);
+static int if_init(struct net_device* dev);
+static int if_open(struct net_device* dev);
+static int if_close(struct net_device* dev);
+static int if_send(struct sk_buff* skb, struct net_device* dev);
+static struct net_device_stats* if_stats(struct net_device* dev);
 
-static void if_tx_timeout (netdevice_t *dev);
+static void if_tx_timeout(struct net_device *dev);
 
 /* CHDLC Firmware interface functions */
 static int chdlc_configure 	(sdla_t* card, void* data);
@@ -158,7 +158,7 @@
 
 /* Miscellaneous CHDLC Functions */
 static int set_chdlc_config (sdla_t* card);
-static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev );
+static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev);
 static int chdlc_error (sdla_t *card, int err, CHDLC_MAILBOX_STRUCT *mb);
 static int process_chdlc_exception(sdla_t *card);
 static int process_global_exception(sdla_t *card);
@@ -176,14 +176,14 @@
 static int intr_test( sdla_t* card);
 static int udp_pkt_type( struct sk_buff *skb , sdla_t* card);
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, netdevice_t* dev,
-                                chdlc_private_area_t* chdlc_priv_area);
-static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,  
+			      struct sk_buff *skb, struct net_device* dev,
+			      chdlc_private_area_t* chdlc_priv_area);
+static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,  
 				chdlc_private_area_t* chdlc_priv_area);
 static unsigned short calc_checksum (char *, int);
 static void s508_lock (sdla_t *card, unsigned long *smp_flags);
 static void s508_unlock (sdla_t *card, unsigned long *smp_flags);
-static void send_ppp_term_request (netdevice_t*);
+static void send_ppp_term_request(struct net_device *dev);
 
 
 static int  Intr_test_counter;
@@ -456,10 +456,10 @@
  * as to minimize the time that we are inside the interrupt handler.
  *
  */
-static int update (wan_device_t* wandev)
+static int update(struct wan_device* wandev)
 {
 	sdla_t* card = wandev->private;
- 	netdevice_t* dev;
+ 	struct net_device* dev;
         volatile chdlc_private_area_t* chdlc_priv_area;
         SHARED_MEMORY_INFO_STRUCT *flags;
 	unsigned long timeout;
@@ -522,11 +522,12 @@
  * Return:	0	o.k.
  *		< 0	failure (channel will not be created)
  */
-static int new_if (wan_device_t* wandev, netdevice_t* pdev, wanif_conf_t* conf)
+static int new_if(struct wan_device* wandev, struct net_device* pdev,
+		  wanif_conf_t* conf)
 {
 
 	struct ppp_device *pppdev = (struct ppp_device *)pdev;
-	netdevice_t *dev=NULL;
+	struct net_device *dev = NULL;
 	struct sppp *sp;
 	sdla_t* card = wandev->private;
 	chdlc_private_area_t* chdlc_priv_area;
@@ -616,7 +617,7 @@
 /*============================================================================
  * Delete logical channel.
  */
-static int del_if (wan_device_t* wandev, netdevice_t* dev)
+static int del_if(struct wan_device* wandev, struct net_device* dev)
 {
 	chdlc_private_area_t *chdlc_priv_area = dev->priv;
 	sdla_t *card = chdlc_priv_area->card;
@@ -651,11 +652,11 @@
  * interface registration.  Returning anything but zero will fail interface
  * registration.
  */
-static int if_init (netdevice_t* dev)
-	{
+static int if_init(struct net_device* dev)
+{
 	chdlc_private_area_t* chdlc_priv_area = dev->priv;
 	sdla_t* card = chdlc_priv_area->card;
-	wan_device_t* wandev = &card->wandev;
+	struct wan_device* wandev = &card->wandev;
 	
 	/* NOTE: Most of the dev initialization was
          *       done in sppp_attach(), called by new_if() 
@@ -694,7 +695,7 @@
 /*============================================================================
  * Handle transmit timeout event from netif watchdog
  */
-static void if_tx_timeout (netdevice_t *dev)
+static void if_tx_timeout(struct net_device *dev)
 {
     	chdlc_private_area_t* chan = dev->priv;
 	sdla_t *card = chan->card;
@@ -719,7 +720,7 @@
  *
  * Return 0 if O.k. or errno.
  */
-static int if_open (netdevice_t* dev)
+static int if_open(struct net_device* dev)
 {
 	chdlc_private_area_t* chdlc_priv_area = dev->priv;
 	sdla_t* card = chdlc_priv_area->card;
@@ -752,7 +753,7 @@
  * o if this is the last close, then disable communications and interrupts.
  * o reset flags.
  */
-static int if_close (netdevice_t* dev)
+static int if_close(struct net_device* dev)
 {
 	chdlc_private_area_t* chdlc_priv_area = dev->priv;
 	sdla_t* card = chdlc_priv_area->card;
@@ -783,7 +784,7 @@
  * 2. Setting tbusy flag will inhibit further transmit requests from the
  *    protocol stack and can be used for flow control with protocol layer.
  */
-static int if_send (struct sk_buff* skb, netdevice_t* dev)
+static int if_send(struct sk_buff* skb, struct net_device* dev)
 {
 	chdlc_private_area_t *chdlc_priv_area = dev->priv;
 	sdla_t *card = chdlc_priv_area->card;
@@ -973,7 +974,7 @@
  * Get ethernet-style interface statistics.
  * Return a pointer to struct enet_statistics.
  */
-static struct net_device_stats* if_stats (netdevice_t* dev)
+static struct net_device_stats* if_stats(struct net_device* dev)
 {
 	sdla_t *my_card;
 	chdlc_private_area_t* chdlc_priv_area;
@@ -1242,7 +1243,7 @@
  */
 STATIC void wsppp_isr (sdla_t* card)
 {
-	netdevice_t* dev;
+	struct net_device* dev;
 	SHARED_MEMORY_INFO_STRUCT* flags = NULL;
 	int i;
 	sdla_t *my_card;
@@ -1355,7 +1356,7 @@
  */
 static void rx_intr (sdla_t* card)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	chdlc_private_area_t *chdlc_priv_area;
 	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
 	CHDLC_DATA_RX_STATUS_EL_STRUCT *rxbuf = card->u.c.rxmb;
@@ -1477,7 +1478,7 @@
  */
 void timer_intr(sdla_t *card)
 {
-        netdevice_t* dev;
+        struct net_device* dev;
         chdlc_private_area_t* chdlc_priv_area = NULL;
         SHARED_MEMORY_INFO_STRUCT* flags = NULL;
 
@@ -1665,8 +1666,8 @@
  */
 
 static int store_udp_mgmt_pkt(char udp_pkt_src, sdla_t* card,
-                                struct sk_buff *skb, netdevice_t* dev,
-                                chdlc_private_area_t* chdlc_priv_area )
+			      struct sk_buff *skb, struct net_device* dev,
+			      chdlc_private_area_t* chdlc_priv_area )
 {
 	int udp_pkt_stored = 0;
 
@@ -1692,7 +1693,7 @@
  * Process UDP management packet.
  */
 
-static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,
+static int process_udp_mgmt_pkt(sdla_t* card, struct net_device* dev,
 				chdlc_private_area_t* chdlc_priv_area ) 
 {
 	unsigned char *buf;
@@ -2076,7 +2077,7 @@
  * Initialize Receive and Transmit Buffers.
  */
 
-static void init_chdlc_tx_rx_buff( sdla_t* card, netdevice_t *dev )
+static void init_chdlc_tx_rx_buff(sdla_t* card, struct net_device *dev)
 {
 	CHDLC_MAILBOX_STRUCT* mb = card->mbox;
 	CHDLC_TX_STATUS_EL_CFG_STRUCT *tx_config;
@@ -2213,7 +2214,7 @@
  */
 static void port_set_state (sdla_t *card, int state)
 {
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	chdlc_private_area_t *chdlc_priv_area = dev->priv;
 
         if (card->u.c.state != state)
@@ -2284,7 +2285,7 @@
 
 static int config_chdlc (sdla_t *card)
 {
-	netdevice_t *dev = card->wandev.dev;
+	struct net_device *dev = card->wandev.dev;
 	SHARED_MEMORY_INFO_STRUCT *flags = card->u.c.flags;
 
 	if (card->u.c.comm_enabled){
@@ -2330,7 +2331,7 @@
 }
 
 
-static void send_ppp_term_request (netdevice_t *dev)
+static void send_ppp_term_request(struct net_device *dev)
 {
 	struct sk_buff *new_skb;
 	unsigned char *buf;
diff -Nru a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c
--- a/drivers/net/wan/x25_asy.c	Mon Apr 21 20:58:40 2003
+++ b/drivers/net/wan/x25_asy.c	Fri May  9 09:35:53 2003
@@ -46,8 +46,6 @@
 MODULE_PARM(x25_asy_maxdev, "i");
 MODULE_LICENSE("GPL");
 
-static struct tty_ldisc	x25_ldisc;
-
 static int x25_asy_esc(unsigned char *p, unsigned char *d, int len);
 static void x25_asy_unesc(struct x25_asy *sl, unsigned char c);
 
@@ -634,8 +632,6 @@
 	if ((err = x25_asy_open(sl->dev)))
 		return err;
 
-	MOD_INC_USE_COUNT;
-
 	/* Done.  We have linked the TTY line to a channel. */
 	return sl->dev->base_addr;
 }
@@ -664,7 +660,6 @@
 	sl->tty = NULL;
 	x25_asy_free(sl);
 	unregister_netdev(sl->dev);
-	MOD_DEC_USE_COUNT;
 }
 
 
@@ -769,32 +764,29 @@
 
 
 /* Perform I/O control on an active X.25 channel. */
-static int x25_asy_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
+static int x25_asy_ioctl(struct tty_struct *tty, struct file *file,
+			 unsigned int cmd,  unsigned long arg)
 {
 	struct x25_asy *sl = (struct x25_asy *) tty->disc_data;
 
 	/* First make sure we're connected. */
-	if (!sl || sl->magic != X25_ASY_MAGIC) {
+	if (!sl || sl->magic != X25_ASY_MAGIC)
 		return -EINVAL;
-	}
 
-	switch(cmd) 
-	{
-		case SIOCGIFNAME:
-			if(copy_to_user(arg, sl->dev->name, strlen(sl->dev->name) + 1))
-				return -EFAULT;
-			return 0;
-
-		case SIOCSIFHWADDR:
-			return -EINVAL;
-
-		/* Allow stty to read, but not set, the serial port */
-		case TCGETS:
-		case TCGETA:
-			return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);
-
-		default:
-			return -ENOIOCTLCMD;
+	switch(cmd) {
+	case SIOCGIFNAME:
+		if (copy_to_user((void *)arg, sl->dev->name,
+					strlen(sl->dev->name) + 1))
+			return -EFAULT;
+		return 0;
+	case SIOCSIFHWADDR:
+		return -EINVAL;
+	/* Allow stty to read, but not set, the serial port */
+	case TCGETS:
+	case TCGETA:
+		return n_tty_ioctl(tty, file, cmd, arg);
+	default:
+		return -ENOIOCTLCMD;
 	}
 }
 
@@ -806,51 +798,7 @@
 	return 0;
 }
 
-/* Initialize X.25 control device -- register X.25 line discipline */
-
-int __init x25_asy_init_ctrl_dev(void)
-{
-	int status;
-
-	if (x25_asy_maxdev < 4) x25_asy_maxdev = 4; /* Sanity */
-
-	printk(KERN_INFO "X.25 async: version 0.00 ALPHA (dynamic channels, max=%d).\n",
-		x25_asy_maxdev );
-	x25_asy_ctrls = (x25_asy_ctrl_t **) kmalloc(sizeof(void*)*x25_asy_maxdev, GFP_KERNEL);
-	if (x25_asy_ctrls == NULL)
-	{
-		printk("X25 async: Can't allocate x25_asy_ctrls[] array!  Uaargh! (-> No X.25 available)\n");
-		return -ENOMEM;
-	}
-
-	/* Clear the pointer array, we allocate devices when we need them */
-	memset(x25_asy_ctrls, 0, sizeof(void*)*x25_asy_maxdev); /* Pointers */
-
-	/* Fill in our line protocol discipline, and register it */
-	memset(&x25_ldisc, 0, sizeof(x25_ldisc));
-	x25_ldisc.magic  = TTY_LDISC_MAGIC;
-	x25_ldisc.name   = "X.25";
-	x25_ldisc.flags  = 0;
-	x25_ldisc.open   = x25_asy_open_tty;
-	x25_ldisc.close  = x25_asy_close_tty;
-	x25_ldisc.read   = NULL;
-	x25_ldisc.write  = NULL;
-	x25_ldisc.ioctl  = (int (*)(struct tty_struct *, struct file *,
-				   unsigned int, unsigned long)) x25_asy_ioctl;
-	x25_ldisc.poll   = NULL;
-	x25_ldisc.receive_buf = x25_asy_receive_buf;
-	x25_ldisc.receive_room = x25_asy_receive_room;
-	x25_ldisc.write_wakeup = x25_asy_write_wakeup;
-	if ((status = tty_register_ldisc(N_X25, &x25_ldisc)) != 0)  {
-		printk("X.25 async: can't register line discipline (err = %d)\n", status);
-	}
-
-	return status;
-}
-
-
 /* Initialise the X.25 driver.  Called by the device init code */
-
 int x25_asy_init(struct net_device *dev)
 {
 	struct x25_asy *sl = (struct x25_asy*)(dev->priv);
@@ -885,43 +833,58 @@
 
 	return 0;
 }
-#ifdef MODULE
 
-int
-init_module(void)
-{
-	return x25_asy_init_ctrl_dev();
+static struct tty_ldisc x25_ldisc = {
+	.owner		= THIS_MODULE,
+	.magic		= TTY_LDISC_MAGIC,
+	.name		= "X.25",
+	.open		= x25_asy_open_tty,
+	.close		= x25_asy_close_tty,
+	.ioctl		= x25_asy_ioctl,
+	.receive_buf	= x25_asy_receive_buf,
+	.receive_room	= x25_asy_receive_room,
+	.write_wakeup	= x25_asy_write_wakeup,
+};
+
+static int __init init_x25_asy(void)
+{
+	if (x25_asy_maxdev < 4)
+		x25_asy_maxdev = 4; /* Sanity */
+
+	printk(KERN_INFO "X.25 async: version 0.00 ALPHA "
+			"(dynamic channels, max=%d).\n", x25_asy_maxdev );
+	x25_asy_ctrls = kmalloc(sizeof(void*)*x25_asy_maxdev, GFP_KERNEL);
+	if (!x25_asy_ctrls) {
+		printk(KERN_WARNING "X25 async: Can't allocate x25_asy_ctrls[] "
+				"array! Uaargh! (-> No X.25 available)\n");
+		return -ENOMEM;
+	}
+	memset(x25_asy_ctrls, 0, sizeof(void*)*x25_asy_maxdev); /* Pointers */
+
+	return tty_register_ldisc(N_X25, &x25_ldisc);
 }
 
-void
-cleanup_module(void)
+
+static void __exit exit_x25_asy(void)
 {
 	int i;
 
-	if (x25_asy_ctrls != NULL)
-	{
-		for (i = 0; i < x25_asy_maxdev; i++)
-		{
-			if (x25_asy_ctrls[i])
-			{
-				/*
-				 * VSV = if dev->start==0, then device
-				 * unregistered while close proc.
-				 */
-				if (netif_running(&(x25_asy_ctrls[i]->dev)))
-					unregister_netdev(&(x25_asy_ctrls[i]->dev));
+	for (i = 0; i < x25_asy_maxdev; i++) {
+		if (x25_asy_ctrls[i]) {
+			/*
+			 * VSV = if dev->start==0, then device
+			 * unregistered while close proc.
+			 */
+			if (netif_running(&(x25_asy_ctrls[i]->dev)))
+				unregister_netdev(&(x25_asy_ctrls[i]->dev));
 
-				kfree(x25_asy_ctrls[i]);
-				x25_asy_ctrls[i] = NULL;
-			}
+			kfree(x25_asy_ctrls[i]);
 		}
-		kfree(x25_asy_ctrls);
-		x25_asy_ctrls = NULL;
-	}
-	if ((i = tty_register_ldisc(N_X25, NULL)))
-	{
-		printk("X.25 async: can't unregister line discipline (err = %d)\n", i);
 	}
+
+	kfree(x25_asy_ctrls);
+	tty_register_ldisc(N_X25, NULL);
 }
-#endif /* MODULE */
 
+module_init(init_x25_asy);
+module_exit(exit_x25_asy);
diff -Nru a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c
--- a/drivers/net/wireless/airo.c	Wed Apr 23 10:43:55 2003
+++ b/drivers/net/wireless/airo.c	Sat May 17 14:09:51 2003
@@ -4838,7 +4838,7 @@
 	readCapabilityRid(local, &cap_rid);
 
 	dwrq->length = sizeof(struct iw_range);
-	memset(range, 0, sizeof(range));
+	memset(range, 0, sizeof(*range));
 	range->min_nwid = 0x0000;
 	range->max_nwid = 0x0000;
 	range->num_channels = 14;
diff -Nru a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c
--- a/drivers/net/wireless/netwave_cs.c	Sat Apr 26 09:16:23 2003
+++ b/drivers/net/wireless/netwave_cs.c	Thu May  1 09:49:47 2003
@@ -227,7 +227,7 @@
 static int netwave_rx( struct net_device *dev);
 
 /* Interrupt routines */
-static void netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static void netwave_watchdog(struct net_device *);
 
 /* Statistics */
@@ -1456,7 +1456,7 @@
  *	     ready to transmit another packet.
  *	  3. A command has completed execution.
  */
-static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
+static irqreturn_t netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
     ioaddr_t iobase;
     u_char *ramBase;
     struct net_device *dev = (struct net_device *)dev_id;
@@ -1465,7 +1465,7 @@
     int i;
     
     if (!netif_device_present(dev))
-	return;
+	return IRQ_NONE;
     
     iobase = dev->base_addr;
     ramBase = priv->ramBase;
@@ -1476,7 +1476,7 @@
 		
 	wait_WOC(iobase);	
 	if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02))
-	    break; /* None of the interrupt sources asserted */
+	    break; /* None of the interrupt sources asserted (normal exit) */
 	
         status = inb(iobase + NETWAVE_REG_ASR);
 		
@@ -1569,6 +1569,8 @@
 	   }
 	   */
     }
+    /* Handled if we looped at least one time - Jean II */
+    return IRQ_RETVAL(i);
 } /* netwave_interrupt */
 
 /*
diff -Nru a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c
--- a/drivers/net/wireless/wavelan.c	Sun Apr 20 23:39:12 2003
+++ b/drivers/net/wireless/wavelan.c	Fri Dec  6 10:10:13 2002
@@ -1717,31 +1717,28 @@
 	return (i);
 }
 
-#ifdef WIRELESS_SPY
+#ifdef IW_WIRELESS_SPY
 /*------------------------------------------------------------------*/
 /*
  * Gather wireless spy statistics:  for each packet, compare the source
  * address with our list, and if they match, get the statistics.
  * Sorry, but this function really needs the wireless extensions.
  */
-static inline void wl_spy_gather(device * dev, u8 * mac,	/* MAC address */
-				 u8 * stats)
-{				/* Statistics to gather */
-	net_local *lp = (net_local *) dev->priv;
-	int i;
+static inline void wl_spy_gather(device * dev,
+				 u8 *	mac,	/* MAC address */
+				 u8 *	stats)	/* Statistics to gather */
+{
+	struct iw_quality wstats;
 
-	/* Check all addresses. */
-	for (i = 0; i < lp->spy_number; i++)
-		/* If match */
-		if (!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE)) {
-			/* Update statistics */
-			lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
-			lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
-			lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
-			lp->spy_stat[i].updated = 0x7;
-		}
+	wstats.qual = stats[2] & MMR_SGNL_QUAL;
+	wstats.level = stats[0] & MMR_SIGNAL_LVL;
+	wstats.noise = stats[1] & MMR_SILENCE_LVL;
+	wstats.updated = 0x7;
+
+	/* Update spy records */
+	wireless_spy_update(dev, mac, &wstats);
 }
-#endif				/* WIRELESS_SPY */
+#endif /* IW_WIRELESS_SPY */
 
 #ifdef HISTOGRAM
 /*------------------------------------------------------------------*/
@@ -1767,7 +1764,7 @@
 	/* Increment interval counter. */
 	(lp->his_sum[i])++;
 }
-#endif				/* HISTOGRAM */
+#endif /* HISTOGRAM */
 
 /*------------------------------------------------------------------*/
 /*
@@ -2203,93 +2200,6 @@
 	return ret;
 }
 
-#ifdef WIRELESS_SPY
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set spy list
- */
-static int wavelan_set_spy(struct net_device *dev,
-			   struct iw_request_info *info,
-			   union iwreq_data *wrqu,
-			   char *extra)
-{
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
-	struct sockaddr *address = (struct sockaddr *) extra;
-	int i;
-	int ret = 0;
-
-	/* Disable spy while we copy the addresses.
-	 * As we don't disable interrupts, we need to do this */
-	lp->spy_number = 0;
-
-	/* Are there are addresses to copy? */
-	if (wrqu->data.length > 0) {
-		/* Copy addresses to the lp structure. */
-		for (i = 0; i < wrqu->data.length; i++) {
-			memcpy(lp->spy_address[i], address[i].sa_data,
-			       WAVELAN_ADDR_SIZE);
-		}
-
-		/* Reset structure. */
-		memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
-
-#ifdef DEBUG_IOCTL_INFO
-		printk(KERN_DEBUG
-		       "SetSpy:  set of new addresses is: \n");
-		for (i = 0; i < wrqu->data.length; i++)
-			printk(KERN_DEBUG
-			       "%02X:%02X:%02X:%02X:%02X:%02X \n",
-			       lp->spy_address[i][0],
-			       lp->spy_address[i][1],
-			       lp->spy_address[i][2],
-			       lp->spy_address[i][3],
-			       lp->spy_address[i][4],
-			       lp->spy_address[i][5]);
-#endif			/* DEBUG_IOCTL_INFO */
-	}
-
-	/* Now we can set the number of addresses */
-	lp->spy_number = wrqu->data.length;
-
-	return ret;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get spy list
- */
-static int wavelan_get_spy(struct net_device *dev,
-			   struct iw_request_info *info,
-			   union iwreq_data *wrqu,
-			   char *extra)
-{
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
-	struct sockaddr *address = (struct sockaddr *) extra;
-	int i;
-
-	/* Set the number of addresses */
-	wrqu->data.length = lp->spy_number;
-
-	/* Copy addresses from the lp structure. */
-	for (i = 0; i < lp->spy_number; i++) {
-		memcpy(address[i].sa_data,
-		       lp->spy_address[i],
-		       WAVELAN_ADDR_SIZE);
-		address[i].sa_family = AF_UNIX;
-	}
-	/* Copy stats to the user buffer (just after). */
-	if(lp->spy_number > 0)
-		memcpy(extra  + (sizeof(struct sockaddr) * lp->spy_number),
-		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
-
-	/* Reset updated flags. */
-	for (i = 0; i < lp->spy_number; i++)
-		lp->spy_stat[i].updated = 0x0;
-
-	return(0);
-}
-#endif			/* WIRELESS_SPY */
-
 /*------------------------------------------------------------------*/
 /*
  * Wireless Private Handler : set quality threshold
@@ -2439,15 +2349,10 @@
 	NULL,				/* SIOCGIWPRIV */
 	NULL,				/* SIOCSIWSTATS */
 	NULL,				/* SIOCGIWSTATS */
-#ifdef WIRELESS_SPY
-	wavelan_set_spy,		/* SIOCSIWSPY */
-	wavelan_get_spy,		/* SIOCGIWSPY */
-#else	/* WIRELESS_SPY */
-	NULL,				/* SIOCSIWSPY */
-	NULL,				/* SIOCGIWSPY */
-#endif	/* WIRELESS_SPY */
-	NULL,				/* -- hole -- */
-	NULL,				/* -- hole -- */
+	iw_handler_set_spy,		/* SIOCSIWSPY */
+	iw_handler_get_spy,		/* SIOCGIWSPY */
+	iw_handler_set_thrspy,		/* SIOCSIWTHRSPY */
+	iw_handler_get_thrspy,		/* SIOCGIWTHRSPY */
 	NULL,				/* SIOCSIWAP */
 	NULL,				/* SIOCGIWAP */
 	NULL,				/* -- hole -- */
@@ -2501,6 +2406,8 @@
 	.standard	= (iw_handler *) wavelan_handler,
 	.private	= (iw_handler *) wavelan_private_handler,
 	.private_args	= (struct iw_priv_args *) wavelan_private_args,
+	.spy_offset	= ((void *) (&((net_local *) NULL)->spy_data) -
+			   (void *) NULL),
 };
 
 /*------------------------------------------------------------------*/
@@ -2618,22 +2525,23 @@
 #endif				/* DEBUG_RX_INFO */
 
 	/* Statistics-gathering and associated stuff.
-	 * It seem a bit messy with all the define, but it's really simple... */
-#if defined(WIRELESS_SPY) || defined(HISTOGRAM)
+	 * It seem a bit messy with all the define, but it's really
+	 * simple... */
 	if (
-#ifdef WIRELESS_SPY
-		   (lp->spy_number > 0) ||
-#endif				/* WIRELESS_SPY */
+#ifdef IW_WIRELESS_SPY		/* defined in iw_handler.h */
+		   (lp->spy_data.spy_number > 0) ||
+#endif /* IW_WIRELESS_SPY */
 #ifdef HISTOGRAM
 		   (lp->his_number > 0) ||
-#endif				/* HISTOGRAM */
+#endif /* HISTOGRAM */
 		   0) {
 		u8 stats[3];	/* signal level, noise level, signal quality */
 
-		/* Read signal level, silence level and signal quality bytes. */
-		/* Note: in the PCMCIA hardware, these are part of the frame.  It seems
-		 * that for the ISA hardware, it's nowhere to be found in the frame,
-		 * so I'm obliged to do this (it has a side effect on /proc/net/wireless).
+		/* Read signal level, silence level and signal quality bytes */
+		/* Note: in the PCMCIA hardware, these are part of the frame.
+		 * It seems that for the ISA hardware, it's nowhere to be
+		 * found in the frame, so I'm obliged to do this (it has a
+		 * side effect on /proc/net/wireless).
 		 * Any ideas?
 		 */
 		mmc_out(ioaddr, mmwoff(0, mmw_freeze), 1);
@@ -2648,15 +2556,14 @@
 #endif
 
 		/* Spying stuff */
-#ifdef WIRELESS_SPY
+#ifdef IW_WIRELESS_SPY
 		wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE,
 			      stats);
-#endif				/* WIRELESS_SPY */
+#endif /* IW_WIRELESS_SPY */
 #ifdef HISTOGRAM
 		wl_his_gather(dev, stats);
-#endif				/* HISTOGRAM */
+#endif /* HISTOGRAM */
 	}
-#endif				/* defined(WIRELESS_SPY) || defined(HISTOGRAM) */
 
 	/*
 	 * Hand the packet to the network module.
@@ -2884,10 +2791,6 @@
 	       length);
 #endif
 
-	/* Do we need some padding? */
-	if (clen < ETH_ZLEN)
-		clen = ETH_ZLEN;
-
 	spin_lock_irqsave(&lp->spinlock, flags);
 
 	/* Check nothing bad has happened */
@@ -3008,12 +2911,6 @@
 	       (unsigned) skb);
 #endif
 
-	if (skb->len < ETH_ZLEN) {
-		skb = skb_padto(skb, ETH_ZLEN);
-		if (skb == NULL)
-			return 0;
-	}
-
 	/*
 	 * Block a timer-based transmit from overlapping.
 	 * In other words, prevent reentering this routine.
@@ -3035,6 +2932,17 @@
 	if (skb->next)
 		printk(KERN_INFO "skb has next\n");
 #endif
+
+	/* Do we need some padding? */
+	/* Note : on wireless the propagation time is in the order of 1us,
+	 * and we don't have the Ethernet specific requirement of beeing
+	 * able to detect collisions, therefore in theory we don't really
+	 * need to pad. Jean II */
+	if (skb->len < ETH_ZLEN) {
+		skb = skb_padto(skb, ETH_ZLEN);
+		if (skb == NULL)
+			return 0;
+	}
 
 	/* Write packet on the card */
 	if(wv_packet_write(dev, skb->data, skb->len))
diff -Nru a/drivers/net/wireless/wavelan.p.h b/drivers/net/wireless/wavelan.p.h
--- a/drivers/net/wireless/wavelan.p.h	Sun Apr 20 23:39:13 2003
+++ b/drivers/net/wireless/wavelan.p.h	Fri Dec  6 10:03:51 2002
@@ -509,13 +509,9 @@
 
 #ifdef WIRELESS_EXT
   iw_stats	wstats;		/* Wireless-specific statistics */
-#endif
 
-#ifdef WIRELESS_SPY
-  int		spy_number;			/* number of addresses to spy */
-  mac_addr	spy_address[IW_MAX_SPY];	/* the addresses to spy */
-  iw_qual	spy_stat[IW_MAX_SPY];		/* statistics gathered */
-#endif	/* WIRELESS_SPY */
+  struct iw_spy_data	spy_data;
+#endif
 
 #ifdef HISTOGRAM
   int		his_number;		/* number of intervals */
diff -Nru a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c
--- a/drivers/net/wireless/wavelan_cs.c	Sat Apr 26 09:16:25 2003
+++ b/drivers/net/wireless/wavelan_cs.c	Thu May  1 11:32:19 2003
@@ -1757,10 +1757,8 @@
   u_short	table[10];	/* Authorized frequency table */
   long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz + 12 MHz */
   int		i;		/* index in the table */
-#if WIRELESS_EXT > 7
   const int	BAND_NUM = 10;	/* Number of bands */
   int		c = 0;		/* Channel number */
-#endif /* WIRELESS_EXT */
 
   /* Read the frequency table */
   fee_read(base, 0x71 /* frequency table */,
@@ -1772,13 +1770,11 @@
     /* Look in the table if the frequency is allowed */
     if(table[9 - (freq / 16)] & (1 << (freq % 16)))
       {
-#if WIRELESS_EXT > 7
 	/* Compute approximate channel number */
 	while((((channel_bands[c] >> 1) - 24) < freq) &&
 	      (c < BAND_NUM))
 	  c++;
 	list[i].i = c;	/* Set the list index */
-#endif /* WIRELESS_EXT */
 
 	/* put in the list */
 	list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
@@ -1792,7 +1788,7 @@
   return(i);
 }
 
-#ifdef WIRELESS_SPY
+#ifdef IW_WIRELESS_SPY
 /*------------------------------------------------------------------*/
 /*
  * Gather wireless spy statistics : for each packet, compare the source
@@ -1804,22 +1800,17 @@
 	      u_char *	mac,		/* MAC address */
 	      u_char *	stats)		/* Statistics to gather */
 {
-  net_local *	lp = (net_local *) dev->priv;
-  int		i;
+  struct iw_quality wstats;
 
-  /* Look all addresses */
-  for(i = 0; i < lp->spy_number; i++)
-    /* If match */
-    if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
-      {
-	/* Update statistics */
-	lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
-	lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
-	lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
-	lp->spy_stat[i].updated = 0x7;
-      }
+  wstats.qual = stats[2] & MMR_SGNL_QUAL;
+  wstats.level = stats[0] & MMR_SIGNAL_LVL;
+  wstats.noise = stats[1] & MMR_SILENCE_LVL;
+  wstats.updated = 0x7;
+
+  /* Update spy records */
+  wireless_spy_update(dev, mac, &wstats);
 }
-#endif	/* WIRELESS_SPY */
+#endif	/* IW_WIRELESS_SPY */
 
 #ifdef HISTOGRAM
 /*------------------------------------------------------------------*/
@@ -1904,17 +1895,10 @@
 	spin_lock_irqsave(&lp->spinlock, flags);
 	
 	/* Set NWID in WaveLAN. */
-#if WIRELESS_EXT > 8
 	if (!wrqu->nwid.disabled) {
 		/* Set NWID in psa */
 		psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8;
 		psa.psa_nwid[1] = wrqu->nwid.value & 0xFF;
-#else	/* WIRELESS_EXT > 8 */
-	if(wrq->u.nwid.on) {
-		/* Set NWID in psa */
-		psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
-		psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
-#endif	/* WIRELESS_EXT > 8 */
 		psa.psa_nwid_select = 0x01;
 		psa_write(dev,
 			  (char *) psa.psa_nwid - (char *) &psa,
@@ -1971,14 +1955,9 @@
 	psa_read(dev,
 		 (char *) psa.psa_nwid - (char *) &psa,
 		 (unsigned char *) psa.psa_nwid, 3);
-#if WIRELESS_EXT > 8
 	wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
 	wrqu->nwid.disabled = !(psa.psa_nwid_select);
 	wrqu->nwid.fixed = 1;	/* Superfluous */
-#else	/* WIRELESS_EXT > 8 */
-	wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
-	wrq->u.nwid.on = psa.psa_nwid_select;
-#endif	/* WIRELESS_EXT > 8 */
 
 	/* Enable interrupts and restore flags. */
 	spin_unlock_irqrestore(&lp->spinlock, flags);
@@ -2081,13 +2060,9 @@
 	spin_lock_irqsave(&lp->spinlock, flags);
 	
 	/* Set the level threshold. */
-#if WIRELESS_EXT > 7
 	/* We should complain loudly if wrqu->sens.fixed = 0, because we
 	 * can't set auto mode... */
 	psa.psa_thr_pre_set = wrqu->sens.value & 0x3F;
-#else	/* WIRELESS_EXT > 7 */
-	psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
-#endif	/* WIRELESS_EXT > 7 */
 	psa_write(dev,
 		  (char *) &psa.psa_thr_pre_set - (char *) &psa,
 		  (unsigned char *) &psa.psa_thr_pre_set, 1);
@@ -2123,12 +2098,8 @@
 	psa_read(dev,
 		 (char *) &psa.psa_thr_pre_set - (char *) &psa,
 		 (unsigned char *) &psa.psa_thr_pre_set, 1);
-#if WIRELESS_EXT > 7
 	wrqu->sens.value = psa.psa_thr_pre_set & 0x3F;
 	wrqu->sens.fixed = 1;
-#else	/* WIRELESS_EXT > 7 */
-	wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
-#endif	/* WIRELESS_EXT > 7 */
 
 	/* Enable interrupts and restore flags. */
 	spin_unlock_irqrestore(&lp->spinlock, flags);
@@ -2136,7 +2107,6 @@
 	return ret;
 }
 
-#if WIRELESS_EXT > 8
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : set encryption key
@@ -2253,10 +2223,8 @@
 
 	return ret;
 }
-#endif	/* WIRELESS_EXT > 8 */
 
 #ifdef WAVELAN_ROAMING_EXT
-#if WIRELESS_EXT > 5
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : set ESSID (domain)
@@ -2367,10 +2335,8 @@
 
 	return -EOPNOTSUPP;
 }
-#endif	/* WIRELESS_EXT > 5 */
 #endif	/* WAVELAN_ROAMING_EXT */
 
-#if WIRELESS_EXT > 8
 #ifdef WAVELAN_ROAMING
 /*------------------------------------------------------------------*/
 /*
@@ -2429,7 +2395,6 @@
 	return 0;
 }
 #endif	/* WAVELAN_ROAMING */
-#endif /* WIRELESS_EXT > 8 */
 
 /*------------------------------------------------------------------*/
 /*
@@ -2452,11 +2417,9 @@
 	/* Set all the info we don't care or don't know about to zero */
 	memset(range, 0, sizeof(struct iw_range));
 
-#if WIRELESS_EXT > 10
 	/* Set the Wireless Extension versions */
 	range->we_version_compiled = WIRELESS_EXT;
 	range->we_version_source = 9;
-#endif /* WIRELESS_EXT > 10 */
 
 	/* Set information in the range struct.  */
 	range->throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
@@ -2467,17 +2430,13 @@
 	range->max_qual.qual = MMR_SGNL_QUAL;
 	range->max_qual.level = MMR_SIGNAL_LVL;
 	range->max_qual.noise = MMR_SILENCE_LVL;
-#if WIRELESS_EXT > 11
 	range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
 	/* Need to get better values for those two */
 	range->avg_qual.level = 30;
 	range->avg_qual.noise = 8;
-#endif /* WIRELESS_EXT > 11 */
 
-#if WIRELESS_EXT > 7
 	range->num_bitrates = 1;
 	range->bitrate[0] = 2000000;	/* 2 Mb/s */
-#endif /* WIRELESS_EXT > 7 */
 
 	/* Disable interrupts and save flags. */
 	spin_lock_irqsave(&lp->spinlock, flags);
@@ -2491,7 +2450,6 @@
 	} else
 		range->num_channels = range->num_frequency = 0;
 
-#if WIRELESS_EXT > 8
 	/* Encryption supported ? */
 	if (mmc_encr(base)) {
 		range->encoding_size[0] = 8;	/* DES = 64 bits key */
@@ -2501,7 +2459,6 @@
 		range->num_encoding_sizes = 0;
 		range->max_encoding_tokens = 0;
 	}
-#endif /* WIRELESS_EXT > 8 */
 
 	/* Enable interrupts and restore flags. */
 	spin_unlock_irqrestore(&lp->spinlock, flags);
@@ -2509,93 +2466,6 @@
 	return ret;
 }
 
-#ifdef WIRELESS_SPY
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : set spy list
- */
-static int wavelan_set_spy(struct net_device *dev,
-			   struct iw_request_info *info,
-			   union iwreq_data *wrqu,
-			   char *extra)
-{
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
-	struct sockaddr *address = (struct sockaddr *) extra;
-	int i;
-	int ret = 0;
-
-	/* Disable spy while we copy the addresses.
-	 * As we don't disable interrupts, we need to do this */
-	lp->spy_number = 0;
-
-	/* Are there are addresses to copy? */
-	if (wrqu->data.length > 0) {
-		/* Copy addresses to the lp structure. */
-		for (i = 0; i < wrqu->data.length; i++) {
-			memcpy(lp->spy_address[i], address[i].sa_data,
-			       WAVELAN_ADDR_SIZE);
-		}
-
-		/* Reset structure. */
-		memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
-
-#ifdef DEBUG_IOCTL_INFO
-		printk(KERN_DEBUG
-		       "SetSpy:  set of new addresses is: \n");
-		for (i = 0; i < wrqu->data.length; i++)
-			printk(KERN_DEBUG
-			       "%02X:%02X:%02X:%02X:%02X:%02X \n",
-			       lp->spy_address[i][0],
-			       lp->spy_address[i][1],
-			       lp->spy_address[i][2],
-			       lp->spy_address[i][3],
-			       lp->spy_address[i][4],
-			       lp->spy_address[i][5]);
-#endif			/* DEBUG_IOCTL_INFO */
-	}
-
-	/* Now we can set the number of addresses */
-	lp->spy_number = wrqu->data.length;
-
-	return ret;
-}
-
-/*------------------------------------------------------------------*/
-/*
- * Wireless Handler : get spy list
- */
-static int wavelan_get_spy(struct net_device *dev,
-			   struct iw_request_info *info,
-			   union iwreq_data *wrqu,
-			   char *extra)
-{
-	net_local *lp = (net_local *) dev->priv;	/* lp is not unused */
-	struct sockaddr *address = (struct sockaddr *) extra;
-	int i;
-
-	/* Set the number of addresses */
-	wrqu->data.length = lp->spy_number;
-
-	/* Copy addresses from the lp structure. */
-	for (i = 0; i < lp->spy_number; i++) {
-		memcpy(address[i].sa_data,
-		       lp->spy_address[i],
-		       WAVELAN_ADDR_SIZE);
-		address[i].sa_family = AF_UNIX;
-	}
-	/* Copy stats to the user buffer (just after). */
-	if(lp->spy_number > 0)
-		memcpy(extra  + (sizeof(struct sockaddr) * lp->spy_number),
-		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
-
-	/* Reset updated flags. */
-	for (i = 0; i < lp->spy_number; i++)
-		lp->spy_stat[i].updated = 0x0;
-
-	return(0);
-}
-#endif			/* WIRELESS_SPY */
-
 /*------------------------------------------------------------------*/
 /*
  * Wireless Private Handler : set quality threshold
@@ -2781,8 +2651,6 @@
   { SIOCGIPHISTO, 0,                     IW_PRIV_TYPE_INT | 16, "gethisto" },
 };
 
-#if WIRELESS_EXT > 12
-
 static const iw_handler		wavelan_handler[] =
 {
 	NULL,				/* SIOCSIWNAME */
@@ -2806,15 +2674,10 @@
 	NULL,				/* SIOCGIWPRIV */
 	NULL,				/* SIOCSIWSTATS */
 	NULL,				/* SIOCGIWSTATS */
-#ifdef WIRELESS_SPY
-	wavelan_set_spy,		/* SIOCSIWSPY */
-	wavelan_get_spy,		/* SIOCGIWSPY */
-#else	/* WIRELESS_SPY */
-	NULL,				/* SIOCSIWSPY */
-	NULL,				/* SIOCGIWSPY */
-#endif	/* WIRELESS_SPY */
-	NULL,				/* -- hole -- */
-	NULL,				/* -- hole -- */
+	iw_handler_set_spy,		/* SIOCSIWSPY */
+	iw_handler_get_spy,		/* SIOCGIWSPY */
+	iw_handler_set_thrspy,		/* SIOCSIWTHRSPY */
+	iw_handler_get_thrspy,		/* SIOCGIWTHRSPY */
 #ifdef WAVELAN_ROAMING_EXT
 	wavelan_set_wap,		/* SIOCSIWAP */
 	wavelan_get_wap,		/* SIOCGIWAP */
@@ -2834,7 +2697,6 @@
 	NULL,				/* SIOCSIWESSID */
 	NULL,				/* SIOCGIWESSID */
 #endif	/* WAVELAN_ROAMING_EXT */
-#if WIRELESS_EXT > 8
 	NULL,				/* SIOCSIWNICKN */
 	NULL,				/* SIOCGIWNICKN */
 	NULL,				/* -- hole -- */
@@ -2851,7 +2713,6 @@
 	NULL,				/* SIOCGIWRETRY */
 	wavelan_set_encode,		/* SIOCSIWENCODE */
 	wavelan_get_encode,		/* SIOCGIWENCODE */
-#endif	/* WIRELESS_EXT > 8 */
 };
 
 static const iw_handler		wavelan_private_handler[] =
@@ -2879,8 +2740,9 @@
 	.standard	= (iw_handler *) wavelan_handler,
 	.private	= (iw_handler *) wavelan_private_handler,
 	.private_args	= (struct iw_priv_args *) wavelan_private_args,
+	.spy_offset	= ((void *) (&((net_local *) NULL)->spy_data) -
+			   (void *) NULL),
 };
-#endif /* WIRELESS_EXT > 12 */
 
 /*------------------------------------------------------------------*/
 /*
@@ -2892,9 +2754,6 @@
 	      struct ifreq *	rq,	/* Data passed */
 	      int		cmd)	/* Ioctl number */
 {
-#if WIRELESS_EXT <= 12
-  struct iwreq *	wrq = (struct iwreq *) rq;
-#endif
   int			ret = 0;
 
 #ifdef DEBUG_IOCTL_TRACE
@@ -2908,284 +2767,6 @@
       ret = wl_netdev_ethtool_ioctl(dev, (void *) rq->ifr_data);
       break;
 
-#if WIRELESS_EXT <= 12
-      /* --------------- WIRELESS EXTENSIONS --------------- */
-      /* Now done as iw_handler - Jean II */
-    case SIOCGIWNAME:
-      wavelan_get_name(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCSIWNWID:
-      ret = wavelan_set_nwid(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCGIWNWID:
-      ret = wavelan_get_nwid(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCSIWFREQ:
-      ret = wavelan_set_freq(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCGIWFREQ:
-      ret = wavelan_get_freq(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCSIWSENS:
-      ret = wavelan_set_sens(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCGIWSENS:
-      ret = wavelan_get_sens(dev, NULL, &(wrq->u), NULL);
-      break;
-
-#if WIRELESS_EXT > 8
-    case SIOCSIWENCODE:
-      {
-	char keybuf[8];
-	if (wrq->u.encoding.pointer) {
-	  /* We actually have a key to set */
-	  if (wrq->u.encoding.length != 8) {
-	    ret = -EINVAL;
-	    break;
-	  }
-	  if (copy_from_user(keybuf,
-			     wrq->u.encoding.pointer,
-			     wrq->u.encoding.length)) {
-	    ret = -EFAULT;
-	    break;
-	  }
-	} else if (wrq->u.encoding.length != 0) {
-	  ret = -EINVAL;
-	  break;
-	}
-	ret = wavelan_set_encode(dev, NULL, &(wrq->u), keybuf);
-      }
-      break;
-
-    case SIOCGIWENCODE:
-      if (! capable(CAP_NET_ADMIN)) {
-	ret = -EPERM;
-	break;
-      }
-      {
-	char keybuf[8];
-	ret = wavelan_get_encode(dev, NULL,
-				 &(wrq->u),
-				 keybuf);
-	if (wrq->u.encoding.pointer) {
-	  if (copy_to_user(wrq->u.encoding.pointer,
-			   keybuf,
-			   wrq->u.encoding.length))
-	    ret = -EFAULT;
-	}
-      }
-      break;
-#endif	/* WIRELESS_EXT > 8 */
-
-#ifdef WAVELAN_ROAMING_EXT
-#if WIRELESS_EXT > 5
-    case SIOCSIWESSID:
-      {
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
-	if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
-	  ret = -E2BIG;
-	  break;
-	}
-	if (copy_from_user(essidbuf, wrq->u.essid.pointer,
-			   wrq->u.essid.length)) {
-	  ret = -EFAULT;
-	  break;
-	}
-	ret = wavelan_set_essid(dev, NULL,
-				&(wrq->u),
-				essidbuf);
-      }
-      break;
-
-    case SIOCGIWESSID:
-      {
-	char essidbuf[IW_ESSID_MAX_SIZE+1];
-	ret = wavelan_get_essid(dev, NULL,
-				&(wrq->u),
-				essidbuf);
-	if (wrq->u.essid.pointer)
-	  if ( copy_to_user(wrq->u.essid.pointer,
-			    essidbuf,
-			    wrq->u.essid.length) )
-	    ret = -EFAULT;
-      }
-      break;
-
-    case SIOCSIWAP:
-      ret = wavelan_set_wap(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCGIWAP:
-      ret = wavelan_get_wap(dev, NULL, &(wrq->u), NULL);
-      break;
-#endif	/* WIRELESS_EXT > 5 */
-#endif	/* WAVELAN_ROAMING_EXT */
-
-#if WIRELESS_EXT > 8
-#ifdef WAVELAN_ROAMING
-    case SIOCSIWMODE:
-      ret = wavelan_set_mode(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCGIWMODE:
-      ret = wavelan_get_mode(dev, NULL, &(wrq->u), NULL);
-      break;
-#endif	/* WAVELAN_ROAMING */
-#endif /* WIRELESS_EXT > 8 */
-
-    case SIOCGIWRANGE:
-      {
-	struct iw_range range;
-	ret = wavelan_get_range(dev, NULL,
-				&(wrq->u),
-				(char *) &range);
-	if (copy_to_user(wrq->u.data.pointer, &range,
-			 sizeof(struct iw_range)))
-	  ret = -EFAULT;
-      }
-      break;
-
-    case SIOCGIWPRIV:
-      /* Basic checking... */
-      if(wrq->u.data.pointer != (caddr_t) 0)
-	{
-	  /* Set the number of ioctl available */
-	  wrq->u.data.length = sizeof(wavelan_private_args) / sizeof(wavelan_private_args[0]);
-
-	  /* Copy structure to the user buffer */
-	  if(copy_to_user(wrq->u.data.pointer, (u_char *) wavelan_private_args,
-		       sizeof(wavelan_private_args)))
-	    ret = -EFAULT;
-	}
-      break;
-
-#ifdef WIRELESS_SPY
-    case SIOCSIWSPY:
-      {
-	struct sockaddr address[IW_MAX_SPY];
-	/* Check the number of addresses */
-	if (wrq->u.data.length > IW_MAX_SPY) {
-	  ret = -E2BIG;
-	  break;
-	}
-	/* Get the data in the driver */
-	if (wrq->u.data.pointer) {
-	  if (copy_from_user((char *) address,
-			     wrq->u.data.pointer,
-			     sizeof(struct sockaddr) *
-			     wrq->u.data.length)) {
-	    ret = -EFAULT;
-	    break;
-	  }
-	} else if (wrq->u.data.length != 0) {
-	  ret = -EINVAL;
-	  break;
-	}
-	ret = wavelan_set_spy(dev, NULL, &(wrq->u),
-			      (char *) address);
-      }
-      break;
-
-    case SIOCGIWSPY:
-      {
-	char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
-				  sizeof(struct iw_quality))];
-	ret = wavelan_get_spy(dev, NULL, &(wrq->u),
-			      buffer);
-	if (wrq->u.data.pointer) {
-	  if (copy_to_user(wrq->u.data.pointer,
-			   buffer,
-			   (wrq->u.data.length *
-			    (sizeof(struct sockaddr) +
-			     sizeof(struct iw_quality)))
-			   ))
-	    ret = -EFAULT;
-	}
-      }
-      break;
-#endif	/* WIRELESS_SPY */
-
-      /* ------------------ PRIVATE IOCTL ------------------ */
-
-    case SIOCSIPQTHR:
-      if(!capable(CAP_NET_ADMIN))
-	{
-	  ret = -EPERM;
-	  break;
-	}
-      ret = wavelan_set_qthr(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCGIPQTHR:
-      ret = wavelan_get_qthr(dev, NULL, &(wrq->u), NULL);
-      break;
-
-#ifdef WAVELAN_ROAMING
-    case SIOCSIPROAM:
-      /* Note : should check if user == root */
-      ret = wavelan_set_roam(dev, NULL, &(wrq->u), NULL);
-      break;
-
-    case SIOCGIPROAM:
-      ret = wavelan_get_roam(dev, NULL, &(wrq->u), NULL);
-      break;
-#endif	/* WAVELAN_ROAMING */
-
-#ifdef HISTOGRAM
-    case SIOCSIPHISTO:
-      /* Verif if the user is root */
-      if(!capable(CAP_NET_ADMIN))
-	{
-	  ret = -EPERM;
-	}
-      {
-	char buffer[16];
-	/* Check the number of intervals */
-	if(wrq->u.data.length > 16)
-	  {
-	    ret = -E2BIG;
-	    break;
-	}
-	/* Get the data in the driver */
-	if (wrq->u.data.pointer) {
-	  if (copy_from_user(buffer,
-			     wrq->u.data.pointer,
-			     sizeof(struct sockaddr) *
-			     wrq->u.data.length)) {
-	    ret = -EFAULT;
-	    break;
-	  }
-	} else if (wrq->u.data.length != 0) {
-	  ret = -EINVAL;
-	  break;
-	}
-	ret = wavelan_set_histo(dev, NULL, &(wrq->u),
-				buffer);
-      }
-      break;
-
-    case SIOCGIPHISTO:
-      {
-	long buffer[16];
-	ret = wavelan_get_histo(dev, NULL, &(wrq->u),
-				(char *) buffer);
-	if (wrq->u.data.pointer) {
-	  if (copy_to_user(wrq->u.data.pointer,
-			   buffer,
-			   (wrq->u.data.length * sizeof(long))))
-	    ret = -EFAULT;
-	}
-      }
-      break;
-#endif	/* HISTOGRAM */
-#endif /* WIRELESS_EXT <= 12 */
-
       /* ------------------- OTHER IOCTL ------------------- */
 
     default:
@@ -3368,9 +2949,9 @@
   /* Statistics gathering & stuff associated.
    * It seem a bit messy with all the define, but it's really simple... */
   if(
-#ifdef WIRELESS_SPY
-     (lp->spy_number > 0) ||
-#endif	/* WIRELESS_SPY */
+#ifdef IW_WIRELESS_SPY
+     (lp->spy_data.spy_number > 0) ||
+#endif	/* IW_WIRELESS_SPY */
 #ifdef HISTOGRAM
      (lp->his_number > 0) ||
 #endif	/* HISTOGRAM */
@@ -3581,10 +3162,6 @@
 
   spin_lock_irqsave(&lp->spinlock, flags);
 
-  /* Check if we need some padding */
-  if(clen < ETH_ZLEN)
-    clen = ETH_ZLEN;
-
   /* Write the length of data buffer followed by the buffer */
   outb(xmtdata_base & 0xff, PIORL(base));
   outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
@@ -3664,6 +3241,17 @@
 		printk(KERN_INFO "skb has next\n");
 #endif
 
+	/* Check if we need some padding */
+	/* Note : on wireless the propagation time is in the order of 1us,
+	 * and we don't have the Ethernet specific requirement of beeing
+	 * able to detect collisions, therefore in theory we don't really
+	 * need to pad. Jean II */
+	if (skb->len < ETH_ZLEN) {
+		skb = skb_padto(skb, ETH_ZLEN);
+		if (skb == NULL)
+			return 0;
+	}
+
   wv_packet_write(dev, skb->data, skb->len);
 
   dev_kfree_skb(skb);
@@ -4644,7 +4232,7 @@
  *	   ready to transmit another packet.
  *	3. A command has completed execution.
  */
-static void
+static irqreturn_t
 wavelan_interrupt(int		irq,
 		  void *	dev_id,
 		  struct pt_regs * regs)
@@ -4661,7 +4249,7 @@
       printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n",
 	     irq);
 #endif
-      return;
+      return IRQ_NONE;
     }
 
 #ifdef DEBUG_INTERRUPT_TRACE
@@ -4883,6 +4471,24 @@
 #ifdef DEBUG_INTERRUPT_TRACE
   printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
 #endif
+
+  /* We always return IRQ_HANDLED, because we will receive empty
+   * interrupts under normal operations. Anyway, it doesn't matter
+   * as we are dealing with an ISA interrupt that can't be shared.
+   *
+   * Explanation : under heavy receive, the following happens :
+   * ->wavelan_interrupt()
+   *    (status0 & SR0_INTERRUPT) != 0
+   *       ->wv_packet_rcv()
+   *    (status0 & SR0_INTERRUPT) != 0
+   *       ->wv_packet_rcv()
+   *    (status0 & SR0_INTERRUPT) == 0	// i.e. no more event
+   * <-wavelan_interrupt()
+   * ->wavelan_interrupt()
+   *    (status0 & SR0_INTERRUPT) == 0	// i.e. empty interrupt
+   * <-wavelan_interrupt()
+   * Jean II */
+  return IRQ_HANDLED;
 } /* wv_interrupt */
 
 /*------------------------------------------------------------------*/
@@ -5189,9 +4795,7 @@
   dev->watchdog_timeo	= WATCHDOG_JIFFIES;
 
 #ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
-#if WIRELESS_EXT > 12
   dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
-#endif /* WIRELESS_EXT > 12 */
   dev->do_ioctl = wavelan_ioctl;	/* old wireless extensions */
   dev->get_wireless_stats = wavelan_get_wireless_stats;
 #endif
diff -Nru a/drivers/net/wireless/wavelan_cs.p.h b/drivers/net/wireless/wavelan_cs.p.h
--- a/drivers/net/wireless/wavelan_cs.p.h	Wed Apr  3 18:06:49 2002
+++ b/drivers/net/wireless/wavelan_cs.p.h	Thu May  1 11:32:19 2003
@@ -443,9 +443,7 @@
 
 #ifdef CONFIG_NET_RADIO
 #include <linux/wireless.h>		/* Wireless extensions */
-#if WIRELESS_EXT > 12
-#include <net/iw_handler.h>
-#endif	/* WIRELESS_EXT > 12 */
+#include <net/iw_handler.h>		/* New driver API */
 #endif
 
 /* Pcmcia headers that we need */
@@ -527,13 +525,6 @@
 
 /* ------------------------ PRIVATE IOCTL ------------------------ */
 
-/* Wireless Extension Backward compatibility - Jean II
- * If the new wireless device private ioctl range is not defined,
- * default to standard device private ioctl range */
-#ifndef SIOCIWFIRSTPRIV
-#define SIOCIWFIRSTPRIV	SIOCDEVPRIVATE
-#endif /* SIOCIWFIRSTPRIV */
-
 #define SIOCSIPQTHR	SIOCIWFIRSTPRIV		/* Set quality threshold */
 #define SIOCGIPQTHR	SIOCIWFIRSTPRIV + 1	/* Get quality threshold */
 #define SIOCSIPROAM     SIOCIWFIRSTPRIV + 2	/* Set roaming state */
@@ -605,16 +596,6 @@
 typedef struct net_local	net_local;
 typedef struct timer_list	timer_list;
 
-#if WIRELESS_EXT <= 12
-/* Wireless extensions backward compatibility */
-/* Part of iw_handler prototype we need */
-struct iw_request_info
-{
-	__u16		cmd;		/* Wireless Extension command */
-	__u16		flags;		/* More to come ;-) */
-};
-#endif	/* WIRELESS_EXT <= 12 */
-
 /* Basic types */
 typedef u_char		mac_addr[WAVELAN_ADDR_SIZE];	/* Hardware address */
 
@@ -647,13 +628,10 @@
 
 #ifdef WIRELESS_EXT
   iw_stats	wstats;		/* Wireless specific stats */
+
+  struct iw_spy_data	spy_data;
 #endif
 
-#ifdef WIRELESS_SPY
-  int		spy_number;		/* Number of addresses to spy */
-  mac_addr	spy_address[IW_MAX_SPY];	/* The addresses to spy */
-  iw_qual	spy_stat[IW_MAX_SPY];		/* Statistics gathered */
-#endif	/* WIRELESS_SPY */
 #ifdef HISTOGRAM
   int		his_number;		/* Number of intervals */
   u_char	his_range[16];		/* Boundaries of interval ]n-1; n] */
@@ -686,11 +664,6 @@
 void wv_roam_cleanup(struct net_device *dev);
 #endif	/* WAVELAN_ROAMING */
 
-/* ----------------------- MISC SUBROUTINES ------------------------ */
-static void
-	cs_error(client_handle_t,	/* Report error to cardmgr */
-		 int,
-		 int);
 /* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
 static inline u_char		/* data */
 	hasr_read(u_long);	/* Read the host interface : base address */
@@ -791,7 +764,7 @@
 	wv_pcmcia_release(u_long),	/* Remove a device */
 	wv_flush_stale_links(void);	/* "detach" all possible devices */
 /* ---------------------- INTERRUPT HANDLING ---------------------- */
-static void
+static irqreturn_t
 	wavelan_interrupt(int,	/* Interrupt handler */
 			  void *,
 			  struct pt_regs *);
diff -Nru a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c
--- a/drivers/net/yellowfin.c	Sun Apr 20 21:58:28 2003
+++ b/drivers/net/yellowfin.c	Tue May 20 20:02:20 2003
@@ -444,6 +444,7 @@
 		return -ENOMEM;
 	}
 	SET_MODULE_OWNER(dev);
+	SET_NETDEV_DEV(dev, &pdev->dev);
 
 	np = dev->priv;
 
diff -Nru a/drivers/pci/pci.ids b/drivers/pci/pci.ids
--- a/drivers/pci/pci.ids	Thu May  1 13:41:38 2003
+++ b/drivers/pci/pci.ids	Sat May 17 14:09:55 2003
@@ -2264,6 +2264,7 @@
 		1028 0095  Integrated 3C905C-TX Fast Etherlink for PC Management NIC
 		10b7 1000  3C905C-TX Fast Etherlink for PC Management NIC
 		10b7 7000  10/100 Mini PCI Ethernet Adapter
+	9210  3C920B-EMB-WNM Integrated Fast Ethernet Controller
 	9300  3CSOHO100B-TX  [910-A01]
 	9800  3c980-TX [Fast Etherlink XL Server Adapter]
 		10b7 9800  3c980-TX Fast Etherlink XL Server Adapter
diff -Nru a/drivers/pci/quirks.c b/drivers/pci/quirks.c
--- a/drivers/pci/quirks.c	Mon Mar 17 15:42:31 2003
+++ b/drivers/pci/quirks.c	Mon May 19 15:46:48 2003
@@ -647,6 +647,87 @@
 }
 
 /*
+ * On ASUS P4B boards, the SMBus PCI Device within the ICH2/4 southbridge
+ * is not activated. The myth is that Asus said that they do not want the
+ * users to be irritated by just another PCI Device in the Win98 device
+ * manager. (see the file prog/hotplug/README.p4b in the lm_sensors 
+ * package 2.7.0 for details)
+ *
+ * The SMBus PCI Device can be activated by setting a bit in the ICH LPC 
+ * bridge. Unfortunately, this device has no subvendor/subdevice ID. So it 
+ * becomes necessary to do this tweak in two steps -- I've chosen the Host
+ * bridge as trigger.
+ */
+
+static int __initdata asus_hides_smbus = 0;
+
+static void __init asus_hides_smbus_hostbridge(struct pci_dev *dev)
+{
+	if (likely(dev->subsystem_vendor != PCI_VENDOR_ID_ASUSTEK))
+		return;
+
+	if ((dev->device == PCI_DEVICE_ID_INTEL_82845_HB) && 
+	    (dev->subsystem_device == 0x8088)) /* P4B533 */
+		asus_hides_smbus = 1;
+	if ((dev->device == PCI_DEVICE_ID_INTEL_82845G_HB) &&
+	    (dev->subsystem_device == 0x80b2)) /* P4PE */
+		asus_hides_smbus = 1;
+	if ((dev->device == PCI_DEVICE_ID_INTEL_82850_HB) &&
+	    (dev->subsystem_device == 0x8030)) /* P4T533 */
+		asus_hides_smbus = 1;
+	return;
+}
+
+static void __init asus_hides_smbus_lpc(struct pci_dev *dev)
+{
+	u16 val;
+	
+	if (likely(!asus_hides_smbus))
+		return;
+
+	pci_read_config_word(dev, 0xF2, &val);
+	if (val & 0x8) {
+		pci_write_config_word(dev, 0xF2, val & (~0x8));
+		pci_read_config_word(dev, 0xF2, &val);
+		if(val & 0x8)
+			printk(KERN_INFO "PCI: i801 SMBus device continues to play 'hide and seek'! 0x%x\n", val);
+		else
+			printk(KERN_INFO "PCI: Enabled i801 SMBus device\n");
+	}
+}
+
+/*
+ * SiS 96x south bridge: BIOS typically hides SMBus device...
+ */
+static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
+{
+	u8 val = 0;
+	printk(KERN_INFO "Enabling SiS 96x SMBus.\n");
+	pci_read_config_byte(dev, 0x77, &val);
+	pci_write_config_byte(dev, 0x77, val & ~0x10);
+	pci_read_config_byte(dev, 0x77, &val);
+}
+
+/*
+ * ... This is further complicated by the fact that some SiS96x south
+ * bridges pretend to be 85C503/5513 instead.  In that case see if we
+ * spotted a compatible north bridge to make sure.
+ * (pci_find_device doesn't work yet)
+ */
+static int __devinitdata sis_96x_compatible = 0;
+
+static void __init quirk_sis_503_smbus(struct pci_dev *dev)
+{
+	if (sis_96x_compatible)
+		quirk_sis_96x_smbus(dev);
+}
+
+static void __init quirk_sis_96x_compatible(struct pci_dev *dev)
+{
+	sis_96x_compatible = 1;
+}
+
+/*
  *  The main table of quirks.
  */
 
@@ -679,6 +760,15 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_INTEL, 	PCI_DEVICE_ID_INTEL_82443BX_2, 	quirk_natoma },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_5597,		quirk_nopcipci },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_496,		quirk_nopcipci },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_503,		quirk_sis_503_smbus },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_645,		quirk_sis_96x_compatible },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_646,		quirk_sis_96x_compatible },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_648,		quirk_sis_96x_compatible },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_650,		quirk_sis_96x_compatible },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_651,		quirk_sis_96x_compatible },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_961,		quirk_sis_96x_smbus },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_962,		quirk_sis_96x_smbus },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_SI,	PCI_DEVICE_ID_SI_963,		quirk_sis_96x_smbus },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1647, 	quirk_alimagik },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_AL, 	PCI_DEVICE_ID_AL_M1651, 	quirk_alimagik },
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_VIA,	PCI_DEVICE_ID_VIA_8363_0,	quirk_vialatency },
@@ -724,6 +814,15 @@
 	{ PCI_FIXUP_FINAL,	PCI_VENDOR_ID_CYRIX,	PCI_DEVICE_ID_CYRIX_PCI_MASTER, quirk_mediagx_master },
 	
 	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82375,	quirk_eisa_bridge },
+
+	/*
+	 * on Asus P4B boards, the i801SMBus device is disabled at startup.
+	 */
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845_HB,	asus_hides_smbus_hostbridge },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82845G_HB,	asus_hides_smbus_hostbridge },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82850_HB,	asus_hides_smbus_hostbridge },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801DB_0,	asus_hides_smbus_lpc },
+	{ PCI_FIXUP_HEADER,	PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82801BA_0,	asus_hides_smbus_lpc },
 
 	{ 0 }
 };
diff -Nru a/drivers/pcmcia/cs.c b/drivers/pcmcia/cs.c
--- a/drivers/pcmcia/cs.c	Tue Apr 29 00:26:44 2003
+++ b/drivers/pcmcia/cs.c	Mon May 12 15:41:01 2003
@@ -302,11 +302,8 @@
     
 ======================================================================*/
 
-static int setup_socket(socket_info_t *);
-static void shutdown_socket(socket_info_t *);
-static void reset_socket(socket_info_t *);
-static void unreset_socket(socket_info_t *);
-static void parse_events(void *info, u_int events);
+static int pccardd(void *__skt);
+void pcmcia_unregister_socket(struct class_device *dev);
 
 #define to_class_data(dev) dev->class_data
 
@@ -317,7 +314,7 @@
 {
 	struct pcmcia_socket_class_data *cls_d = class_get_devdata(class_dev);
 	socket_info_t *s_info;
-	unsigned int i, j;
+	unsigned int i, j, ret;
 
 	if (!cls_d)
 		return -EINVAL;
@@ -330,6 +327,7 @@
 	memset(s_info, 0, cls_d->nsock * sizeof(socket_info_t));
 
 	cls_d->s_info = s_info;
+	ret = 0;
 
 	/* socket initialization */
 	for (i = 0; i < cls_d->nsock; i++) {
@@ -344,7 +342,7 @@
 		s->erase_busy.next = s->erase_busy.prev = &s->erase_busy;
 		INIT_LIST_HEAD(&s->cis_cache);
 		spin_lock_init(&s->lock);
-    
+
 		/* TBD: remove usage of socket_table, use class_for_each_dev instead */
 		for (j = 0; j < sockets; j++)
 			if (socket_table[j] == NULL) break;
@@ -353,6 +351,20 @@
 
 		init_socket(s);
 		s->ss_entry->inquire_socket(s->sock, &s->cap);
+
+		init_completion(&s->thread_done);
+		init_waitqueue_head(&s->thread_wait);
+		init_MUTEX(&s->skt_sem);
+		spin_lock_init(&s->thread_lock);
+		ret = kernel_thread(pccardd, s, CLONE_KERNEL);
+		if (ret < 0) {
+			pcmcia_unregister_socket(class_dev);
+			break;
+		}
+
+		wait_for_completion(&s->thread_done);
+		BUG_ON(!s->thread);
+
 #ifdef CONFIG_PROC_FS
 		if (proc_pccard) {
 			char name[3];
@@ -368,7 +380,7 @@
 		}
 #endif
 	}
-	return 0;
+	return ret;
 } /* pcmcia_register_socket */
 
 
@@ -407,8 +419,12 @@
 			remove_proc_entry(name, proc_pccard);
 		}
 #endif
-		
-		shutdown_socket(s);
+		if (s->thread) {
+			init_completion(&s->thread_done);
+			s->thread = NULL;
+			wake_up(&s->thread_wait);
+			wait_for_completion(&s->thread_done);
+		}
 		release_cis_mem(s);
 		while (s->clients) {
 			client = s->clients;
@@ -450,15 +466,6 @@
 
 static int send_event(socket_info_t *s, event_t event, int priority);
 
-/*
- * Sleep for n_cs centiseconds (1 cs = 1/100th of a second)
- */
-static void cs_sleep(unsigned int n_cs)
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout( (n_cs * HZ + 99) / 100);
-}
-
 static void shutdown_socket(socket_info_t *s)
 {
     client_t **c;
@@ -505,132 +512,6 @@
     free_regions(&s->c_region);
 } /* shutdown_socket */
 
-/*
- * Return zero if we think the card isn't actually present
- */
-static int setup_socket(socket_info_t *s)
-{
-	int val, ret;
-	int setup_timeout = 100;
-
-	/* Wait for "not pending" */
-	for (;;) {
-		get_socket_status(s, &val);
-		if (!(val & SS_PENDING))
-			break;
-		if (--setup_timeout) {
-			cs_sleep(10);
-			continue;
-		}
-		printk(KERN_NOTICE "cs: socket %p voltage interrogation"
-			" timed out\n", s);
-		ret = 0;
-		goto out;
-	}
-
-	if (val & SS_DETECT) {
-		DEBUG(1, "cs: setup_socket(%p): applying power\n", s);
-		s->state |= SOCKET_PRESENT;
-		s->socket.flags &= SS_DEBOUNCED;
-		if (val & SS_3VCARD)
-		    s->socket.Vcc = s->socket.Vpp = 33;
-		else if (!(val & SS_XVCARD))
-		    s->socket.Vcc = s->socket.Vpp = 50;
-		else {
-		    printk(KERN_NOTICE "cs: socket %p: unsupported "
-			   "voltage key\n", s);
-		    s->socket.Vcc = 0;
-		}
-		if (val & SS_CARDBUS) {
-		    s->state |= SOCKET_CARDBUS;
-#ifndef CONFIG_CARDBUS
-		    printk(KERN_NOTICE "cs: unsupported card type detected!\n");
-#endif
-		}
-		set_socket(s, &s->socket);
-		cs_sleep(vcc_settle);
-		reset_socket(s);
-		ret = 1;
-	} else {
-		DEBUG(0, "cs: setup_socket(%p): no card!\n", s);
-		ret = 0;
-	}
-out:
-	return ret;
-} /* setup_socket */
-
-/*======================================================================
-
-    Reset_socket() and unreset_socket() handle hard resets.  Resets
-    have several causes: card insertion, a call to reset_socket, or
-    recovery from a suspend/resume cycle.  Unreset_socket() sends
-    a CS event that matches the cause of the reset.
-    
-======================================================================*/
-
-static void reset_socket(socket_info_t *s)
-{
-    DEBUG(1, "cs: resetting socket %p\n", s);
-    s->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
-    set_socket(s, &s->socket);
-    udelay((long)reset_time);
-    s->socket.flags &= ~SS_RESET;
-    set_socket(s, &s->socket);
-    cs_sleep(unreset_delay);
-    unreset_socket(s);
-} /* reset_socket */
-
-#define EVENT_MASK \
-(SOCKET_SETUP_PENDING|SOCKET_SUSPEND|SOCKET_RESET_PENDING)
-
-static void unreset_socket(socket_info_t *s)
-{
-	int setup_timeout = unreset_limit;
-	int val;
-
-	/* Wait for "ready" */
-	for (;;) {
-		get_socket_status(s, &val);
-		if (val & SS_READY)
-			break;
-		DEBUG(2, "cs: socket %d not ready yet\n", s->sock);
-		if (--setup_timeout) {
-			cs_sleep(unreset_check);
-			continue;
-		}
-		printk(KERN_NOTICE "cs: socket %p timed out during"
-			" reset.  Try increasing setup_delay.\n", s);
-		s->state &= ~EVENT_MASK;
-		return;
-	}
-
-	DEBUG(1, "cs: reset done on socket %p\n", s);
-	if (s->state & SOCKET_SUSPEND) {
-	    s->state &= ~EVENT_MASK;
-	    if (verify_cis_cache(s) != 0)
-		parse_events(s, SS_DETECT);
-	    else
-		send_event(s, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
-	} else if (s->state & SOCKET_SETUP_PENDING) {
-#ifdef CONFIG_CARDBUS
-	    if (s->state & SOCKET_CARDBUS) {
-		cb_alloc(s);
-		s->state |= SOCKET_CARDBUS_CONFIG;
-	    }
-#endif
-	    send_event(s, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
-	    s->state &= ~SOCKET_SETUP_PENDING;
-	} else {
-	    send_event(s, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
-	    if (s->reset_handle) { 
-		    s->reset_handle->event_callback_args.info = NULL;
-		    EVENT(s->reset_handle, CS_EVENT_RESET_COMPLETE,
-			  CS_EVENT_PRI_LOW);
-	    }
-	    s->state &= ~EVENT_MASK;
-	}
-} /* unreset_socket */
-
 /*======================================================================
 
     The central event handler.  Send_event() sends an event to all
@@ -661,61 +542,266 @@
     return ret;
 } /* send_event */
 
-static void do_shutdown(socket_info_t *s)
+static void pcmcia_error(socket_info_t *skt, const char *fmt, ...)
 {
-    client_t *client;
-    if (s->state & SOCKET_SHUTDOWN_PENDING)
-	return;
-    s->state |= SOCKET_SHUTDOWN_PENDING;
-    send_event(s, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
-    for (client = s->clients; client; client = client->next)
-	if (!(client->Attributes & INFO_MASTER_CLIENT))
-	    client->state |= CLIENT_STALE;
-    if (s->state & (SOCKET_SETUP_PENDING|SOCKET_RESET_PENDING)) {
-	DEBUG(0, "cs: flushing pending setup\n");
-	s->state &= ~EVENT_MASK;
-    }
-    cs_sleep(shutdown_delay);
-    s->state &= ~SOCKET_PRESENT;
-    shutdown_socket(s);
+	static char buf[128];
+	va_list ap;
+	int len;
+
+	va_start(ap, fmt);
+	len = vsnprintf(buf, sizeof(buf), fmt, ap);
+	va_end(ap);
+	buf[len] = '\0';
+
+	printk(KERN_ERR "PCMCIA: socket %p: %s", skt, buf);
+}
+
+#define cs_to_timeout(cs) (((cs) * HZ + 99) / 100)
+
+static void socket_remove_drivers(socket_info_t *skt)
+{
+	client_t *client;
+
+	send_event(skt, CS_EVENT_CARD_REMOVAL, CS_EVENT_PRI_HIGH);
+
+	for (client = skt->clients; client; client = client->next)
+		if (!(client->Attributes & INFO_MASTER_CLIENT))
+			client->state |= CLIENT_STALE;
+}
+
+static void socket_shutdown(socket_info_t *skt)
+{
+	socket_remove_drivers(skt);
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(cs_to_timeout(shutdown_delay));
+	skt->state &= ~SOCKET_PRESENT;
+	shutdown_socket(skt);
+}
+
+static int socket_reset(socket_info_t *skt)
+{
+	int status, i;
+
+	skt->socket.flags |= SS_OUTPUT_ENA | SS_RESET;
+	set_socket(skt, &skt->socket);
+	udelay((long)reset_time);
+
+	skt->socket.flags &= ~SS_RESET;
+	set_socket(skt, &skt->socket);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(cs_to_timeout(unreset_delay));
+	for (i = 0; i < unreset_limit; i++) {
+		get_socket_status(skt, &status);
+
+		if (!(status & SS_DETECT))
+			return CS_NO_CARD;
+
+		if (status & SS_READY)
+			return CS_SUCCESS;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(cs_to_timeout(unreset_check));
+	}
+
+	pcmcia_error(skt, "time out after reset.\n");
+	return CS_GENERAL_FAILURE;
+}
+
+static int socket_setup(socket_info_t *skt, int initial_delay)
+{
+	int status, i;
+
+	get_socket_status(skt, &status);
+	if (!(status & SS_DETECT))
+		return CS_NO_CARD;
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(cs_to_timeout(initial_delay));
+
+	for (i = 0; i < 100; i++) {
+		get_socket_status(skt, &status);
+		if (!(status & SS_DETECT))
+			return CS_NO_CARD;
+
+		if (!(status & SS_PENDING))
+			break;
+
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(cs_to_timeout(10));
+	}
+
+	if (status & SS_PENDING) {
+		pcmcia_error(skt, "voltage interrogation timed out.\n");
+		return CS_GENERAL_FAILURE;
+	}
+
+	if (status & SS_CARDBUS) {
+		skt->state |= SOCKET_CARDBUS;
+#ifndef CONFIG_CARDBUS
+		pcmcia_error(skt, "cardbus cards are not supported.\n");
+		return CS_BAD_TYPE;
+#endif
+	}
+
+	/*
+	 * Decode the card voltage requirements, and apply power to the card.
+	 */
+	if (status & SS_3VCARD)
+		skt->socket.Vcc = skt->socket.Vpp = 33;
+	else if (!(status & SS_XVCARD))
+		skt->socket.Vcc = skt->socket.Vpp = 50;
+	else {
+		pcmcia_error(skt, "unsupported voltage key.\n");
+		return CS_BAD_TYPE;
+	}
+	skt->state |= SOCKET_PRESENT;
+	skt->socket.flags = SS_DEBOUNCED;
+	set_socket(skt, &skt->socket);
+
+	/*
+	 * Wait "vcc_settle" for the supply to stabilise.
+	 */
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(cs_to_timeout(vcc_settle));
+
+	return socket_reset(skt);
+}
+
+/*
+ * Handle card insertion.  Setup the socket, reset the card,
+ * and then tell the rest of PCMCIA that a card is present.
+ */
+static int socket_insert(socket_info_t *skt)
+{
+	int ret;
+
+	ret = socket_setup(skt, setup_delay);
+	if (ret == CS_SUCCESS) {
+#ifdef CONFIG_CARDBUS
+		if (skt->state & SOCKET_CARDBUS) {
+			cb_alloc(skt);
+			skt->state |= SOCKET_CARDBUS_CONFIG;
+		}
+#endif
+		send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+		skt->socket.flags &= ~SS_DEBOUNCED;
+	} else
+		socket_shutdown(skt);
+
+	return ret;
+}
+
+static int socket_suspend(socket_info_t *skt)
+{
+	if (skt->state & SOCKET_SUSPEND)
+		return CS_IN_USE;
+
+	send_event(skt, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
+	suspend_socket(skt);
+	skt->state |= SOCKET_SUSPEND;
+
+	return CS_SUCCESS;
+}
+
+/*
+ * Resume a socket.  If a card is present, verify its CIS against
+ * our cached copy.  If they are different, the card has been
+ * replaced, and we need to tell the drivers.
+ */
+static int socket_resume(socket_info_t *skt)
+{
+	int ret;
+
+	if (!(skt->state & SOCKET_SUSPEND))
+		return CS_IN_USE;
+
+	init_socket(skt);
+
+	ret = socket_setup(skt, resume_delay);
+	if (ret == CS_SUCCESS) {
+		/*
+		 * FIXME: need a better check here for cardbus cards.
+		 */
+		if (verify_cis_cache(skt) != 0) {
+			socket_remove_drivers(skt);
+			destroy_cis_cache(skt);
+			send_event(skt, CS_EVENT_CARD_INSERTION, CS_EVENT_PRI_LOW);
+		} else {
+			send_event(skt, CS_EVENT_PM_RESUME, CS_EVENT_PRI_LOW);
+		}
+		skt->socket.flags &= ~SS_DEBOUNCED;
+	} else
+		socket_shutdown(skt);
+
+	skt->state &= ~SOCKET_SUSPEND;
+
+	return CS_SUCCESS;
+}
+
+static int pccardd(void *__skt)
+{
+	socket_info_t *skt = __skt;
+	DECLARE_WAITQUEUE(wait, current);
+
+	daemonize("pccardd");
+	skt->thread = current;
+	complete(&skt->thread_done);
+
+	add_wait_queue(&skt->thread_wait, &wait);
+	for (;;) {
+		unsigned long flags;
+		unsigned int events;
+
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irqsave(&skt->thread_lock, flags);
+		events = skt->thread_events;
+		skt->thread_events = 0;
+		spin_unlock_irqrestore(&skt->thread_lock, flags);
+
+		if (events) {
+			down(&skt->skt_sem);
+			if (events & SS_DETECT && !(skt->state & SOCKET_SUSPEND)) {
+				int status;
+
+				get_socket_status(skt, &status);
+				if ((skt->state & SOCKET_PRESENT) &&
+				     !(status & SS_DETECT))
+					socket_shutdown(skt);
+				if (status & SS_DETECT)
+					socket_insert(skt);
+			}
+			if (events & SS_BATDEAD)
+				send_event(skt, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
+			if (events & SS_BATWARN)
+				send_event(skt, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
+			if (events & SS_READY)
+				send_event(skt, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
+			up(&skt->skt_sem);
+			continue;
+		}
+
+		schedule();
+		if (!skt->thread)
+			break;
+	}
+	remove_wait_queue(&skt->thread_wait, &wait);
+
+	socket_shutdown(skt);
+
+	complete_and_exit(&skt->thread_done, 0);
 }
 
 static void parse_events(void *info, u_int events)
 {
-    socket_info_t *s = info;
-    if (events & SS_DETECT) {
-	int status;
-
-	get_socket_status(s, &status);
-	if ((s->state & SOCKET_PRESENT) &&
-	    (!(s->state & SOCKET_SUSPEND) ||
-	     !(status & SS_DETECT)))
-	    do_shutdown(s);
-	if (status & SS_DETECT) {
-	    if (s->state & SOCKET_SETUP_PENDING) {
-		DEBUG(1, "cs: delaying pending setup\n");
-		return;
-	    }
-	    s->state |= SOCKET_SETUP_PENDING;
-	    if (s->state & SOCKET_SUSPEND)
-		cs_sleep(resume_delay);
-	    else
-		cs_sleep(setup_delay);
-	    s->socket.flags |= SS_DEBOUNCED;
-	    if (setup_socket(s) == 0)
-		s->state &= ~SOCKET_SETUP_PENDING;
-	    s->socket.flags &= ~SS_DEBOUNCED;
-	}
-    }
-    if (events & SS_BATDEAD)
-	send_event(s, CS_EVENT_BATTERY_DEAD, CS_EVENT_PRI_LOW);
-    if (events & SS_BATWARN)
-	send_event(s, CS_EVENT_BATTERY_LOW, CS_EVENT_PRI_LOW);
-    if (events & SS_READY) {
-	if (!(s->state & SOCKET_RESET_PENDING))
-	    send_event(s, CS_EVENT_READY_CHANGE, CS_EVENT_PRI_LOW);
-	else DEBUG(1, "cs: ready change during reset\n");
-    }
+	socket_info_t *s = info;
+
+	spin_lock(&s->thread_lock);
+	s->thread_events |= events;
+	spin_unlock(&s->thread_lock);
+
+	wake_up(&s->thread_wait);
 } /* parse_events */
 
 /*======================================================================
@@ -727,27 +813,18 @@
     
 ======================================================================*/
 
-void pcmcia_suspend_socket (socket_info_t *s)
+void pcmcia_suspend_socket (socket_info_t *skt)
 {
-    if ((s->state & SOCKET_PRESENT) && !(s->state & SOCKET_SUSPEND)) {
-	send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
-	suspend_socket(s);
-	s->state |= SOCKET_SUSPEND;
-    }
+	down(&skt->skt_sem);
+	socket_suspend(skt);
+	up(&skt->skt_sem);
 }
 
-void pcmcia_resume_socket (socket_info_t *s)
+void pcmcia_resume_socket (socket_info_t *skt)
 {
-    int	stat;
-
-    /* Do this just to reinitialize the socket */
-    init_socket(s);
-    get_socket_status(s, &stat);
-
-    /* If there was or is a card here, we need to do something
-    about it... but parse_events will sort it all out. */
-    if ((s->state & SOCKET_PRESENT) || (stat & SS_DETECT))
-	parse_events(s, SS_DETECT);
+	down(&skt->skt_sem);
+	socket_resume(skt);
+	up(&skt->skt_sem);
 }
 
 
@@ -1461,15 +1538,8 @@
 
     s = socket_table[ns];
     if (++s->real_clients == 1) {
-	int status;
 	register_callback(s, &parse_events, s);
-	get_socket_status(s, &status);
-	if ((status & SS_DETECT) &&
-	    !(s->state & SOCKET_SETUP_PENDING)) {
-	    s->state |= SOCKET_SETUP_PENDING;
-	    if (setup_socket(s) == 0)
-		    s->state &= ~SOCKET_SETUP_PENDING;
-	}
+	parse_events(s, SS_DETECT);
     }
 
     *handle = client;
@@ -2022,30 +2092,44 @@
 
 int pcmcia_reset_card(client_handle_t handle, client_req_t *req)
 {
-    int i, ret;
-    socket_info_t *s;
+	socket_info_t *skt;
+	int ret;
     
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
-    if (s->state & SOCKET_RESET_PENDING)
-	return CS_IN_USE;
-    s->state |= SOCKET_RESET_PENDING;
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: resetting socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (!(skt->state & SOCKET_PRESENT)) {
+			ret = CS_NO_CARD;
+			break;
+		}
+		if (skt->state & SOCKET_SUSPEND) {
+			ret = CS_IN_USE;
+			break;
+		}
+		if (skt->state & SOCKET_CARDBUS) {
+			ret = CS_UNSUPPORTED_FUNCTION;
+			break;
+		}
 
-    ret = send_event(s, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
-    if (ret != 0) {
-	s->state &= ~SOCKET_RESET_PENDING;
-	handle->event_callback_args.info = (void *)(u_long)ret;
-	EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
-    } else {
-	DEBUG(1, "cs: resetting socket %d\n", i);
-	send_event(s, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
-	s->reset_handle = handle;
-	reset_socket(s);
-    }
-    return CS_SUCCESS;
+		ret = send_event(skt, CS_EVENT_RESET_REQUEST, CS_EVENT_PRI_LOW);
+		if (ret == 0) {
+			send_event(skt, CS_EVENT_RESET_PHYSICAL, CS_EVENT_PRI_LOW);
+			if (socket_reset(skt) == CS_SUCCESS)
+				send_event(skt, CS_EVENT_CARD_RESET, CS_EVENT_PRI_LOW);
+		}
+
+		handle->event_callback_args.info = (void *)(u_long)ret;
+		EVENT(handle, CS_EVENT_RESET_COMPLETE, CS_EVENT_PRI_LOW);
+
+		ret = CS_SUCCESS;
+	} while (0);
+	up(&skt->skt_sem);
+
+	return ret;
 } /* reset_card */
 
 /*======================================================================
@@ -2057,42 +2141,56 @@
 
 int pcmcia_suspend_card(client_handle_t handle, client_req_t *req)
 {
-    int i;
-    socket_info_t *s;
+	socket_info_t *skt;
+	int ret;
     
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
-    if (s->state & SOCKET_SUSPEND)
-	return CS_IN_USE;
-
-    DEBUG(1, "cs: suspending socket %d\n", i);
-    send_event(s, CS_EVENT_PM_SUSPEND, CS_EVENT_PRI_LOW);
-    suspend_socket(s);
-    s->state |= SOCKET_SUSPEND;
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: suspending socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (!(skt->state & SOCKET_PRESENT)) {
+			ret = CS_NO_CARD;
+			break;
+		}
+		if (skt->state & SOCKET_CARDBUS) {
+			ret = CS_UNSUPPORTED_FUNCTION;
+			break;
+		}
+		ret = socket_suspend(skt);
+	} while (0);
+	up(&skt->skt_sem);
 
-    return CS_SUCCESS;
+	return ret;
 } /* suspend_card */
 
 int pcmcia_resume_card(client_handle_t handle, client_req_t *req)
 {
-    int i;
-    socket_info_t *s;
+	socket_info_t *skt;
+	int ret;
     
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
-    if (!(s->state & SOCKET_SUSPEND))
-	return CS_IN_USE;
-
-    DEBUG(1, "cs: waking up socket %d\n", i);
-    setup_socket(s);
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: waking up socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (!(skt->state & SOCKET_PRESENT)) {
+			ret = CS_NO_CARD;
+			break;
+		}
+		if (skt->state & SOCKET_CARDBUS) {
+			ret = CS_UNSUPPORTED_FUNCTION;
+			break;
+		}
+		ret = socket_resume(skt);
+	} while (0);
+	up(&skt->skt_sem);
 
-    return CS_SUCCESS;
+	return ret;
 } /* resume_card */
 
 /*======================================================================
@@ -2103,57 +2201,58 @@
 
 int pcmcia_eject_card(client_handle_t handle, client_req_t *req)
 {
-    int i, ret;
-    socket_info_t *s;
-    u_long flags;
+	socket_info_t *skt;
+	int ret;
     
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (!(s->state & SOCKET_PRESENT))
-	return CS_NO_CARD;
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: user eject request on socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (!(skt->state & SOCKET_PRESENT)) {
+			ret = CS_NO_CARD;
+			break;
+		}
 
-    DEBUG(1, "cs: user eject request on socket %d\n", i);
+		ret = send_event(skt, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
+		if (ret != 0)
+			break;
 
-    ret = send_event(s, CS_EVENT_EJECTION_REQUEST, CS_EVENT_PRI_LOW);
-    if (ret != 0)
-	return ret;
+		socket_shutdown(skt);
+		ret = CS_SUCCESS;
+	} while (0);
+	up(&skt->skt_sem);
 
-    spin_lock_irqsave(&s->lock, flags);
-    do_shutdown(s);
-    spin_unlock_irqrestore(&s->lock, flags);
-    
-    return CS_SUCCESS;
-    
+	return ret;
 } /* eject_card */
 
 int pcmcia_insert_card(client_handle_t handle, client_req_t *req)
 {
-    int i, status;
-    socket_info_t *s;
-    u_long flags;
-    
-    if (CHECK_HANDLE(handle))
-	return CS_BAD_HANDLE;
-    i = handle->Socket; s = socket_table[i];
-    if (s->state & SOCKET_PRESENT)
-	return CS_IN_USE;
-
-    DEBUG(1, "cs: user insert request on socket %d\n", i);
+	socket_info_t *skt;
+	int ret;
 
-    spin_lock_irqsave(&s->lock, flags);
-    if (!(s->state & SOCKET_SETUP_PENDING)) {
-	s->state |= SOCKET_SETUP_PENDING;
-	spin_unlock_irqrestore(&s->lock, flags);
-	get_socket_status(s, &status);
-	if ((status & SS_DETECT) == 0 || (setup_socket(s) == 0)) {
-	    s->state &= ~SOCKET_SETUP_PENDING;
-	    return CS_NO_CARD;
-	}
-    } else
-	spin_unlock_irqrestore(&s->lock, flags);
+	if (CHECK_HANDLE(handle))
+		return CS_BAD_HANDLE;
+	DEBUG(1, "cs: user insert request on socket %d\n", handle->Socket);
+	skt = SOCKET(handle);
+
+	down(&skt->skt_sem);
+	do {
+		if (skt->state & SOCKET_PRESENT) {
+			ret = CS_IN_USE;
+			break;
+		}
+		if (socket_insert(skt) == CS_NO_CARD) {
+			ret = CS_NO_CARD;
+			break;
+		}
+		ret = CS_SUCCESS;
+	} while (0);
+	up(&skt->skt_sem);
 
-    return CS_SUCCESS;
+	return ret;
 } /* insert_card */
 
 /*======================================================================
diff -Nru a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
--- a/drivers/pcmcia/cs_internal.h	Wed Apr 23 14:03:15 2003
+++ b/drivers/pcmcia/cs_internal.h	Mon May 12 15:41:01 2003
@@ -133,7 +133,6 @@
     u_short			lock_count;
     client_handle_t		clients;
     u_int			real_clients;
-    client_handle_t		reset_handle;
     pccard_mem_map		cis_mem;
     u_char			*cis_virt;
     config_t			*config;
@@ -155,6 +154,14 @@
 #ifdef CONFIG_PROC_FS
     struct proc_dir_entry	*proc;
 #endif
+
+    struct semaphore		skt_sem;	/* protects socket h/w state */
+
+    struct task_struct		*thread;
+    struct completion		thread_done;
+    wait_queue_head_t		thread_wait;
+    spinlock_t			thread_lock;	/* protects thread_events */
+    unsigned int		thread_events;
 } socket_info_t;
 
 /* Flags in config state */
diff -Nru a/drivers/pcmcia/sa11xx_core.c b/drivers/pcmcia/sa11xx_core.c
--- a/drivers/pcmcia/sa11xx_core.c	Sun Mar 30 00:13:50 2003
+++ b/drivers/pcmcia/sa11xx_core.c	Mon May 12 16:21:24 2003
@@ -120,7 +120,6 @@
 	unsigned long flags;
 	unsigned short speed;
 	unsigned int bs_io, bs_mem, bs_attr;
-	int i;
 
 	speed = calc_speed(skt->spd_io, MAX_IO_WIN, SA1100_PCMCIA_IO_ACCESS);
 	bs_io = skt->ops->socket_get_timing(skt, cpu_clock, speed);
@@ -324,13 +323,15 @@
  * handling code performs scheduling operations which cannot be
  * executed from within an interrupt context.
  */
-static void sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
+static irqreturn_t sa1100_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs)
 {
 	struct sa1100_pcmcia_socket *skt = dev;
 
 	DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq);
 
 	schedule_work(&skt->work);
+
+	return IRQ_HANDLED;
 }
 
 /* sa1100_pcmcia_register_callback()
diff -Nru a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
--- a/drivers/pnp/pnpbios/core.c	Thu Apr 10 06:38:19 2003
+++ b/drivers/pnp/pnpbios/core.c	Tue Apr 22 09:38:38 2003
@@ -252,41 +252,59 @@
 {
 	switch(status) {
 	case PNP_SUCCESS:
-	printk(KERN_ERR "PnPBIOS: %s: function successful\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: function successful\n", module);
+		break;
 	case PNP_NOT_SET_STATICALLY:
-	printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: unable to set static resources\n", module);
+		break;
 	case PNP_UNKNOWN_FUNCTION:
-	printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: invalid function number passed\n", module);
+		break;
 	case PNP_FUNCTION_NOT_SUPPORTED:
-	printk(KERN_ERR "PnPBIOS: %s: function not supported on this system\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: function not supported on this system\n", module);
+		break;
 	case PNP_INVALID_HANDLE:
-	printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: invalid handle\n", module);
+		break;
 	case PNP_BAD_PARAMETER:
-	printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: invalid parameters were passed\n", module);
+		break;
 	case PNP_SET_FAILED:
-	printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: unable to set resources\n", module);
+		break;
 	case PNP_EVENTS_NOT_PENDING:
-	printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: no events are pending\n", module);
+		break;
 	case PNP_SYSTEM_NOT_DOCKED:
-	printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: the system is not docked\n", module);
+		break;
 	case PNP_NO_ISA_PNP_CARDS:
-	printk(KERN_ERR "PnPBIOS: %s: no isapnp cards are installed on this system\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: no isapnp cards are installed on this system\n", module);
+		break;
 	case PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES:
-	printk(KERN_ERR "PnPBIOS: %s: cannot determine the capabilities of the docking station\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: cannot determine the capabilities of the docking station\n", module);
+		break;
 	case PNP_CONFIG_CHANGE_FAILED_NO_BATTERY:
-	printk(KERN_ERR "PnPBIOS: %s: unable to undock, the system does not have a battery\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: unable to undock, the system does not have a battery\n", module);
+		break;
 	case PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT:
-	printk(KERN_ERR "PnPBIOS: %s: could not dock due to resource conflicts\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: could not dock due to resource conflicts\n", module);
+		break;
 	case PNP_BUFFER_TOO_SMALL:
-	printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: the buffer passed is too small\n", module);
+		break;
 	case PNP_USE_ESCD_SUPPORT:
-	printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: use ESCD instead\n", module);
+		break;
 	case PNP_MESSAGE_NOT_SUPPORTED:
-	printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: the message is unsupported\n", module);
+		break;
 	case PNP_HARDWARE_ERROR:
-	printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", module);
+		printk(KERN_ERR "PnPBIOS: %s: a hardware failure has occured\n", module);
+		break;
 	default:
-	printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module, status);
+		printk(KERN_ERR "PnPBIOS: %s: unexpected status 0x%x\n", module, status);
+		break;
 	}
 }
 
diff -Nru a/drivers/pnp/resource.c b/drivers/pnp/resource.c
--- a/drivers/pnp/resource.c	Sun Apr 20 14:14:29 2003
+++ b/drivers/pnp/resource.c	Mon May 12 21:23:10 2003
@@ -422,7 +422,7 @@
 
 static irqreturn_t pnp_test_handler(int irq, void *dev_id, struct pt_regs *regs)
 {
-	return IRQ_NONE;
+	return IRQ_HANDLED;
 }
 
 int pnp_check_irq(struct pnp_dev * dev, int idx)
diff -Nru a/drivers/s390/char/tuball.c b/drivers/s390/char/tuball.c
--- a/drivers/s390/char/tuball.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/s390/char/tuball.c	Wed May  7 08:47:30 2003
@@ -468,9 +468,8 @@
 	}
 #endif /* CONFIG_TN3270_CONSOLE */
 
-#ifdef CONFIG_DEVFS_FS
-	fs3270_devfs_register(tubp);
-#endif
+	devfs_mk_cdev(MKDEV(IBM_FS3270_MAJOR, tubp->minor),
+			S_IFCHR|S_IRUSR|S_IWUSR, "3270/tub%.4x");
 
 	TUBUNLOCK(tubp->irq, flags);
 	return minor;
@@ -492,9 +491,7 @@
 	for (i = 0; i < TUBMAXMINS; i++) {
 		tubpp = &(*tubminors)[i];
 		if ((tubp = *tubpp)) {
-#ifdef CONFIG_DEVFS_FS
-			fs3270_devfs_unregister(tubp);
-#endif
+			devfs_remove("3270/tub%.4x", tubp->devno);
 			tubdelbyirq(tubp, tubp->irq);
 			tty3270_rcl_fini(tubp);
 			kfree(tubp->tty_bcb.bc_buf);
diff -Nru a/drivers/s390/char/tubfs.c b/drivers/s390/char/tubfs.c
--- a/drivers/s390/char/tubfs.c	Fri Apr 18 11:14:59 2003
+++ b/drivers/s390/char/tubfs.c	Wed May  7 08:47:30 2003
@@ -23,9 +23,7 @@
 extern void tty3270_refresh(tub_t *);
 
 static struct file_operations fs3270_fops = {
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
 	.owner = THIS_MODULE,		/* owner */
-#endif
 	.read 	= fs3270_read,	/* read */
 	.write	= fs3270_write,	/* write */
 	.ioctl	= fs3270_ioctl,	/* ioctl */
@@ -33,27 +31,6 @@
 	.release = fs3270_close,	/* release */
 };
 
-#ifdef CONFIG_DEVFS_FS
-void fs3270_devfs_register(tub_t *tubp)
-{
-	char name[16];
-
-	sprintf(name, "3270/tub%.4x", tubp->devno);
-	devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-		       IBM_FS3270_MAJOR, tubp->minor,
-		       S_IFCHR | S_IRUSR | S_IWUSR, &fs3270_fops, NULL);
-	sprintf(name, "tty%.4x", tubp->devno);
-	tty_register_devfs_name(&tty3270_driver, 0, tubp->minor,
-				NULL, name);
-}
-
-void fs3270_devfs_unregister(tub_t *tubp)
-{
-	devfs_remove("3270/tub%.4x", tubp->devno);
-	devfs_remove("3270/tty%.4x", tubp->devno);
-}
-#endif
-
 /*
  * fs3270_init() -- Initialize fullscreen tubes
  */
@@ -69,10 +46,8 @@
 		return -1;
 	}
 	devfs_mk_dir("3270");
-	devfs_register(NULL, "3270/tub", 0,
-			       IBM_FS3270_MAJOR, 0,
-			       S_IFCHR | S_IRUGO | S_IWUGO, 
-			       &fs3270_fops, NULL);
+	devfs_mk_cdev(MKDEV(IBM_FS3270_MAJOR, 0),
+			S_IFCHR|S_IRUGO|S_IWUGO, "3270/tub");
 	fs3270_major = IBM_FS3270_MAJOR;
 	return 0;
 }
diff -Nru a/drivers/s390/char/tubio.h b/drivers/s390/char/tubio.h
--- a/drivers/s390/char/tubio.h	Mon Apr 21 20:58:42 2003
+++ b/drivers/s390/char/tubio.h	Wed May  7 08:47:30 2003
@@ -337,10 +337,6 @@
 extern int tty3270_proc_misc;
 extern enum tubwhat tty3270_proc_what;
 extern struct tty_driver tty3270_driver;
-#ifdef CONFIG_DEVFS_FS
-extern void fs3270_devfs_register(tub_t *);
-extern void fs3270_devfs_unregister(tub_t *);
-#endif
 
 #ifndef spin_trylock_irqsave
 #define spin_trylock_irqsave(lock, flags) \
diff -Nru a/drivers/s390/char/tubtty.c b/drivers/s390/char/tubtty.c
--- a/drivers/s390/char/tubtty.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/s390/char/tubtty.c	Wed May  7 08:47:30 2003
@@ -90,9 +90,7 @@
 	td->subtype = SYSTEM_TYPE_TTY;
 	td->init_termios = tty_std_termios;
 	td->flags = TTY_DRIVER_RESET_TERMIOS;
-#ifdef CONFIG_DEVFS_FS
 	td->flags |= TTY_DRIVER_NO_DEVFS;
-#endif
 	td->refcount = &tty3270_refcount;
 	td->table = tty3270_table;
 	td->termios = tty3270_termios;
diff -Nru a/drivers/sbus/char/bpp.c b/drivers/sbus/char/bpp.c
--- a/drivers/sbus/char/bpp.c	Sat Mar 22 07:38:04 2003
+++ b/drivers/sbus/char/bpp.c	Wed May  7 08:47:30 2003
@@ -1051,11 +1051,8 @@
 	}
 	devfs_mk_dir("bpp");
 	for (idx = 0; idx < BPP_NO; idx++) {
-		char name[16];
-		sprintf(name, "bpp/%d", idx);
-		devfs_register(NULL, name, DEVFS_FL_DEFAULT,
-			       BPP_MAJOR, idx, S_IFCHR | S_IRUSR | S_IWUSR,
-			       &bpp_fops, NULL);
+		devfs_mk_cdev(MKDEV(BPP_MAJOR, idx),
+				S_IFCHR | S_IRUSR | S_IWUSR, "bpp/%d", idx);
 	}
 
 	return 0;
diff -Nru a/drivers/sbus/char/vfc_dev.c b/drivers/sbus/char/vfc_dev.c
--- a/drivers/sbus/char/vfc_dev.c	Sat Mar 22 07:38:05 2003
+++ b/drivers/sbus/char/vfc_dev.c	Wed May  7 08:47:30 2003
@@ -143,8 +143,6 @@
 
 int init_vfc_device(struct sbus_dev *sdev,struct vfc_dev *dev, int instance)
 {
-	char devname[16];
-
 	if(dev == NULL) {
 		printk(KERN_ERR "VFC: Bogus pointer passed\n");
 		return -ENOMEM;
@@ -167,11 +165,9 @@
 	if (init_vfc_hw(dev))
 		return -EIO;
 
-	sprintf (devname, "vfc/%d", instance);
-	dev->de = devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
-				  VFC_MAJOR, instance,
-				  S_IFCHR | S_IRUSR | S_IWUSR,
-				  &vfc_fops, NULL);
+	devfs_mk_cdev(MKDEV(VFC_MAJOR, instance),
+			S_IFCHR | S_IRUSR | S_IWUSR,
+			"vfc/%d", instance);
 	return 0;
 }
 
diff -Nru a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
--- a/drivers/scsi/3w-xxxx.c	Sat Apr 26 07:28:11 2003
+++ b/drivers/scsi/3w-xxxx.c	Sun May  4 02:56:43 2003
@@ -3439,7 +3439,24 @@
 	outl(control_reg_value, control_reg_addr);
 } /* End tw_unmask_command_interrupt() */
 
-/* Now get things going */
-static Scsi_Host_Template driver_template = TWXXXX;
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "3w-xxxx",
+	.proc_info		= tw_scsi_proc_info,
+	.name			= "3ware Storage Controller",
+	.detect			= tw_scsi_detect,
+	.release		= tw_scsi_release,
+	.queuecommand		= tw_scsi_queue,
+	.eh_abort_handler	= tw_scsi_eh_abort,
+	.eh_host_reset_handler	= tw_scsi_eh_reset,
+	.bios_param		= tw_scsi_biosparam,
+	.can_queue		= TW_Q_LENGTH-2,
+	.this_id		= -1,
+	.sg_tablesize		= TW_MAX_SGL_LENGTH,
+	.max_sectors		= TW_MAX_SECTORS,
+	.cmd_per_lun		= TW_MAX_CMDS_PER_LUN,	
+	.use_clustering		= ENABLE_CLUSTERING,
+	.emulated		= 1,
+	.highmem_io		= 1,
+};
 #include "scsi_module.c"
 
diff -Nru a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h
--- a/drivers/scsi/3w-xxxx.h	Sat Mar 22 12:19:28 2003
+++ b/drivers/scsi/3w-xxxx.h	Sun May  4 02:56:43 2003
@@ -497,26 +497,4 @@
 int tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id);
 void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev);
 
-/* Scsi_Host_Template Initializer */
-#define TWXXXX {					\
-	.proc_name	= "3w-xxxx",			\
-	.proc_info	= tw_scsi_proc_info,		\
-	.name		= "3ware Storage Controller",	\
-	.detect		= tw_scsi_detect,		\
-	.release	= tw_scsi_release,		\
-	.queuecommand	= tw_scsi_queue,		\
-	.eh_abort_handler	= tw_scsi_eh_abort,	\
-	.eh_host_reset_handler	= tw_scsi_eh_reset,	\
-	.bios_param	= tw_scsi_biosparam,		\
-	.can_queue	= TW_Q_LENGTH-2,		\
-	.this_id	= -1,				\
-	.sg_tablesize	= TW_MAX_SGL_LENGTH,		\
-	.max_sectors    = TW_MAX_SECTORS,		\
-	.cmd_per_lun	= TW_MAX_CMDS_PER_LUN,		\
-	.present	= 0,				\
-	.unchecked_isa_dma	= 0,			\
-	.use_clustering	= ENABLE_CLUSTERING,		\
-	.emulated	= 1,				\
-	.highmem_io	= 1				\
-}
 #endif /* _3W_XXXX_H */
diff -Nru a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c
--- a/drivers/scsi/AM53C974.c	Wed Feb 26 11:32:42 2003
+++ b/drivers/scsi/AM53C974.c	Sun May  4 02:56:43 2003
@@ -2453,5 +2453,21 @@
 MODULE_LICENSE("GPL");
 
 
-static Scsi_Host_Template driver_template = AM53C974;
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "am53c974",
+	.name           	= "AM53C974",
+	.detect         	= AM53C974_pci_detect,
+	.release        	= AM53C974_release,	
+	.info			= AM53C974_info,
+	.command		= AM53C974_command,
+	.queuecommand		= AM53C974_queue_command,
+	.abort			= AM53C974_abort,
+	.reset			= AM53C974_reset,
+	.can_queue		= 12,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/AM53C974.h b/drivers/scsi/AM53C974.h
--- a/drivers/scsi/AM53C974.h	Tue Dec 10 12:28:34 2002
+++ b/drivers/scsi/AM53C974.h	Sun May  4 02:56:43 2003
@@ -50,23 +50,6 @@
 	unsigned char max_offset[8];	/* max. sync. offset (setup), only valid if corresponding sync_en is nonzero */
 };
 
-#define AM53C974 {				  \
-    .proc_name      = "am53c974",    	          \
-    .name           = "AM53C974",        		  \
-    .detect         = AM53C974_pci_detect,	  \
-    .release        = AM53C974_release,		  \
-    .info           = AM53C974_info,     		  \
-    .command        = AM53C974_command,  		  \
-    .queuecommand   = AM53C974_queue_command,	  \
-    .abort          = AM53C974_abort,    		  \
-    .reset          = AM53C974_reset,    		  \
-    .can_queue      = 12,                 	  \
-    .this_id        = -1,                           \
-    .sg_tablesize   = SG_ALL,            		  \
-    .cmd_per_lun    = 1,                 		  \
-    .use_clustering = DISABLE_CLUSTERING 		  \
-    }
-
 static int AM53C974_pci_detect(Scsi_Host_Template * tpnt);
 static int AM53C974_release(struct Scsi_Host *shp);
 static const char *AM53C974_info(struct Scsi_Host *);
diff -Nru a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
--- a/drivers/scsi/BusLogic.c	Sat Apr 26 07:28:12 2003
+++ b/drivers/scsi/BusLogic.c	Sun May  4 02:56:43 2003
@@ -3213,6 +3213,7 @@
 	    Place CCB back on the Host Adapter's free list.
 	  */
 	  BusLogic_DeallocateCCB(CCB);
+#if 0	/* this needs to be redone different for new EH */
 	  /*
 	    Bus Device Reset CCBs have the Command field non-NULL only when a
 	    Bus Device Reset was requested for a Command that did not have a
@@ -3228,6 +3229,7 @@
 	      Command->scsi_done(Command);
 	      Command = NextCommand;
 	    }
+#endif
 	  /*
 	    Iterate over the CCBs for this Host Adapter performing completion
 	    processing for any CCBs marked as Reset for this Target.
@@ -3948,6 +3950,7 @@
       {
 	Command = CCB->Command;
 	BusLogic_DeallocateCCB(CCB);
+#if 0	/* this needs to be redone different for new EH */
 	while (Command != NULL)
 	  {
 	    SCSI_Command_T *NextCommand = Command->reset_chain;
@@ -3956,6 +3959,7 @@
 	    Command->scsi_done(Command);
 	    Command = NextCommand;
 	  }
+#endif
       }
   for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
     {
@@ -3967,7 +3971,7 @@
   return Result;
 }
 
-
+#if 0	/* old-style EH code references a dead struct scsi_cmnd member */
 /*
   BusLogic_SendBusDeviceReset sends a Bus Device Reset to the Target
   Device associated with Command.
@@ -4204,6 +4208,7 @@
     }
   return SCSI_RESET_PUNT;
 }
+#endif
 
 
 /*
@@ -5113,6 +5118,18 @@
 */
 MODULE_LICENSE("GPL");
 
-static SCSI_Host_Template_T driver_template = BUSLOGIC;
-
+static SCSI_Host_Template_T driver_template = {
+	.proc_name		= "BusLogic",
+	.proc_info		= BusLogic_ProcDirectoryInfo,
+	.name			= "BusLogic",
+	.detect			= BusLogic_DetectHostAdapter,
+	.release		= BusLogic_ReleaseHostAdapter,
+	.info			= BusLogic_DriverInfo,
+	.queuecommand		= BusLogic_QueueCommand,
+	.slave_configure	= BusLogic_SlaveConfigure,
+	.bios_param		= BusLogic_BIOSDiskParameters,
+	.unchecked_isa_dma	= 1,
+	.max_sectors		= 128,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
--- a/drivers/scsi/BusLogic.h	Sat Apr 26 07:28:13 2003
+++ b/drivers/scsi/BusLogic.h	Sun May  4 02:56:43 2003
@@ -59,30 +59,6 @@
 extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
 extern int BusLogic_SlaveConfigure(SCSI_Device_T *);
 
-
-/*
-  Define the BusLogic SCSI Host Template structure.
-*/
-
-#define BUSLOGIC							       \
-  { .proc_name      = "BusLogic",			  /* ProcFS Directory Entry */ \
-    .proc_info      = BusLogic_ProcDirectoryInfo,	  /* ProcFS Info Function   */ \
-    .name           = "BusLogic",			  /* Driver Name            */ \
-    .detect         = BusLogic_DetectHostAdapter,	  /* Detect Host Adapter    */ \
-    .release        = BusLogic_ReleaseHostAdapter,  /* Release Host Adapter   */ \
-    .info           = BusLogic_DriverInfo,	  /* Driver Info Function   */ \
-    .queuecommand   = BusLogic_QueueCommand,	  /* Queue Command Function */ \
-    .slave_configure = BusLogic_SlaveConfigure,	  /* Configure a SCSI_Device*/ \
-    .bios_param     = BusLogic_BIOSDiskParameters,  /* BIOS Disk Parameters   */ \
-    .unchecked_isa_dma = 1,			  /* Default Initial Value  */ \
-    .max_sectors    = 128,			  /* I/O queue len limit    */ \
-    .use_clustering = ENABLE_CLUSTERING }		  /* Enable Clustering	    */
-
-
-/*
-  BusLogic_DriverVersion protects the private portion of this file.
-*/
-
 #ifdef BusLogic_DriverVersion
 
 
diff -Nru a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
--- a/drivers/scsi/Kconfig	Sat Apr 26 14:19:41 2003
+++ b/drivers/scsi/Kconfig	Sat May 17 06:52:30 2003
@@ -1602,7 +1602,7 @@
 	  whenever you want). If you want to compile it as a module, say M
 	  here and read <file:Documentation/modules.txt>.
 
-source "drivers/acorn/scsi/Kconfig"
+source "drivers/scsi/arm/Kconfig"
 
 config JAZZ_ESP
 	bool "MIPS JAZZ FAS216 SCSI support"
diff -Nru a/drivers/scsi/Makefile b/drivers/scsi/Makefile
--- a/drivers/scsi/Makefile	Sat Apr 26 14:19:41 2003
+++ b/drivers/scsi/Makefile	Sat May 17 08:48:39 2003
@@ -114,7 +114,7 @@
 obj-$(CONFIG_SCSI_LASI700)	+= lasi700.o 53c700.o
 obj-$(CONFIG_SCSI_NSP32)	+= nsp32.o
 
-obj-$(CONFIG_ARCH_ACORN)	+= ../acorn/scsi/
+obj-$(CONFIG_ARM)		+= arm/
 
 obj-$(CONFIG_CHR_DEV_ST)	+= st.o
 obj-$(CONFIG_CHR_DEV_OSST)	+= osst.o
@@ -124,7 +124,8 @@
 
 scsi_mod-y			+= scsi.o hosts.o scsi_ioctl.o constants.o \
 				   scsicam.o scsi_error.o scsi_lib.o \
-				   scsi_scan.o scsi_syms.o scsi_sysfs.o
+				   scsi_scan.o scsi_syms.o scsi_sysfs.o \
+				   scsi_devinfo.o
 scsi_mod-$(CONFIG_PROC_FS)	+= scsi_proc.o
 scsi_mod-$(CONFIG_X86_PC9800)	+= scsi_pc98.o
 			
diff -Nru a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
--- a/drivers/scsi/NCR5380.c	Sat Apr 26 07:28:13 2003
+++ b/drivers/scsi/NCR5380.c	Thu May 15 18:42:51 2003
@@ -2471,11 +2471,11 @@
 
 					if (cmd->cmnd[0] != REQUEST_SENSE)
 						cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
-					else if (cmd->SCp.Status != GOOD)
+					else if (status_byte(cmd->SCp.Status) != GOOD)
 						cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
 
 #ifdef AUTOSENSE
-					if ((cmd->cmnd[0] != REQUEST_SENSE) && (cmd->SCp.Status == CHECK_CONDITION)) {
+					if ((cmd->cmnd[0] != REQUEST_SENSE) && (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
 						dprintk(NDEBUG_AUTOSENSE, ("scsi%d : performing request sense\n", instance->host_no));
 						cmd->cmnd[0] = REQUEST_SENSE;
 						cmd->cmnd[1] &= 0xe0;
diff -Nru a/drivers/scsi/NCR_D700.c b/drivers/scsi/NCR_D700.c
--- a/drivers/scsi/NCR_D700.c	Thu Feb 20 08:41:07 2003
+++ b/drivers/scsi/NCR_D700.c	Thu May  1 09:54:33 2003
@@ -92,18 +92,12 @@
 
 #define NCR_D700_VERSION "2.2"
 
-#include <linux/config.h>
-#include <linux/blk.h>
+#include <linux/blkdev.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/mca.h>
-
-#include <asm/dma.h>
-#include <asm/system.h>
 #include <asm/io.h>
-#include <asm/pgtable.h>
-#include <asm/byteorder.h>
 
 #include "scsi.h"
 #include "hosts.h"
@@ -111,16 +105,6 @@
 #include "53c700.h"
 #include "NCR_D700.h"
 
-#ifndef CONFIG_MCA
-#error "NCR_D700 driver only compiles for MCA"
-#endif
-
-#ifdef NCR_D700_DEBUG
-#define STATIC
-#else
-#define STATIC static
-#endif
-
 char *NCR_D700;			/* command line from insmod */
 
 MODULE_AUTHOR("James Bottomley");
@@ -170,34 +154,101 @@
 	return 1;
 }
 
-#ifndef MODULE
-__setup("NCR_D700=", param_setup);
-#endif
+/* Host template.  The 53c700 routine NCR_700_detect will
+ * fill in all of the missing routines */
+static Scsi_Host_Template NCR_D700_driver_template = {
+	.module			= THIS_MODULE,
+	.name			= "NCR Dual 700 MCA",
+	.proc_name		= "NCR_D700",
+	.this_id		= 7,
+};
 
-/* private stack allocated structure for passing device information from
- * detect to probe */
-struct NCR_700_info {
-	Scsi_Host_Template *tpnt;
-	int found;
+/* We needs this helper because we have two hosts per struct device */
+struct NCR_D700_private {
+	struct device		*dev;
+	struct Scsi_Host	*hosts[2];
 };
 
-/* Detect a D700 card.  Note, because of the set up---the chips are
+static int 
+NCR_D700_probe_one(struct NCR_D700_private *p, int siop,
+		int irq, int slot, u32 region, int differential)
+{
+	struct NCR_700_Host_Parameters *hostdata;
+	struct Scsi_Host *host;
+	int ret;
+
+	hostdata = kmalloc(sizeof(*hostdata), GFP_KERNEL);
+	if (!hostdata) {
+		printk(KERN_ERR "NCR D700: SIOP%d: Failed to allocate host"
+		       "data, detatching\n", siop);
+		return -ENOMEM;
+	}
+	memset(hostdata, 0, sizeof(*hostdata));
+
+	if (!request_region(region, 64, "NCR_D700")) {
+		printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n",
+				region);
+		ret = -ENODEV;
+		goto region_failed;
+	}
+		
+	/* Fill in the three required pieces of hostdata */
+	hostdata->base = region;
+	hostdata->differential = (((1<<siop) & differential) != 0);
+	hostdata->clock = NCR_D700_CLOCK_MHZ;
+
+	/* and register the siop */
+	host = NCR_700_detect(&NCR_D700_driver_template, hostdata);
+	if (!host) {
+		ret = -ENOMEM;
+		goto detect_failed;
+	}
+
+	host->irq = irq;
+	/* FIXME: Read this from SUS */
+	host->this_id = id_array[slot * 2 + siop];
+	printk(KERN_NOTICE "NCR D700: SIOP%d, SCSI id is %d\n",
+			siop, host->this_id);
+	if (request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) {
+		printk(KERN_ERR "NCR D700: SIOP%d: irq problem, "
+				"detatching\n", siop);
+		ret = -ENODEV;
+		goto irq_failed;
+	}
+
+	scsi_add_host(host, p->dev);
+
+	p->hosts[siop] = host;
+	hostdata->dev = p->dev;
+	return 0;
+
+ irq_failed:
+	scsi_unregister(host);
+	NCR_700_release(host);
+ detect_failed:
+	release_region(host->base, 64);
+ region_failed:
+	kfree(hostdata);
+
+	return ret;
+}
+
+/* Detect a D700 card.  Note, because of the setup --- the chips are
  * essentially connectecd to the MCA bus independently, it is easier
  * to set them up as two separate host adapters, rather than one
  * adapter with two channels */
 static int
 NCR_D700_probe(struct device *dev)
 {
+	struct NCR_D700_private *p;
 	int differential;
 	static int banner = 1;
 	struct mca_device *mca_dev = to_mca_device(dev);
 	int slot = mca_dev->slot;
-	struct NCR_700_info *info = to_mca_driver(dev->driver)->driver_data;
 	int found = 0;
 	int irq, i;
 	int pos3j, pos3k, pos3a, pos3b, pos4;
 	__u32 base_addr, offset_addr;
-	struct Scsi_Host *host = NULL;
 
 	/* enable board interrupt */
 	pos4 = mca_device_read_pos(mca_dev, 4);
@@ -232,8 +283,6 @@
 
 	printk(KERN_NOTICE "NCR D700: found in slot %d  irq = %d  I/O base = 0x%x\n", slot, irq, offset_addr);
 
-	info->tpnt->proc_name = "NCR_D700";
-
 	/*outb(BOARD_RESET, base_addr);*/
 
 	/* clear any pending interrupts */
@@ -259,70 +308,56 @@
 		break;
 	}
 
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return -ENOMEM;
+	p->dev = dev;
+
 	/* plumb in both 700 chips */
-	for(i=0; i<2; i++) {
-		__u32 region = offset_addr | (0x80 * i);
-		struct NCR_700_Host_Parameters *hostdata =
-			kmalloc(sizeof(struct NCR_700_Host_Parameters),
-				GFP_KERNEL);
-		if(hostdata == NULL) {
-			printk(KERN_ERR "NCR D700: Failed to allocate host data for channel %d, detatching\n", i);
-			continue;
-		}
-		memset(hostdata, 0, sizeof(struct NCR_700_Host_Parameters));
-		if(request_region(region, 64, "NCR_D700") == NULL) {
-			printk(KERN_ERR "NCR D700: Failed to reserve IO region 0x%x\n", region);
-			kfree(hostdata);
-			continue;
-		}
-		
-		/* Fill in the three required pieces of hostdata */
-		hostdata->base = region;
-		hostdata->differential = (((1<<i) & differential) != 0);
-		hostdata->clock = NCR_D700_CLOCK_MHZ;
-		/* and register the chip */
-		if((host = NCR_700_detect(info->tpnt, hostdata)) == NULL) {
-			kfree(hostdata);
-			release_region(host->base, 64);
-			continue;
-		}
-		host->irq = irq;
-		/* FIXME: Read this from SUS */
-		host->this_id = id_array[slot * 2 + i];
-		printk(KERN_NOTICE "NCR D700: SIOP%d, SCSI id is %d\n",
-		       i, host->this_id);
-		if(request_irq(irq, NCR_700_intr, SA_SHIRQ, "NCR_D700", host)) {
-			printk(KERN_ERR "NCR D700, channel %d: irq problem, detatching\n", i);
-			scsi_unregister(host);
-			NCR_700_release(host);
-			continue;
-		}
-		scsi_set_device(host, dev);
-		hostdata->dev = dev;
-		found++;
+	for (i = 0; i < 2; i++) {
+		int err;
+
+		if ((err = NCR_D700_probe_one(p, i, irq, slot,
+					      offset_addr + (0x80 * i),
+					      differential)) != 0)
+			printk("D700: SIOP%d: probe failed, error = %d\n",
+			       i, err);
+		else
+			found++;
 	}
-	info->found += found;
 
-	if(found) {
-		mca_device_set_claim(mca_dev, 1);
-		strncpy(dev->name, "NCR_D700", sizeof(dev->name));
+	if (!found) {
+		kfree(p);
+		return -ENODEV;
 	}
 
-	return found? 0 : -ENODEV;
+	mca_device_set_claim(mca_dev, 1);
+	strncpy(dev->name, "NCR_D700", sizeof(dev->name));
+	dev_set_drvdata(dev, p);
+	return 0;
 }
 
-
-STATIC int
-D700_release(struct Scsi_Host *host)
+static void
+NCR_D700_remove_one(struct Scsi_Host *host)
 {
-	struct D700_Host_Parameters *hostdata = 
-		(struct D700_Host_Parameters *)host->hostdata[0];
-
+	scsi_remove_host(host);
 	NCR_700_release(host);
-	kfree(hostdata);
+	kfree((struct NCR_700_Host_Parameters *)host->hostdata[0]);
 	free_irq(host->irq, host);
 	release_region(host->base, 64);
-	return 1;
+}
+
+static int
+NCR_D700_remove(struct device *dev)
+{
+	struct NCR_D700_private *p = dev_get_drvdata(dev);
+	int i;
+
+	for (i = 0; i < 2; i++)
+		NCR_D700_remove_one(p->hosts[i]);
+
+	kfree(p);
+	return 0;
 }
 
 static short NCR_D700_id_table[] = { NCR_D700_MCA_ID, 0 };
@@ -330,34 +365,29 @@
 struct mca_driver NCR_D700_driver = {
 	.id_table = NCR_D700_id_table,
 	.driver = {
-		.name = "NCR_D700",
-		.bus = &mca_bus_type,
-		.probe = NCR_D700_probe,
+		.name		= "NCR_D700",
+		.bus		= &mca_bus_type,
+		.probe		= NCR_D700_probe,
+		.remove		= NCR_D700_remove,
 	},
 };
-		
 
-STATIC int __init
-D700_detect(Scsi_Host_Template *tpnt)
+static int __init NCR_D700_init(void)
 {
-	struct NCR_700_info info;
-
-	if(!MCA_bus)
-		return 0;
-
 #ifdef MODULE
-	if(NCR_D700)
+	if (NCR_D700)
 		param_setup(NCR_D700);
 #endif
-	info.tpnt = tpnt;
-	info.found = 0;
-	NCR_D700_driver.driver_data = &info;
-	mca_register_driver(&NCR_D700_driver);
 
-	return info.found;
+	return mca_register_driver(&NCR_D700_driver);
+}
+
+static void __exit NCR_D700_exit(void)
+{
+	mca_unregister_driver(&NCR_D700_driver);
 }
-	
-static Scsi_Host_Template driver_template = NCR_D700_SCSI;
 
-#include "scsi_module.c"
+module_init(NCR_D700_init);
+module_exit(NCR_D700_exit);
 
+__setup("NCR_D700=", param_setup);
diff -Nru a/drivers/scsi/NCR_D700.h b/drivers/scsi/NCR_D700.h
--- a/drivers/scsi/NCR_D700.h	Fri Nov 22 20:24:13 2002
+++ b/drivers/scsi/NCR_D700.h	Thu May  1 09:52:21 2003
@@ -14,22 +14,6 @@
 /* The MCA identifier */
 #define NCR_D700_MCA_ID		0x0092
 
-static int D700_detect(Scsi_Host_Template *);
-static int D700_release(struct Scsi_Host *host);
-
-
-/* Host template.  Note the name and proc_name are optional, all the
- * remaining parameters shown below must be filled in.  The 53c700
- * routine NCR_700_detect will fill in all of the missing routines */
-#define NCR_D700_SCSI {						\
-	.name =				"NCR Dual 700 MCA",	\
-	.proc_name =			"NCR_D700",		\
-	.detect = 			D700_detect,		\
-	.release =			D700_release,		\
-	.this_id =			7,			\
-}
-
-
 /* Defines for the Board registers */
 #define	BOARD_RESET		0x80	/* board level reset */
 #define ADD_PARENB		0x04	/* Address Parity Enabled */
diff -Nru a/drivers/scsi/aacraid/README b/drivers/scsi/aacraid/README
--- a/drivers/scsi/aacraid/README	Wed Oct  2 13:37:46 2002
+++ b/drivers/scsi/aacraid/README	Wed May  7 19:08:36 2003
@@ -18,6 +18,12 @@
 	ADAPTEC 2120S
 	ADAPTEC 2200S
 	ADAPTEC 5400S
+	Legend S220
+	Legend S230
+	Adaptec 3230S
+	Adaptec 3240S
+	ASR-2020S PCI-X
+	AAR-2410SA SATA
 
 People
 -------------------------
@@ -28,6 +34,9 @@
 					 added new ioctls, changed scsi interface to use new error handler,
 					 increased the number of fibs and outstanding commands to a container)
 
+					(fixed 64bit and 64G memory model, changed confusing naming convention
+					 where fibs that go to the hardware are consistently called hw_fibs and
+					 not just fibs like the name of the driver tracking structure)
 Original Driver
 -------------------------
 Adaptec Unix OEM Product Group
diff -Nru a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
--- a/drivers/scsi/aacraid/aachba.c	Mon Jan 27 12:45:03 2003
+++ b/drivers/scsi/aacraid/aachba.c	Thu May  8 11:24:16 2003
@@ -40,8 +40,7 @@
 #include "aacraid.h"
 
 /*	SCSI Commands */
-/*	TODO:  dmb - use the ones defined in include/scsi/scsi.h */
-
+/* TODO dmb - use the ones defined in include/scsi/scsi.h*/
 #define	SS_TEST			0x00	/* Test unit ready */
 #define SS_REZERO		0x01	/* Rezero unit */
 #define	SS_REQSEN		0x03	/* Request Sense */
@@ -60,15 +59,15 @@
 #define SS_SEEK			0x2B	/* Seek */
 
 /* values for inqd_pdt: Peripheral device type in plain English */
-#define	INQD_PDT_DA	0x00		/* Direct-access (DISK) device */
-#define	INQD_PDT_PROC	0x03		/* Processor device */
-#define	INQD_PDT_CHNGR	0x08		/* Changer (jukebox, scsi2) */
-#define	INQD_PDT_COMM	0x09		/* Communication device (scsi2) */
-#define	INQD_PDT_NOLUN2 0x1f		/* Unknown Device (scsi2) */
-#define	INQD_PDT_NOLUN	0x7f		/* Logical Unit Not Present */
+#define	INQD_PDT_DA	0x00	/* Direct-access (DISK) device */
+#define	INQD_PDT_PROC	0x03	/* Processor device */
+#define	INQD_PDT_CHNGR	0x08	/* Changer (jukebox, scsi2) */
+#define	INQD_PDT_COMM	0x09	/* Communication device (scsi2) */
+#define	INQD_PDT_NOLUN2 0x1f	/* Unknown Device (scsi2) */
+#define	INQD_PDT_NOLUN	0x7f	/* Logical Unit Not Present */
 
-#define	INQD_PDT_DMASK	0x1F		/* Peripheral Device Type Mask */
-#define	INQD_PDT_QMASK	0xE0		/* Peripheral Device Qualifer Mask */
+#define	INQD_PDT_DMASK	0x1F	/* Peripheral Device Type Mask */
+#define	INQD_PDT_QMASK	0xE0	/* Peripheral Device Qualifer Mask */
 
 #define	TARGET_LUN_TO_CONTAINER(target, lun)	(target)
 #define CONTAINER_TO_TARGET(cont)		((cont))
@@ -81,22 +80,22 @@
 /*
  *	Sense keys
  */
-#define SENKEY_NO_SENSE      			0x00	
-#define SENKEY_UNDEFINED     			0x01	
-#define SENKEY_NOT_READY     			0x02	
-#define SENKEY_MEDIUM_ERR    			0x03	
-#define SENKEY_HW_ERR        			0x04	
-#define SENKEY_ILLEGAL       			0x05	
-#define SENKEY_ATTENTION     			0x06	
-#define SENKEY_PROTECTED     			0x07	
-#define SENKEY_BLANK         			0x08	
-#define SENKEY_V_UNIQUE      			0x09	
-#define SENKEY_CPY_ABORT     			0x0A	
-#define SENKEY_ABORT         			0x0B	
-#define SENKEY_EQUAL         			0x0C	
-#define SENKEY_VOL_OVERFLOW  			0x0D	
-#define SENKEY_MISCOMP       			0x0E	
-#define SENKEY_RESERVED      			0x0F	
+#define SENKEY_NO_SENSE      0x00	
+#define SENKEY_UNDEFINED     0x01	
+#define SENKEY_NOT_READY     0x02	
+#define SENKEY_MEDIUM_ERR    0x03	
+#define SENKEY_HW_ERR        0x04	
+#define SENKEY_ILLEGAL       0x05	
+#define SENKEY_ATTENTION     0x06	
+#define SENKEY_PROTECTED     0x07	
+#define SENKEY_BLANK         0x08	
+#define SENKEY_V_UNIQUE      0x09	
+#define SENKEY_CPY_ABORT     0x0A	
+#define SENKEY_ABORT         0x0B	
+#define SENKEY_EQUAL         0x0C	
+#define SENKEY_VOL_OVERFLOW  0x0D	
+#define SENKEY_MISCOMP       0x0E	
+#define SENKEY_RESERVED      0x0F	
 
 /*
  *	Sense codes
@@ -160,24 +159,24 @@
  *----------------------------------------------------------------------------*/
 /* SCSI inquiry data */
 struct inquiry_data {
-	u8 inqd_pdt;		/* Peripheral qualifier | Peripheral Device Type  */
-	u8 inqd_dtq;		/* RMB | Device Type Qualifier  */
-	u8 inqd_ver;		/* ISO version | ECMA version | ANSI-approved version */
-	u8 inqd_rdf;		/* AENC | TrmIOP | Response data format */
-	u8 inqd_len;		/* Additional length (n-4) */
-	u8 inqd_pad1[2];	/* Reserved - must be zero */
-	u8 inqd_pad2;		/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
-	u8 inqd_vid[8];		/* Vendor ID */
-	u8 inqd_pid[16];	/* Product ID */
-	u8 inqd_prl[4];		/* Product Revision Level */
+	u8 inqd_pdt;	/* Peripheral qualifier | Peripheral Device Type  */
+	u8 inqd_dtq;	/* RMB | Device Type Qualifier  */
+	u8 inqd_ver;	/* ISO version | ECMA version | ANSI-approved version */
+	u8 inqd_rdf;	/* AENC | TrmIOP | Response data format */
+	u8 inqd_len;	/* Additional length (n-4) */
+	u8 inqd_pad1[2];/* Reserved - must be zero */
+	u8 inqd_pad2;	/* RelAdr | WBus32 | WBus16 |  Sync  | Linked |Reserved| CmdQue | SftRe */
+	u8 inqd_vid[8];	/* Vendor ID */
+	u8 inqd_pid[16];/* Product ID */
+	u8 inqd_prl[4];	/* Product Revision Level */
 };
 
 struct sense_data {
 	u8 error_code;		/* 70h (current errors), 71h(deferred errors) */
 	u8 valid:1;		/* A valid bit of one indicates that the information  */
-	/* field contains valid information as defined in the
-	 * SCSI-2 Standard.
-	 */
+				/* field contains valid information as defined in the
+				 * SCSI-2 Standard.
+				 */
 	u8 segment_number;	/* Only used for COPY, COMPARE, or COPY AND VERIFY Commands */
 	u8 sense_key:4;		/* Sense Key */
 	u8 reserved:1;
@@ -257,13 +256,14 @@
 				    1, 1,
 				    NULL, NULL);
 		if (status < 0 ) {
-			printk(KERN_WARNING "ProbeContainers: SendFIB failed.\n");
+			printk(KERN_WARNING "aac_get_containers: SendFIB failed.\n");
 			break;
 		}
 		dresp = (struct aac_mount *)fib_data(fibptr);
 
 		if ((le32_to_cpu(dresp->status) == ST_OK) &&
-		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
+		    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
+		    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
 			fsa_dev_ptr->valid[index] = 1;
 			fsa_dev_ptr->type[index] = le32_to_cpu(dresp->mnt[0].vol);
 			fsa_dev_ptr->size[index] = le32_to_cpu(dresp->mnt[0].capacity);
@@ -274,8 +274,9 @@
 		/*
 		 *	If there are no more containers, then stop asking.
 		 */
-		if ((index + 1) >= le32_to_cpu(dresp->count))
+		if ((index + 1) >= le32_to_cpu(dresp->count)){
 			break;
+		}
 	}
 	fib_free(fibptr);
 	fsa_dev[instance] = fsa_dev_ptr;
@@ -328,7 +329,8 @@
 	dresp = (struct aac_mount *) fib_data(fibptr);
 
 	if ((le32_to_cpu(dresp->status) == ST_OK) &&
-	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE)) {
+	    (le32_to_cpu(dresp->mnt[0].vol) != CT_NONE) &&
+	    (le32_to_cpu(dresp->mnt[0].state) != FSCS_HIDDEN)) {
 		fsa_dev_ptr->valid[cid] = 1;
 		fsa_dev_ptr->type[cid] = le32_to_cpu(dresp->mnt[0].vol);
 		fsa_dev_ptr->size[cid] = le32_to_cpu(dresp->mnt[0].capacity);
@@ -429,7 +431,7 @@
 	sense_buf[1] = 0;	/* Segment number, always zero */
 
 	if (incorrect_length) {
-		sense_buf[2] = sense_key | 0x20;	/* Set ILI bit | sense key */
+		sense_buf[2] = sense_key | 0x20;/* Set ILI bit | sense key */
 		sense_buf[3] = BYTE3(residue);
 		sense_buf[4] = BYTE2(residue);
 		sense_buf[5] = BYTE1(residue);
@@ -448,11 +450,11 @@
 		sense_buf[15] = 0;
 
 		if (sense_code == SENCODE_INVALID_PARAM_FIELD)
-			sense_buf[15] = 0x80;	/* Std sense key specific field */
+			sense_buf[15] = 0x80;/* Std sense key specific field */
 		/* Illegal parameter is in the parameter block */
 
 		if (sense_code == SENCODE_INVALID_CDB_FIELD)
-			sense_buf[15] = 0xc0;	/* Std sense key specific field */
+			sense_buf[15] = 0xc0;/* Std sense key specific field */
 		/* Illegal parameter is in the CDB block */
 		sense_buf[15] |= bit_pointer;
 		sense_buf[16] = field_pointer >> 8;	/* MSB */
@@ -463,9 +465,10 @@
 static void aac_io_done(Scsi_Cmnd * scsicmd)
 {
 	unsigned long cpu_flags;
-	spin_lock_irqsave(scsicmd->device->host->host_lock, cpu_flags);
+	struct Scsi_Host *host = scsicmd->device->host;
+	spin_lock_irqsave(host->host_lock, cpu_flags);
 	scsicmd->scsi_done(scsicmd);
-	spin_unlock_irqrestore(scsicmd->device->host->host_lock, cpu_flags);
+	spin_unlock_irqrestore(host->host_lock, cpu_flags);
 }
 
 static void __aac_io_done(Scsi_Cmnd * scsicmd)
@@ -498,40 +501,53 @@
 	memcpy(&dev->adapter_info, info, sizeof(struct aac_adapter_info));
 
 	tmp = dev->adapter_info.kernelrev;
-	printk(KERN_INFO "%s%d: kernel %d.%d.%d build %d\n", 
+	printk(KERN_INFO"%s%d: kernel %d.%d.%d build %d\n", 
 			dev->name, dev->id,
 			tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
 			dev->adapter_info.kernelbuild);
 	tmp = dev->adapter_info.monitorrev;
-	printk(KERN_INFO "%s%d: monitor %d.%d.%d build %d\n", 
+	printk(KERN_INFO"%s%d: monitor %d.%d.%d build %d\n", 
 			dev->name, dev->id,
 			tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
 			dev->adapter_info.monitorbuild);
 	tmp = dev->adapter_info.biosrev;
-	printk(KERN_INFO "%s%d: bios %d.%d.%d build %d\n", 
+	printk(KERN_INFO"%s%d: bios %d.%d.%d build %d\n", 
 			dev->name, dev->id,
 			tmp>>24,(tmp>>16)&0xff,(tmp>>8)&0xff,
 			dev->adapter_info.biosbuild);
-	printk(KERN_INFO "%s%d: serial %x%x\n",
+	printk(KERN_INFO"%s%d: serial %x%x\n",
 			dev->name, dev->id,
 			dev->adapter_info.serial[0],
 			dev->adapter_info.serial[1]);
-	dev->pae_support = 0;
+
 	dev->nondasd_support = 0;
-	if( BITS_PER_LONG >= 64 && 
-	  (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
-		printk(KERN_INFO "%s%d: 64 Bit PAE enabled\n", dev->name, dev->id);
+	if(dev->adapter_info.options & AAC_OPT_NONDASD){
+//		dev->nondasd_support = 1;
+// dmb - temporarily disable nondasd
+	}
+	if(nondasd != -1) {  
+		dev->nondasd_support = (nondasd!=0);
+	}
+	if(dev->nondasd_support != 0){
+		printk(KERN_INFO"%s%d: Non-DASD support enabled\n",dev->name, dev->id);
+	}
+
+	dev->pae_support = 0;
+	if( (sizeof(dma_addr_t) > 4) && (dev->adapter_info.options & AAC_OPT_SGMAP_HOST64)){
 		dev->pae_support = 1;
 	}
-	/* TODO - dmb temporary until fw can set this bit  */
-	dev->pae_support = (BITS_PER_LONG >= 64);
+
+	if(paemode != -1){
+		dev->pae_support = (paemode!=0);
+	}
 	if(dev->pae_support != 0) {
-		printk(KERN_INFO "%s%d: 64 Bit PAE enabled\n", dev->name, dev->id);
+		printk(KERN_INFO"%s%d: 64 Bit PAE enabled\n", dev->name, dev->id);
+		pci_set_dma_mask(dev->pdev, (dma_addr_t)0xFFFFFFFFFFFFFFFFULL);
 	}
 
-	if(dev->adapter_info.options & AAC_OPT_NONDASD){
-		dev->nondasd_support = 1;
-	}
+	fib_complete(fibptr);
+	fib_free(fibptr);
+
 	return rcode;
 }
 
@@ -550,7 +566,7 @@
 	cid =TARGET_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
 
 	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
-	dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %d, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	dprintk((KERN_DEBUG "read_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
 
 	if (fibptr == NULL)
 		BUG();
@@ -561,7 +577,7 @@
 			scsicmd->use_sg,
 			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 	else if(scsicmd->request_bufflen)
-		pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
+		pci_unmap_single(dev->pdev, (dma_addr_t)(ulong)scsicmd->SCp.ptr,
 				 scsicmd->request_bufflen,
 				 scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 	readreply = (struct aac_read_reply *)fib_data(fibptr);
@@ -595,7 +611,7 @@
 	cid = TARGET_LUN_TO_CONTAINER(scsicmd->device->id, scsicmd->device->lun);
 
 	lba = ((scsicmd->cmnd[1] & 0x1F) << 16) | (scsicmd->cmnd[2] << 8) | scsicmd->cmnd[3];
-	dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %d, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	dprintk((KERN_DEBUG "write_callback[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
 	if (fibptr == NULL)
 		BUG();
 
@@ -605,7 +621,7 @@
 			scsicmd->use_sg,
 			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 	else if(scsicmd->request_bufflen)
-		pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
+		pci_unmap_single(dev->pdev, (dma_addr_t)(ulong)scsicmd->SCp.ptr,
 				 scsicmd->request_bufflen,
 				 scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 
@@ -677,7 +693,7 @@
 		readcmd->block = cpu_to_le32(lba);
 		readcmd->pad   = cpu_to_le16(0);
 		readcmd->flags = cpu_to_le16(0); 
-		
+
 		aac_build_sg64(scsicmd, &readcmd->sg);
 		if(readcmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
 			BUG();
@@ -718,8 +734,9 @@
 			  (fib_callback) read_callback, 
 			  (void *) scsicmd);
 	}
+
 	
-	
+
 	/*
 	 *	Check that the command queued to the controller
 	 */
@@ -761,7 +778,7 @@
 		lba = (scsicmd->cmnd[2] << 24) | (scsicmd->cmnd[3] << 16) | (scsicmd->cmnd[4] << 8) | scsicmd->cmnd[5];
 		count = (scsicmd->cmnd[7] << 8) | scsicmd->cmnd[8];
 	}
-	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %lu, t = %ld.\n", smp_processor_id(), lba, jiffies));
+	dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %u, t = %ld.\n", smp_processor_id(), lba, jiffies));
 	/*
 	 *	Allocate and initialize a Fib then setup a BlockWrite command
 	 */
@@ -772,8 +789,7 @@
 	}
 	fib_init(cmd_fibcontext);
 
-	if(dev->pae_support == 1)
-	{
+	if(dev->pae_support == 1){
 		struct aac_write64 *writecmd;
 		writecmd = (struct aac_write64 *) fib_data(cmd_fibcontext);
 		writecmd->command = cpu_to_le32(VM_CtHostWrite64);
@@ -797,9 +813,7 @@
 			  0, 1, 
 			  (fib_callback) write_callback, 
 			  (void *) scsicmd);
-	}
-	else 
-	{
+	} else {
 		struct aac_write *writecmd;
 		writecmd = (struct aac_write *) fib_data(cmd_fibcontext);
 		writecmd->command = cpu_to_le32(VM_CtBlockWrite);
@@ -809,8 +823,10 @@
 		writecmd->sg.count = cpu_to_le32(1);
 		/* ->stable is not used - it did mean which type of write */
 
-		if (count * 512 > (64 * 1024))
+		if (count * 512 > (64 * 1024)) {
 			BUG();
+		}
+
 		aac_build_sg(scsicmd, &writecmd->sg);
 		if(writecmd->sg.count > MAX_DRIVER_SG_SEGMENT_COUNT)
 			BUG();
@@ -861,18 +877,19 @@
 	struct fsa_scsi_hba *fsa_dev_ptr;
 	int cardtype;
 	int ret;
-	struct aac_dev *dev = (struct aac_dev *)scsicmd->device->host->hostdata;
+	struct Scsi_Host *host = scsicmd->device->host;
+	struct aac_dev *dev = (struct aac_dev *)host->hostdata;
 	
 	cardtype = dev->cardtype;
 
-	fsa_dev_ptr = fsa_dev[scsicmd->device->host->unique_id];
+	fsa_dev_ptr = fsa_dev[host->unique_id];
 
 	/*
 	 *	If the bus, target or lun is out of range, return fail
 	 *	Test does not apply to ID 16, the pseudo id for the controller
 	 *	itself.
 	 */
-	if (scsicmd->device->id != scsicmd->device->host->this_id) {
+	if (scsicmd->device->id != host->this_id) {
 		if ((scsicmd->device->channel == 0) ){
 			if( (scsicmd->device->id >= AAC_MAX_TARGET) || (scsicmd->device->lun != 0)){ 
 				scsicmd->result = DID_NO_CONNECT << 16;
@@ -890,9 +907,9 @@
 				case SS_INQUIR:
 				case SS_RDCAP:
 				case SS_TEST:
-					spin_unlock_irq(scsicmd->device->host->host_lock);
+					spin_unlock_irq(host->host_lock);
 					probe_container(dev, cid);
-					spin_lock_irq(scsicmd->device->host->host_lock);
+					spin_lock_irq(host->host_lock);
 					if (fsa_dev_ptr->valid[cid] == 0) {
 						scsicmd->result = DID_NO_CONNECT << 16;
 						__aac_io_done(scsicmd);
@@ -959,7 +976,7 @@
 		 *	see: <vendor>.c i.e. aac.c
 		 */
 		setinqstr(cardtype, (void *) (inq_data_ptr->inqd_vid), fsa_dev_ptr->type[cid]);
-		if (scsicmd->device->id == scsicmd->device->host->this_id)
+		if (scsicmd->device->id == host->this_id)
 			inq_data_ptr->inqd_pdt = INQD_PDT_PROC;	/* Processor device */
 		else
 			inq_data_ptr->inqd_pdt = INQD_PDT_DA;	/* Direct/random access device */
@@ -1053,20 +1070,21 @@
 			 *	containers to /dev/sd device names
 			 */
 			 
-			spin_unlock_irq(scsicmd->device->host->host_lock);
+			spin_unlock_irq(host->host_lock);
 			if  (scsicmd->request->rq_disk)
 				memcpy(fsa_dev_ptr->devname[cid],
 					scsicmd->request->rq_disk->disk_name,
 					8);
+
 			ret = aac_read(scsicmd, cid);
-			spin_lock_irq(scsicmd->device->host->host_lock);
+			spin_lock_irq(host->host_lock);
 			return ret;
 
 		case SS_WRITE:
 		case SM_WRITE:
-			spin_unlock_irq(scsicmd->device->host->host_lock);
+			spin_unlock_irq(host->host_lock);
 			ret = aac_write(scsicmd, cid);
-			spin_lock_irq(scsicmd->device->host->host_lock);
+			spin_lock_irq(host->host_lock);
 			return ret;
 		default:
 			/*
@@ -1219,8 +1237,7 @@
 			scsicmd->use_sg,
 			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 	else if(scsicmd->request_bufflen)
-		pci_unmap_single(dev->pdev, scsicmd->SCp.dma_handle,
-			scsicmd->request_bufflen,
+		pci_unmap_single(dev->pdev, (ulong)scsicmd->SCp.ptr, scsicmd->request_bufflen,
 			scsi_to_pci_dma_dir(scsicmd->sc_data_direction));
 
 	/*
@@ -1239,17 +1256,23 @@
 	/*
 	 * Next check the srb status
 	 */
-	switch(le32_to_cpu(srbreply->srb_status)){
+	switch( (le32_to_cpu(srbreply->srb_status))&0x3f){
 	case SRB_STATUS_ERROR_RECOVERY:
 	case SRB_STATUS_PENDING:
 	case SRB_STATUS_SUCCESS:
 		if(scsicmd->cmnd[0] == INQUIRY ){
 			u8 b;
+			u8 b1;
 			/* We can't expose disk devices because we can't tell whether they
-			 * are the raw container drives or stand alone drives
+			 * are the raw container drives or stand alone drives.  If they have
+			 * the removable bit set then we should expose them though.
 			 */
-			b = *(u8*)scsicmd->buffer;
-			if( (b & 0x0f) == TYPE_DISK ){
+			b = (*(u8*)scsicmd->buffer)&0x1f;
+			b1 = ((u8*)scsicmd->buffer)[1];
+			if( b==TYPE_TAPE || b==TYPE_WORM || b==TYPE_ROM || b==TYPE_MOD|| b==TYPE_MEDIUM_CHANGER 
+					|| (b==TYPE_DISK && (b1&0x80)) ){
+				scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+			} else {
 				scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
 			}
 		} else {
@@ -1271,6 +1294,22 @@
 			}
 			scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
 			break;
+		case INQUIRY: {
+			u8 b;
+			u8 b1;
+			/* We can't expose disk devices because we can't tell whether they
+			* are the raw container drives or stand alone drives
+			*/
+			b = (*(u8*)scsicmd->buffer)&0x0f;
+			b1 = ((u8*)scsicmd->buffer)[1];
+			if( b==TYPE_TAPE || b==TYPE_WORM || b==TYPE_ROM || b==TYPE_MOD|| b==TYPE_MEDIUM_CHANGER
+					|| (b==TYPE_DISK && (b1&0x80)) ){
+				scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
+			} else {
+				scsicmd->result = DID_NO_CONNECT << 16 | COMMAND_COMPLETE << 8;
+			}
+			break;
+		}
 		default:
 			scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8;
 			break;
@@ -1326,17 +1365,19 @@
 	case SRB_STATUS_DOMAIN_VALIDATION_FAIL:
 	default:
 #ifdef AAC_DETAILED_STATUS_INFO
-		printk("aacraid: SRB ERROR (%s)\n",aac_get_status_string(le32_to_cpu(srbreply->srb_status)));
+		printk("aacraid: SRB ERROR(%u) %s scsi cmd 0x%x - scsi status 0x%x\n",le32_to_cpu(srbreply->srb_status&0x3f),aac_get_status_string(le32_to_cpu(srbreply->srb_status)), scsicmd->cmnd[0], le32_to_cpu(srbreply->scsi_status) );
 #endif
 		scsicmd->result = DID_ERROR << 16 | COMMAND_COMPLETE << 8;
 		break;
 	}
 	if (le32_to_cpu(srbreply->scsi_status) == 0x02 ){  // Check Condition
 		int len;
+		scsicmd->result |= CHECK_CONDITION;
 		len = (srbreply->sense_data_size > sizeof(scsicmd->sense_buffer))?
 				sizeof(scsicmd->sense_buffer):srbreply->sense_data_size;
 		printk(KERN_WARNING "aac_srb_callback: check condition, status = %d len=%d\n", le32_to_cpu(srbreply->status), len);
 		memcpy(scsicmd->sense_buffer, srbreply->sense_data, len);
+		
 	}
 	/*
 	 * OR in the scsi status (already shifted up a bit)
@@ -1365,6 +1406,7 @@
 	struct aac_srb *srbcmd;
 	u16 fibsize;
 	u32 flag;
+	u32 timeout;
 
 	if( scsicmd->device->id > 15 || scsicmd->device->lun > 7) {
 		scsicmd->result = DID_NO_CONNECT << 16;
@@ -1406,7 +1448,11 @@
 	srbcmd->target   = cpu_to_le32(scsicmd->device->id);
 	srbcmd->lun      = cpu_to_le32(scsicmd->device->lun);
 	srbcmd->flags    = cpu_to_le32(flag);
-	srbcmd->timeout  = cpu_to_le32(0);  // timeout not used
+	timeout = (scsicmd->timeout-jiffies)/HZ;
+	if(timeout == 0){
+		timeout = 1;
+	}
+	srbcmd->timeout  = cpu_to_le32(timeout);  // timeout in seconds
 	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
 	srbcmd->cdb_size = cpu_to_le32(scsicmd->cmd_len);
 	
@@ -1511,7 +1557,7 @@
 		psg->count = cpu_to_le32(1);
 		psg->sg[0].addr = cpu_to_le32(addr);
 		psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
-		scsicmd->SCp.dma_handle = addr;
+		scsicmd->SCp.ptr = (char *)addr;
 		byte_count = scsicmd->request_bufflen;
 	}
 	return byte_count;
@@ -1572,7 +1618,7 @@
 		psg->sg[0].addr[1] = (u32)(le_addr>>32);
 		psg->sg[0].addr[0] = (u32)(le_addr & 0xffffffff);
 		psg->sg[0].count = cpu_to_le32(scsicmd->request_bufflen);  
-		scsicmd->SCp.dma_handle = addr;
+		scsicmd->SCp.ptr = (char *)addr;
 		byte_count = scsicmd->request_bufflen;
 	}
 	return byte_count;
diff -Nru a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h
--- a/drivers/scsi/aacraid/aacraid.h	Thu Feb  6 07:33:47 2003
+++ b/drivers/scsi/aacraid/aacraid.h	Thu May  8 11:24:16 2003
@@ -1,18 +1,17 @@
+//#define dprintk(x) printk x
 #define dprintk(x)
-/*#define dprintk(x) printk x */
 
 /*------------------------------------------------------------------------------
  *              D E F I N E S
  *----------------------------------------------------------------------------*/
-
 #define MAXIMUM_NUM_CONTAINERS	31
 #define MAXIMUM_NUM_ADAPTERS	8
 
 #define AAC_NUM_FIB	578
-#define AAC_NUM_IO_FIB	512
+//#define AAC_NUM_IO_FIB	512
+#define AAC_NUM_IO_FIB	100
 
 #define AAC_MAX_TARGET (MAXIMUM_NUM_CONTAINERS+1)
-//#define AAC_MAX_TARGET 	(16)
 #define AAC_MAX_LUN	(8)
 
 /*
@@ -24,6 +23,9 @@
 
 #define AAC_DETAILED_STATUS_INFO
 
+extern int nondasd;
+extern int paemode;
+
 struct diskparm
 {
 	int heads;
@@ -237,6 +239,92 @@
 };
 
 /*
+ * Implement our own version of these so we have 64 bit compatability
+ * The adapter uses these and can only handle 32 bit addresses
+ */
+
+struct aac_list_head {
+	u32 next;
+	u32 prev;
+};
+
+#define AAC_INIT_LIST_HEAD(ptr) do { \
+	(ptr)->next = (u32)(ulong)(ptr); \
+	(ptr)->prev = (u32)(ulong)(ptr); \
+} while (0)
+/**
+ * aac_list_empty - tests whether a list is empty
+ * @head: the list to test.
+ */
+static __inline__ int aac_list_empty(struct aac_list_head *head)
+{
+	return head->next == ((u32)(ulong)head);
+}
+
+/*
+ * Insert a new entry between two known consecutive entries. 
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void aac_list_add(struct aac_list_head * n,
+	struct aac_list_head * prev,
+	struct aac_list_head * next)
+{
+	next->prev = (u32)(ulong)n;
+	n->next = (u32)(ulong)next;
+	n->prev = (u32)(ulong)prev;
+	prev->next = (u32)(ulong)n;
+}
+
+/**
+ * list_add_tail - add a new entry
+ * @new: new entry to be added
+ * @head: list head to add it before
+ *
+ * Insert a new entry before the specified head.
+ * This is useful for implementing queues.
+ */
+static __inline__ void aac_list_add_tail(struct aac_list_head *n, struct aac_list_head *head)
+{
+	aac_list_add(n, (struct aac_list_head*)(ulong)(head->prev), head);
+}
+
+/*
+ * Delete a list entry by making the prev/next entries
+ * point to each other.
+ *
+ * This is only for internal list manipulation where we know
+ * the prev/next entries already!
+ */
+static __inline__ void __aac_list_del(struct aac_list_head * p,
+				  struct aac_list_head * n)
+{
+	n->prev = (u32)(ulong)p;
+	p->next = (u32)(ulong)n;
+}
+
+/**
+ * aac_list_del - deletes entry from list.
+ * @entry: the element to delete from the list.
+ * Note: list_empty on entry does not return true after this, the entry is in an undefined state.
+ */
+static __inline__ void aac_list_del(struct aac_list_head *entry)
+{
+	__aac_list_del((struct aac_list_head*)(ulong)entry->prev,(struct aac_list_head*)(ulong) entry->next);
+	entry->next = entry->prev = 0;
+}
+
+/**
+ * aac_list_entry - get the struct for this entry
+ * @ptr:	the &struct list_head pointer.
+ * @type:	the type of the struct this is embedded in.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define aac_list_entry(ptr, type, member) \
+	((type *)((char *)(ptr)-(ulong)(&((type *)0)->member)))
+
+/*
  *	Assign type values to the FSA communication data structures
  */
 
@@ -249,11 +337,11 @@
 #define		FsaNormal	1
 #define		FsaHigh		2
 
+
 /*
  * Define the FIB. The FIB is the where all the requested data and
  * command information are put to the application on the FSA adapter.
  */
-
 struct aac_fibhdr {
 	u32 XferState;			// Current transfer state for this CCB
 	u16 Command;			// Routing information for the destination
@@ -269,7 +357,8 @@
 		    u32 _ReceiverTimeStart; 	// Timestamp for receipt of fib
 		    u32 _ReceiverTimeDone;	// Timestamp for completion of fib
 		} _s;
-		struct list_head _FibLinks;	// Used to link Adapter Initiated Fibs on the host
+		struct aac_list_head _FibLinks;	// Used to link Adapter Initiated Fibs on the host
+//		struct list_head _FibLinks;	// Used to link Adapter Initiated Fibs on the host
 	} _u;
 };
 
@@ -451,21 +540,22 @@
  */
  
 struct aac_queue {
-	u64		 	logical;		/* This is the address we give the adapter */
-	struct aac_entry	*base;		   	/* This is the system virtual address */
-	struct aac_qhdr 	headers;       		/* A pointer to the producer and consumer queue headers for this queue */
-	u32	 		entries;	   	/* Number of queue entries on this queue */
-	wait_queue_head_t	qfull;		      	/* Event to wait on if the queue is full */
-	wait_queue_head_t	cmdready;	  	/* Indicates there is a Command ready from the adapter on this queue. */
-                                        		/* This is only valid for adapter to host command queues. */                      
-	spinlock_t	 	*lock;		     	/* Spinlock for this queue must take this lock before accessing the lock */
-	spinlock_t		lockdata;		/* Actual lock (used only on one side of the lock) */
-	unsigned long		SavedIrql;      	/* Previous IRQL when the spin lock is taken */
-	u32			padding;		/* Padding - FIXME - can remove I believe */
-	struct list_head 	cmdq;		   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
+	u64		 	logical;	/*address we give the adapter */
+	struct aac_entry	*base;		/*system virtual address */
+	struct aac_qhdr 	headers;       	/*producer,consumer q headers*/
+	u32	 		entries;	/*Number of queue entries */
+	wait_queue_head_t	qfull;		/*Event to wait on if q full */
+	wait_queue_head_t	cmdready;	/*Cmd ready from the adapter */
+                  /* This is only valid for adapter to host command queues. */ 
+	spinlock_t	 	*lock;		/* Spinlock for this queue must take this lock before accessing the lock */
+	spinlock_t		lockdata;	/* Actual lock (used only on one side of the lock) */
+	u32 			SavedIrql;     	/* Previous IRQL when the spin lock is taken */
+	u32			padding;	/* Padding - FIXME - can remove I believe */
+	struct aac_list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
+//	struct list_head 	cmdq;	   	/* A queue of FIBs which need to be prcessed by the FS thread. This is */
                                 		        /* only valid for command queues which receive entries from the adapter. */
 	struct list_head	pendingq;		/* A queue of outstanding fib's to the adapter. */
-	unsigned long		numpending;		/* Number of entries on outstanding queue. */
+	u32			numpending;		/* Number of entries on outstanding queue. */
 	struct aac_dev *	dev;			/* Back pointer to adapter structure */
 };
 
@@ -629,7 +719,7 @@
 	struct semaphore 	wait_sem;	// this is used to wait for the next fib to arrive.
 	int			wait;		// Set to true when thread is in WaitForSingleObject
 	unsigned long		count;		// total number of FIBs on FibList
-	struct list_head	fibs;
+	struct aac_list_head	hw_fib_list;	// this holds hw_fibs which should be 32 bit addresses
 };
 
 struct fsa_scsi_hba {
@@ -650,7 +740,6 @@
 	 *	The Adapter that this I/O is destined for.
 	 */
 	struct aac_dev 		*dev;
-	u64			logicaladdr;	/* 64 bit */
 	/*
 	 *	This is the event the sendfib routine will wait on if the
 	 *	caller did not pass one and this is synch io.
@@ -669,7 +758,8 @@
 	struct list_head	queue;
 
 	void 			*data;
-	struct hw_fib		*fib;		/* Actual shared object */
+	struct hw_fib		*hw_fib;		/* Actual shared object */
+	dma_addr_t		hw_fib_pa;		/* physical address of hw_fib*/
 };
 
 /*
@@ -696,6 +786,7 @@
 	u32	biosrev;
 	u32	biosbuild;
 	u32	cluster;
+	u32	clusterchannelmask; 
 	u32	serial[2];
 	u32	battery;
 	u32	options;
@@ -746,13 +837,13 @@
 	 */	
 	dma_addr_t		hw_fib_pa;
 	struct hw_fib		*hw_fib_va;
-#if BITS_PER_LONG >= 64
 	ulong			fib_base_va;
-#endif
 	/*
 	 *	Fib Headers
 	 */
-	struct fib		fibs[AAC_NUM_FIB];
+// dmb	struct fib              fibs[AAC_NUM_FIB]; /* Doing it here takes up too much from the scsi pool*/
+	struct fib              *fibs;
+
 	struct fib		*free_fib;
 	struct fib		*timeout_fib;
 	spinlock_t		fib_lock;
@@ -771,6 +862,7 @@
 	unsigned long		fsrev;		/* Main driver's revision number */
 	
 	struct aac_init		*init;		/* Holds initialization info to communicate with adapter */
+//	void *			init_pa; 	/* Holds physical address of the init struct */
 	dma_addr_t		init_pa; 	/* Holds physical address of the init struct */
 	
 	struct pci_dev		*pdev;		/* Our PCI interface */
@@ -1148,7 +1240,9 @@
 	u32			altoid;		// != oid <==> snapshot or broken mirror exists
 };
 
-#define FSCS_READONLY	0x0002	/*	possible result of broken mirror */
+#define FSCS_NOTCLEAN	0x0001  /* fsck is neccessary before mounting */
+#define FSCS_READONLY	0x0002	/* possible result of broken mirror */
+#define FSCS_HIDDEN	0x0004	/* should be ignored - set during a clear */
 
 struct aac_query_mount {
 	u32		command;
@@ -1359,16 +1453,6 @@
 	u8 data[1];		/* Undefined length (from kernel viewpoint) */
 };
 
-static inline u32 fib2addr(struct hw_fib *hw)
-{
-	return (u32)hw;
-}
-
-static inline struct hw_fib *addr2fib(u32 addr)
-{
-	return (struct hw_fib *)addr;
-}
-
 /**
  * 	Convert capacity to cylinders
  *  	accounting for the fact capacity could be a 64 bit value
@@ -1376,12 +1460,8 @@
  */
 static inline u32 cap_to_cyls(sector_t capacity, u32 divisor)
 {
-#ifdef CONFIG_LBD
-	do_div(capacity, divisor);
-#else
-	capacity /= divisor;
-#endif
-	return (u32) capacity;
+	sector_div(capacity, divisor);
+	return (u32)capacity;
 }
 
 const char *aac_driverinfo(struct Scsi_Host *);
@@ -1397,7 +1477,7 @@
 int aac_consumer_avail(struct aac_dev * dev, struct aac_queue * q);
 void aac_consumer_free(struct aac_dev * dev, struct aac_queue * q, u32 qnum);
 int fib_complete(struct fib * context);
-#define fib_data(fibctx) ((void *)(fibctx)->fib->data)
+#define fib_data(fibctx) ((void *)(fibctx)->hw_fib->data)
 int aac_detach(struct aac_dev *dev);
 struct aac_dev *aac_init_adapter(struct aac_dev *dev);
 int aac_get_containers(struct aac_dev *dev);
diff -Nru a/drivers/scsi/aacraid/commctrl.c b/drivers/scsi/aacraid/commctrl.c
--- a/drivers/scsi/aacraid/commctrl.c	Wed Oct  2 13:37:46 2002
+++ b/drivers/scsi/aacraid/commctrl.c	Wed May  7 19:08:36 2003
@@ -63,7 +63,7 @@
 	if(fibptr == NULL)
 		return -ENOMEM;
 		
-	kfib = fibptr->fib;
+	kfib = fibptr->hw_fib;
 	/*
 	 *	First copy in the header so that we can check the size field.
 	 */
@@ -150,7 +150,7 @@
 		 *	the list to 0.
 		 */
 		fibctx->count = 0;
-		INIT_LIST_HEAD(&fibctx->fibs);
+		AAC_INIT_LIST_HEAD(&fibctx->hw_fib_list);
 		fibctx->jiffies = jiffies/HZ;
 		/*
 		 *	Now add this context onto the adapter's 
@@ -181,7 +181,7 @@
 {
 	struct fib_ioctl f;
 	struct aac_fib_context *fibctx, *aifcp;
-	struct hw_fib * fib;
+	struct hw_fib * hw_fib;
 	int status;
 	struct list_head * entry;
 	int found;
@@ -224,25 +224,25 @@
 	 *	-EAGAIN
 	 */
 return_fib:
-	if (!list_empty(&fibctx->fibs)) {
-		struct list_head * entry;
+	if (!aac_list_empty(&fibctx->hw_fib_list)) {
+		struct aac_list_head * entry;
 		/*
 		 *	Pull the next fib from the fibs
 		 */
-		entry = fibctx->fibs.next;
-		list_del(entry);
+		entry = (struct aac_list_head*)(ulong)fibctx->hw_fib_list.next;
+		aac_list_del(entry);
 		
-		fib = list_entry(entry, struct hw_fib, header.FibLinks);
+		hw_fib = aac_list_entry(entry, struct hw_fib, header.FibLinks);
 		fibctx->count--;
 		spin_unlock_irqrestore(&dev->fib_lock, flags);
-		if (copy_to_user(f.fib, fib, sizeof(struct hw_fib))) {
-			kfree(fib);
+		if (copy_to_user(f.fib, hw_fib, sizeof(struct hw_fib))) {
+			kfree(hw_fib);
 			return -EFAULT;
 		}	
 		/*
 		 *	Free the space occupied by this copy of the fib.
 		 */
-		kfree(fib);
+		kfree(hw_fib);
 		status = 0;
 		fibctx->jiffies = jiffies/HZ;
 	} else {
@@ -264,24 +264,24 @@
 
 int aac_close_fib_context(struct aac_dev * dev, struct aac_fib_context * fibctx)
 {
-	struct hw_fib *fib;
+	struct hw_fib *hw_fib;
 
 	/*
 	 *	First free any FIBs that have not been consumed.
 	 */
-	while (!list_empty(&fibctx->fibs)) {
-		struct list_head * entry;
+	while (!aac_list_empty(&fibctx->hw_fib_list)) {
+		struct aac_list_head * entry;
 		/*
 		 *	Pull the next fib from the fibs
 		 */
-		entry = fibctx->fibs.next;
-		list_del(entry);
-		fib = list_entry(entry, struct hw_fib, header.FibLinks);
+		entry = (struct aac_list_head*)(ulong)(fibctx->hw_fib_list.next);
+		aac_list_del(entry);
+		hw_fib = aac_list_entry(entry, struct hw_fib, header.FibLinks);
 		fibctx->count--;
 		/*
 		 *	Free the space occupied by this copy of the fib.
 		 */
-		kfree(fib);
+		kfree(hw_fib);
 	}
 	/*
 	 *	Remove the Context from the AdapterFibContext List
@@ -372,6 +372,204 @@
 	return 0;
 }
 
+/**
+ *
+ * aac_send_raw_scb
+ *
+ */
+
+int aac_send_raw_srb(struct aac_dev* dev, void* arg)
+{
+	struct fib* srbfib;
+	int status;
+	struct aac_srb *srbcmd;
+	struct aac_srb *user_srb = arg;
+	struct aac_srb_reply* user_reply;
+	struct aac_srb_reply* reply;
+	u32 fibsize = 0;
+	u32 flags = 0;
+	s32 rcode = 0;
+	u32 data_dir;
+	ulong sg_user[32];
+	ulong sg_list[32];
+	u32   sg_indx = 0;
+	u32 byte_count = 0;
+	u32 actual_fibsize = 0;
+	int i;
+
+
+	if (!capable(CAP_SYS_ADMIN)){
+		printk(KERN_DEBUG"aacraid: No permission to send raw srb\n"); 
+		return -EPERM;
+	}
+	/*
+	 *	Allocate and initialize a Fib then setup a BlockWrite command
+	 */
+	if (!(srbfib = fib_alloc(dev))) {
+		return -1;
+	}
+	fib_init(srbfib);
+
+	srbcmd = (struct aac_srb*) fib_data(srbfib);
+
+	if(copy_from_user((void*)&fibsize, (void*)&user_srb->count,sizeof(u32))){
+		printk(KERN_DEBUG"aacraid: Could not copy data size from user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+	if(copy_from_user(srbcmd, user_srb,fibsize)){
+		printk(KERN_DEBUG"aacraid: Could not copy srb from user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+	user_reply = arg+fibsize;
+
+	flags = srbcmd->flags;
+	// Fix up srb for endian and force some values
+	srbcmd->function = cpu_to_le32(SRBF_ExecuteScsi);	// Force this
+	srbcmd->channel  = cpu_to_le32(srbcmd->channel);
+	srbcmd->target   = cpu_to_le32(srbcmd->target);
+	srbcmd->lun      = cpu_to_le32(srbcmd->lun);
+	srbcmd->flags    = cpu_to_le32(srbcmd->flags);
+	srbcmd->timeout  = cpu_to_le32(srbcmd->timeout);
+	srbcmd->retry_limit =cpu_to_le32(0); // Obsolete parameter
+	srbcmd->cdb_size = cpu_to_le32(srbcmd->cdb_size);
+	
+	switch(srbcmd->flags){
+	case SRB_DataOut:
+		data_dir = SCSI_DATA_WRITE;
+		break;
+	case (SRB_DataIn | SRB_DataOut):
+		data_dir = SCSI_DATA_UNKNOWN;  
+		break;
+	case SRB_DataIn:
+		data_dir = SCSI_DATA_READ;
+		break;
+	default:
+		data_dir = SCSI_DATA_NONE;
+	}
+	if( dev->pae_support ==1 ) {
+		struct sgmap64* psg = (struct sgmap64*)&srbcmd->sg;
+		byte_count = 0;
+
+		// This should also catch if user used the 32 bit sgmap
+		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry64));
+		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
+			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+
+		for (i = 0; i < psg->count; i++) {
+			dma_addr_t addr; 
+			u64 le_addr;
+			void* p;
+			p = kmalloc(psg->sg[i].count,GFP_KERNEL|__GFP_DMA);
+			if(p == 0) {
+				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				psg->sg[i].count,i,psg->count);
+				rcode = -ENOMEM;
+				goto cleanup;
+			}
+			sg_user[i] = (ulong)psg->sg[i].addr;
+			sg_list[i] = (ulong)p; // save so we can clean up later
+			sg_indx = i;
+
+			if( flags & SRB_DataOut ){
+				if(copy_from_user(p,psg->sg[i].addr,psg->sg[i].count)){
+					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, scsi_to_pci_dma_dir(data_dir));
+
+			le_addr = cpu_to_le64(addr);
+			psg->sg[i].addr[1] = (u32)(le_addr>>32);
+			psg->sg[i].addr[0] = (u32)(le_addr & 0xffffffff);
+			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
+			byte_count += psg->sg[i].count;
+		}
+
+		srbcmd->count = cpu_to_le32(byte_count);
+		status = fib_send(ScsiPortCommand64, srbfib, actual_fibsize, FsaNormal, 1, 1,0,0);
+	} else {
+		struct sgmap* psg = &srbcmd->sg;
+		byte_count = 0;
+
+		actual_fibsize = sizeof (struct aac_srb) + (((srbcmd->sg.count & 0xff) - 1) * sizeof (struct sgentry));
+		if(actual_fibsize != fibsize){ // User made a mistake - should not continue
+			printk(KERN_DEBUG"aacraid: Bad Size specified in Raw SRB command\n");
+			rcode = -EINVAL;
+			goto cleanup;
+		}
+		for (i = 0; i < psg->count; i++) {
+			dma_addr_t addr; 
+			void* p;
+			p = kmalloc(psg->sg[i].count,GFP_KERNEL);
+			if(p == 0) {
+				printk(KERN_DEBUG"aacraid: Could not allocate SG buffer - size = %d buffer number %d of %d\n",
+				psg->sg[i].count,i,psg->count);
+				rcode = -ENOMEM;
+				goto cleanup;
+			}
+			sg_user[i] = (ulong)(psg->sg[i].addr);
+			sg_list[i] = (ulong)p; // save so we can clean up later
+			sg_indx = i;
+
+			if( flags & SRB_DataOut ){
+				if(copy_from_user((void*)p,(void*)(ulong)(psg->sg[i].addr),psg->sg[i].count)){
+					printk(KERN_DEBUG"aacraid: Could not copy sg data from user\n"); 
+					rcode = -EFAULT;
+					goto cleanup;
+				}
+			}
+			addr = pci_map_single(dev->pdev, p, psg->sg[i].count, scsi_to_pci_dma_dir(data_dir));
+
+			psg->sg[i].addr = cpu_to_le32(addr);
+			psg->sg[i].count = cpu_to_le32(psg->sg[i].count);  
+			byte_count += psg->sg[i].count;
+		}
+		srbcmd->count = cpu_to_le32(byte_count);
+		status = fib_send(ScsiPortCommand, srbfib, actual_fibsize, FsaNormal, 1, 1, 0, 0);
+	}
+
+	if (status != 0){
+		printk(KERN_DEBUG"aacraid: Could not send raw srb fib to hba\n"); 
+		rcode = -1;
+		goto cleanup;
+	}
+
+	if( flags & SRB_DataIn ) {
+		for(i = 0 ; i <= sg_indx; i++){
+			if(copy_to_user((void*)(sg_user[i]),(void*)(sg_list[i]),le32_to_cpu(srbcmd->sg.sg[i].count))){
+				printk(KERN_DEBUG"aacraid: Could not copy sg data to user\n"); 
+				rcode = -EFAULT;
+				goto cleanup;
+
+			}
+		}
+	}
+
+	reply = (struct aac_srb_reply *) fib_data(srbfib);
+	if(copy_to_user(user_reply,reply,sizeof(struct aac_srb_reply))){
+		printk(KERN_DEBUG"aacraid: Could not copy reply to user\n"); 
+		rcode = -EFAULT;
+		goto cleanup;
+	}
+
+cleanup:
+	for(i=0; i <= sg_indx; i++){
+		kfree((void*)sg_list[i]);
+	}
+	fib_complete(srbfib);
+	fib_free(srbfib);
+
+	return rcode;
+}
+
 
 struct aac_pci_info {
         u32 bus;
@@ -386,8 +584,10 @@
 	pci_info.bus = dev->pdev->bus->number;
 	pci_info.slot = PCI_SLOT(dev->pdev->devfn);
 
-       if(copy_to_user( arg, (void*)&pci_info, sizeof(struct aac_pci_info)))
+       if(copy_to_user( arg, (void*)&pci_info, sizeof(struct aac_pci_info))){
+		printk(KERN_DEBUG "aacraid: Could not copy pci info\n");
                return -EFAULT;
+	}
         return 0;
  }
  
@@ -419,6 +619,9 @@
 		break;
 	case FSACTL_CLOSE_GET_ADAPTER_FIB:
 		status = close_getadapter_fib(dev, arg);
+		break;
+	case FSACTL_SEND_RAW_SRB:
+		status = aac_send_raw_srb(dev,arg);
 		break;
 	case FSACTL_GET_PCI_INFO:
 		status = aac_get_pci_info(dev,arg);
diff -Nru a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c
--- a/drivers/scsi/aacraid/comminit.c	Mon Feb 24 09:56:29 2003
+++ b/drivers/scsi/aacraid/comminit.c	Wed May  7 15:17:12 2003
@@ -39,6 +39,7 @@
 #include <linux/slab.h>
 #include <linux/blk.h>
 #include <linux/completion.h>
+#include <linux/mm.h>
 #include <asm/semaphore.h>
 #include "scsi.h"
 #include "hosts.h"
@@ -58,10 +59,11 @@
 	struct aac_init *init;
 	dma_addr_t phys;
 
-	/* FIXME: Adaptec add 128 bytes to this value - WHY ?? */
 	size = fibsize + sizeof(struct aac_init) + commsize + commalign + printfbufsiz;
 
+ 
 	base = pci_alloc_consistent(dev->pdev, size, &phys);
+
 	if(base == NULL)
 	{
 		printk(KERN_ERR "aacraid: unable to create mapping.\n");
@@ -70,18 +72,10 @@
 	dev->comm_addr = (void *)base;
 	dev->comm_phys = phys;
 	dev->comm_size = size;
-
+	
 	dev->init = (struct aac_init *)(base + fibsize);
 	dev->init_pa = phys + fibsize;
 
-	/*
-	 *	Cache the upper bits of the virtual mapping for 64bit boxes
-	 *	FIXME: this crap should be rewritten
-	 */
-#if BITS_PER_LONG >= 64 
-	dev->fib_base_va = ((ulong)base & 0xffffffff00000000);
-#endif
-
 	init = dev->init;
 
 	init->InitStructRevision = cpu_to_le32(ADAPTER_INIT_STRUCT_REVISION);
@@ -92,16 +86,19 @@
 	 *	Adapter Fibs are the first thing allocated so that they
 	 *	start page aligned
 	 */
-	init->AdapterFibsVirtualAddress = cpu_to_le32((u32)base);
-	init->AdapterFibsPhysicalAddress = cpu_to_le32(phys);
+	dev->fib_base_va = (ulong)base;
+	
+	init->AdapterFibsVirtualAddress = cpu_to_le32((u32)(ulong)phys);
+	init->AdapterFibsPhysicalAddress = cpu_to_le32((u32)phys);
 	init->AdapterFibsSize = cpu_to_le32(fibsize);
 	init->AdapterFibAlign = cpu_to_le32(sizeof(struct hw_fib));
+	init->HostPhysMemPages = cpu_to_le32(num_physpages);		// number of 4k pages of host physical memory
 
 	/*
 	 * Increment the base address by the amount already used
 	 */
 	base = base + fibsize + sizeof(struct aac_init);
-	phys = phys + fibsize + sizeof(struct aac_init);
+	phys = (dma_addr_t)((ulong)phys + fibsize + sizeof(struct aac_init));
 	/*
 	 *	Align the beginning of Headers to commalign
 	 */
@@ -111,8 +108,8 @@
 	/*
 	 *	Fill in addresses of the Comm Area Headers and Queues
 	 */
-	*commaddr = (unsigned long *)base;
-	init->CommHeaderAddress = cpu_to_le32(phys);
+	*commaddr = base;
+	init->CommHeaderAddress = cpu_to_le32((u32)phys);
 	/*
 	 *	Increment the base address by the size of the CommArea
 	 */
@@ -134,14 +131,14 @@
 	q->dev = dev;
 	INIT_LIST_HEAD(&q->pendingq);
 	init_waitqueue_head(&q->cmdready);
-	INIT_LIST_HEAD(&q->cmdq);
+	AAC_INIT_LIST_HEAD(&q->cmdq);
 	init_waitqueue_head(&q->qfull);
 	spin_lock_init(&q->lockdata);
 	q->lock = &q->lockdata;
 	q->headers.producer = mem;
 	q->headers.consumer = mem+1;
-	*q->headers.producer = cpu_to_le32(qsize);
-	*q->headers.consumer = cpu_to_le32(qsize);
+	*(q->headers.producer) = cpu_to_le32(qsize);
+	*(q->headers.consumer) = cpu_to_le32(qsize);
 	q->entries = qsize;
 }
 
@@ -227,7 +224,6 @@
 	struct aac_entry * queues;
 	unsigned long size;
 	struct aac_queue_block * comm = dev->queues;
-
 	/*
 	 *	Now allocate and initialize the zone structures used as our 
 	 *	pool of FIB context records.  The size of the zone is based
@@ -246,9 +242,9 @@
 	if (!aac_alloc_comm(dev, (void * *)&headers, size, QUEUE_ALIGNMENT))
 		return -ENOMEM;
 
-	queues = (struct aac_entry *)((unsigned char *)headers + hdrsize);
+	queues = (struct aac_entry *)(((ulong)headers) + hdrsize);
 
-	/* Adapter to Host normal proirity Command queue */ 
+	/* Adapter to Host normal priority Command queue */ 
 	comm->queue[HostNormCmdQueue].base = queues;
 	aac_queue_init(dev, &comm->queue[HostNormCmdQueue], headers, HOST_NORM_CMD_ENTRIES);
 	queues += HOST_NORM_CMD_ENTRIES;
@@ -278,7 +274,6 @@
 	/* adapter to host normal priority response queue */
 	comm->queue[HostNormRespQueue].base = queues;
 	aac_queue_init(dev, &comm->queue[HostNormRespQueue], headers, HOST_NORM_RESP_ENTRIES);
-    
 	queues += HOST_NORM_RESP_ENTRIES;
 	headers += 2;
 
@@ -313,6 +308,7 @@
 	/*
 	 *	Ok now init the communication subsystem
 	 */
+
 	dev->queues = (struct aac_queue_block *) kmalloc(sizeof(struct aac_queue_block), GFP_KERNEL);
 	if (dev->queues == NULL) {
 		printk(KERN_ERR "Error could not allocate comm region.\n");
@@ -320,13 +316,17 @@
 	}
 	memset(dev->queues, 0, sizeof(struct aac_queue_block));
 
-	if (aac_comm_init(dev)<0)
+	if (aac_comm_init(dev)<0){
+		kfree(dev->queues);
 		return NULL;
+	}
 	/*
 	 *	Initialize the list of fibs
 	 */
-	if(fib_setup(dev)<0)
+	if(fib_setup(dev)<0){
+		kfree(dev->queues);
 		return NULL;
+	}
 		
 	INIT_LIST_HEAD(&dev->fib_list);
 	init_completion(&dev->aif_completion);
diff -Nru a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c
--- a/drivers/scsi/aacraid/commsup.c	Mon Feb 24 09:56:31 2003
+++ b/drivers/scsi/aacraid/commsup.c	Wed May  7 19:18:41 2003
@@ -79,39 +79,39 @@
  *	fib_setup	-	setup the fibs
  *	@dev: Adapter to set up
  *
- *	Allocate the PCI space for the fibs, map it and then initialise the
+ *	Allocate the PCI space for the fibs, map it and then intialise the
  *	fib area, the unmapped fib data and also the free list
  */
 
 int fib_setup(struct aac_dev * dev)
 {
 	struct fib *fibptr;
-	struct hw_fib *fib;
-	dma_addr_t fibpa;
+	struct hw_fib *hw_fib_va;
+	dma_addr_t hw_fib_pa;
 	int i;
 	
 	if(fib_map_alloc(dev)<0)
 		return -ENOMEM;
 		
-	fib = dev->hw_fib_va;
-	fibpa = dev->hw_fib_pa;
-	memset(fib, 0, sizeof(struct hw_fib) * AAC_NUM_FIB);
+	hw_fib_va = dev->hw_fib_va;
+	hw_fib_pa = dev->hw_fib_pa;
+	memset(hw_fib_va, 0, sizeof(struct hw_fib) * AAC_NUM_FIB);
 	/*
 	 *	Initialise the fibs
 	 */
 	for (i = 0, fibptr = &dev->fibs[i]; i < AAC_NUM_FIB; i++, fibptr++) 
 	{
 		fibptr->dev = dev;
-		fibptr->fib = fib;
-		fibptr->data = (void *) fibptr->fib->data;
+		fibptr->hw_fib = hw_fib_va;
+		fibptr->data = (void *) fibptr->hw_fib->data;
 		fibptr->next = fibptr+1;	/* Forward chain the fibs */
 		init_MUTEX_LOCKED(&fibptr->event_wait);
 		spin_lock_init(&fibptr->event_lock);
-		fib->header.XferState = cpu_to_le32(0xffffffff);
-		fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
-		fibptr->logicaladdr = (unsigned long) fibpa;
-		fib = (struct hw_fib *)((unsigned char *)fib + sizeof(struct hw_fib));
-		fibpa = fibpa + sizeof(struct hw_fib);
+		hw_fib_va->header.XferState = cpu_to_le32(0xffffffff);
+		hw_fib_va->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+		fibptr->hw_fib_pa = hw_fib_pa;
+		hw_fib_va = (struct hw_fib *)((unsigned char *)hw_fib_va + sizeof(struct hw_fib));
+		hw_fib_pa = hw_fib_pa + sizeof(struct hw_fib); 
 	}
 	/*
 	 *	Add the fib chain to the free list
@@ -136,11 +136,15 @@
 {
 	struct fib * fibptr;
 	unsigned long flags;
-	
 	spin_lock_irqsave(&dev->fib_lock, flags);
 	fibptr = dev->free_fib;	
-	if(!fibptr)
-		BUG();
+	while(!fibptr){
+		spin_unlock_irqrestore(&dev->fib_lock, flags);
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		schedule_timeout(1);
+		spin_lock_irqsave(&dev->fib_lock, flags);
+		fibptr = dev->free_fib;	
+	}
 	dev->free_fib = fibptr->next;
 	spin_unlock_irqrestore(&dev->fib_lock, flags);
 	/*
@@ -152,7 +156,7 @@
 	 *	Null out fields that depend on being zero at the start of
 	 *	each I/O
 	 */
-	fibptr->fib->header.XferState = cpu_to_le32(0);
+	fibptr->hw_fib->header.XferState = cpu_to_le32(0);
 	fibptr->callback = NULL;
 	fibptr->callback_data = NULL;
 
@@ -172,15 +176,14 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(&fibptr->dev->fib_lock, flags);
-
 	if (fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT) {
 		aac_config.fib_timeouts++;
 		fibptr->next = fibptr->dev->timeout_fib;
 		fibptr->dev->timeout_fib = fibptr;
 	} else {
-		if (fibptr->fib->header.XferState != 0) {
+		if (fibptr->hw_fib->header.XferState != 0) {
 			printk(KERN_WARNING "fib_free, XferState != 0, fibptr = 0x%p, XferState = 0x%x\n", 
-				 (void *)fibptr, fibptr->fib->header.XferState);
+				 (void*)fibptr, fibptr->hw_fib->header.XferState);
 		}
 		fibptr->next = fibptr->dev->free_fib;
 		fibptr->dev->free_fib = fibptr;
@@ -197,14 +200,14 @@
  
 void fib_init(struct fib *fibptr)
 {
-	struct hw_fib *fib = fibptr->fib;
+	struct hw_fib *hw_fib = fibptr->hw_fib;
 
-	fib->header.StructType = FIB_MAGIC;
-	fib->header.Size = cpu_to_le16(sizeof(struct hw_fib));
-        fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable);
-	fib->header.SenderFibAddress = cpu_to_le32(0);
-	fib->header.ReceiverFibAddress = cpu_to_le32(0);
-	fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
+	hw_fib->header.StructType = FIB_MAGIC;
+	hw_fib->header.Size = cpu_to_le16(sizeof(struct hw_fib));
+        hw_fib->header.XferState = cpu_to_le32(HostOwned | FibInitialized | FibEmpty | FastResponseCapable);
+	hw_fib->header.SenderFibAddress = cpu_to_le32(fibptr->hw_fib_pa);
+	hw_fib->header.ReceiverFibAddress = cpu_to_le32(fibptr->hw_fib_pa);
+	hw_fib->header.SenderSize = cpu_to_le16(sizeof(struct hw_fib));
 }
 
 /**
@@ -217,10 +220,10 @@
  
 void fib_dealloc(struct fib * fibptr)
 {
-	struct hw_fib *fib = fibptr->fib;
-	if(fib->header.StructType != FIB_MAGIC) 
+	struct hw_fib *hw_fib = fibptr->hw_fib;
+	if(hw_fib->header.StructType != FIB_MAGIC) 
 		BUG();
-	fib->header.XferState = cpu_to_le32(0);        
+	hw_fib->header.XferState = cpu_to_le32(0);        
 }
 
 /*
@@ -257,7 +260,7 @@
 	q = &dev->queues->queue[qid];
 	
 	*index = le32_to_cpu(*(q->headers.producer));
-		if (*index - 2 == le32_to_cpu(*(q->headers.consumer)))
+	if ((*index - 2) == le32_to_cpu(*(q->headers.consumer)))
 			*nonotify = 1; 
 
 	if (qid == AdapHighCmdQueue) {
@@ -277,10 +280,14 @@
 		if (*index >= ADAP_NORM_RESP_ENTRIES) 
 			*index = 0; /* Wrap to front of the Producer Queue. */
 	}
-	else BUG();
+	else {
+		printk("aacraid: invalid qid\n");
+		BUG();
+	}
 
-        if (*index + 1 == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
-		printk(KERN_WARNING "Queue %d full, %ld outstanding.\n", qid, q->numpending);
+        if ((*index + 1) == le32_to_cpu(*(q->headers.consumer))) { /* Queue is full */
+		printk(KERN_WARNING "Queue %d full, %d outstanding.\n",
+				qid, q->numpending);
 		return 0;
 	} else {
 	        *entry = q->base + *index;
@@ -288,7 +295,7 @@
 	}
 }   
 
-/**
+/*Command thread: *
  *	aac_queue_get		-	get the next free QE
  *	@dev: Adapter
  *	@index: Returned index
@@ -304,7 +311,7 @@
  *	success.
  */
 
-static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * fib, int wait, struct fib * fibptr, unsigned long *nonotify)
+static int aac_queue_get(struct aac_dev * dev, u32 * index, u32 qid, struct hw_fib * hw_fib, int wait, struct fib * fibptr, unsigned long *nonotify)
 {
 	struct aac_entry * entry = NULL;
 	int map = 0;
@@ -322,7 +329,7 @@
 	        /*
 	         *	Setup queue entry with a command, status and fib mapped
 	         */
-	        entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size));
+	        entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
 	        map = 1;
 	}
 	else if (qid == AdapHighRespQueue || qid == AdapNormRespQueue)
@@ -334,17 +341,18 @@
         	/*
         	 *	Setup queue entry with command, status and fib mapped
         	 */
-        	entry->size = cpu_to_le32(le16_to_cpu(fib->header.Size));
-        	entry->addr = cpu_to_le32(fib->header.SenderFibAddress);     		/* Restore adapters pointer to the FIB */
-		fib->header.ReceiverFibAddress = fib->header.SenderFibAddress;		/* Let the adapter now where to find its data */
+        	entry->size = cpu_to_le32(le16_to_cpu(hw_fib->header.Size));
+        	entry->addr = hw_fib->header.SenderFibAddress;
+     			/* Restore adapters pointer to the FIB */
+		hw_fib->header.ReceiverFibAddress = hw_fib->header.SenderFibAddress;	/* Let the adapter now where to find its data */
         	map = 0;
-	} 
+	}
 	/*
 	 *	If MapFib is true than we need to map the Fib and put pointers
 	 *	in the queue entry.
 	 */
 	if (map)
-		entry->addr = cpu_to_le32((unsigned long)(fibptr->logicaladdr));
+		entry->addr = fibptr->hw_fib_pa;
 	return 0;
 }
 
@@ -415,11 +423,10 @@
 	u32 qid;
 	struct aac_dev * dev = fibptr->dev;
 	unsigned long nointr = 0;
-	struct hw_fib * fib = fibptr->fib;
+	struct hw_fib * hw_fib = fibptr->hw_fib;
 	struct aac_queue * q;
 	unsigned long flags = 0;
-
-	if (!(le32_to_cpu(fib->header.XferState) & HostOwned))
+	if (!(le32_to_cpu(hw_fib->header.XferState) & HostOwned))
 		return -EBUSY;
 	/*
 	 *	There are 5 cases with the wait and reponse requested flags. 
@@ -435,19 +442,22 @@
 	if (wait && !reply) {
 		return -EINVAL;
 	} else if (!wait && reply) {
-		fib->header.XferState |= cpu_to_le32(Async | ResponseExpected);
+		hw_fib->header.XferState |= cpu_to_le32(Async | ResponseExpected);
 		FIB_COUNTER_INCREMENT(aac_config.AsyncSent);
 	} else if (!wait && !reply) {
-		fib->header.XferState |= cpu_to_le32(NoResponseExpected);
+		hw_fib->header.XferState |= cpu_to_le32(NoResponseExpected);
 		FIB_COUNTER_INCREMENT(aac_config.NoResponseSent);
 	} else if (wait && reply) {
-		fib->header.XferState |= cpu_to_le32(ResponseExpected);
+		hw_fib->header.XferState |= cpu_to_le32(ResponseExpected);
 		FIB_COUNTER_INCREMENT(aac_config.NormalSent);
 	} 
 	/*
 	 *	Map the fib into 32bits by using the fib number
 	 */
-	fib->header.SenderData = fibptr-&dev->fibs[0];	/* for callback */
+
+//	hw_fib->header.SenderFibAddress = ((u32)(fibptr-dev->fibs)) << 1;
+	hw_fib->header.SenderFibAddress = cpu_to_le32((u32)(ulong)fibptr->hw_fib_pa);
+	hw_fib->header.SenderData = (u32)(fibptr - dev->fibs);
 	/*
 	 *	Set FIB state to indicate where it came from and if we want a
 	 *	response from the adapter. Also load the command from the
@@ -455,15 +465,14 @@
 	 *
 	 *	Map the hw fib pointer as a 32bit value
 	 */
-	fib->header.SenderFibAddress = fib2addr(fib);
-	fib->header.Command = cpu_to_le16(command);
-	fib->header.XferState |= cpu_to_le32(SentFromHost);
-	fibptr->fib->header.Flags = 0;				/* Zero the flags field - its internal only...	 */
+	hw_fib->header.Command = cpu_to_le16(command);
+	hw_fib->header.XferState |= cpu_to_le32(SentFromHost);
+	fibptr->hw_fib->header.Flags = 0;	/* 0 the flags field - internal only*/
 	/*
 	 *	Set the size of the Fib we want to send to the adapter
 	 */
-	fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size);
-	if (le16_to_cpu(fib->header.Size) > le16_to_cpu(fib->header.SenderSize)) {
+	hw_fib->header.Size = cpu_to_le16(sizeof(struct aac_fibhdr) + size);
+	if (le16_to_cpu(hw_fib->header.Size) > le16_to_cpu(hw_fib->header.SenderSize)) {
 		return -EMSGSIZE;
 	}                
 	/*
@@ -471,22 +480,25 @@
 	 *	the adapter a command is ready.
 	 */
 	if (priority == FsaHigh) {
-		fib->header.XferState |= cpu_to_le32(HighPriority);
+		hw_fib->header.XferState |= cpu_to_le32(HighPriority);
 		qid = AdapHighCmdQueue;
 	} else {
-		fib->header.XferState |= cpu_to_le32(NormalPriority);
+		hw_fib->header.XferState |= cpu_to_le32(NormalPriority);
 		qid = AdapNormCmdQueue;
 	}
 	q = &dev->queues->queue[qid];
 
 	if(wait)
 		spin_lock_irqsave(&fibptr->event_lock, flags);
-	if(aac_queue_get( dev, &index, qid, fib, 1, fibptr, &nointr)<0)
+	if(aac_queue_get( dev, &index, qid, hw_fib, 1, fibptr, &nointr)<0)
 		return -EWOULDBLOCK;
 	dprintk((KERN_DEBUG "fib_send: inserting a queue entry at index %d.\n",index));
 	dprintk((KERN_DEBUG "Fib contents:.\n"));
-	dprintk((KERN_DEBUG "  Command =               %d.\n", fib->header.Command));
-	dprintk((KERN_DEBUG "  XferState  =            %x.\n", fib->header.XferState));
+	dprintk((KERN_DEBUG "  Command =               %d.\n", hw_fib->header.Command));
+	dprintk((KERN_DEBUG "  XferState  =            %x.\n", hw_fib->header.XferState));
+	dprintk((KERN_DEBUG "  hw_fib va being sent=%p\n",fibptr->hw_fib));
+	dprintk((KERN_DEBUG "  hw_fib pa being sent=%xl\n",(ulong)fibptr->hw_fib_pa));
+	dprintk((KERN_DEBUG "  fib being sent=%p\n",fibptr));
 	/*
 	 *	Fill in the Callback and CallbackContext if we are not
 	 *	going to wait.
@@ -500,6 +512,7 @@
 	q->numpending++;
 
 	fibptr->done = 0;
+	fibptr->flags = 0;
 
 	if(aac_insert_entry(dev, index, qid, (nointr & aac_config.irq_mod)) < 0)
 		return -EWOULDBLOCK;
@@ -513,10 +526,11 @@
 		if(fibptr->done == 0)
 			BUG();
 			
-		if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT))
+		if((fibptr->flags & FIB_CONTEXT_FLAG_TIMED_OUT)){
 			return -ETIMEDOUT;
-		else
+		} else {
 			return 0;
+		}
 	}
 	/*
 	 *	If the user does not want a response than return success otherwise
@@ -543,8 +557,7 @@
 {
 	u32 index;
 	int status;
-
-	if (*q->headers.producer == *q->headers.consumer) {
+	if (le32_to_cpu(*q->headers.producer) == le32_to_cpu(*q->headers.consumer)) {
 		status = 0;
 	} else {
 		/*
@@ -564,7 +577,7 @@
 
 int aac_consumer_avail(struct aac_dev *dev, struct aac_queue * q)
 {
-	return (*q->headers.producer != *q->headers.consumer);
+	return (le32_to_cpu(*q->headers.producer) != le32_to_cpu(*q->headers.consumer));
 }
 
 
@@ -583,7 +596,7 @@
 	int wasfull = 0;
 	u32 notify;
 
-	if (*q->headers.producer+1 == *q->headers.consumer)
+	if ((le32_to_cpu(*q->headers.producer)+1) == le32_to_cpu(*q->headers.consumer))
 		wasfull = 1;
         
 	if (le32_to_cpu(*q->headers.consumer) >= q->entries)
@@ -625,16 +638,15 @@
 
 int fib_adapter_complete(struct fib * fibptr, unsigned short size)
 {
-	struct hw_fib * fib = fibptr->fib;
+	struct hw_fib * hw_fib = fibptr->hw_fib;
 	struct aac_dev * dev = fibptr->dev;
 	unsigned long nointr = 0;
-
-	if (le32_to_cpu(fib->header.XferState) == 0)
+	if (le32_to_cpu(hw_fib->header.XferState) == 0)
         	return 0;
 	/*
 	 *	If we plan to do anything check the structure type first.
 	 */ 
-	if ( fib->header.StructType != FIB_MAGIC ) {
+	if ( hw_fib->header.StructType != FIB_MAGIC ) {
         	return -EINVAL;
 	}
 	/*
@@ -644,37 +656,36 @@
 	 *	and want to send a response back to the adapter. This will 
 	 *	send the completed cdb to the adapter.
 	 */
-	if (fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
-	        fib->header.XferState |= cpu_to_le32(HostProcessed);
-	        if (fib->header.XferState & cpu_to_le32(HighPriority)) {
+	if (hw_fib->header.XferState & cpu_to_le32(SentFromAdapter)) {
+	        hw_fib->header.XferState |= cpu_to_le32(HostProcessed);
+	        if (hw_fib->header.XferState & cpu_to_le32(HighPriority)) {
         		u32 index;
        			if (size) 
 			{
 				size += sizeof(struct aac_fibhdr);
-				if (size > le16_to_cpu(fib->header.SenderSize))
+				if (size > le16_to_cpu(hw_fib->header.SenderSize))
 					return -EMSGSIZE;
-				fib->header.Size = cpu_to_le16(size);
+				hw_fib->header.Size = cpu_to_le16(size);
 			}
-			if(aac_queue_get(dev, &index, AdapHighRespQueue, fib, 1, NULL, &nointr) < 0) {
+			if(aac_queue_get(dev, &index, AdapHighRespQueue, hw_fib, 1, NULL, &nointr) < 0) {
 				return -EWOULDBLOCK;
 			}
 			if (aac_insert_entry(dev, index, AdapHighRespQueue,  (nointr & (int)aac_config.irq_mod)) != 0) {
 			}
 		}
-		else if (fib->header.XferState & NormalPriority) 
+		else if (hw_fib->header.XferState & NormalPriority) 
 		{
 			u32 index;
 
 			if (size) {
 				size += sizeof(struct aac_fibhdr);
-				if (size > le16_to_cpu(fib->header.SenderSize)) 
+				if (size > le16_to_cpu(hw_fib->header.SenderSize)) 
 					return -EMSGSIZE;
-				fib->header.Size = cpu_to_le16(size);
+				hw_fib->header.Size = cpu_to_le16(size);
 			}
-			if (aac_queue_get(dev, &index, AdapNormRespQueue, fib, 1, NULL, &nointr) < 0) 
+			if (aac_queue_get(dev, &index, AdapNormRespQueue, hw_fib, 1, NULL, &nointr) < 0) 
 				return -EWOULDBLOCK;
-			if (aac_insert_entry(dev, index, AdapNormRespQueue, 
-				(nointr & (int)aac_config.irq_mod)) != 0) 
+			if (aac_insert_entry(dev, index, AdapNormRespQueue, (nointr & (int)aac_config.irq_mod)) != 0) 
 			{
 			}
 		}
@@ -696,19 +707,19 @@
  
 int fib_complete(struct fib * fibptr)
 {
-	struct hw_fib * fib = fibptr->fib;
+	struct hw_fib * hw_fib = fibptr->hw_fib;
 
 	/*
 	 *	Check for a fib which has already been completed
 	 */
 
-	if (fib->header.XferState == cpu_to_le32(0))
+	if (hw_fib->header.XferState == cpu_to_le32(0))
         	return 0;
 	/*
 	 *	If we plan to do anything check the structure type first.
 	 */ 
 
-	if (fib->header.StructType != FIB_MAGIC)
+	if (hw_fib->header.StructType != FIB_MAGIC)
 	        return -EINVAL;
 	/*
 	 *	This block completes a cdb which orginated on the host and we 
@@ -716,19 +727,19 @@
 	 *	command is complete that we had sent to the adapter and this
 	 *	cdb could be reused.
 	 */
-	if((fib->header.XferState & cpu_to_le32(SentFromHost)) &&
-		(fib->header.XferState & cpu_to_le32(AdapterProcessed)))
+	if((hw_fib->header.XferState & cpu_to_le32(SentFromHost)) &&
+		(hw_fib->header.XferState & cpu_to_le32(AdapterProcessed)))
 	{
 		fib_dealloc(fibptr);
 	}
-	else if(fib->header.XferState & cpu_to_le32(SentFromHost))
+	else if(hw_fib->header.XferState & cpu_to_le32(SentFromHost))
 	{
 		/*
 		 *	This handles the case when the host has aborted the I/O
 		 *	to the adapter because the adapter is not responding
 		 */
 		fib_dealloc(fibptr);
-	} else if(fib->header.XferState & cpu_to_le32(HostOwned)) {
+	} else if(hw_fib->header.XferState & cpu_to_le32(HostOwned)) {
 		fib_dealloc(fibptr);
 	} else {
 		BUG();
@@ -778,13 +789,13 @@
 
 static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr)
 {
-	struct hw_fib * fib = fibptr->fib;
+	struct hw_fib * hw_fib = fibptr->hw_fib;
 	/*
 	 * Set the status of this FIB to be Invalid parameter.
 	 *
 	 *	*(u32 *)fib->data = ST_INVAL;
 	 */
-	*(u32 *)fib->data = cpu_to_le32(ST_OK);
+	*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
 	fib_adapter_complete(fibptr, sizeof(u32));
 }
 
@@ -800,7 +811,7 @@
  
 int aac_command_thread(struct aac_dev * dev)
 {
-	struct hw_fib *fib, *newfib;
+	struct hw_fib *hw_fib, *newfib;
 	struct fib fibptr; /* for error logging */
 	struct aac_queue_block *queues = dev->queues;
 	struct aac_fib_context *fibctx;
@@ -828,17 +839,18 @@
 	while(1) 
 	{
 		spin_lock_irqsave(queues->queue[HostNormCmdQueue].lock, flags);
-		while(!list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) {
-			struct list_head *entry;
+		while(!aac_list_empty(&(queues->queue[HostNormCmdQueue].cmdq))) {
+			struct aac_list_head *entry;
 			struct aac_aifcmd * aifcmd;
 
 			set_current_state(TASK_RUNNING);
 		
-			entry = queues->queue[HostNormCmdQueue].cmdq.next;
-			list_del(entry);
+			entry = (struct aac_list_head*)(ulong)(queues->queue[HostNormCmdQueue].cmdq.next);
+			dprintk(("aacraid: Command thread: removing fib from cmdq (%p)\n",entry));
+			aac_list_del(entry);
 			
 			spin_unlock_irqrestore(queues->queue[HostNormCmdQueue].lock, flags);
-			fib = list_entry(entry, struct hw_fib, header.FibLinks);
+			hw_fib = aac_list_entry(entry, struct hw_fib, header.FibLinks);
 			/*
 			 *	We will process the FIB here or pass it to a 
 			 *	worker thread that is TBD. We Really can't 
@@ -848,16 +860,17 @@
 			memset(&fibptr, 0, sizeof(struct fib));
 			fibptr.type = FSAFS_NTC_FIB_CONTEXT;
 			fibptr.size = sizeof( struct fib );
-			fibptr.fib = fib;
-			fibptr.data = fib->data;
+			fibptr.hw_fib = hw_fib;
+			fibptr.data = hw_fib->data;
 			fibptr.dev = dev;
 			/*
 			 *	We only handle AifRequest fibs from the adapter.
 			 */
-			aifcmd = (struct aac_aifcmd *) fib->data;
+			aifcmd = (struct aac_aifcmd *) hw_fib->data;
 			if (aifcmd->command == le16_to_cpu(AifCmdDriverNotify)) {
 				aac_handle_aif(dev, &fibptr);
 			} else {
+				struct list_head *entry;
 				/* The u32 here is important and intended. We are using
 				   32bit wrapping time to fit the adapter field */
 				   
@@ -906,12 +919,12 @@
 						/*
 						 * Make the copy of the FIB
 						 */
-						memcpy(newfib, fib, sizeof(struct hw_fib));
+						memcpy(newfib, hw_fib, sizeof(struct hw_fib));
 						/*
 						 * Put the FIB onto the
 						 * fibctx's fibs
 						 */
-						list_add_tail(&newfib->header.FibLinks, &fibctx->fibs);
+						aac_list_add_tail(&newfib->header.FibLinks, &fibctx->hw_fib_list);
 						fibctx->count++;
 						/* 
 						 * Set the event to wake up the
@@ -926,7 +939,7 @@
 				/*
 				 *	Set the status of this FIB
 				 */
-				*(u32 *)fib->data = cpu_to_le32(ST_OK);
+				*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
 				fib_adapter_complete(&fibptr, sizeof(u32));
 				spin_unlock_irqrestore(&dev->fib_lock, flagv);
 			}
diff -Nru a/drivers/scsi/aacraid/dpcsup.c b/drivers/scsi/aacraid/dpcsup.c
--- a/drivers/scsi/aacraid/dpcsup.c	Wed Oct  2 13:37:46 2002
+++ b/drivers/scsi/aacraid/dpcsup.c	Wed May  7 15:37:53 2003
@@ -65,7 +65,6 @@
 	unsigned long flags;
 
 	spin_lock_irqsave(q->lock, flags);	
-
 	/*
 	 *	Keep pulling response QEs off the response queue and waking
 	 *	up the waiters until there are no more QEs. We then return
@@ -74,12 +73,13 @@
 	 */
 	while(aac_consumer_get(dev, q, &entry))
 	{
-		int fast;
+		u32 fast ;
+		fast = (entry->addr & cpu_to_le32(0x01));
+		hwfib = (struct hw_fib *)((char *)dev->hw_fib_va + 
+				((entry->addr & ~0x01) - dev->hw_fib_pa));
+		fib = &dev->fibs[hwfib->header.SenderData];
 
-		fast = (int) (entry->addr & 0x01);
-		hwfib = addr2fib(entry->addr & ~0x01);
 		aac_consumer_free(dev, q, HostNormRespQueue);
-		fib = &dev->fibs[hwfib->header.SenderData];
 		/*
 		 *	Remove this fib from the Outstanding I/O queue.
 		 *	But only if it has not already been timed out.
@@ -93,6 +93,7 @@
 			dev->queues->queue[AdapNormCmdQueue].numpending--;
 		} else {
 			printk(KERN_WARNING "aacraid: FIB timeout (%x).\n", fib->flags);
+			printk(KERN_DEBUG"aacraid: hwfib=%p fib index=%i fib=%p\n",hwfib, hwfib->header.SenderData,fib);
 			continue;
 		}
 		spin_unlock_irqrestore(q->lock, flags);
@@ -171,11 +172,12 @@
 	 */
 	while(aac_consumer_get(dev, q, &entry))
 	{
-		struct hw_fib * fib;
-		fib = addr2fib(entry->addr);
+		struct hw_fib * hw_fib;
+		hw_fib = (struct hw_fib *)((char *)dev->hw_fib_va + 
+				((entry->addr & ~0x01) - dev->hw_fib_pa));
 
 		if (dev->aif_thread) {
-		        list_add_tail(&fib->header.FibLinks, &q->cmdq);
+		        aac_list_add_tail(&hw_fib->header.FibLinks, &q->cmdq);
 	 	        aac_consumer_free(dev, q, HostNormCmdQueue);
 		        wake_up_interruptible(&q->cmdready);
 		} else {
@@ -185,13 +187,13 @@
 			memset(&fibctx, 0, sizeof(struct fib));
 			fibctx.type = FSAFS_NTC_FIB_CONTEXT;
 			fibctx.size = sizeof(struct fib);
-			fibctx.fib = fib;
-			fibctx.data = fib->data;
+			fibctx.hw_fib = hw_fib;
+			fibctx.data = hw_fib->data;
 			fibctx.dev = dev;
 			/*
 			 *	Set the status of this FIB
 			 */
-			*(u32 *)fib->data = cpu_to_le32(ST_OK);
+			*(u32 *)hw_fib->data = cpu_to_le32(ST_OK);
 			fib_adapter_complete(&fibctx, sizeof(u32));
 			spin_lock_irqsave(q->lock, flags);
 		}		
diff -Nru a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
--- a/drivers/scsi/aacraid/linit.c	Sat Apr 26 07:28:29 2003
+++ b/drivers/scsi/aacraid/linit.c	Thu May  8 11:24:16 2003
@@ -35,7 +35,7 @@
  *	
  */
 
-#define AAC_DRIVER_VERSION		"0.9.9ac6-TEST"
+#define AAC_DRIVER_VERSION		"1.1.2"
 #define AAC_DRIVER_BUILD_DATE		__DATE__
 
 #include <linux/module.h>
@@ -53,20 +53,23 @@
 #include <linux/blk.h>
 #include "scsi.h"
 #include "hosts.h"
-
 #include <scsi/scsicam.h>
 
 #include "aacraid.h"
 
+
 #define AAC_DRIVERNAME	"aacraid"
 
 MODULE_AUTHOR("Red Hat Inc and Adaptec");
-MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, PERC 320/DC, Adaptec 2120S, 2200S, 5400S, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
+MODULE_DESCRIPTION("Supports Dell PERC2, 2/Si, 3/Si, 3/Di, Adaptec Advanced Raid Products, and HP NetRAID-4M devices. http://domsch.com/linux/ or http://linux.adaptec.com");
 MODULE_LICENSE("GPL");
 MODULE_PARM(nondasd, "i");
 MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on");
+MODULE_PARM(paemode, "i");
+MODULE_PARM_DESC(paemode, "Control whether dma addressing is using PAE. 0=off, 1=on");
 
-static int nondasd=-1;
+int nondasd=-1;
+int paemode=-1;
 
 struct aac_dev *aac_devices[MAXIMUM_NUM_ADAPTERS];
 
@@ -76,12 +79,12 @@
 /*
  * Because of the way Linux names scsi devices, the order in this table has
  * become important.  Check for on-board Raid first, add-in cards second.
- *
+ */
+/*
  * dmb - For now we add the number of channels to this structure.  
  * In the future we should add a fib that reports the number of channels
  * for the card.  At that time we can remove the channels from here
  */
- 
 static struct aac_driver_ident aac_drivers[] = {
 	{ 0x1028, 0x0001, 0x1028, 0x0001, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 2/Si */
 	{ 0x1028, 0x0002, 0x1028, 0x0002, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* PERC 3/Di */
@@ -97,11 +100,22 @@
 	{ 0x9005, 0x0285, 0x9005, 0x0286, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2120S   ", 1 }, /* Adaptec 2120S (Crusader)*/
 	{ 0x9005, 0x0285, 0x9005, 0x0285, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2 }, /* Adaptec 2200S (Vulcan)*/
 	{ 0x9005, 0x0285, 0x9005, 0x0287, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 2200S   ", 2 }, /* Adaptec 2200S (Vulcan-2m)*/
-	{ 0x9005, 0x0285, 0x1028, 0x0287, aac_rx_init, "percraid", "DELL    ", "PERCRAID        ", 2 }, /* Dell PERC 320/DC */
+	{ 0x9005, 0x0285, 0x17aa, 0x0286, aac_rx_init, "aacraid",  "Legend  ", "Legend S220     ", 1 }, /* Legend S220*/
+	{ 0x9005, 0x0285, 0x17aa, 0x0287, aac_rx_init, "aacraid",  "Legend  ", "Legend S230     ", 2 }, /* Legend S230*/
+
+	{ 0x9005, 0x0285, 0x9005, 0x0288, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3230S   ", 2 }, /* Adaptec 3230S (Harrier)*/
+	{ 0x9005, 0x0285, 0x9005, 0x0289, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec 3240S   ", 2 }, /* Adaptec 3240S (Tornado)*/
+	{ 0x9005, 0x0285, 0x9005, 0x028a, aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S PCI-X ZCR (Skyhawk)*/
+	{ 0x9005, 0x0285, 0x9005, 0x028b, aac_rx_init, "aacraid",  "ADAPTEC ", "ASR-2020S PCI-X ", 2 }, /* ASR-2020S SO-DIMM PCI-X ZCR(Terminator)*/
+	{ 0x9005, 0x0285, 0x9005, 0x0290, aac_rx_init, "aacraid",  "ADAPTEC ", "AAR-2410SA SATA ", 2 }, /* AAR-2410SA PCI SATA 4ch (Jaguar II)*/
+	{ 0x9005, 0x0250, 0x1014, 0x0279, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec         ", 2 }, /* (Marco)*/
+	{ 0x9005, 0x0250, 0x1014, 0x028c, aac_rx_init, "aacraid",  "ADAPTEC ", "Adaptec         ", 2 }, /* (Sebring)*/
+
+	{ 0x9005, 0x0285, 0x1028, 0x0287, aac_rx_init, "percraid", "DELL    ", "PERC 320/DC     ", 2 }, /* Perc 320/DC*/
 	{ 0x1011, 0x0046, 0x9005, 0x0365, aac_sa_init, "aacraid",  "ADAPTEC ", "Adaptec 5400S   ", 4 }, /* Adaptec 5400S (Mustang)*/
 	{ 0x1011, 0x0046, 0x9005, 0x0364, aac_sa_init, "aacraid",  "ADAPTEC ", "AAC-364         ", 4 }, /* Adaptec 5400S (Mustang)*/
 	{ 0x1011, 0x0046, 0x9005, 0x1364, aac_sa_init, "percraid", "DELL    ", "PERCRAID        ", 4 }, /* Dell PERC2 "Quad Channel" */
-	{ 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid",  "HP      ", "NetRAID-4M      ", 4 }  /* HP NetRAID-4M */
+	{ 0x1011, 0x0046, 0x103c, 0x10c2, aac_sa_init, "hpnraid",  "HP      ", "NetRAID         ", 4 }  /* HP NetRAID-4M */
 };
 
 #define NUM_AACTYPES	(sizeof(aac_drivers) / sizeof(struct aac_driver_ident))
@@ -122,7 +136,7 @@
 static int aac_release(struct Scsi_Host *);
 static int aac_queuecommand(Scsi_Cmnd *, void (*CompletionRoutine)(Scsi_Cmnd *));
 static int aac_biosparm(struct scsi_device *, struct block_device *,
-		sector_t, int *);
+			sector_t, int *);
 static int aac_procinfo(char *, char **, off_t, int, int, int);
 static int aac_ioctl(Scsi_Device *, int, void *);
 static int aac_eh_abort(Scsi_Cmnd * cmd);
@@ -130,7 +144,7 @@
 static int aac_eh_bus_reset(Scsi_Cmnd* cmd);
 static int aac_eh_reset(Scsi_Cmnd* cmd);
 
-static int aac_slave_configure(Scsi_Device *);
+static int aac_slave_configure(struct scsi_device *);
 
 /**
  *	aac_detect	-	Probe for aacraid cards
@@ -162,13 +176,12 @@
 	struct fsa_scsi_hba *fsa_dev_ptr;
 	char *name = NULL;
 	
-	printk(KERN_INFO "Red Hat/Adaptec aacraid driver, %s\n", AAC_DRIVER_BUILD_DATE);
+	printk(KERN_INFO "Red Hat/Adaptec aacraid driver (%s %s)\n", AAC_DRIVER_VERSION, AAC_DRIVER_BUILD_DATE);
 
 	/* setting up the proc directory structure */
 	template->proc_name = "aacraid";
 
-	for( index = 0; index != num_aacdrivers; index++ )
-	{
+	for( index = 0; index != num_aacdrivers; index++ ) {
 		device_id = aac_drivers[index].device;
 		vendor_id = aac_drivers[index].vendor;
 		name = aac_drivers[index].name;
@@ -206,16 +219,10 @@
 			 * specific information.
 			 */
 			host_ptr = scsi_register( template, sizeof(struct aac_dev) );
-			if(host_ptr == NULL)
-				continue;
-
 			/* 
 			 * These three parameters can be used to allow for wide SCSI 
 			 * and for host adapters that support multiple buses.
 			 */
-			host_ptr->max_id = 17;
-			host_ptr->max_lun = 8;
-			host_ptr->max_channel = 1;
 			host_ptr->irq = dev->irq;		/* Adapter IRQ number */
 			/* host_ptr->base = ( char * )(dev->resource[0].start & ~0xff); */
 			host_ptr->base = dev->resource[0].start;
@@ -236,9 +243,13 @@
 			/* attach a pointer back to Scsi_Host */
 			aac->scsi_host_ptr = host_ptr;	
 			aac->pdev = dev;
-			aac->cardtype =  index;
 			aac->name = aac->scsi_host_ptr->hostt->name;
 			aac->id = aac->scsi_host_ptr->unique_id;
+			aac->cardtype =  index;
+
+			aac->fibs = (struct fib*) kmalloc(sizeof(struct fib)*AAC_NUM_FIB, GFP_KERNEL);
+			spin_lock_init(&aac->fib_lock);
+
 			/* Initialize the ordinal number of the device to -1 */
 			fsa_dev_ptr = &(aac->fsa_dev);
 			for( container = 0; container < MAXIMUM_NUM_CONTAINERS; container++ )
@@ -255,46 +266,28 @@
 			} 
 			dprintk((KERN_DEBUG "%s:%d device initialization successful.\n", name, host_ptr->unique_id));
 			aac_get_adapter_info(aac);
-			if(nondasd != -1) 
-			{
-				/* someone told us how to set this on the cmdline */
-				aac->nondasd_support = (nondasd!=0);
-			}
-			if(aac->nondasd_support != 0){
-				printk(KERN_INFO "%s%d: Non-DASD support enabled\n", aac->name, aac->id);
-			}
-			dprintk((KERN_DEBUG "%s:%d options flag %04x.\n",name, host_ptr->unique_id,aac->adapter_info.options));
-			if(aac->nondasd_support == 1)
-			{
-				/*
-				 * max channel will be the physical channels plus 1 virtual channel 
-				 * all containers are on the virtual channel 0
-				 * physical channels are address by their actual physical number+1
-				 */
+			if(aac->nondasd_support == 1){
+			/*
+			 * max channel will be the physical channels plus 1 virtual channel 
+			 * all containers are on the virtual channel 0
+			 * physical channels are address by their actual physical number+1
+			 */
 				host_ptr->max_channel = aac_drivers[index].channels+1;
 			} else {
 				host_ptr->max_channel = 1;
- 			}
-			dprintk((KERN_DEBUG "Device has %d logical channels\n", host_ptr->max_channel));
+			}
+			dprintk((KERN_DEBUG "Device has %d logical channels\n",host_ptr->max_channel));
 			aac_get_containers(aac);
 			aac_devices[aac_count-1] = aac;
+//			spin_unlock_irqrestore(&aac->fib_lock, flags);
 
 			/*
-			 * dmb - we may need to move these 3 parms somewhere else once
+			 * dmb - we may need to move the setting of these parms somewhere else once
 			 * we get a fib that can report the actual numbers
 			 */
 			host_ptr->max_id = AAC_MAX_TARGET;
 			host_ptr->max_lun = AAC_MAX_LUN;
-			
-			/*
-			 *  If we are PAE capable then our future DMA mappings
-			 *  (for read/write commands) are 64bit clean and don't 
-			 *  need bouncing. This assumes we do no other 32bit only
-			 *  allocations (eg fib table expands) after this point.
-			 */
-			 
-			if(aac->pae_support)
-				pci_set_dma_mask(dev, 0xFFFFFFFFFFFFFFFFUL);
+
 		}
 	}
 
@@ -356,17 +349,19 @@
  *	Queues a command for execution by the associated Host Adapter.
  */ 
 
-static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*complete)(Scsi_Cmnd *))
+static int aac_queuecommand(Scsi_Cmnd *scsi_cmnd_ptr, void (*CompletionRoutine)(Scsi_Cmnd *))
 {
 	int ret;
 
-	scsi_cmnd_ptr->scsi_done = complete;
+	scsi_cmnd_ptr->scsi_done = CompletionRoutine;
 	/*
 	 *	aac_scsi_cmd() handles command processing, setting the 
 	 *	result code and calling completion routine. 
 	 */
-	if((ret = aac_scsi_cmd(scsi_cmnd_ptr)) != 0)
+	if((ret = aac_scsi_cmd(scsi_cmnd_ptr)) != 0){
 		dprintk((KERN_DEBUG "aac_scsi_cmd failed.\n"));
+		return FAILED;
+	}
 	return ret;
 } 
 
@@ -396,8 +391,9 @@
 
 /**
  *	aac_biosparm	-	return BIOS parameters for disk
- *	@disk: SCSI disk object to process
- *	@device: Disk in question
+ *	@sdev: The scsi device corresponding to the disk
+ *	@bdev: the block device corresponding to the disk
+ *	@capacity: the sector capacity of the disk
  *	@geom: geometry block to fill in
  *
  *	Return the Heads/Sectors/Cylinders BIOS Disk Parameters for Disk.  
@@ -416,10 +412,10 @@
  */
  
 static int aac_biosparm(struct scsi_device *sdev, struct block_device *bdev,
-		sector_t capacity, int *geom)
+			sector_t capacity, int *geom)
 {
 	struct diskparm *param = (struct diskparm *)geom;
-	u8 *buf;
+	unsigned char *buf;
 
 	dprintk((KERN_DEBUG "aac_biosparm.\n"));
 
@@ -445,15 +441,14 @@
 		param->sectors = 32;
 	}
 
-	param->cylinders = cap_to_cyls(capacity,
-			(param->heads * param->sectors));
+	param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
 
 	/*
-	 *	Read the partition table block
+	 *	Read the first 1024 bytes from the disk device
 	 */
 
 	buf = scsi_bios_ptable(bdev);
-	
+
 	/* 
 	 *	If the boot sector partition table is valid, search for a partition 
 	 *	table entry whose end_head matches one of the standard geometry 
@@ -462,7 +457,7 @@
 	 
 	if(*(unsigned short *)(buf + 0x40) == cpu_to_le16(0xaa55))
 	{
-		struct partition *first = (struct partition *)buf;
+		struct partition *first = (struct partition * )buf;
 		struct partition *entry = first;
 		int saved_cylinders = param->cylinders;
 		int num;
@@ -500,8 +495,7 @@
 			end_sec = first->end_sector & 0x3f;
 		}
 
-		param->cylinders = cap_to_cyls(capacity,
-				(param->heads * param->sectors));
+		param->cylinders = cap_to_cyls(capacity, param->heads * param->sectors);
 
 		if(num < 4 && end_sec == param->sectors)
 		{
@@ -522,15 +516,17 @@
 }
 
 /**
- *	aac_slave_configure	-	do device specific setup
- *	@dev:	SCSI device we are attaching
+ *	aac_queuedepth		-	compute queue depths
+ *	@host:	SCSI host in question
+ *	@dev:	SCSI device we are considering
  *
- * 	Currently, all we do is set the queue depth on the device.
+ *	Selects queue depths for each target device based on the host adapter's
+ *	total capacity and the queue depth supported by the target device.
+ *	A queue depth of one automatically disables tagged queueing.
  */
 
-static int aac_slave_configure(Scsi_Device * dev )
+static int aac_slave_configure(struct scsi_device * dev )
 {
-
 	if(dev->tagged_supported)
 		scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, 128);
 	else
@@ -543,75 +539,13 @@
 	return 0;
 }
 
+/*------------------------------------------------------------------------------
+	aac_ioctl()
 
-/**
- *	aac_eh_abort	-	Abort command if possible.
- *	@cmd:	SCSI command block to abort
- *
- *	Called when the midlayer wishes to abort a command. We don't support
- *	this facility, and our firmware looks after life for us. We just
- *	report this as failing
- */
- 
-static int aac_eh_abort(Scsi_Cmnd *cmd)
-{
-	return FAILED;
-}
-
-/**
- *	aac_eh_device_reset	-	Reset command handling
- *	@cmd:	SCSI command block causing the reset
- *
- *	Issue a reset of a SCSI device. We are ourselves not truely a SCSI
- *	controller and our firmware will do the work for us anyway. Thus this
- *	is a no-op. We just return FAILED.
- */
-
-static int aac_eh_device_reset(Scsi_Cmnd *cmd)
-{
-	return FAILED;
-}
-
-/**
- *	aac_eh_bus_reset	-	Reset command handling
- *	@scsi_cmd:	SCSI command block causing the reset
- *
- *	Issue a reset of a SCSI bus. We are ourselves not truely a SCSI
- *	controller and our firmware will do the work for us anyway. Thus this
- *	is a no-op. We just return FAILED.
- */
-
-static int aac_eh_bus_reset(Scsi_Cmnd* cmd)
-{
-	return FAILED;
-}
-
-/**
- *	aac_eh_hba_reset	-	Reset command handling
- *	@scsi_cmd:	SCSI command block causing the reset
- *
- *	Issue a reset of a SCSI host. If things get this bad then arguably we should
- *	go take a look at what the host adapter is doing and see if something really
- *	broke (as can occur at least on my Dell QC card if a drive keeps failing spinup)
- */
-
-static int aac_eh_reset(Scsi_Cmnd* cmd)
-{
-	printk(KERN_ERR "aacraid: Host adapter reset request. SCSI hang ?\n");
-	return FAILED;
-}
-
-/**
- *	aac_ioctl 	-	Handle SCSI ioctls
- *	@scsi_dev_ptr: scsi device to operate upon
- *	@cmd: ioctl command to use issue
- *	@arg: ioctl data pointer
- *
- *	Issue an ioctl on an aacraid device. Returns a standard unix error code or
- *	zero for success
- */
- 
+		Handle SCSI ioctls
+ *----------------------------------------------------------------------------*/
 static int aac_ioctl(Scsi_Device * scsi_dev_ptr, int cmd, void * arg)
+/*----------------------------------------------------------------------------*/
 {
 	struct aac_dev *dev;
 	dprintk((KERN_DEBUG "aac_ioctl.\n"));
@@ -694,13 +628,58 @@
 	.this_id        		= 16,
 	.sg_tablesize   		= 16,
 	.max_sectors    		= 128,
-	.cmd_per_lun    		= 1,
-	.eh_abort_handler       	= aac_eh_abort,
-	.eh_device_reset_handler 	= aac_eh_device_reset,
+	.cmd_per_lun    		= AAC_NUM_IO_FIB, 
+	.eh_abort_handler		= aac_eh_abort,
+	.eh_device_reset_handler	= aac_eh_device_reset,
 	.eh_bus_reset_handler		= aac_eh_bus_reset,
 	.eh_host_reset_handler		= aac_eh_reset,
 	.use_clustering			= ENABLE_CLUSTERING,
 };
+
+/*===========================================================================
+ * Error Handling routines
+ *===========================================================================
+ */
+
+
+/*
+ *
+ * We don't support abortting commands.
+ */
+static int aac_eh_abort(Scsi_Cmnd * scsicmd)
+{
+	printk("aacraid: abort failed\n");
+	return FAILED;
+}
+
+/*
+ * We don't support device resets.
+ */
+static int aac_eh_device_reset(Scsi_Cmnd* cmd)
+{
+	printk("aacraid: device reset failed\n");
+	return FAILED;
+}
+
+
+static int aac_eh_bus_reset(Scsi_Cmnd* cmd)
+{
+	printk("aacraid: bus reset failed\n");
+	return FAILED;
+}
+
+static int aac_eh_reset(Scsi_Cmnd* cmd)
+{
+	printk("aacraid: hba reset failed\n");
+	return FAILED;
+}
+
+
+/*===========================================================================
+ * 
+ *===========================================================================
+ */
+
 
 #include "scsi_module.c"
 
diff -Nru a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c
--- a/drivers/scsi/aacraid/sa.c	Sat Apr 26 07:28:30 2003
+++ b/drivers/scsi/aacraid/sa.c	Wed May  7 19:08:36 2003
@@ -352,7 +352,7 @@
 	 *	Wait for the adapter to be up and running. Wait up to 3 minutes.
 	 */
 	while (!(sa_readl(dev, Mailbox7) & KERNEL_UP_AND_RUNNING)) {
-		if (time_after(start+180*HZ, jiffies)) {
+		if (time_after(jiffies, start+180*HZ)) {
 			status = sa_readl(dev, Mailbox7) >> 16;
 			printk(KERN_WARNING "%s%d: adapter kernel failed to start, init status = %d.\n", name, instance, le32_to_cpu(status));
 			return -1;
diff -Nru a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
--- a/drivers/scsi/advansys.c	Sat Apr 26 07:28:17 2003
+++ b/drivers/scsi/advansys.c	Thu May  8 11:31:08 2003
@@ -4303,7 +4303,6 @@
     int                 leftlen;
     char                *curbuf;
     off_t               advoffset;
-    Scsi_Device         *scd;
 #ifdef ADVANSYS_STATS
     int                 tgt_id;
 #endif /* ADVANSYS_STATS */
@@ -6198,13 +6197,33 @@
  * --- Loadable Driver Support
  */
 
-#if ASC_LINUX_KERNEL24
-static
-#endif
-#if ASC_LINUX_KERNEL24 || (ASC_LINUX_KERNEL22 && defined(MODULE))
-Scsi_Host_Template driver_template = ADVANSYS;
-# include "scsi_module.c"
-#endif
+static Scsi_Host_Template driver_template = {
+    .proc_name                  = "advansys",
+    .proc_info                  = advansys_proc_info,
+    .name                       = "advansys",
+    .detect                     = advansys_detect, 
+    .release                    = advansys_release,
+    .info                       = advansys_info,
+    .queuecommand               = advansys_queuecommand,
+    .eh_bus_reset_handler	= advansys_reset,
+    .bios_param                 = advansys_biosparam,
+    .slave_configure		= advansys_slave_configure,
+    /*
+     * Because the driver may control an ISA adapter 'unchecked_isa_dma'
+     * must be set. The flag will be cleared in advansys_detect for non-ISA
+     * adapters. Refer to the comment in scsi_module.c for more information.
+     */
+    .unchecked_isa_dma          = 1,
+    /*
+     * All adapters controlled by this driver are capable of large
+     * scatter-gather lists. According to the mid-level SCSI documentation
+     * this obviates any performance gain provided by setting
+     * 'use_clustering'. But empirically while CPU utilization is increased
+     * by enabling clustering, I/O throughput increases as well.
+     */
+    .use_clustering             = ENABLE_CLUSTERING,
+};
+#include "scsi_module.c"
 
 
 /*
diff -Nru a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
--- a/drivers/scsi/advansys.h	Tue Dec 10 12:28:34 2002
+++ b/drivers/scsi/advansys.h	Sun May  4 02:56:43 2003
@@ -67,61 +67,4 @@
 /* init/main.c setup function */
 void advansys_setup(char *, int *);
 
-/*
- * AdvanSys Host Driver Scsi_Host_Template (struct SHT) from hosts.h.
- */
-#if ASC_LINUX_KERNEL24
-#define ADVANSYS { \
-    .proc_name                  = "advansys", \
-    .proc_info                  = advansys_proc_info, \
-    .name                       = "advansys", \
-    .detect                     = advansys_detect, \
-    .release                    = advansys_release, \
-    .info                       = advansys_info, \
-    .queuecommand               = advansys_queuecommand, \
-    .eh_bus_reset_handler	= advansys_reset, \
-    .bios_param                 = advansys_biosparam, \
-    .slave_configure		= advansys_slave_configure, \
-    /* \
-     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
-     * must be set. The flag will be cleared in advansys_detect for non-ISA \
-     * adapters. Refer to the comment in scsi_module.c for more information. \
-     */ \
-    .unchecked_isa_dma          = 1, \
-    /* \
-     * All adapters controlled by this driver are capable of large \
-     * scatter-gather lists. According to the mid-level SCSI documentation \
-     * this obviates any performance gain provided by setting \
-     * 'use_clustering'. But empirically while CPU utilization is increased \
-     * by enabling clustering, I/O throughput increases as well. \
-     */ \
-    .use_clustering             = ENABLE_CLUSTERING, \
-}
-#elif ASC_LINUX_KERNEL22
-#define ADVANSYS { \
-    .proc_info                  = advansys_proc_info, \
-    .name                       = "advansys", \
-    .detect                     = advansys_detect, \
-    .release                    = advansys_release, \
-    .info                       = advansys_info, \
-    .queuecommand               = advansys_queuecommand, \
-    .use_new_eh_code		= 1, \
-    .eh_bus_reset_handler	= advansys_reset, \
-    .bios_param                 = advansys_biosparam, \
-    /* \
-     * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
-     * must be set. The flag will be cleared in advansys_detect for non-ISA \
-     * adapters. Refer to the comment in scsi_module.c for more information. \
-     */ \
-    .unchecked_isa_dma          = 1, \
-    /* \
-     * All adapters controlled by this driver are capable of large \
-     * scatter-gather lists. According to the mid-level SCSI documentation \
-     * this obviates any performance gain provided by setting \
-     * 'use_clustering'. But empirically while CPU utilization is increased \
-     * by enabling clustering, I/O throughput increases as well. \
-     */ \
-    .use_clustering             = ENABLE_CLUSTERING, \
-}
-#endif
 #endif /* _ADVANSYS_H */
diff -Nru a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
--- a/drivers/scsi/aha1542.c	Sat Apr 26 07:28:18 2003
+++ b/drivers/scsi/aha1542.c	Thu May  8 11:24:14 2003
@@ -67,7 +67,7 @@
 		       int nseg,
 		       int badseg)
 {
-	printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%x length %d\n",
+	printk(KERN_CRIT "sgpnt[%d:%d] page %p/0x%x length %ld\n",
 	       badseg, nseg,
 	       page_address(sgpnt[badseg].page) + sgpnt[badseg].offset,
 	       SCSI_SG_PA(&sgpnt[badseg]),
@@ -1813,7 +1813,22 @@
 MODULE_LICENSE("GPL");
 
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = AHA1542;
-
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "aha1542",
+	.name			= "Adaptec 1542",
+	.detect			= aha1542_detect,
+	.command		= aha1542_command,
+	.queuecommand		= aha1542_queuecommand,
+	.eh_abort_handler	= aha1542_abort,
+	.eh_device_reset_handler= aha1542_dev_reset,
+	.eh_bus_reset_handler	= aha1542_bus_reset,
+	.eh_host_reset_handler	= aha1542_host_reset,
+	.bios_param		= aha1542_biosparam,
+	.can_queue		= AHA1542_MAILBOXES, 
+	.this_id		= 7,
+	.sg_tablesize		= AHA1542_SCATTER,
+	.cmd_per_lun		= AHA1542_CMDLUN,
+	.unchecked_isa_dma	= 1, 
+	.use_clustering		= ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
--- a/drivers/scsi/aha1542.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/aha1542.h	Sun May  4 02:56:43 2003
@@ -151,21 +151,4 @@
 	#define NULL 0
 #endif
 
-#define AHA1542 {    .proc_name			= "aha1542",		\
-		     .name			= "Adaptec 1542", 	\
-		     .detect			= aha1542_detect,		\
-		     .command			= aha1542_command,	\
-		     .queuecommand		= aha1542_queuecommand,	\
-		     .eh_abort_handler		= aha1542_abort,		\
-		     .eh_device_reset_handler	= aha1542_dev_reset,	\
-		     .eh_bus_reset_handler	= aha1542_bus_reset,	\
-		     .eh_host_reset_handler	= aha1542_host_reset,	\
-		     .bios_param		= aha1542_biosparam,      \
-		     .can_queue			= AHA1542_MAILBOXES, 	\
-		     .this_id			= 7, 			\
-		     .sg_tablesize		= AHA1542_SCATTER, 	\
-		     .cmd_per_lun		= AHA1542_CMDLUN, 	\
-		     .unchecked_isa_dma		= 1, 			\
-		     .use_clustering		= ENABLE_CLUSTERING	\
-}
 #endif
diff -Nru a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
--- a/drivers/scsi/aha1740.c	Sat Apr 26 07:28:18 2003
+++ b/drivers/scsi/aha1740.c	Sun May  4 02:56:43 2003
@@ -598,9 +598,20 @@
 
 MODULE_LICENSE("GPL");
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = AHA1740;
-
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "aha1740",
+	.proc_info		= aha1740_proc_info,
+	.name			= "Adaptec 174x (EISA)",
+	.detect			= aha1740_detect,
+	.command		= aha1740_command,
+	.queuecommand		= aha1740_queuecommand,
+	.bios_param		= aha1740_biosparam,
+	.can_queue		= AHA1740_ECBS,
+	.this_id		= 7, 
+	.sg_tablesize		= AHA1740_SCATTER,
+	.cmd_per_lun		= AHA1740_CMDLUN, 
+	.use_clustering		= ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
 
 /* Okay, you made it all the way through.  As of this writing, 3/31/93, I'm
diff -Nru a/drivers/scsi/aha1740.h b/drivers/scsi/aha1740.h
--- a/drivers/scsi/aha1740.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/aha1740.h	Sun May  4 02:56:43 2003
@@ -162,17 +162,4 @@
 #define AHA1740_SCATTER 16
 #define AHA1740_CMDLUN 1
 
-#define AHA1740 {  .proc_name      = "aha1740",				\
-		   .proc_info      = aha1740_proc_info,	                \
-		   .name           = "Adaptec 174x (EISA)",		\
-		   .detect         = aha1740_detect,			\
-		   .command        = aha1740_command,			\
-		   .queuecommand   = aha1740_queuecommand,		\
-		   .bios_param     = aha1740_biosparam,                   \
-		   .can_queue      = AHA1740_ECBS, 			\
-		   .this_id        = 7, 					\
-		   .sg_tablesize   = AHA1740_SCATTER, 			\
-		   .cmd_per_lun    = AHA1740_CMDLUN, 			\
-		   .use_clustering = ENABLE_CLUSTERING}
-
 #endif
diff -Nru a/drivers/scsi/aic7xxx/Makefile b/drivers/scsi/aic7xxx/Makefile
--- a/drivers/scsi/aic7xxx/Makefile	Tue Jan  7 18:29:40 2003
+++ b/drivers/scsi/aic7xxx/Makefile	Fri May  2 11:04:40 2003
@@ -1,7 +1,7 @@
 #
 # Makefile for the Linux aic7xxx SCSI driver.
 #
-# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Makefile#5 $
+# $Id: //depot/linux-aic79xx-2.5.0/drivers/scsi/aic7xxx/Makefile#6 $
 #
 
 # Let kbuild descend into aicasm when cleaning
@@ -33,7 +33,7 @@
 						   aic79xx_proc.o	\
 						   aic79xx_osm_pci.o
 
-EXTRA_CFLAGS += -Idrivers/scsi
+EXTRA_CFLAGS += -Idrivers/scsi -Werror
 #EXTRA_CFLAGS += -g
 
 # Files generated that shall be removed upon make clean
diff -Nru a/drivers/scsi/aic7xxx/aic7770.c b/drivers/scsi/aic7xxx/aic7770.c
--- a/drivers/scsi/aic7xxx/aic7770.c	Thu Feb 20 14:50:08 2003
+++ b/drivers/scsi/aic7xxx/aic7770.c	Wed Apr  9 12:01:02 2003
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#29 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7770.c#30 $
  *
  * $FreeBSD$
  */
@@ -314,7 +314,7 @@
 	if (bootverbose)
 		printf("%s: Reading SEEPROM...", ahc_name(ahc));
 	have_seeprom = ahc_read_seeprom(&sd, (uint16_t *)sc,
-					/*start_addr*/0, sizeof(sc)/2);
+					/*start_addr*/0, sizeof(*sc)/2);
 
 	if (have_seeprom) {
 
diff -Nru a/drivers/scsi/aic7xxx/aic79xx.h b/drivers/scsi/aic7xxx/aic79xx.h
--- a/drivers/scsi/aic7xxx/aic79xx.h	Tue Mar 25 16:12:22 2003
+++ b/drivers/scsi/aic7xxx/aic79xx.h	Thu Apr 24 11:15:39 2003
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#88 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.h#89 $
  *
  * $FreeBSD$
  */
@@ -494,13 +494,11 @@
  *	  transfer.
  */ 
 #define SG_PTR_MASK	0xFFFFFFF8
-/*16*/	uint16_t tag;
-/*18*/	uint8_t  cdb_len;
-/*19*/	uint8_t  task_management;
-/*20*/	uint32_t next_hscb_busaddr;
-/*24*/	uint64_t dataptr;
-/*32*/	uint32_t datacnt;	/* Byte 3 is spare. */
-/*36*/	uint32_t sgptr;
+/*16*/	uint64_t dataptr;
+/*24*/	uint32_t datacnt;	/* Byte 3 is spare. */
+/*28*/	uint32_t sgptr;
+/*32*/	uint32_t hscb_busaddr;
+/*36*/	uint32_t next_hscb_busaddr;
 /*40*/	uint8_t  control;	/* See SCB_CONTROL in aic79xx.reg for details */
 /*41*/	uint8_t	 scsiid;	/*
 				 * Selection out Id
@@ -508,8 +506,10 @@
 				 */
 /*42*/	uint8_t  lun;
 /*43*/	uint8_t  task_attribute;
-/*44*/	uint32_t hscb_busaddr;
-/******* Long lun field only downloaded for full 8 byte lun support *******/
+/*44*/	uint8_t  cdb_len;
+/*45*/	uint8_t  task_management;
+/*46*/	uint16_t tag;		/* Reused by Sequencer. */
+/********** Long lun field only downloaded for full 8 byte lun support ********/
 /*48*/  uint8_t	 pkt_long_lun[8];
 /******* Fields below are not Downloaded (Sequencer may use for scratch) ******/
 /*56*/  uint8_t	 spare[8];
diff -Nru a/drivers/scsi/aic7xxx/aic79xx.reg b/drivers/scsi/aic7xxx/aic79xx.reg
--- a/drivers/scsi/aic7xxx/aic79xx.reg	Tue Mar 25 16:12:22 2003
+++ b/drivers/scsi/aic7xxx/aic79xx.reg	Thu Apr 24 11:46:35 2003
@@ -39,7 +39,7 @@
  *
  * $FreeBSD$
  */
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $"
 
 /*
  * This file is processed by the aic7xxx_asm utility for use in assembling
@@ -194,7 +194,8 @@
 		TRACEPOINT1,
 		TRACEPOINT2,
 		TRACEPOINT3,
-		SAW_HWERR
+		SAW_HWERR,
+		BAD_SCB_STATUS
 	}
 }
 
@@ -3484,9 +3485,6 @@
 	LONGJMP_ADDR {
 		size		2
 	}
-	LONGJMP_SCB {
-		size		2
-	}
 	ACCUM_SAVE {
 		size		1
 	}
@@ -3799,23 +3797,6 @@
 		size	4
 		alias	SCB_NEXT_COMPLETE
 	}
-	SCB_TAG {
-		size	2
-	}
-	SCB_CDB_LEN {
-		size	1
-		field	SCB_CDB_LEN_PTR	0x80	/* CDB in host memory */
-	}
-	SCB_TASK_MANAGEMENT {
-		size	1
-	}
-	SCB_NEXT {
-		alias	SCB_NEXT_SCB_BUSADDR
-		size	2
-	}
-	SCB_NEXT2 {
-		size	2
-	}
 	SCB_DATAPTR {
 		size	8
 	}
@@ -3834,6 +3815,16 @@
 		field	SG_FULL_RESID	0x02	/* In the first byte */
 		field	SG_LIST_NULL	0x01	/* In the first byte */
 	}
+	SCB_BUSADDR {
+		size	4
+	}
+	SCB_NEXT {
+		alias	SCB_NEXT_SCB_BUSADDR
+		size	2
+	}
+	SCB_NEXT2 {
+		size	2
+	}
 	SCB_CONTROL {
 		size	1
 		field	TARGET_SCB	0x80
@@ -3856,8 +3847,16 @@
 	SCB_TASK_ATTRIBUTE {
 		size	1
 	}
-	SCB_BUSADDR {
-		size	4
+	SCB_CDB_LEN {
+		size	1
+		field	SCB_CDB_LEN_PTR	0x80	/* CDB in host memory */
+	}
+	SCB_TASK_MANAGEMENT {
+		size	1
+	}
+	SCB_TAG {
+		alias	SCB_FIFO_USE_COUNT
+		size	2
 	}
 	SCB_SPARE {
 		size	8
diff -Nru a/drivers/scsi/aic7xxx/aic79xx.seq b/drivers/scsi/aic7xxx/aic79xx.seq
--- a/drivers/scsi/aic7xxx/aic79xx.seq	Tue Mar 25 16:12:22 2003
+++ b/drivers/scsi/aic7xxx/aic79xx.seq	Thu Apr 24 11:46:35 2003
@@ -40,7 +40,7 @@
  * $FreeBSD$
  */
 
-VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $"
+VERSION = "$Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $"
 PATCH_ARG_LIST = "struct ahd_softc *ahd"
 PREFIX = "ahd_"
 
@@ -108,8 +108,8 @@
 	test	LQISTAT2, LQIGSAVAIL jz return;
 	/*
 	 * We have received good status for this transaction.  There may
-	 * still be data in our FIFOs draining to the host.  Setup
-	 * monitoring of the draining process or complete the SCB.
+	 * still be data in our FIFOs draining to the host.  Complete
+	 * the SCB only if all data has transferred to the host.
 	 */
 good_status_IU_done:
 	bmov	SCBPTR, GSFIFO, 2;
@@ -135,42 +135,20 @@
 	 * 1) Configured and draining to the host, with a FIFO handler.
 	 * 2) Pending cfg4data, fifo not empty.
 	 *
-	 * Case 1 can be detected by noticing that a longjmp is active for
-	 * the FIFO and LONGJMP_SCB matches our SCB.  In this case, we allow
-	 * the routine servicing the FIFO to complete the SCB.
+	 * Case 1 can be detected by noticing a non-zero FIFO active
+	 * count in the SCB.  In this case, we allow the routine servicing
+	 * the FIFO to complete the SCB.
 	 * 
 	 * Case 2 implies either a pending or yet to occur save data
 	 * pointers for this same context in the other FIFO.  So, if
 	 * we detect case 1, we will properly defer the post of the SCB
 	 * and achieve the desired result.  The pending cfg4data will
 	 * notice that status has been received and complete the SCB.
-	 *
-	 * If the data-transfer has been completed, or no data transfer
-	 * was needed for this SCB, it is safe to complete the command.
-	 */
-	test	SCB_SGPTR, SG_LIST_NULL jz good_status_check_fifos;
-	/*
-	 * All segments have been loaded (or no data transfer), so
-	 * it is safe to complete the command.  Since this was a
-	 * cheap command to check for completion, loop to see if
-	 * more entries can be removed from the GSFIFO.
 	 */
+	test	SCB_FIFO_USE_COUNT, 0xFF jnz idle_loop_gsfifo_in_scsi_mode;
 	call	complete;
 END_CRITICAL;
 	jmp	idle_loop_gsfifo_in_scsi_mode;
-BEGIN_CRITICAL;
-good_status_check_fifos:
-	clc;
-	bmov	ARG_1, SCBPTR, 2;
-	SET_MODE(M_DFF0, M_DFF0)
-	call	check_fifo;
-	jc	return;
-	SET_MODE(M_DFF1, M_DFF1)
-	call	check_fifo;
-	jc	return;
-	SET_MODE(M_SCSI, M_SCSI)
-	jmp	queue_scb_completion;
-END_CRITICAL;
 
 idle_loop_service_fifos:
 	SET_MODE(M_DFF0, M_DFF0)
@@ -179,6 +157,7 @@
 idle_loop_next_fifo:
 	SET_MODE(M_DFF1, M_DFF1)
 	test	LONGJMP_ADDR[1], INVALID_ADDR jz longjmp;
+return:
 	ret;
 
 idle_loop_cchan:
@@ -196,12 +175,31 @@
 scbdma_tohost_done:
 	test	CCSCBCTL, CCARREN jz fill_qoutfifo_dmadone;
 	/*
-	 * A complete SCB upload requires no intervention.
-	 * The SCB is already on the COMPLETE_SCB list
-	 * and its completion notification will now be
-	 * handled just like any other SCB.
+	 * An SCB has been succesfully uploaded to the host.
+	 * If the SCB was uploaded for some reason other than
+	 * bad SCSI status (currently only for underruns), we
+	 * queue the SCB for normal completion.  Otherwise, we
+	 * wait until any select-out activity has halted, and
+	 * then notify the host so that the transaction can be
+	 * dealt with.
+	 */
+	test	SCB_SCSI_STATUS, 0xff jnz scbdma_notify_host;
+	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
+	bmov	COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
+	bmov	SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
+	bmov	COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
+scbdma_notify_host:
+	SET_MODE(M_SCSI, M_SCSI)
+	test	SCSISEQ0, ENSELO jnz return;
+	test	SSTAT0, (SELDO|SELINGO) jnz return;
+	SET_MODE(M_CCHAN, M_CCHAN)
+	/*
+	 * Remove SCB and notify host.
 	 */
-	and	CCSCBCTL, ~(CCARREN|CCSCBEN) ret;
+	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
+	bmov	COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
+	SET_SEQINTCODE(BAD_SCB_STATUS)
+	ret;
 fill_qoutfifo_dmadone:
 	and	CCSCBCTL, ~(CCARREN|CCSCBEN);
 	call	qoutfifo_updated;
@@ -263,6 +261,13 @@
 	clr	A;
 	add	CMDS_PENDING, 1;
 	adc	CMDS_PENDING[1], A;
+	/*
+	 * The FIFO use count field is shared with the
+	 * tag set by the host so that our SCB dma engine
+	 * knows the correct location to store the SCB.
+	 * Set it to zero before processing the SCB.
+	 */
+	mov	SCB_FIFO_USE_COUNT, ALLZEROS;
 	/* Update the next SCB address to download. */
 	bmov	NEXT_QUEUED_SCB_ADDR, SCB_NEXT_SCB_BUSADDR, 4;
 	mvi	SCB_NEXT[1], SCB_LIST_NULL;
@@ -339,15 +344,7 @@
 dma_complete_scb:
 	bmov	SCBPTR, COMPLETE_DMA_SCB_HEAD, 2;
 	bmov	SCBHADDR, SCB_BUSADDR, 4;
-	mvi	CCARREN|CCSCBEN|CCSCBRESET call dma_scb;
-	/*
-	 * Now that we've started the DMA, push us onto
-	 * the normal completion queue to have our SCBID
-	 * posted to the kernel.
-	 */
-	bmov	COMPLETE_DMA_SCB_HEAD, SCB_NEXT_COMPLETE, 2;
-	bmov	SCB_NEXT_COMPLETE, COMPLETE_SCB_HEAD, 2;
-	bmov	COMPLETE_SCB_HEAD, SCBPTR, 2 ret;
+	mvi	CCARREN|CCSCBEN|CCSCBRESET jmp dma_scb;
 END_CRITICAL;
 
 /*
@@ -366,8 +363,6 @@
 	mov	CCSCBCTL, SINDEX ret;
 
 BEGIN_CRITICAL;
-setjmp_setscb:
-	bmov	LONGJMP_SCB, SCBPTR, 2;
 setjmp:
 	bmov	LONGJMP_ADDR, STACK, 2 ret;
 setjmp_inline:
@@ -1035,9 +1030,18 @@
 	or	SEQ_FLAGS2, SELECTOUT_QFROZEN;
 	mov	A, ACCUM_SAVE ret;
 
-queue_arg1_scb_completion:
+/*
+ * Complete the current FIFO's SCB if data for this same
+ * SCB is not transferring in the other FIFO.
+ */
+SET_SRC_MODE	M_DFF1;
+SET_DST_MODE	M_DFF1;
+pkt_complete_scb_if_fifos_idle:
+	bmov	ARG_1, SCBPTR, 2;
+	mvi	DFFSXFRCTL, CLRCHN;
 	SET_MODE(M_SCSI, M_SCSI)
 	bmov	SCBPTR, ARG_1, 2;
+	test	SCB_FIFO_USE_COUNT, 0xFF jnz return;
 queue_scb_completion:
 	test	SCB_SCSI_STATUS,0xff	jnz bad_status;
 	/*
@@ -1053,6 +1057,12 @@
 	cmp	SCB_SCSI_STATUS, STATUS_PKT_SENSE je upload_scb;
 	call	freeze_queue;
 upload_scb:
+	/*
+	 * Restore SCB TAG since we reuse this field
+	 * in the sequencer.  We don't want to corrupt
+	 * it on the host.
+	 */
+	bmov	SCB_TAG, SCBPTR, 2;
 	bmov	SCB_NEXT_COMPLETE, COMPLETE_DMA_SCB_HEAD, 2;
 	bmov	COMPLETE_DMA_SCB_HEAD, SCBPTR, 2;
 	or	SCB_SGPTR, SG_STATUS_VALID ret;
@@ -1363,7 +1373,7 @@
 	clr	SG_STATE ret;
 
 p_data_handle_xfer:
-	call	setjmp_setscb;
+	call	setjmp;
 	test	SG_STATE, LOADING_NEEDED jnz service_fifo;
 p_data_clear_handler:
 	or	LONGJMP_ADDR[1], INVALID_ADDR ret;
@@ -1616,25 +1626,32 @@
 		 * and deffer the test by one instruction.
 		 */
 		mov	REG_ISR, LQISTAT2;
-		test	REG_ISR, LQIWORKONLQ jz data_valid;
-		test	SEQINTSRC, SAVEPTRS  jz data_valid;
+		test	REG_ISR, LQIWORKONLQ jz main_isr;
+		test	SEQINTSRC, SAVEPTRS  jz main_isr;
 		test	LONGJMP_ADDR[1], INVALID_ADDR jz saveptr_active_fifo;
 		/*
-		 * Switch to the active FIFO.
+		 * Switch to the active FIFO after clearing the snapshot
+		 * savepointer in the current FIFO.  We do this so that
+		 * a pending CTXTDONE or SAVEPTR is visible in the active
+		 * FIFO.  This status is the only way we can detect if we
+		 * have lost the race (e.g. host paused us) and our attepts
+		 * to disable the channel occurred after all REQs were
+		 * already seen and acked (REQINIT never comes true).
 		 */
+		mvi	DFFSXFRCTL, CLRCHN;
 		xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
-		test	DFCNTRL, DIRECTION jz snapshot_other_fifo;
+		test	DFCNTRL, DIRECTION jz interrupt_return;
 		and	DFCNTRL, ~SCSIEN;
-		test	SSTAT1, REQINIT	jz .;
+snapshot_wait_data_valid:
+		test	SEQINTSRC, (CTXTDONE|SAVEPTRS) jnz snapshot_data_valid;
+		test	SSTAT1, REQINIT	jz snapshot_wait_data_valid;
+snapshot_data_valid:
 		or	DFCNTRL, SCSIEN;
-		/* FALLTHROUGH */
-snapshot_other_fifo:
-		xor	MODE_PTR, MK_MODE(M_DFF1, M_DFF1);
-		/* FALLTHROUGH */
+		or	SEQINTCTL, IRET ret;
 snapshot_saveptr:
 		mvi	DFFSXFRCTL, CLRCHN;
 		or	SEQINTCTL, IRET ret;
-data_valid:
+main_isr:
 	}
 	test	SEQINTSRC, CFG4DATA	jnz cfg4data_intr;
 	test	SEQINTSRC, CFG4ISTAT	jnz cfg4istat_intr;
@@ -1667,9 +1684,11 @@
 	or	SEQINTCTL, IRET ret;
 
 cfg4data_intr:
-	test	SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun;
+	test	SCB_SGPTR[0], SG_LIST_NULL jnz pkt_handle_overrun_inc_use_count;
 	call	load_first_seg;
 	call	pkt_handle_xfer;
+	inc	SCB_FIFO_USE_COUNT;
+interrupt_return:
 	or	SEQINTCTL, IRET ret;
 
 cfg4istat_intr:
@@ -1729,7 +1748,6 @@
 	test	DFSTATUS, FIFOEMP jz pkt_handle_overrun
 
 pkt_handle_xfer:
-	bmov	LONGJMP_SCB, SCBPTR, 2;
 	test	SG_STATE, LOADING_NEEDED jz pkt_last_seg;
 	call	setjmp;
 	test	SEQINTSRC, SAVEPTRS jnz pkt_saveptrs;
@@ -1751,7 +1769,7 @@
 pkt_last_seg:
 	call	setjmp;
 	test	SEQINTSRC, SAVEPTRS jnz pkt_saveptrs;
-	test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz last_pkt_xfer_done;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_last_seg_done;
 	test	SCSIPHASE, ~DATA_PHASE_MASK jz . + 2;
 	test	SCSISIGO, ATNO jnz . + 2;
 	test	SSTAT2, NONPACKREQ jz return;
@@ -1760,7 +1778,7 @@
 
 /*
  * Either a SAVEPTRS interrupt condition is pending for this FIFO
- * or we have a pending nonpackreq for this FIFO.  We differentiate
+ * or we have a pending NONPACKREQ for this FIFO.  We differentiate
  * between the two by capturing the state of the SAVEPTRS interrupt
  * prior to clearing this status and executing the common code for
  * these two cases.
@@ -1789,118 +1807,134 @@
 pkt_saveptrs_check_status:
 	or	LONGJMP_ADDR[1], INVALID_ADDR;
 	test	REG0, SAVEPTRS jz unexpected_nonpkt_phase;
-	test	SCB_CONTROL, STATUS_RCVD jz pkt_saveptrs_clrchn;
-	jmp	last_pkt_complete;
-pkt_saveptrs_clrchn:
+	dec	SCB_FIFO_USE_COUNT;
+	test	SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
 	mvi	DFFSXFRCTL, CLRCHN ret;
 END_CRITICAL;
 
-last_pkt_xfer_done:
+/*
+ * LAST_SEG_DONE status has been seen in the current FIFO.
+ * This indicates that all of the allowed data for this
+ * command has transferred across the SCSI and host buses.
+ * Check for overrun and see if we can complete this command.
+ */
+pkt_last_seg_done:
 BEGIN_CRITICAL;
-	if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
-		or	DFCNTRL, FIFOFLUSH;
-	}
-	test	SCB_CONTROL, STATUS_RCVD jz wait_pkt_end;
-	check_overrun;
-	or	SCB_SGPTR, SG_LIST_NULL;
 	/*
-	 * It is safe to skip the other FIFO check since
-	 * we defer CLRCHN on SAVEPTRS until all data in
-	 * the FIFO are seen by the host and a CFG4DATA
-	 * in this FIFO for the same context is held off
-	 * by hardware.
+	 * Mark transfer as completed.
 	 */
-last_pkt_queue_scb:
-	or	LONGJMP_ADDR[1], INVALID_ADDR;
-	bmov	ARG_1, SCBPTR, 2;
-	mvi	DFFSXFRCTL, CLRCHN;
-	jmp	queue_arg1_scb_completion;
-
-last_pkt_complete:
-	bmov	ARG_1, SCBPTR, 2;
-	mvi	DFFSXFRCTL, CLRCHN;
-check_other_fifo:
-	clc;
-	TOGGLE_DFF_MODE
-	call	check_fifo;
-	jnc	queue_arg1_scb_completion;
-return:
-	ret;
+	or	SCB_SGPTR, SG_LIST_NULL;
 
-wait_pkt_end:
+	/*
+	 * Wait for the current context to finish to verify that
+	 * no overrun condition has occurred.
+	 */
+	test	SEQINTSRC, CTXTDONE jnz pkt_ctxt_done;
 	call	setjmp;
-END_CRITICAL;
-wait_pkt_end_loop:
-	test	SEQINTSRC, CTXTDONE jnz pkt_end;
+pkt_wait_ctxt_done_loop:
+	test	SEQINTSRC, CTXTDONE jnz pkt_ctxt_done;
+	/*
+	 * A sufficiently large overrun or a NONPACKREQ may
+	 * prevent CTXTDONE from ever asserting, so we must
+	 * poll for these statuses too.
+	 */
 	check_overrun;
 	test	SSTAT2, NONPACKREQ jz return;
 	test	SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase;
-pkt_end:
-BEGIN_CRITICAL;
+	/* FALLTHROUGH */
+
+pkt_ctxt_done:
 	check_overrun;
 	or	LONGJMP_ADDR[1], INVALID_ADDR;
-	or	SCB_SGPTR, SG_LIST_NULL;
-	test	SCB_CONTROL, STATUS_RCVD jnz last_pkt_complete;
+	/*
+	 * If status has been received, it is safe to skip
+	 * the check to see if another FIFO is active because
+	 * LAST_SEG_DONE has been observed.  However, we check
+	 * the FIFO anyway since it costs us only one extra
+	 * instruction to leverage common code to perform the
+	 * SCB completion.
+	 */
+	dec	SCB_FIFO_USE_COUNT;
+	test	SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
 	mvi	DFFSXFRCTL, CLRCHN ret;
 END_CRITICAL;
 
 /*
+ * Must wait until CDB xfer is over before issuing the
+ * clear channel.
+ */
+pkt_handle_cdb:
+	call	setjmp;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jz return;
+	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	mvi	DFFSXFRCTL, CLRCHN ret;
+
+/*
  * Watch over the status transfer.  Our host sense buffer is
  * large enough to take the maximum allowed status packet.
  * None-the-less, we must still catch and report overruns to
- * the host.
+ * the host.  Additionally, properly catch unexpected non-packet
+ * phases that are typically caused by CRC errors in status packet
+ * transmission.
  */
 pkt_handle_status:
-	call	setjmp_setscb;
-	test	SG_CACHE_SHADOW, LAST_SEG_DONE jz check_status_overrun;
-	test	SEQINTSRC, CTXTDONE jz return;
-status_IU_done:
-BEGIN_CRITICAL;
+	call	setjmp;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun;
+	test	SEQINTSRC, CTXTDONE jz pkt_status_check_nonpackreq;
+	test	SG_CACHE_SHADOW, LAST_SEG_DONE jnz pkt_status_check_overrun;
+pkt_status_IU_done:
 	if ((ahd->bugs & AHD_AUTOFLUSH_BUG) != 0) {
 		or	DFCNTRL, FIFOFLUSH;
 	}
+	test	DFSTATUS, FIFOEMP jz return;
+BEGIN_CRITICAL;
 	or	LONGJMP_ADDR[1], INVALID_ADDR;
 	mvi	SCB_SCSI_STATUS, STATUS_PKT_SENSE;
 	or	SCB_CONTROL, STATUS_RCVD;
-	jmp	last_pkt_complete;
+	jmp	pkt_complete_scb_if_fifos_idle;
 END_CRITICAL;
-check_status_overrun:
+pkt_status_check_overrun:
 	/*
-	 * We've filled the entire sense buffer.
-	 * Wait for either context done or a negative
-	 * shaddow count.  If the context completes without
-	 * causing the shaddow count to go negative, then
-	 * this was a successful transfer up to the status
-	 * limit.  Otherwise we report the error.
-	 */
-	test	SHCNT[2], 0xFF jnz report_status_overrun;
-	test	SEQINTSRC, CTXTDONE jz return;
-	test	SHCNT[2], 0xFF jz status_IU_done;
-report_status_overrun:
+	 * Status PKT overruns are uncerimoniously recovered with a
+	 * bus reset.  If we've overrun, let the host know so that
+	 * recovery can be performed.
+	 *
+	 * LAST_SEG_DONE has been observed.  If either CTXTDONE or
+	 * a NONPACKREQ phase change have occurred and the FIFO is
+	 * empty, there is no overrun.
+	 */
+	test	DFSTATUS, FIFOEMP jz pkt_status_report_overrun;
+	test	SEQINTSRC, CTXTDONE jz . + 2;
+	test	DFSTATUS, FIFOEMP jnz pkt_status_IU_done;
+	test	SCSIPHASE, ~DATA_PHASE_MASK jz return;
+	test	DFSTATUS, FIFOEMP jnz pkt_status_check_nonpackreq;
+pkt_status_report_overrun:
 	SET_SEQINTCODE(STATUS_OVERRUN)
-	jmp	status_IU_done;
-
-SET_SRC_MODE	M_DFF0;
-SET_DST_MODE	M_DFF0;
-BEGIN_CRITICAL;
-check_fifo:
-	test	LONGJMP_ADDR[1], INVALID_ADDR jnz return;
-	mov	A, ARG_2;
-	cmp	LONGJMP_SCB[1], A	jne return;
-	mov	A, ARG_1;
-	cmp	LONGJMP_SCB[0], A	jne return;
-	stc	ret;
-END_CRITICAL;
-
-/*
- * Must wait until CDB xfer is over before issuing the
- * clear channel.
- */
-pkt_handle_cdb:
-	call	setjmp_setscb;
-	test	SG_CACHE_SHADOW, LAST_SEG_DONE jz return;
-	or	LONGJMP_ADDR[1], INVALID_ADDR;
-	mvi	DFFSXFRCTL, CLRCHN ret;
+	/* SEQUENCER RESTARTED */
+pkt_status_check_nonpackreq:
+	/*
+	 * CTXTDONE may be held off if a NONPACKREQ is associated with
+	 * the current context.  If a NONPACKREQ is observed, decide
+	 * if it is for the current context.  If it is for the current
+	 * context, we must defer NONPACKREQ processing until all data
+	 * has transferred to the host.
+	 */
+	test	SCSIPHASE, ~DATA_PHASE_MASK jz return;
+	test	SCSISIGO, ATNO jnz . + 2;
+	test	SSTAT2, NONPACKREQ jz return;
+	test	SEQINTSRC, CTXTDONE jnz pkt_status_IU_done;
+	test	DFSTATUS, FIFOEMP jz return;
+	/*
+	 * The unexpected nonpkt phase handler assumes that any
+	 * data channel use will have a FIFO reference count.  It
+	 * turns out that the status handler doesn't need a refernce
+	 * count since the status received flag, and thus completion
+	 * processing, cannot be set until the handler is finished.
+	 * We increment the count here to make the nonpkt handler
+	 * happy.
+	 */
+	inc	SCB_FIFO_USE_COUNT;
+	/* FALLTHROUGH */
 
 /*
  * Nonpackreq is a polled status.  It can come true in three situations:
@@ -1929,6 +1963,7 @@
 SET_SRC_MODE	M_DFF0;
 SET_DST_MODE	M_DFF0;
 	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	dec	SCB_FIFO_USE_COUNT;
 	mvi	DFFSXFRCTL, CLRCHN;
 	mvi	CLRSINT2, CLRNONPACKREQ;
 	test	SCSIPHASE, ~(MSG_IN_PHASE|MSG_OUT_PHASE) jnz illegal_phase;
@@ -1945,6 +1980,8 @@
  * data.  Otherwise use an overrun buffer in the host to simulate
  * BITBUCKET.
  */
+pkt_handle_overrun_inc_use_count:
+	inc	SCB_FIFO_USE_COUNT;
 pkt_handle_overrun:
 	SET_SEQINTCODE(CFG4OVERRUN)
 	call	freeze_queue;
@@ -1970,8 +2007,9 @@
 pkt_overrun_end:
 	or	SCB_RESIDUAL_SGPTR, SG_OVERRUN_RESID;
 	test	SEQINTSRC, CTXTDONE jz unexpected_nonpkt_phase;
-	test	SCB_CONTROL, STATUS_RCVD jnz last_pkt_queue_scb;
+	dec	SCB_FIFO_USE_COUNT;
 	or	LONGJMP_ADDR[1], INVALID_ADDR;
+	test	SCB_CONTROL, STATUS_RCVD jnz pkt_complete_scb_if_fifos_idle;
 	mvi	DFFSXFRCTL, CLRCHN ret;
 
 if ((ahd->bugs & AHD_PKT_BITBUCKET_BUG) != 0) {
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
--- a/drivers/scsi/aic7xxx/aic79xx_core.c	Tue Mar 25 16:12:22 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c	Thu May  1 10:00:20 2003
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#178 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.c#190 $
  *
  * $FreeBSD$
  */
@@ -556,6 +556,26 @@
 		       ahd_name(ahd), seqintcode);
 #endif
 	switch (seqintcode) {
+	case BAD_SCB_STATUS:
+	{
+		struct	scb *scb;
+		u_int	scbid;
+		int	cmds_pending;
+
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb != NULL) {
+			ahd_complete_scb(ahd, scb);
+		} else {
+			printf("%s: WARNING no command for scb %d "
+			       "(bad status)\n", ahd_name(ahd), scbid);
+			ahd_dump_card_state(ahd);
+		}
+		cmds_pending = ahd_inw(ahd, CMDS_PENDING);
+		if (cmds_pending > 0)
+			ahd_outw(ahd, CMDS_PENDING, cmds_pending - 1);
+		break;
+	}
 	case ENTERING_NONPACK:
 	{
 		struct	scb *scb;
@@ -604,7 +624,16 @@
 		break;
 	case STATUS_OVERRUN:
 	{
-		printf("%s: Status Overrun", ahd_name(ahd));
+		struct	scb *scb;
+		u_int	scbid;
+
+		scbid = ahd_get_scbptr(ahd);
+		scb = ahd_lookup_scb(ahd, scbid);
+		if (scb != NULL)
+			ahd_print_path(ahd, scb);
+		else
+			printf("%s: ", ahd_name(ahd));
+		printf("SCB %d Packetized Status Overrun", scbid);
 		ahd_dump_card_state(ahd);
 		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
 		break;
@@ -1023,7 +1052,7 @@
 
 			switch (scb->hscb->task_management) {
 			case SIU_TASKMGMT_ABORT_TASK:
-				tag = scb->hscb->tag;
+				tag = SCB_GET_TAG(scb);
 			case SIU_TASKMGMT_ABORT_TASK_SET:
 			case SIU_TASKMGMT_CLEAR_TASK_SET:
 				lun = scb->hscb->lun;
@@ -1087,7 +1116,7 @@
 			ahd_outb(ahd, SCB_TASK_MANAGEMENT, 0);
 			ahd_search_qinfifo(ahd, SCB_GET_TARGET(ahd, scb),
 					   SCB_GET_CHANNEL(ahd, scb),  
-					   SCB_GET_LUN(scb), scb->hscb->tag, 
+					   SCB_GET_LUN(scb), SCB_GET_TAG(scb), 
 					   ROLE_INITIATOR, /*status*/0,   
 					   SEARCH_REMOVE);
 		}
@@ -1166,7 +1195,7 @@
 		/*
 		 * A change in I/O mode is equivalent to a bus reset.
 		 */
-		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/FALSE);
+		ahd_reset_channel(ahd, 'A', /*Initiate Reset*/TRUE);
 		ahd_pause(ahd);
 		ahd_setup_iocell_workaround(ahd);
 		ahd_unpause(ahd);
@@ -2183,6 +2212,13 @@
 		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 		ahd_outb(ahd, SEQCTL0, ahd_inb(ahd, SEQCTL0) & ~STEP);
   		ahd_outb(ahd, SIMODE1, simode1);
+		/*
+		 * SCSIINT seems to glitch occassionally when
+		 * the interrupt masks are restored.  Clear SCSIINT
+		 * one more time so that only persistent errors
+		 * are seen as a real interrupt.
+		 */
+		ahd_outb(ahd, CLRINT, CLRSCSIINT);
 	}
 	ahd_restore_modes(ahd, saved_modes);
 }
@@ -4887,7 +4923,6 @@
 {
 	int i;
 
-	ahd_fini_scbdata(ahd);
 	switch (ahd->init_level) {
 	default:
 	case 5:
@@ -4919,6 +4954,7 @@
 	ahd_dma_tag_destroy(ahd, ahd->parent_dmat);
 #endif
 	ahd_platform_free(ahd);
+	ahd_fini_scbdata(ahd);
 	for (i = 0; i < AHD_NUM_TARGETS; i++) {
 		struct ahd_tmode_tstate *tstate;
 
@@ -5481,7 +5517,7 @@
 	/* Clean up for the next user */
 	scb->flags = SCB_FLAG_NONE;
 	scb->hscb->control = 0;
-	ahd->scb_data.scbindex[scb->hscb->tag] = NULL;
+	ahd->scb_data.scbindex[SCB_GET_TAG(scb)] = NULL;
 
 	if (scb->col_scb == NULL) {
 
@@ -5584,8 +5620,8 @@
 	if (scb_data->sgs_left != 0) {
 		int offset;
 
-		offset = ahd_sglist_allocsize(ahd)
-		       - (scb_data->sgs_left * ahd_sglist_size(ahd));
+		offset = ((ahd_sglist_allocsize(ahd) / ahd_sglist_size(ahd))
+		       - scb_data->sgs_left) * ahd_sglist_size(ahd);
 		sg_map = SLIST_FIRST(&scb_data->sg_maps);
 		segs = sg_map->vaddr + offset;
 		sg_busaddr = sg_map->physaddr + offset;
@@ -5894,7 +5930,7 @@
 	 * specially from the DMA safe memory chunk used for the QOUTFIFO.
 	 */
 	ahd->next_queued_hscb = (struct hardware_scb *)next_vaddr;
-	ahd->next_queued_hscb->hscb_busaddr = next_baddr;
+	ahd->next_queued_hscb->hscb_busaddr = ahd_htole32(next_baddr);
 
 	ahd->init_level++;
 
@@ -6056,7 +6092,6 @@
 	for (i = 0; i < 2; i++) {
 		ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i);
 		ahd_outb(ahd, LONGJMP_ADDR + 1, INVALID_ADDR);
-		ahd_outw(ahd, LONGJMP_SCB, SCB_LIST_NULL);
 		ahd_outb(ahd, SG_STATE, 0);
 		ahd_outb(ahd, CLRSEQINTSRC, 0xFF);
 		ahd_outb(ahd, SEQIMODE,
@@ -6605,24 +6640,29 @@
 void
 ahd_pause_and_flushwork(struct ahd_softc *ahd)
 {
-	ahd_mode_state	saved_modes;
-	u_int		intstat;
-	u_int		maxloops;
-	int		paused;
+	u_int intstat;
+	u_int maxloops;
+	u_int qfreeze_cnt;
 
 	maxloops = 1000;
 	ahd->flags |= AHD_ALL_INTERRUPTS;
-	paused = FALSE;
+	ahd_pause(ahd);
+	/*
+	 * Increment the QFreeze Count so that the sequencer
+	 * will not start new selections.  We do this only
+	 * until we are safely paused without further selections
+	 * pending.
+	 */
+	ahd_outw(ahd, QFREEZE_COUNT, ahd_inw(ahd, QFREEZE_COUNT) + 1);
+	ahd_outb(ahd, SEQ_FLAGS2, ahd_inb(ahd, SEQ_FLAGS2) | SELECTOUT_QFROZEN);
 	do {
 		struct scb *waiting_scb;
 
-		if (paused)
-			ahd_unpause(ahd);
+		ahd_unpause(ahd);
 		ahd_intr(ahd);
 		ahd_pause(ahd);
-		paused = TRUE;
 		ahd_clear_critical_section(ahd);
-		saved_modes = ahd_save_modes(ahd);
+		intstat = ahd_inb(ahd, INTSTAT);
 		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 		if ((ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) == 0)
 			ahd_outb(ahd, SCSISEQ0,
@@ -6639,22 +6679,32 @@
 		 && (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0)
 			ahd_outb(ahd, SCSISEQ0,
 				 ahd_inb(ahd, SCSISEQ0) | ENSELO);
-
-		intstat = ahd_inb(ahd, INTSTAT);
 	} while (--maxloops
 	      && (intstat != 0xFF || (ahd->features & AHD_REMOVABLE) == 0)
 	      && ((intstat & INT_PEND) != 0
-	       || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO))));
+	       || (ahd_inb(ahd, SCSISEQ0) & ENSELO) != 0
+	       || (ahd_inb(ahd, SSTAT0) & (SELDO|SELINGO)) != 0));
+
 	if (maxloops == 0) {
 		printf("Infinite interrupt loop, INTSTAT = %x",
 		      ahd_inb(ahd, INTSTAT));
 	}
+	qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
+	if (qfreeze_cnt == 0) {
+		printf("%s: ahd_pause_and_flushwork with 0 qfreeze count!\n",
+		       ahd_name(ahd));
+	} else {
+		qfreeze_cnt--;
+	}
+	ahd_outw(ahd, QFREEZE_COUNT, qfreeze_cnt);
+	if (qfreeze_cnt == 0)
+		ahd_outb(ahd, SEQ_FLAGS2,
+			 ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
 
 	ahd_flush_qoutfifo(ahd);
 
 	ahd_platform_flushwork(ahd);
 	ahd->flags &= ~AHD_ALL_INTERRUPTS;
-	ahd_restore_modes(ahd, saved_modes);
 }
 
 int
@@ -7514,14 +7564,17 @@
 		ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 		ahd_outb(ahd, DFFSTAT, next_fifo);
 	} while (next_fifo != fifo);
+
 	/*
 	 * Reset the bus if we are initiating this reset
 	 */
 	ahd_clear_msg_state(ahd);
 	ahd_outb(ahd, SIMODE1,
 		 ahd_inb(ahd, SIMODE1) & ~(ENBUSFREE|ENSCSIRST|ENBUSFREE));
+
 	if (initiate_reset)
 		ahd_reset_current_bus(ahd);
+
 	ahd_clear_intstat(ahd);
 
 	/*
@@ -7719,9 +7772,6 @@
 	hscb = scb->hscb; 
 
 	/* Freeze the queue until the client sees the error. */
-	ahd_pause(ahd);
-	ahd_clear_critical_section(ahd);
-	ahd_set_modes(ahd, AHD_MODE_SCSI, AHD_MODE_SCSI);
 	ahd_freeze_devq(ahd, scb);
 	ahd_freeze_scb(scb);
 	qfreeze_cnt = ahd_inw(ahd, QFREEZE_COUNT);
@@ -7734,7 +7784,7 @@
 	if (qfreeze_cnt == 0)
 		ahd_outb(ahd, SEQ_FLAGS2,
 			 ahd_inb(ahd, SEQ_FLAGS2) & ~SELECTOUT_QFROZEN);
-	ahd_unpause(ahd);
+
 	/* Don't want to clobber the original sense code */
 	if ((scb->flags & SCB_SENSE) != 0) {
 		/*
@@ -8592,11 +8642,11 @@
 	LIST_FOREACH(scb, &ahd->pending_scbs, pending_links) {
 		if (i++ > AHD_SCB_MAX)
 			break;
-		cur_col = printf("\n%3d ", SCB_GET_TAG(scb));
+		cur_col = printf("\n%3d FIFO_USE[0x%x] ", SCB_GET_TAG(scb),
+				 ahd_inb(ahd, SCB_FIFO_USE_COUNT));
 		ahd_set_scbptr(ahd, SCB_GET_TAG(scb));
 		ahd_scb_control_print(ahd_inb(ahd, SCB_CONTROL), &cur_col, 60);
 		ahd_scb_scsiid_print(ahd_inb(ahd, SCB_SCSIID), &cur_col, 60);
-		ahd_scb_tag_print(ahd_inb(ahd, SCB_TAG), &cur_col, 60);
 	}
 	printf("\nTotal %d\n", i);
 
@@ -8659,12 +8709,10 @@
 
 		ahd_set_modes(ahd, AHD_MODE_DFF0 + i, AHD_MODE_DFF0 + i);
 		fifo_scbptr = ahd_get_scbptr(ahd);
-		printf("\n%s: FIFO%d %s, LONGJMP == 0x%x, "
-		       "SCB 0x%x, LJSCB 0x%x\n",
+		printf("\n%s: FIFO%d %s, LONGJMP == 0x%x, SCB 0x%x\n",
 		       ahd_name(ahd), i,
 		       (dffstat & (FIFO0FREE << i)) ? "Free" : "Active",
-		       ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr,
-		       ahd_inw(ahd, LONGJMP_SCB));
+		       ahd_inw(ahd, LONGJMP_ADDR), fifo_scbptr);
 		cur_col = 0;
 		ahd_seqimode_print(ahd_inb(ahd, SEQIMODE), &cur_col, 50);
 		ahd_seqintsrc_print(ahd_inb(ahd, SEQINTSRC), &cur_col, 50);
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_inline.h b/drivers/scsi/aic7xxx/aic79xx_inline.h
--- a/drivers/scsi/aic7xxx/aic79xx_inline.h	Mon Mar 10 12:10:41 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_inline.h	Thu May  1 10:00:20 2003
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#44 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_inline.h#48 $
  *
  * $FreeBSD$
  */
@@ -223,7 +223,7 @@
 		ahd_set_modes(ahd, ahd->saved_src_mode, ahd->saved_dst_mode);
 	}
 
-	if ((ahd_inb(ahd, INTSTAT) & ~(SWTMINT | CMDCMPLT)) == 0)
+	if ((ahd_inb(ahd, INTSTAT) & ~CMDCMPLT) == 0)
 		ahd_outb(ahd, HCNTRL, ahd->unpause);
 
 	ahd_known_modes(ahd, AHD_MODE_UNKNOWN, AHD_MODE_UNKNOWN);
@@ -298,9 +298,12 @@
 		scb->hscb->datacnt = sg->len;
 	} else {
 		struct ahd_dma_seg *sg;
+		uint32_t *dataptr_words;
 
 		sg = (struct ahd_dma_seg *)scb->sg_list;
-		scb->hscb->dataptr = sg->addr;
+		dataptr_words = (uint32_t*)&scb->hscb->dataptr;
+		dataptr_words[0] = sg->addr;
+		dataptr_words[1] = 0;
 		if ((ahd->flags & AHD_39BIT_ADDRESSING) != 0) {
 			uint64_t high_addr;
 
@@ -777,12 +780,15 @@
 
 #ifdef AHD_DEBUG
 	if ((ahd_debug & AHD_SHOW_QUEUE) != 0) {
+		uint64_t host_dataptr;
+
+		host_dataptr = ahd_le64toh(scb->hscb->dataptr);
 		printf("%s: Queueing SCB 0x%x bus addr 0x%x - 0x%x%x/0x%x\n",
 		       ahd_name(ahd),
-		       SCB_GET_TAG(scb), scb->hscb->hscb_busaddr,
-		       (u_int)((scb->hscb->dataptr >> 32) & 0xFFFFFFFF),
-		       (u_int)(scb->hscb->dataptr & 0xFFFFFFFF),
-		       scb->hscb->datacnt);
+		       SCB_GET_TAG(scb), ahd_le32toh(scb->hscb->hscb_busaddr),
+		       (u_int)((host_dataptr >> 32) & 0xFFFFFFFF),
+		       (u_int)(host_dataptr & 0xFFFFFFFF),
+		       ahd_le32toh(scb->hscb->datacnt));
 	}
 #endif
 	/* Tell the adapter about the newly queued SCB */
@@ -805,7 +811,7 @@
 static __inline void	ahd_sync_qoutfifo(struct ahd_softc *ahd, int op);
 static __inline void	ahd_sync_tqinfifo(struct ahd_softc *ahd, int op);
 static __inline u_int	ahd_check_cmdcmpltqueues(struct ahd_softc *ahd);
-static __inline void	ahd_intr(struct ahd_softc *ahd);
+static __inline int	ahd_intr(struct ahd_softc *ahd);
 
 static __inline void
 ahd_sync_qoutfifo(struct ahd_softc *ahd, int op)
@@ -864,7 +870,7 @@
 /*
  * Catch an interrupt from the adapter
  */
-static __inline void
+static __inline int
 ahd_intr(struct ahd_softc *ahd)
 {
 	u_int	intstat;
@@ -876,7 +882,7 @@
 		 * so just return.  This is likely just a shared
 		 * interrupt.
 		 */
-		return;
+		return (0);
 	}
 
 	/*
@@ -891,6 +897,9 @@
 	else
 		intstat = ahd_inb(ahd, INTSTAT);
 
+	if ((intstat & INT_PEND) == 0)
+		return (0);
+
 	if (intstat & CMDCMPLT) {
 		ahd_outb(ahd, CLRINT, CLRCMDINT);
 
@@ -924,28 +933,25 @@
 #endif
 	}
 
-	if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0)
-		/* Hot eject */
-		return;
-
-	if ((intstat & INT_PEND) == 0)
-		return;
-
-	if (intstat & HWERRINT) {
+	/*
+	 * Handle statuses that may invalidate our cached
+	 * copy of INTSTAT separately.
+	 */
+	if (intstat == 0xFF && (ahd->features & AHD_REMOVABLE) != 0) {
+		/* Hot eject.  Do nothing */
+	} else if (intstat & HWERRINT) {
 		ahd_handle_hwerrint(ahd);
-		return;
-	}
-
-	if ((intstat & (PCIINT|SPLTINT)) != 0) {
+	} else if ((intstat & (PCIINT|SPLTINT)) != 0) {
 		ahd->bus_intr(ahd);
-		return;
-	}
+	} else {
 
-	if ((intstat & SEQINT) != 0)
-		ahd_handle_seqint(ahd, intstat);
+		if ((intstat & SEQINT) != 0)
+			ahd_handle_seqint(ahd, intstat);
 
-	if ((intstat & SCSIINT) != 0)
-		ahd_handle_scsiint(ahd, intstat);
+		if ((intstat & SCSIINT) != 0)
+			ahd_handle_scsiint(ahd, intstat);
+	}
+	return (1);
 }
 
 #endif  /* _AIC79XX_INLINE_H_ */
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c	Tue Mar 25 16:12:23 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c	Thu May  8 11:24:16 2003
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC79xx device driver for Linux.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#141 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.c#160 $
  *
  * --------------------------------------------------------------------------
  * Copyright (c) 1994-2000 Justin T. Gibbs.
@@ -67,12 +67,10 @@
 #include <linux/unistd.h>
 static int errno;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 /*
  * Lock protecting manipulation of the ahd softc list.
  */
 spinlock_t ahd_list_spinlock;
-#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 struct proc_dir_entry proc_scsi_aic79xx = {
@@ -82,6 +80,11 @@
 };
 #endif
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/* For dynamic sglist size calculation. */
+u_int ahd_linux_nseg;
+#endif
+
 /*
  * Bucket size for counting good commands in between bad ones.
  */
@@ -352,14 +355,14 @@
  * disabled at the very end.  That should fix everyone up unless there are
  * really strange cirumstances.
  */
-static int aic79xx_reverse_scan = 0;
+static uint32_t aic79xx_reverse_scan;
 
 /*
  * 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 aic79xx_extended = 0;
+static uint32_t aic79xx_extended;
 
 /*
  * PCI bus parity checking of the Adaptec controllers.  This is somewhat
@@ -367,16 +370,15 @@
  * 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
+ *   0	   = Shut off PCI parity check
+ *   non-0 = Enable PCI parity check
  *
  * 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 aic79xx_pci_parity = 0;
+static uint32_t aic79xx_pci_parity = ~0;
 
 /*
  * There are lots of broken chipsets in the world.  Some of them will
@@ -384,7 +386,7 @@
  * controller.  I/O mapped register access, if allowed by the given
  * platform, will work in almost all cases.
  */
-int aic79xx_allow_memio = 1;
+uint32_t aic79xx_allow_memio = ~0;
 
 /*
  * aic79xx_detect() has been run, so register all device arrivals
@@ -403,7 +405,7 @@
  * We default to 256ms because some older devices need a longer time
  * to respond to initial selection.
  */
-static int aic79xx_seltime = 0x00;
+static uint32_t aic79xx_seltime;
 
 /*
  * Certain devices do not perform any aging on commands.  Should the
@@ -413,7 +415,7 @@
  * force all outstanding transactions to be serviced prior to a new
  * transaction.
  */
-int aic79xx_periodic_otag;
+uint32_t aic79xx_periodic_otag;
 
 /*
  * Module information and settable options.
@@ -478,6 +480,7 @@
 static void ahd_linux_dev_timed_unfreeze(u_long arg);
 static void ahd_linux_sem_timeout(u_long arg);
 static void ahd_linux_initialize_scsi_bus(struct ahd_softc *ahd);
+static void ahd_linux_size_nseg(void);
 static void ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd);
 static void ahd_linux_start_dv(struct ahd_softc *ahd);
 static void ahd_linux_dv_timeout(struct scsi_cmnd *cmd);
@@ -548,20 +551,17 @@
 static aic_option_callback_t ahd_linux_setup_iocell_info;
 static int ahd_linux_next_unit(void);
 static void ahd_runq_tasklet(unsigned long data);
-static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf);
 static int aic79xx_setup(char *c);
 
 /****************************** Inlines ***************************************/
-static __inline void ahd_schedule_completeq(struct ahd_softc *ahd,
-					    struct ahd_cmd *acmd);
+static __inline void ahd_schedule_completeq(struct ahd_softc *ahd);
 static __inline void ahd_schedule_runq(struct ahd_softc *ahd);
 static __inline void ahd_setup_runq_tasklet(struct ahd_softc *ahd);
 static __inline void ahd_teardown_runq_tasklet(struct ahd_softc *ahd);
 static __inline struct ahd_linux_device*
 		     ahd_linux_get_device(struct ahd_softc *ahd, u_int channel,
 					  u_int target, u_int lun, int alloc);
-static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd,
-						    struct ahd_cmd *acmd);
+static struct ahd_cmd *ahd_linux_run_complete_queue(struct ahd_softc *ahd);
 static __inline void ahd_linux_check_device_queue(struct ahd_softc *ahd,
 						  struct ahd_linux_device *dev);
 static __inline struct ahd_linux_device *
@@ -574,26 +574,8 @@
 				      bus_addr_t addr, bus_size_t len);
 
 static __inline void
-ahd_schedule_completeq(struct ahd_softc *ahd, struct ahd_cmd *acmd)
+ahd_schedule_completeq(struct ahd_softc *ahd)
 {
-	while (acmd != NULL) {
-		struct ahd_completeq *completeq;
-		struct ahd_cmd *list_cmd;
-		struct ahd_cmd *next_cmd;
-
-		next_cmd = TAILQ_NEXT(acmd, acmd_links.tqe);
-		completeq = &ahd->platform_data->completeq;
-		list_cmd = TAILQ_FIRST(completeq);
-		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);
-		acmd = next_cmd;
-	}
 	if ((ahd->platform_data->flags & AHD_RUN_CMPLT_Q_TIMER) == 0) {
 		ahd->platform_data->flags |= AHD_RUN_CMPLT_Q_TIMER;
 		ahd->platform_data->completeq_timer.expires = jiffies;
@@ -662,25 +644,17 @@
 
 #define AHD_LINUX_MAX_RETURNED_ERRORS 4
 static struct ahd_cmd *
-ahd_linux_run_complete_queue(struct ahd_softc *ahd, struct ahd_cmd *acmd)
+ahd_linux_run_complete_queue(struct ahd_softc *ahd)
 {	
+	struct	ahd_cmd *acmd;
 	u_long	done_flags;
 	int	with_errors;
 
 	with_errors = 0;
 	ahd_done_lock(ahd, &done_flags);
-	while (acmd != NULL) {
+	while ((acmd = TAILQ_FIRST(&ahd->platform_data->completeq)) != NULL) {
 		Scsi_Cmnd *cmd;
 
-		cmd = &acmd_scsi_cmd(acmd);
-		acmd = TAILQ_NEXT(acmd, acmd_links.tqe);
-		cmd->host_scribble = NULL;
-		if (ahd_cmd_get_transaction_status(cmd) != DID_OK
-		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)
-			with_errors++;
-
-		cmd->scsi_done(cmd);
-
 		if (with_errors > AHD_LINUX_MAX_RETURNED_ERRORS) {
 			/*
 			 * Linux uses stack recursion to requeue
@@ -690,8 +664,18 @@
 			 * the operating system in case they are going
 			 * to be retried. "ick"
 			 */
+			ahd_schedule_completeq(ahd);
 			break;
 		}
+		TAILQ_REMOVE(&ahd->platform_data->completeq,
+			     acmd, acmd_links.tqe);
+		cmd = &acmd_scsi_cmd(acmd);
+		cmd->host_scribble = NULL;
+		if (ahd_cmd_get_transaction_status(cmd) != DID_OK
+		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)
+			with_errors++;
+
+		cmd->scsi_done(cmd);
 	}
 	ahd_done_unlock(ahd, &done_flags);
 	return (acmd);
@@ -825,6 +809,67 @@
 static int	   ahd_linux_abort(Scsi_Cmnd *);
 
 /*
+ * Calculate a safe value for AHD_NSEG (as expressed through ahd_linux_nseg).
+ *
+ * In pre-2.5.X...
+ * The midlayer allocates an S/G array dynamically when a command is issued
+ * using SCSI malloc.  This array, which is in an OS dependent format that
+ * must later be copied to our private S/G list, is sized to house just the
+ * number of segments needed for the current transfer.  Since the code that
+ * sizes the SCSI malloc pool does not take into consideration fragmentation
+ * of the pool, executing transactions numbering just a fraction of our
+ * concurrent transaction limit with SG list lengths aproaching AHC_NSEG will
+ * quickly depleat the SCSI malloc pool of usable space.  Unfortunately, the
+ * mid-layer does not properly handle this scsi malloc failures for the S/G
+ * array and the result can be a lockup of the I/O subsystem.  We try to size
+ * our S/G list so that it satisfies our drivers allocation requirements in
+ * addition to avoiding fragmentation of the SCSI malloc pool.
+ */
+static void
+ahd_linux_size_nseg(void)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	u_int cur_size;
+	u_int best_size;
+
+	/*
+	 * The SCSI allocator rounds to the nearest 512 bytes
+	 * an cannot allocate across a page boundary.  Our algorithm
+	 * is to start at 1K of scsi malloc space per-command and
+	 * loop through all factors of the PAGE_SIZE and pick the best.
+	 */
+	best_size = 0;
+	for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) {
+		u_int nseg;
+
+		nseg = cur_size / sizeof(struct scatterlist);
+		if (nseg < AHD_LINUX_MIN_NSEG)
+			continue;
+
+		if (best_size == 0) {
+			best_size = cur_size;
+			ahd_linux_nseg = nseg;
+		} else {
+			u_int best_rem;
+			u_int cur_rem;
+
+			/*
+			 * Compare the traits of the current "best_size"
+			 * with the current size to determine if the
+			 * current size is a better size.
+			 */
+			best_rem = best_size % sizeof(struct scatterlist);
+			cur_rem = cur_size % sizeof(struct scatterlist);
+			if (cur_rem < best_rem) {
+				best_size = cur_size;
+				ahd_linux_nseg = nseg;
+			}
+		}
+	}
+#endif
+}
+
+/*
  * Try to detect an Adaptec 79XX controller.
  */
 static int
@@ -852,6 +897,10 @@
 		printf("ahd_linux_detect: Unable to attach\n");
 		return (0);
 	}
+	/*
+	 * Determine an appropriate size for our Scatter Gatther lists.
+	 */
+	ahd_linux_size_nseg();
 #ifdef MODULE
 	/*
 	 * If we've been passed any parameters, process them now.
@@ -991,7 +1040,7 @@
 
 		ahd_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
 		ahd_linux_queue_cmd_complete(ahd, cmd);
-		ahd_schedule_completeq(ahd, NULL);
+		ahd_schedule_completeq(ahd);
 		ahd_midlayer_entrypoint_unlock(ahd, &flags);
 		return (0);
 	}
@@ -1001,7 +1050,7 @@
 	if (dev == NULL) {
 		ahd_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);
 		ahd_linux_queue_cmd_complete(ahd, cmd);
-		ahd_schedule_completeq(ahd, NULL);
+		ahd_schedule_completeq(ahd);
 		ahd_midlayer_entrypoint_unlock(ahd, &flags);
 		printf("%s: aic79xx_linux_queue - Unable to allocate device!\n",
 		       ahd_name(ahd));
@@ -1087,7 +1136,8 @@
 	 && (dev->flags & AHD_DEV_SLAVE_CONFIGURED) != 0) {
 		dev->flags |= AHD_DEV_UNCONFIGURED;
 		if (TAILQ_EMPTY(&dev->busyq)
-		 && dev->active == 0)
+		 && dev->active == 0
+		 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
 			ahd_linux_free_device(ahd, dev);
 	}
 	ahd_midlayer_entrypoint_unlock(ahd, &flags);
@@ -1102,15 +1152,30 @@
 			     Scsi_Device * scsi_devs)
 {
 	Scsi_Device *device;
+	Scsi_Device *ldev;
 	struct	ahd_softc *ahd;
 	u_long	flags;
-	int	scbnum;
 
 	ahd = *((struct ahd_softc **)host->hostdata);
 	ahd_lock(ahd, &flags);
-	scbnum = 0;
 	for (device = scsi_devs; device != NULL; device = device->next) {
 
+		/*
+		 * Watch out for duplicate devices.  This works around
+		 * some quirks in how the SCSI scanning code does its
+		 * device management.
+		 */
+		for (ldev = scsi_devs; ldev != device; ldev = ldev->next) {
+			if (ldev->host == device->host
+			 && ldev->channel == device->channel
+			 && ldev->id == device->id
+			 && ldev->lun == device->lun)
+				break;
+		}
+		/* Skip duplicate. */
+		if (ldev != device)
+			continue;
+
 		if (device->host == host) {
 			struct	 ahd_linux_device *dev;
 
@@ -1226,6 +1291,7 @@
 	u_int  last_phase;
 	u_int  cdb_byte;
 	int    retval;
+	int    was_paused;
 	int    paused;
 	int    wait;
 	int    disconnected;
@@ -1265,7 +1331,7 @@
 	 * 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.
+	 * command, return success.
 	 */
 	dev = ahd_linux_get_device(ahd, cmd->device->channel,
 				   cmd->device->id, cmd->device->lun,
@@ -1328,6 +1394,7 @@
 	 * didn't "just" miss an interrupt that would
 	 * affect this cmd.
 	 */
+	was_paused = ahd_is_paused(ahd);
 	ahd_pause_and_flushwork(ahd);
 	paused = TRUE;
 
@@ -1338,11 +1405,13 @@
 		goto no_cmd;
 	}
 
+	printf("%s: At time of recovery, card was %spaused\n",
+	       ahd_name(ahd), was_paused ? "" : "not ");
 	ahd_dump_card_state(ahd);
 
 	disconnected = TRUE;
 	if (ahd_search_qinfifo(ahd, cmd->device->id, cmd->device->channel + 'A',
-			       cmd->device->lun, pending_scb->hscb->tag,
+			       cmd->device->lun, SCB_GET_TAG(pending_scb),
 			       ROLE_INITIATOR, CAM_REQ_ABORTED,
 			       SEARCH_COMPLETE) > 0) {
 		printf("%s:%d:%d:%d: Cmd aborted from QINFIFO\n",
@@ -1371,7 +1440,7 @@
 	 * bus or is in the disconnected state.
 	 */
 	if (last_phase != P_BUSFREE
-	 && pending_scb->hscb->tag == active_scbptr) {
+	 && SCB_GET_TAG(pending_scb) == active_scbptr) {
 
 		/*
 		 * We're active on the bus, so assert ATN
@@ -1392,7 +1461,7 @@
 		 * to select the device before it reconnects.
 		 */
 		pending_scb->flags |= SCB_RECOVERY_SCB|SCB_ABORT;
-		ahd_set_scbptr(ahd, pending_scb->hscb->tag);
+		ahd_set_scbptr(ahd, SCB_GET_TAG(pending_scb));
 		pending_scb->hscb->cdb_len = 0;
 		pending_scb->hscb->task_attribute = 0;
 		pending_scb->hscb->task_management = SIU_TASKMGMT_ABORT_TASK;
@@ -1476,21 +1545,15 @@
 		printf("Recovery code sleeping\n");
 		down(&ahd->platform_data->eh_sem);
 		printf("Recovery code awake\n");
-        	ret = del_timer(&timer);
+        	ret = del_timer_sync(&timer);
 		if (ret == 0) {
 			printf("Timer Expired\n");
 			retval = FAILED;
 		}
 		spin_lock_irq(&ahd->platform_data->spin_lock);
 	}
-	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
-	TAILQ_INIT(&ahd->platform_data->completeq);
 	ahd_schedule_runq(ahd);
-	if (acmd != NULL) {
-		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL)
-			ahd_schedule_completeq(ahd, acmd);
-	}
+	ahd_linux_run_complete_queue(ahd);
 	ahd_midlayer_entrypoint_unlock(ahd, &s);
 	return (retval);
 }
@@ -1515,7 +1578,6 @@
 	struct	ahd_tmode_tstate *tstate;
 	struct	scb *scb;
 	struct	hardware_scb *hscb;
-	struct	ahd_cmd *acmd;
 	u_long	s;
 	struct	timer_list timer;
 	int	retval;
@@ -1581,19 +1643,13 @@
 	down(&ahd->platform_data->eh_sem);
 	printf("Recovery code awake\n");
 	retval = SUCCESS;
-	if (del_timer(&timer) == 0) {
+	if (del_timer_sync(&timer) == 0) {
 		printf("Timer Expired\n");
 		retval = FAILED;
 	}
 	spin_lock_irq(&ahd->platform_data->spin_lock);
-	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
-	TAILQ_INIT(&ahd->platform_data->completeq);
 	ahd_schedule_runq(ahd);
-	if (acmd != NULL) {
-		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL)
-			ahd_schedule_completeq(ahd, acmd);
-	}
+	ahd_linux_run_complete_queue(ahd);
 	ahd_midlayer_entrypoint_unlock(ahd, &s);
 	printf("%s: Device reset returning 0x%x\n", ahd_name(ahd), retval);
 	return (retval);
@@ -1606,7 +1662,6 @@
 ahd_linux_bus_reset(Scsi_Cmnd *cmd)
 {
 	struct ahd_softc *ahd;
-	struct ahd_cmd *acmd;
 	u_long s;
 	int    found;
 
@@ -1619,14 +1674,7 @@
 	ahd_midlayer_entrypoint_lock(ahd, &s);
 	found = ahd_reset_channel(ahd, cmd->device->channel + 'A',
 				  /*initiate reset*/TRUE);
-	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
-	TAILQ_INIT(&ahd->platform_data->completeq);
-
-	if (acmd != NULL) {
-		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL)
-			ahd_schedule_completeq(ahd, acmd);
-	}
+	ahd_linux_run_complete_queue(ahd);
 	ahd_midlayer_entrypoint_unlock(ahd, &s);
 
 	if (bootverbose)
@@ -1650,7 +1698,6 @@
 #endif
 	.can_queue		= AHD_MAX_QUEUE,
 	.this_id		= -1,
-	.sg_tablesize		= AHD_NSEG,
 	.cmd_per_lun		= 2,
 	.use_clustering		= ENABLE_CLUSTERING,
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
@@ -1708,44 +1755,17 @@
 		TAILQ_REMOVE(&ahd->platform_data->device_runq, dev, links);
 		dev->flags &= ~AHD_DEV_ON_RUN_LIST;
 		ahd_linux_check_device_queue(ahd, dev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 		/* Yeild to our interrupt handler */
 		ahd_unlock(ahd, &flags);
 		ahd_lock(ahd, &flags);
+#endif
 	}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	ahd_unlock(ahd, &flags);
 #endif
 }
 
-/************************ Shutdown/halt/reboot hook ***************************/
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-
-static struct notifier_block ahd_linux_notifier = {
-	ahd_linux_halt, NULL, 0
-};
-
-static int ahd_linux_halt(struct notifier_block *nb, u_long event, void *buf)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	struct ahd_softc *ahd;
-
-	/*
-	 * In 2.5.X, this is called prior to the filesystems
-	 * being synced and the SCSI layer being properly
-	 * shutdown.  A different API is required there,
-	 * but the device hooks for this don't quite look
-	 * right.
-	 */
-	if (event == SYS_DOWN || event == SYS_HALT) {
-		TAILQ_FOREACH(ahd, &ahd_tailq, links) {
-			ahd_shutdown(ahd);
-		}
-	}
-#endif
-	return (NOTIFY_OK);
-}
-
 /******************************** Bus DMA *************************************/
 int
 ahd_dma_tag_create(struct ahd_softc *ahd, bus_dma_tag_t parent,
@@ -1927,7 +1947,7 @@
 }
 
 static void
-ahd_linux_setup_tag_info(void *arg, int instance, int targ, int32_t value)
+ahd_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
 {
 
 	if ((instance >= 0) && (targ >= 0)
@@ -1940,18 +1960,18 @@
 }
 
 static void
-ahd_linux_setup_rd_strm_info(void *arg, int instance, int targ, int32_t value)
+ahd_linux_setup_rd_strm_info(u_long arg, int instance, int targ, int32_t value)
 {
 	if ((instance >= 0)
 	 && (instance < NUM_ELEMENTS(aic79xx_rd_strm_info))) {
-		aic79xx_rd_strm_info[instance] = value * 0xFFFF;
+		aic79xx_rd_strm_info[instance] = value & 0xFFFF;
 		if (bootverbose)
 			printf("rd_strm[%d] = 0x%x\n", instance, value);
 	}
 }
 
 static void
-ahd_linux_setup_dv(void *arg, int instance, int targ, int32_t value)
+ahd_linux_setup_dv(u_long arg, int instance, int targ, int32_t value)
 {
 	if ((instance >= 0)
 	 && (instance < NUM_ELEMENTS(aic79xx_dv_settings))) {
@@ -1962,11 +1982,9 @@
 }
 
 static void
-ahd_linux_setup_iocell_info(void *arg, int instance, int targ, int32_t value)
+ahd_linux_setup_iocell_info(u_long index, int instance, int targ, int32_t value)
 {
-	u_int index;
 
-	index = (u_int)arg;
 	if ((instance >= 0)
 	 && (instance < NUM_ELEMENTS(aic79xx_iocell_info))) {
 		uint8_t *iocell_info;
@@ -1974,7 +1992,7 @@
 		iocell_info = (uint8_t*)&aic79xx_iocell_info[instance];
 		iocell_info[index] = value & 0xFFFF;
 		if (bootverbose)
-			printf("iocell[%d:%d] = %d\n", instance, index, value);
+			printf("iocell[%d:%ld] = %d\n", instance, index, value);
 	}
 }
 
@@ -2053,32 +2071,31 @@
 			ahd_linux_setup_tag_info_global(p + n);
 		} else if (strncmp(p, "tag_info", n) == 0) {
 			s = aic_parse_brace_option("tag_info", p + n, end,
-			    2, ahd_linux_setup_tag_info, NULL);
+			    2, ahd_linux_setup_tag_info, 0);
 		} else if (strncmp(p, "rd_strm", n) == 0) {
-			printf("Calling brace parse for %s\n", p);
 			s = aic_parse_brace_option("rd_strm", p + n, end,
-			    1, ahd_linux_setup_rd_strm_info, NULL);
+			    1, ahd_linux_setup_rd_strm_info, 0);
 		} else if (strncmp(p, "dv", n) == 0) {
 			s = aic_parse_brace_option("dv", p + n, end, 1,
-			    ahd_linux_setup_dv, NULL);
+			    ahd_linux_setup_dv, 0);
 		} else if (strncmp(p, "slewrate", n) == 0) {
 			s = aic_parse_brace_option("slewrate",
 			    p + n, end, 1, ahd_linux_setup_iocell_info,
-			    (void *)AIC79XX_SLEWRATE_INDEX);
+			    AIC79XX_SLEWRATE_INDEX);
 		} else if (strncmp(p, "precomp", n) == 0) {
 			s = aic_parse_brace_option("precomp",
 			    p + n, end, 1, ahd_linux_setup_iocell_info,
-			    (void *)AIC79XX_PRECOMP_INDEX);
+			    AIC79XX_PRECOMP_INDEX);
 		} else if (strncmp(p, "amplitude", n) == 0) {
 			s = aic_parse_brace_option("amplitude",
 			    p + n, end, 1, ahd_linux_setup_iocell_info,
-			    (void *)AIC79XX_AMPLITUDE_INDEX);
+			    AIC79XX_AMPLITUDE_INDEX);
 		} 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));
+			*(options[i].flag) ^= 0xFFFFFFFF;
 		}
 	}
 	return 1;
@@ -2088,7 +2105,7 @@
 __setup("aic79xx=", aic79xx_setup);
 #endif
 
-int aic79xx_verbose;
+uint32_t aic79xx_verbose;
 
 int
 ahd_linux_register_host(struct ahd_softc *ahd, Scsi_Host_Template *template)
@@ -2120,6 +2137,7 @@
 	host->max_id = (ahd->features & AHD_WIDE) ? 16 : 8;
 	host->max_lun = AHD_NUM_LUNS;
 	host->max_channel = 0;
+	host->sg_tablesize = AHD_NSEG;
 	ahd_set_unit(ahd, ahd_linux_next_unit());
 	sprintf(buf, "scsi%d", host->host_no);
 	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
@@ -2291,8 +2309,6 @@
 #endif
 	ahd_setup_runq_tasklet(ahd);
 	ahd->seltime = (aic79xx_seltime & 0x3) << 4;
-	if (TAILQ_EMPTY(&ahd_tailq))
-		register_reboot_notifier(&ahd_linux_notifier);
 	return (0);
 }
 
@@ -2304,6 +2320,7 @@
 	int i, j;
 
 	if (ahd->platform_data != NULL) {
+		del_timer_sync(&ahd->platform_data->completeq_timer);
 		ahd_linux_kill_dv_thread(ahd);
 		ahd_teardown_runq_tasklet(ahd);
 		if (ahd->platform_data->host != NULL) {
@@ -2317,15 +2334,20 @@
 		for (i = 0; i < AHD_NUM_TARGETS; i++) {
 			targ = ahd->platform_data->targets[i];
 			if (targ != NULL) {
+				/* Keep target around through the loop. */
+				targ->refcount++;
 				for (j = 0; j < AHD_NUM_LUNS; j++) {
-					if (targ->devices[j] != NULL) {
-						dev = targ->devices[j];
-						ahd_linux_free_device(ahd, dev);
-					}
-					if (ahd->platform_data->targets[i] ==
-					    NULL)
-						break;
+
+					if (targ->devices[j] == NULL)
+						continue;
+					dev = targ->devices[j];
+					ahd_linux_free_device(ahd, dev);
 				}
+				/*
+				 * Forcibly free the target now that
+				 * all devices are gone.
+				 */
+				ahd_linux_free_target(ahd, targ);
 			}
 		}
 
@@ -2546,19 +2568,12 @@
 static void
 ahd_linux_thread_run_complete_queue(struct ahd_softc *ahd)
 {
-	struct ahd_cmd *acmd;
 	u_long flags;
 
 	ahd_lock(ahd, &flags);
 	del_timer(&ahd->platform_data->completeq_timer);
 	ahd->platform_data->flags &= ~AHD_RUN_CMPLT_Q_TIMER;
-	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
-	TAILQ_INIT(&ahd->platform_data->completeq);
-	if (acmd != NULL) {
-		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL)
-			ahd_schedule_completeq(ahd, acmd);
-	}
+	ahd_linux_run_complete_queue(ahd);
 	ahd_unlock(ahd, &flags);
 }
 
@@ -2921,10 +2936,14 @@
 	}
 
 	ahd_lock(ahd, &s);
-	if (targ->dv_buffer != NULL)
+	if (targ->dv_buffer != NULL) {
 		free(targ->dv_buffer, M_DEVBUF);
-	if (targ->dv_buffer1 != NULL)
+		targ->dv_buffer = NULL;
+	}
+	if (targ->dv_buffer1 != NULL) {
 		free(targ->dv_buffer1, M_DEVBUF);
+		targ->dv_buffer1 = NULL;
+	}
 	targ->flags &= ~AHD_DV_REQUIRED;
 	if (targ->refcount == 0)
 		ahd_linux_free_target(ahd, targ);
@@ -3760,7 +3779,6 @@
 ahd_linux_dv_timeout(struct scsi_cmnd *cmd)
 {
 	struct	ahd_softc *ahd;
-	struct	ahd_cmd *acmd;
 	struct	scb *scb;
 	u_long	flags;
 
@@ -3807,16 +3825,9 @@
 	ahd->platform_data->reset_timer.function =
 	    (ahd_linux_callback_t *)ahd_release_simq;
 	add_timer(&ahd->platform_data->reset_timer);
-	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
-	TAILQ_INIT(&ahd->platform_data->completeq);
 	if (ahd_linux_next_device_to_run(ahd) != NULL)
 		ahd_schedule_runq(ahd);
-	if (acmd != NULL) {
-		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL) {
-			ahd_schedule_completeq(ahd, acmd);
-		}
-	}
+	ahd_linux_run_complete_queue(ahd);
 	ahd_unlock(ahd, &flags);
 }
 
@@ -4025,9 +4036,8 @@
 	 && dev->scsi_device->tagged_supported != 0) {
 
 		ahd_set_tags(ahd, &devinfo, AHD_QUEUE_TAGGED);
-		printf("scsi%d:%c:%d:%d: Tagged Queuing enabled.  Depth %d\n",
-	       	       ahd->platform_data->host->host_no, devinfo.channel,
-		       devinfo.target, devinfo.lun, tags);
+		ahd_print_devinfo(ahd, &devinfo);
+		printf("Tagged Queuing enabled.  Depth %d\n", tags);
 	} else {
 		ahd_set_tags(ahd, &devinfo, AHD_QUEUE_NONE);
 	}
@@ -4201,38 +4211,29 @@
 /*
  * SCSI controller interrupt handler.
  */
-void
+AIC_LINUX_IRQRETURN_T
 ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct	ahd_softc *ahd;
-	struct	ahd_cmd *acmd;
 	u_long	flags;
+	int	ours;
 
 	ahd = (struct ahd_softc *) dev_id;
 	ahd_lock(ahd, &flags); 
-	ahd_intr(ahd);
-	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
-	TAILQ_INIT(&ahd->platform_data->completeq);
+	ours = ahd_intr(ahd);
 	if (ahd_linux_next_device_to_run(ahd) != NULL)
 		ahd_schedule_runq(ahd);
-	if (acmd != NULL) {
-		acmd = ahd_linux_run_complete_queue(ahd, acmd);
-		if (acmd != NULL) {
-			ahd_schedule_completeq(ahd, acmd);
-		}
-	}
+	ahd_linux_run_complete_queue(ahd);
 	ahd_unlock(ahd, &flags);
+	AIC_LINUX_IRQRETURN(ours);
 }
 
 void
 ahd_platform_flushwork(struct ahd_softc *ahd)
 {
-	struct ahd_cmd *acmd;
 
-	acmd = TAILQ_FIRST(&ahd->platform_data->completeq);
-	TAILQ_INIT(&ahd->platform_data->completeq);
-	while (acmd != NULL)
-		acmd = ahd_linux_run_complete_queue(ahd, acmd);
+	while (ahd_linux_run_complete_queue(ahd) != NULL)
+		;
 }
 
 static struct ahd_linux_target*
@@ -4403,22 +4404,19 @@
 	}
         case AC_SENT_BDR:
 	{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		WARN_ON(lun != CAM_LUN_WILDCARD);
+		scsi_report_device_reset(ahd->platform_data->host,
+					 channel - 'A', target);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
 		Scsi_Device *scsi_dev;
 
 		/*
 		 * Find the SCSI device associated with this
 		 * request and indicate that a UA is expected.
-		 * XXX This should really be handled by the mid-layer.
 		 */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-		list_for_each_entry(scsi_dev,
-				    &ahd->platform_data->host->my_devices,
-				    siblings) {
-#else
 		for (scsi_dev = ahd->platform_data->host->host_queue;
 		     scsi_dev != NULL; scsi_dev = scsi_dev->next) {
-#endif
 			if (channel - 'A' == scsi_dev->channel
 			 && target == scsi_dev->id
 			 && (lun == CAM_LUN_WILDCARD
@@ -4452,13 +4450,12 @@
 	Scsi_Cmnd *cmd;
 	struct	  ahd_linux_device *dev;
 
-	LIST_REMOVE(scb, pending_links);
-
 	if ((scb->flags & SCB_ACTIVE) == 0) {
-		printf("SCB %d done'd twice\n", scb->hscb->tag);
+		printf("SCB %d done'd twice\n", SCB_GET_TAG(scb));
 		ahd_dump_card_state(ahd);
 		panic("Stopping for safety");
 	}
+	LIST_REMOVE(scb, pending_links);
 	cmd = scb->io_ctx;
 	dev = scb->platform_data->dev;
 	dev->active--;
@@ -4542,7 +4539,8 @@
 
 	if (TAILQ_EMPTY(&dev->busyq)) {
 		if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
-		 && dev->active == 0)
+		 && dev->active == 0
+		 && (dev->flags & AHD_DEV_TIMER_ACTIVE) == 0)
 			ahd_linux_free_device(ahd, dev);
 	} else if ((dev->flags & AHD_DEV_ON_RUN_LIST) == 0) {
 		TAILQ_INSERT_TAIL(&ahd->platform_data->device_runq, dev, links);
@@ -5065,6 +5063,9 @@
 	if (dev->qfrozen == 0
 	 && (dev->flags & AHD_DEV_ON_RUN_LIST) == 0)
 		ahd_linux_run_device_queue(ahd, dev);
+	if ((dev->flags & AHD_DEV_UNCONFIGURED) != 0
+	 && dev->active == 0)
+		ahd_linux_free_device(ahd, dev);
 	ahd_unlock(ahd, &s);
 }
 
@@ -5143,8 +5144,6 @@
 	scsi_unregister_module(MODULE_SCSI_HA, &aic79xx_driver_template);
 #endif
 	ahd_linux_pci_exit();
-
-	unregister_reboot_notifier(&ahd_linux_notifier);
 }
 
 module_init(ahd_linux_init);
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_osm.h b/drivers/scsi/aic7xxx/aic79xx_osm.h
--- a/drivers/scsi/aic7xxx/aic79xx_osm.h	Tue Mar 25 16:12:23 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.h	Mon May 12 20:52:59 2003
@@ -36,7 +36,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#121 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_osm.h#130 $
  *
  */
 #ifndef _AIC79XX_LINUX_H_
@@ -139,7 +139,7 @@
 #endif /* BYTE_ORDER */
 
 /************************* Configuration Data *********************************/
-extern int aic79xx_allow_memio;
+extern uint32_t aic79xx_allow_memio;
 extern int aic79xx_detect_complete;
 extern Scsi_Host_Template aic79xx_driver_template;
 
@@ -246,7 +246,7 @@
 typedef struct timer_list ahd_timer_t;
 
 /********************************** Includes **********************************/
-#if CONFIG_AIC79XX_REG_PRETTY_PRINT
+#ifdef CONFIG_AIC79XX_REG_PRETTY_PRINT
 #define AIC_DEBUG_REGISTERS 1
 #else
 #define AIC_DEBUG_REGISTERS 0
@@ -255,7 +255,7 @@
 
 /***************************** Timer Facilities *******************************/
 #define ahd_timer_init init_timer
-#define ahd_timer_stop del_timer
+#define ahd_timer_stop del_timer_sync
 typedef void ahd_linux_callback_t (u_long);  
 static __inline void ahd_timer_reset(ahd_timer_t *timer, u_int usec,
 				     ahd_callback_t *func, void *arg);
@@ -293,7 +293,7 @@
 #define AHD_SCSI_HAS_HOST_LOCK 0
 #endif
 
-#define AIC79XX_DRIVER_VERSION "1.3.5"
+#define AIC79XX_DRIVER_VERSION "1.3.8"
 
 /**************************** Front End Queues ********************************/
 /*
@@ -488,7 +488,18 @@
  * manner and are allocated below 4GB, the number of S/G segments is
  * unrestricted.
  */
-#define        AHD_NSEG 128
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/*
+ * We dynamically adjust the number of segments in pre-2.5 kernels to
+ * avoid fragmentation issues in the SCSI mid-layer's private memory
+ * allocator.  See aic79xx_osm.c ahd_linux_size_nseg() for details.
+ */
+extern u_int ahd_linux_nseg;
+#define	AHD_NSEG ahd_linux_nseg
+#define	AHD_LINUX_MIN_NSEG 64
+#else
+#define	AHD_NSEG 128
+#endif
 
 /*
  * Per-SCB OSM storage.
@@ -532,9 +543,7 @@
 	TAILQ_HEAD(, ahd_linux_device) device_runq;
 	struct ahd_completeq	 completeq;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
 	spinlock_t		 spin_lock;
-#endif
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	struct tasklet_struct	 runq_tasklet;
 #endif
@@ -730,7 +739,6 @@
 static __inline void ahd_list_lock(unsigned long *flags);
 static __inline void ahd_list_unlock(unsigned long *flags);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
 static __inline void
 ahd_lockinit(struct ahd_softc *ahd)
 {
@@ -818,63 +826,6 @@
 	spin_unlock_irqrestore(&ahd_list_spinlock, *flags);
 }
 
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */
-
-ahd_lockinit(struct ahd_softc *ahd)
-{
-}
-
-static __inline void
-ahd_lock(struct ahd_softc *ahd, unsigned long *flags)
-{
-	save_flags(*flags);
-	cli();
-}
-
-static __inline void
-ahd_unlock(struct ahd_softc *ahd, unsigned long *flags)
-{
-	restore_flags(*flags);
-}
-
-ahd_done_lockinit(struct ahd_softc *ahd)
-{
-}
-
-static __inline void
-ahd_done_lock(struct ahd_softc *ahd, unsigned long *flags)
-{
-	/*
-	 * The done lock is always held while
-	 * the ahd lock is held so blocking
-	 * interrupts again would have no effect.
-	 */
-}
-
-static __inline void
-ahd_done_unlock(struct ahd_softc *ahd, unsigned long *flags)
-{
-}
-
-static __inline void
-ahd_list_lockinit()
-{
-}
-
-static __inline void
-ahd_list_lock(unsigned long *flags)
-{
-	save_flags(*flags);
-	cli();
-}
-
-static __inline void
-ahd_list_unlock(unsigned long *flags)
-{
-	restore_flags(*flags);
-}
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */
-
 /******************************* PCI Definitions ******************************/
 /*
  * PCIM_xxx: mask to locate subfield in register
@@ -945,16 +896,6 @@
 			    ahd_power_state new_state);
 
 /******************************* 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 supported under 2.1.92 and above"
-#endif
-#include <linux/bios32.h>
-#endif
-
 int			 ahd_linux_pci_init(void);
 void			 ahd_linux_pci_exit(void);
 int			 ahd_pci_map_registers(struct ahd_softc *ahd);
@@ -1270,7 +1211,8 @@
 int	ahd_platform_abort_scbs(struct ahd_softc *ahd, int target,
 				char channel, int lun, u_int tag,
 				role_t role, uint32_t status);
-void	ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
+AIC_LINUX_IRQRETURN_T
+	ahd_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
 void	ahd_platform_flushwork(struct ahd_softc *ahd);
 int	ahd_softc_comp(struct ahd_softc *, struct ahd_softc *);
 void	ahd_done(struct ahd_softc*, struct scb*);
@@ -1285,5 +1227,5 @@
 #define AHD_PCI_CONFIG 0
 #endif
 #define bootverbose aic79xx_verbose
-extern int aic79xx_verbose;
+extern uint32_t aic79xx_verbose;
 #endif /* _AIC79XX_LINUX_H_ */
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_pci.c b/drivers/scsi/aic7xxx/aic79xx_pci.c
--- a/drivers/scsi/aic7xxx/aic79xx_pci.c	Tue Mar 25 16:12:23 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_pci.c	Thu May  1 10:00:20 2003
@@ -38,7 +38,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#70 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx_pci.c#71 $
  *
  * $FreeBSD$
  */
@@ -565,14 +565,13 @@
 #if AHD_DEBUG
 	if (have_seeprom != 0
 	 && (ahd_debug & AHD_DUMP_SEEPROM) != 0) {
-		uint8_t *sc_data;
-		int	 i;
+		uint16_t *sc_data;
+		int	  i;
 
 		printf("%s: Seeprom Contents:", ahd_name(ahd));
-		sc_data = (uint8_t *)sc;
+		sc_data = (uint16_t *)sc;
 		for (i = 0; i < (sizeof(*sc)); i += 2)
-			printf("\n\t0x%.4x", 
-			       sc_data[i] | (sc_data[i+1] << 8));
+			printf("\n\t0x%.4x", sc_data[i]);
 		printf("\n");
 	}
 #endif
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c	Tue Mar 25 16:12:23 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c	Thu Apr 24 14:10:07 2003
@@ -37,7 +37,7 @@
  * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
  * sym driver.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#14 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic79xx_proc.c#17 $
  */
 #include "aic79xx_osm.h"
 #include "aic79xx_inline.h"
@@ -173,8 +173,7 @@
 
 	tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
 				    target_id, &tstate);
-	copy_info(info, "Channel %c Target %d Negotiation Settings\n",
-		  channel, target_id);
+	copy_info(info, "Target %d Negotiation Settings\n", target_id);
 	copy_info(info, "\tUser: ");
 	ahd_format_transinfo(info, &tinfo->user);
 	targ = ahd->platform_data->targets[target_offset];
@@ -318,7 +317,11 @@
 		  AIC79XX_DRIVER_VERSION);
 	copy_info(&info, "%s\n", ahd->description);
 	ahd_controller_info(ahd, ahd_info);
-	copy_info(&info, "%s\n\n", ahd_info);
+	copy_info(&info, "%s\n", ahd_info);
+	copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n",
+		  ahd->scb_data.numscbs, AHD_NSEG);
+
+	max_targ = 15;
 
 	if (ahd->seep_config == NULL)
 		copy_info(&info, "No Serial EEPROM\n");
@@ -335,7 +338,6 @@
 	}
 	copy_info(&info, "\n");
 
-	max_targ = 15;
 	if ((ahd->features & AHD_WIDE) == 0)
 		max_targ = 7;
 
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped
--- a/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped	Tue Mar 25 16:12:23 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_reg.h_shipped	Thu Apr 24 11:46:35 2003
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
  */
 typedef int (ahd_reg_print_t)(u_int, u_int *, u_int);
 typedef struct ahd_reg_parse_entry {
@@ -1924,17 +1924,10 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_longjmp_scb_print;
-#else
-#define ahd_longjmp_scb_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "LONGJMP_SCB", 0xfa, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
 ahd_reg_print_t ahd_accum_save_print;
 #else
 #define ahd_accum_save_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "ACCUM_SAVE", 0xfc, regvalue, cur_col, wrap)
+    ahd_print_register(NULL, 0, "ACCUM_SAVE", 0xfa, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -2246,59 +2239,45 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_tag_print;
-#else
-#define ahd_scb_tag_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCB_TAG", 0x190, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_cdb_len_print;
-#else
-#define ahd_scb_cdb_len_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCB_CDB_LEN", 0x192, regvalue, cur_col, wrap)
-#endif
-
-#if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_task_management_print;
+ahd_reg_print_t ahd_scb_dataptr_print;
 #else
-#define ahd_scb_task_management_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", 0x193, regvalue, cur_col, wrap)
+#define ahd_scb_dataptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_DATAPTR", 0x190, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_next_print;
+ahd_reg_print_t ahd_scb_datacnt_print;
 #else
-#define ahd_scb_next_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCB_NEXT", 0x194, regvalue, cur_col, wrap)
+#define ahd_scb_datacnt_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_DATACNT", 0x198, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_next2_print;
+ahd_reg_print_t ahd_scb_sgptr_print;
 #else
-#define ahd_scb_next2_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCB_NEXT2", 0x196, regvalue, cur_col, wrap)
+#define ahd_scb_sgptr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_SGPTR", 0x19c, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_dataptr_print;
+ahd_reg_print_t ahd_scb_busaddr_print;
 #else
-#define ahd_scb_dataptr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCB_DATAPTR", 0x198, regvalue, cur_col, wrap)
+#define ahd_scb_busaddr_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_BUSADDR", 0x1a0, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_datacnt_print;
+ahd_reg_print_t ahd_scb_next_print;
 #else
-#define ahd_scb_datacnt_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCB_DATACNT", 0x1a0, regvalue, cur_col, wrap)
+#define ahd_scb_next_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_NEXT", 0x1a4, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_sgptr_print;
+ahd_reg_print_t ahd_scb_next2_print;
 #else
-#define ahd_scb_sgptr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCB_SGPTR", 0x1a4, regvalue, cur_col, wrap)
+#define ahd_scb_next2_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_NEXT2", 0x1a6, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -2330,10 +2309,24 @@
 #endif
 
 #if AIC_DEBUG_REGISTERS
-ahd_reg_print_t ahd_scb_busaddr_print;
+ahd_reg_print_t ahd_scb_cdb_len_print;
 #else
-#define ahd_scb_busaddr_print(regvalue, cur_col, wrap) \
-    ahd_print_register(NULL, 0, "SCB_BUSADDR", 0x1ac, regvalue, cur_col, wrap)
+#define ahd_scb_cdb_len_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_CDB_LEN", 0x1ac, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_task_management_print;
+#else
+#define ahd_scb_task_management_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT", 0x1ad, regvalue, cur_col, wrap)
+#endif
+
+#if AIC_DEBUG_REGISTERS
+ahd_reg_print_t ahd_scb_tag_print;
+#else
+#define ahd_scb_tag_print(regvalue, cur_col, wrap) \
+    ahd_print_register(NULL, 0, "SCB_TAG", 0x1ae, regvalue, cur_col, wrap)
 #endif
 
 #if AIC_DEBUG_REGISTERS
@@ -2367,6 +2360,7 @@
 #define		SPLTINT         	0x01
 
 #define	SEQINTCODE      		0x02
+#define		BAD_SCB_STATUS  	0x1a
 #define		SAW_HWERR       	0x19
 #define		TRACEPOINT3     	0x18
 #define		TRACEPOINT2     	0x17
@@ -3508,9 +3502,7 @@
 
 #define	LONGJMP_ADDR    		0xf8
 
-#define	LONGJMP_SCB     		0xfa
-
-#define	ACCUM_SAVE      		0xfc
+#define	ACCUM_SAVE      		0xfa
 
 #define	WAITING_SCB_TAILS		0x100
 
@@ -3656,29 +3648,24 @@
 #define	SCB_SENSE_BUSADDR		0x18c
 #define	SCB_NEXT_COMPLETE		0x18c
 
-#define	SCB_TAG         		0x190
-
-#define	SCB_CDB_LEN     		0x192
-#define		SCB_CDB_LEN_PTR 	0x80
-
-#define	SCB_TASK_MANAGEMENT		0x193
-
-#define	SCB_NEXT        		0x194
-#define	SCB_NEXT_SCB_BUSADDR		0x194
+#define	SCB_DATAPTR     		0x190
 
-#define	SCB_NEXT2       		0x196
-
-#define	SCB_DATAPTR     		0x198
-
-#define	SCB_DATACNT     		0x1a0
+#define	SCB_DATACNT     		0x198
 #define		SG_LAST_SEG     	0x80
 #define		SG_HIGH_ADDR_BITS	0x7f
 
-#define	SCB_SGPTR       		0x1a4
+#define	SCB_SGPTR       		0x19c
 #define		SG_STATUS_VALID 	0x04
 #define		SG_FULL_RESID   	0x02
 #define		SG_LIST_NULL    	0x01
 
+#define	SCB_BUSADDR     		0x1a0
+
+#define	SCB_NEXT        		0x1a4
+#define	SCB_NEXT_SCB_BUSADDR		0x1a4
+
+#define	SCB_NEXT2       		0x1a6
+
 #define	SCB_CONTROL     		0x1a8
 #define		TARGET_SCB      	0x80
 #define		DISCENB         	0x40
@@ -3697,7 +3684,13 @@
 
 #define	SCB_TASK_ATTRIBUTE		0x1ab
 
-#define	SCB_BUSADDR     		0x1ac
+#define	SCB_CDB_LEN     		0x1ac
+#define		SCB_CDB_LEN_PTR 	0x80
+
+#define	SCB_TASK_MANAGEMENT		0x1ad
+
+#define	SCB_TAG         		0x1ae
+#define	SCB_FIFO_USE_COUNT		0x1ae
 
 #define	SCB_SPARE       		0x1b0
 #define	SCB_PKT_LUN     		0x1b0
@@ -3775,5 +3768,5 @@
 
 
 /* Exported Labels */
-#define	LABEL_seq_isr 	0x26d
-#define	LABEL_timer_isr	0x269
+#define	LABEL_seq_isr 	0x270
+#define	LABEL_timer_isr	0x26c
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped
--- a/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped	Tue Mar 25 16:12:23 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_reg_print.c_shipped	Thu Apr 24 11:46:35 2003
@@ -2,8 +2,8 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
  */
 
 #include "aic79xx_osm.h"
@@ -65,13 +65,14 @@
 	{ "TRACEPOINT1",	0x16, 0xff },
 	{ "TRACEPOINT2",	0x17, 0xff },
 	{ "TRACEPOINT3",	0x18, 0xff },
-	{ "SAW_HWERR",		0x19, 0xff }
+	{ "SAW_HWERR",		0x19, 0xff },
+	{ "BAD_SCB_STATUS",	0x1a, 0xff }
 };
 
 int
 ahd_seqintcode_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(SEQINTCODE_parse_table, 26, "SEQINTCODE",
+	return (ahd_print_register(SEQINTCODE_parse_table, 27, "SEQINTCODE",
 	    0x02, regvalue, cur_col, wrap));
 }
 
@@ -3098,17 +3099,10 @@
 }
 
 int
-ahd_longjmp_scb_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "LONGJMP_SCB",
-	    0xfa, regvalue, cur_col, wrap));
-}
-
-int
 ahd_accum_save_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "ACCUM_SAVE",
-	    0xfc, regvalue, cur_col, wrap));
+	    0xfa, regvalue, cur_col, wrap));
 }
 
 int
@@ -3492,49 +3486,10 @@
 }
 
 int
-ahd_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "SCB_TAG",
-	    0x190, regvalue, cur_col, wrap));
-}
-
-static ahd_reg_parse_entry_t SCB_CDB_LEN_parse_table[] = {
-	{ "SCB_CDB_LEN_PTR",	0x80, 0x80 }
-};
-
-int
-ahd_scb_cdb_len_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(SCB_CDB_LEN_parse_table, 1, "SCB_CDB_LEN",
-	    0x192, regvalue, cur_col, wrap));
-}
-
-int
-ahd_scb_task_management_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT",
-	    0x193, regvalue, cur_col, wrap));
-}
-
-int
-ahd_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "SCB_NEXT",
-	    0x194, regvalue, cur_col, wrap));
-}
-
-int
-ahd_scb_next2_print(u_int regvalue, u_int *cur_col, u_int wrap)
-{
-	return (ahd_print_register(NULL, 0, "SCB_NEXT2",
-	    0x196, regvalue, cur_col, wrap));
-}
-
-int
 ahd_scb_dataptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(NULL, 0, "SCB_DATAPTR",
-	    0x198, regvalue, cur_col, wrap));
+	    0x190, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t SCB_DATACNT_parse_table[] = {
@@ -3546,7 +3501,7 @@
 ahd_scb_datacnt_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(SCB_DATACNT_parse_table, 2, "SCB_DATACNT",
-	    0x1a0, regvalue, cur_col, wrap));
+	    0x198, regvalue, cur_col, wrap));
 }
 
 static ahd_reg_parse_entry_t SCB_SGPTR_parse_table[] = {
@@ -3559,9 +3514,30 @@
 ahd_scb_sgptr_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
 	return (ahd_print_register(SCB_SGPTR_parse_table, 3, "SCB_SGPTR",
+	    0x19c, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_busaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_BUSADDR",
+	    0x1a0, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_next_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_NEXT",
 	    0x1a4, regvalue, cur_col, wrap));
 }
 
+int
+ahd_scb_next2_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_NEXT2",
+	    0x1a6, regvalue, cur_col, wrap));
+}
+
 static ahd_reg_parse_entry_t SCB_CONTROL_parse_table[] = {
 	{ "SCB_TAG_TYPE",	0x03, 0x03 },
 	{ "DISCONNECTED",	0x04, 0x04 },
@@ -3609,11 +3585,29 @@
 	    0x1ab, regvalue, cur_col, wrap));
 }
 
+static ahd_reg_parse_entry_t SCB_CDB_LEN_parse_table[] = {
+	{ "SCB_CDB_LEN_PTR",	0x80, 0x80 }
+};
+
 int
-ahd_scb_busaddr_print(u_int regvalue, u_int *cur_col, u_int wrap)
+ahd_scb_cdb_len_print(u_int regvalue, u_int *cur_col, u_int wrap)
 {
-	return (ahd_print_register(NULL, 0, "SCB_BUSADDR",
+	return (ahd_print_register(SCB_CDB_LEN_parse_table, 1, "SCB_CDB_LEN",
 	    0x1ac, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_task_management_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_TASK_MANAGEMENT",
+	    0x1ad, regvalue, cur_col, wrap));
+}
+
+int
+ahd_scb_tag_print(u_int regvalue, u_int *cur_col, u_int wrap)
+{
+	return (ahd_print_register(NULL, 0, "SCB_TAG",
+	    0x1ae, regvalue, cur_col, wrap));
 }
 
 int
diff -Nru a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped
--- a/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped	Tue Mar 25 16:12:23 2003
+++ b/drivers/scsi/aic7xxx/aic79xx_seq.h_shipped	Thu Apr 24 11:46:35 2003
@@ -2,102 +2,104 @@
  * DO NOT EDIT - This file is automatically generated
  *		 from the following source files:
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#89 $
- * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#65 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.seq#91 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic79xx.reg#67 $
  */
 static uint8_t seqprog[] = {
 	0xff, 0x02, 0x06, 0x78,
-	0x00, 0xea, 0x50, 0x59,
+	0x00, 0xea, 0x4e, 0x59,
 	0x01, 0xea, 0x04, 0x30,
 	0xff, 0x04, 0x0c, 0x78,
-	0x19, 0xea, 0x50, 0x59,
+	0x19, 0xea, 0x4e, 0x59,
 	0x19, 0xea, 0x04, 0x00,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x42, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x60, 0x3a, 0x1a, 0x68,
 	0x04, 0x47, 0x1b, 0x68,
 	0xff, 0x21, 0x1b, 0x70,
-	0x40, 0x4b, 0x92, 0x69,
-	0x00, 0xe2, 0x54, 0x59,
-	0x40, 0x4b, 0x92, 0x69,
-	0x20, 0x4b, 0x82, 0x69,
+	0x40, 0x4b, 0x90, 0x69,
+	0x00, 0xe2, 0x52, 0x59,
+	0x40, 0x4b, 0x90, 0x69,
+	0x20, 0x4b, 0x80, 0x69,
 	0xfc, 0x42, 0x24, 0x78,
 	0x10, 0x40, 0x24, 0x78,
-	0x00, 0xe2, 0xe0, 0x5d,
+	0x00, 0xe2, 0xd2, 0x5d,
 	0x20, 0x4d, 0x28, 0x78,
-	0x00, 0xe2, 0xe0, 0x5d,
+	0x00, 0xe2, 0xd2, 0x5d,
 	0x30, 0x3f, 0xc0, 0x09,
 	0x30, 0xe0, 0x30, 0x60,
 	0x7f, 0x4a, 0x94, 0x08,
 	0x00, 0xe2, 0x32, 0x40,
 	0xc0, 0x4a, 0x94, 0x00,
 	0x00, 0xe2, 0x3e, 0x58,
-	0x00, 0xe2, 0x70, 0x58,
-	0x00, 0xe2, 0x80, 0x58,
+	0x00, 0xe2, 0x56, 0x58,
+	0x00, 0xe2, 0x66, 0x58,
 	0x00, 0xe2, 0x06, 0x40,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x42, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x01, 0x52, 0x96, 0x7d,
+	0x01, 0x52, 0x64, 0x78,
 	0x02, 0x58, 0x50, 0x31,
 	0xff, 0xea, 0x10, 0x0b,
-	0xff, 0x93, 0x4f, 0x78,
+	0xff, 0xad, 0x4f, 0x78,
 	0x50, 0x4b, 0x4a, 0x68,
 	0xbf, 0x3a, 0x74, 0x08,
-	0x14, 0xea, 0x50, 0x59,
+	0x14, 0xea, 0x4e, 0x59,
 	0x14, 0xea, 0x04, 0x00,
 	0x08, 0xa8, 0x51, 0x03,
-	0x01, 0xa4, 0x57, 0x78,
-	0x00, 0xe2, 0x4c, 0x5b,
+	0xff, 0xae, 0x3f, 0x68,
+	0x00, 0xe2, 0x50, 0x5b,
 	0x00, 0xe2, 0x3e, 0x40,
-	0xff, 0xea, 0xd4, 0x19,
-	0x02, 0xa8, 0x84, 0x32,
-	0x00, 0xea, 0x44, 0x59,
+	0x00, 0xea, 0x42, 0x59,
 	0x01, 0xea, 0x00, 0x30,
-	0x00, 0xe2, 0xcc, 0x5d,
-	0x00, 0xe2, 0x96, 0x4d,
-	0x11, 0xea, 0x44, 0x59,
+	0x80, 0xf9, 0x5e, 0x68,
+	0x00, 0xe2, 0x40, 0x59,
+	0x11, 0xea, 0x42, 0x59,
 	0x11, 0xea, 0x00, 0x00,
-	0x00, 0xe2, 0xcc, 0x5d,
-	0x00, 0xe2, 0x96, 0x4d,
-	0x33, 0xea, 0x44, 0x59,
-	0x33, 0xea, 0x00, 0x00,
-	0x00, 0xe2, 0x44, 0x43,
-	0x00, 0xea, 0x44, 0x59,
-	0x01, 0xea, 0x00, 0x30,
-	0x80, 0xf9, 0x78, 0x68,
-	0x00, 0xe2, 0x42, 0x59,
-	0x11, 0xea, 0x44, 0x59,
-	0x11, 0xea, 0x00, 0x00,
-	0x80, 0xf9, 0x42, 0x79,
+	0x80, 0xf9, 0x40, 0x79,
 	0xff, 0xea, 0xd4, 0x0d,
-	0x22, 0xea, 0x44, 0x59,
+	0x22, 0xea, 0x42, 0x59,
 	0x22, 0xea, 0x00, 0x00,
-	0x10, 0x16, 0x8a, 0x78,
+	0x10, 0x16, 0x70, 0x78,
 	0x01, 0x0b, 0xa2, 0x32,
 	0x10, 0x16, 0x2c, 0x00,
-	0x18, 0xad, 0xf8, 0x78,
-	0x04, 0xad, 0xc6, 0x68,
-	0x80, 0xad, 0x96, 0x7d,
-	0x10, 0xad, 0x94, 0x78,
-	0xe7, 0xad, 0x5a, 0x0d,
+	0x18, 0xad, 0xfe, 0x78,
+	0x04, 0xad, 0xca, 0x68,
+	0x80, 0xad, 0x64, 0x78,
+	0x10, 0xad, 0x98, 0x78,
+	0xff, 0x88, 0x83, 0x68,
+	0xe7, 0xad, 0x5a, 0x09,
+	0x02, 0x8c, 0x59, 0x32,
+	0x02, 0x28, 0x19, 0x33,
+	0x02, 0xa8, 0x50, 0x36,
+	0x33, 0xea, 0x42, 0x59,
+	0x33, 0xea, 0x00, 0x00,
+	0x40, 0x3a, 0x64, 0x68,
+	0x50, 0x4b, 0x64, 0x68,
+	0x22, 0xea, 0x42, 0x59,
+	0x22, 0xea, 0x00, 0x00,
 	0xe7, 0xad, 0x5a, 0x09,
-	0x00, 0xe2, 0xa2, 0x58,
+	0x02, 0x8c, 0x59, 0x32,
+	0x1a, 0xea, 0x4e, 0x59,
+	0x1a, 0xea, 0x04, 0x00,
+	0xff, 0xea, 0xd4, 0x0d,
+	0xe7, 0xad, 0x5a, 0x09,
+	0x00, 0xe2, 0xa6, 0x58,
 	0xff, 0xea, 0x56, 0x02,
 	0x04, 0x7c, 0x78, 0x32,
-	0x20, 0x16, 0x96, 0x7d,
+	0x20, 0x16, 0x64, 0x78,
 	0x04, 0x38, 0x79, 0x32,
 	0x80, 0x37, 0x6f, 0x16,
-	0xff, 0x2d, 0xb1, 0x60,
-	0xff, 0x29, 0xb1, 0x60,
-	0x40, 0x51, 0xc1, 0x78,
-	0xff, 0x4f, 0xb1, 0x68,
+	0xff, 0x2d, 0xb5, 0x60,
+	0xff, 0x29, 0xb5, 0x60,
+	0x40, 0x51, 0xc5, 0x78,
+	0xff, 0x4f, 0xb5, 0x68,
 	0xff, 0x4d, 0xc1, 0x19,
 	0x00, 0x4e, 0xd5, 0x19,
-	0x00, 0xe2, 0xc0, 0x50,
+	0x00, 0xe2, 0xc4, 0x50,
 	0x01, 0x4c, 0xc1, 0x31,
 	0x00, 0x50, 0xd5, 0x19,
-	0x00, 0xe2, 0xc0, 0x48,
-	0x80, 0x18, 0x96, 0x7d,
+	0x00, 0xe2, 0xc4, 0x48,
+	0x80, 0x18, 0x64, 0x78,
 	0x02, 0x4a, 0x1d, 0x30,
 	0x10, 0xea, 0x18, 0x00,
 	0x60, 0x18, 0x30, 0x00,
@@ -105,35 +107,36 @@
 	0x02, 0xea, 0x02, 0x00,
 	0xff, 0xea, 0xa0, 0x0a,
 	0x80, 0x18, 0x30, 0x04,
-	0x40, 0xad, 0x96, 0x7d,
+	0x40, 0xad, 0x64, 0x78,
 	0xe7, 0xad, 0x5a, 0x09,
 	0x02, 0xa8, 0x40, 0x31,
 	0xff, 0xea, 0xc0, 0x09,
 	0x01, 0x4e, 0x9d, 0x1a,
 	0x00, 0x4f, 0x9f, 0x22,
-	0x04, 0x94, 0x49, 0x32,
-	0xff, 0xea, 0x2a, 0x03,
-	0xff, 0xea, 0x2e, 0x03,
+	0x01, 0xea, 0x5c, 0x33,
+	0x04, 0xa4, 0x49, 0x32,
+	0xff, 0xea, 0x4a, 0x03,
+	0xff, 0xea, 0x4e, 0x03,
 	0x01, 0x10, 0xd4, 0x31,
-	0x10, 0xa8, 0xed, 0x68,
+	0x10, 0xa8, 0xf3, 0x68,
 	0x3d, 0xa9, 0xc5, 0x29,
 	0xfe, 0xe2, 0xc4, 0x09,
 	0x01, 0xea, 0xc6, 0x01,
 	0x02, 0xe2, 0xc8, 0x31,
 	0x02, 0xec, 0x50, 0x31,
 	0x02, 0xa0, 0xda, 0x31,
-	0xff, 0xa9, 0xec, 0x70,
-	0x02, 0xa0, 0x28, 0x37,
-	0xff, 0x21, 0xf5, 0x70,
+	0xff, 0xa9, 0xf2, 0x70,
+	0x02, 0xa0, 0x48, 0x37,
+	0xff, 0x21, 0xfb, 0x70,
 	0x02, 0x22, 0x51, 0x31,
-	0x02, 0xa0, 0x2c, 0x33,
+	0x02, 0xa0, 0x4c, 0x33,
 	0x02, 0xa0, 0x44, 0x36,
 	0x02, 0xa0, 0x40, 0x32,
 	0x02, 0xa0, 0x44, 0x36,
-	0x04, 0x47, 0xfd, 0x68,
-	0x40, 0x16, 0x28, 0x69,
-	0xff, 0x2d, 0x2d, 0x61,
-	0xff, 0x29, 0x97, 0x75,
+	0x04, 0x47, 0x03, 0x69,
+	0x40, 0x16, 0x2e, 0x69,
+	0xff, 0x2d, 0x33, 0x61,
+	0xff, 0x29, 0x65, 0x70,
 	0x01, 0x37, 0xc1, 0x31,
 	0x02, 0x28, 0x55, 0x32,
 	0x01, 0xea, 0x5a, 0x01,
@@ -145,11 +148,11 @@
 	0x01, 0x50, 0xa1, 0x1a,
 	0xff, 0x4e, 0x9d, 0x1a,
 	0xff, 0x4f, 0x9f, 0x22,
-	0xff, 0x8d, 0x21, 0x71,
-	0x80, 0xac, 0x20, 0x71,
-	0x20, 0x16, 0x20, 0x69,
+	0xff, 0x8d, 0x27, 0x71,
+	0x80, 0xac, 0x26, 0x71,
+	0x20, 0x16, 0x26, 0x69,
 	0x02, 0x8c, 0x51, 0x31,
-	0x00, 0xe2, 0x0a, 0x41,
+	0x00, 0xe2, 0x10, 0x41,
 	0x01, 0xac, 0x08, 0x31,
 	0x09, 0xea, 0x5a, 0x01,
 	0x02, 0x8c, 0x51, 0x32,
@@ -157,14 +160,10 @@
 	0x04, 0x24, 0xf9, 0x30,
 	0x1d, 0xea, 0x38, 0x41,
 	0x02, 0x2c, 0x51, 0x31,
-	0x04, 0xac, 0xf9, 0x30,
-	0x19, 0xea, 0x38, 0x59,
-	0x02, 0x8c, 0x59, 0x32,
-	0x02, 0x28, 0x19, 0x33,
-	0x02, 0xa8, 0x50, 0x36,
+	0x04, 0xa0, 0xf9, 0x30,
+	0x19, 0xea, 0x38, 0x41,
 	0x06, 0xea, 0x08, 0x81,
 	0x01, 0xe2, 0x5a, 0x35,
-	0x02, 0xa8, 0xf4, 0x31,
 	0x02, 0xf2, 0xf0, 0x35,
 	0x02, 0xf2, 0xf0, 0x31,
 	0x02, 0xf8, 0xe4, 0x35,
@@ -180,23 +179,23 @@
 	0x02, 0x20, 0xb9, 0x30,
 	0x02, 0x20, 0x51, 0x31,
 	0x4c, 0xa9, 0xd7, 0x28,
-	0x10, 0xa8, 0x63, 0x79,
+	0x10, 0xa8, 0x61, 0x79,
 	0x01, 0x6b, 0xc0, 0x30,
 	0x02, 0x64, 0xc8, 0x00,
 	0x40, 0x3a, 0x74, 0x04,
-	0x00, 0xe2, 0x70, 0x58,
-	0x33, 0xea, 0x44, 0x59,
+	0x00, 0xe2, 0x56, 0x58,
+	0x33, 0xea, 0x42, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x30, 0x3f, 0xc0, 0x09,
-	0x30, 0xe0, 0x64, 0x61,
-	0x20, 0x3f, 0x7a, 0x69,
-	0x10, 0x3f, 0x64, 0x79,
+	0x30, 0xe0, 0x62, 0x61,
+	0x20, 0x3f, 0x78, 0x69,
+	0x10, 0x3f, 0x62, 0x79,
 	0x02, 0xea, 0x7e, 0x00,
-	0x00, 0xea, 0x44, 0x59,
+	0x00, 0xea, 0x42, 0x59,
 	0x01, 0xea, 0x00, 0x30,
 	0x02, 0x48, 0x51, 0x35,
 	0x01, 0xea, 0x7e, 0x00,
-	0x11, 0xea, 0x44, 0x59,
+	0x11, 0xea, 0x42, 0x59,
 	0x11, 0xea, 0x00, 0x00,
 	0x02, 0x48, 0x51, 0x35,
 	0x08, 0xea, 0x98, 0x00,
@@ -206,11 +205,11 @@
 	0x0f, 0x67, 0xc0, 0x09,
 	0x00, 0x34, 0x69, 0x02,
 	0x20, 0xea, 0x96, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x40, 0x3a, 0xae, 0x69,
+	0x00, 0xe2, 0xf6, 0x41,
+	0x40, 0x3a, 0xac, 0x69,
 	0x02, 0x55, 0x06, 0x68,
-	0x02, 0x56, 0xae, 0x69,
-	0xff, 0x5b, 0xae, 0x61,
+	0x02, 0x56, 0xac, 0x69,
+	0xff, 0x5b, 0xac, 0x61,
 	0x02, 0x20, 0x51, 0x31,
 	0x80, 0xea, 0xb2, 0x01,
 	0x44, 0xea, 0x00, 0x00,
@@ -218,36 +217,36 @@
 	0x33, 0xea, 0x00, 0x00,
 	0xff, 0xea, 0xb2, 0x09,
 	0xff, 0xe0, 0xc0, 0x19,
-	0xff, 0xe0, 0xb0, 0x79,
-	0x02, 0x94, 0x51, 0x31,
-	0x00, 0xe2, 0xa6, 0x41,
+	0xff, 0xe0, 0xae, 0x79,
+	0x02, 0xa4, 0x51, 0x31,
+	0x00, 0xe2, 0xa4, 0x41,
 	0x02, 0x5e, 0x50, 0x31,
 	0x02, 0xa8, 0xb8, 0x30,
 	0x02, 0x5c, 0x50, 0x31,
-	0xff, 0x95, 0xc1, 0x71,
-	0x02, 0x94, 0x41, 0x31,
+	0xff, 0xa5, 0xbf, 0x71,
+	0x02, 0xa4, 0x41, 0x31,
 	0x02, 0x22, 0x51, 0x31,
-	0x02, 0xa0, 0x2c, 0x33,
+	0x02, 0xa0, 0x4c, 0x33,
 	0x02, 0xa0, 0x44, 0x32,
-	0x00, 0xe2, 0xca, 0x41,
-	0x10, 0xa8, 0xcb, 0x69,
+	0x00, 0xe2, 0xc8, 0x41,
+	0x10, 0xa8, 0xc9, 0x69,
 	0x3d, 0xa9, 0xc9, 0x29,
 	0x01, 0xe4, 0xc8, 0x01,
 	0x01, 0xea, 0xca, 0x01,
 	0xff, 0xea, 0xda, 0x01,
 	0x02, 0x20, 0x51, 0x31,
-	0x02, 0x96, 0x41, 0x32,
-	0xff, 0x21, 0xd3, 0x61,
+	0x02, 0xa6, 0x41, 0x32,
+	0xff, 0x21, 0xd1, 0x61,
 	0xff, 0xea, 0x46, 0x02,
 	0x02, 0x5c, 0x50, 0x31,
 	0x40, 0xea, 0x96, 0x00,
-	0x02, 0x56, 0xe8, 0x6d,
-	0x01, 0x55, 0xe8, 0x6d,
-	0x10, 0xa8, 0xdf, 0x79,
-	0x10, 0x40, 0xe8, 0x69,
-	0x01, 0x56, 0xe8, 0x79,
-	0xff, 0x93, 0x07, 0x78,
-	0x13, 0xea, 0x50, 0x59,
+	0x02, 0x56, 0xda, 0x6d,
+	0x01, 0x55, 0xda, 0x6d,
+	0x10, 0xa8, 0xdd, 0x79,
+	0x10, 0x40, 0xe6, 0x69,
+	0x01, 0x56, 0xe6, 0x79,
+	0xff, 0xad, 0x07, 0x78,
+	0x13, 0xea, 0x4e, 0x59,
 	0x13, 0xea, 0x04, 0x00,
 	0x00, 0xe2, 0x06, 0x40,
 	0xbf, 0x3a, 0x74, 0x08,
@@ -258,104 +257,104 @@
 	0x40, 0xea, 0x66, 0x02,
 	0x08, 0x3c, 0x78, 0x00,
 	0x80, 0xea, 0x62, 0x02,
-	0x00, 0xe2, 0xac, 0x5b,
+	0x00, 0xe2, 0xb2, 0x5b,
 	0x01, 0x36, 0xc1, 0x31,
-	0x9f, 0xe0, 0x4e, 0x7c,
-	0x80, 0xe0, 0x0c, 0x72,
-	0xa0, 0xe0, 0x44, 0x72,
-	0xc0, 0xe0, 0x3a, 0x72,
-	0xe0, 0xe0, 0x74, 0x72,
-	0x01, 0xea, 0x50, 0x59,
+	0x9f, 0xe0, 0x54, 0x7c,
+	0x80, 0xe0, 0x0a, 0x72,
+	0xa0, 0xe0, 0x42, 0x72,
+	0xc0, 0xe0, 0x38, 0x72,
+	0xe0, 0xe0, 0x72, 0x72,
+	0x01, 0xea, 0x4e, 0x59,
 	0x01, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x80, 0x33, 0x13, 0x7a,
-	0x03, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0xf6, 0x41,
+	0x80, 0x33, 0x11, 0x7a,
+	0x03, 0xea, 0x4e, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0xee, 0x00, 0x1a, 0x6a,
+	0xee, 0x00, 0x18, 0x6a,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x42, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x02, 0xa8, 0x90, 0x32,
-	0x00, 0xe2, 0x6a, 0x59,
-	0xef, 0x92, 0xd5, 0x19,
-	0x00, 0xe2, 0x2a, 0x52,
+	0x00, 0xe2, 0x68, 0x59,
+	0xef, 0xac, 0xd5, 0x19,
+	0x00, 0xe2, 0x28, 0x52,
 	0x09, 0x80, 0xe1, 0x30,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x30, 0x42,
-	0x01, 0x92, 0xd1, 0x30,
+	0x00, 0xe2, 0x2e, 0x42,
+	0x01, 0xac, 0xd1, 0x30,
 	0x10, 0x80, 0x89, 0x31,
 	0x20, 0xea, 0x32, 0x00,
 	0xbf, 0x33, 0x67, 0x0a,
-	0x20, 0x19, 0x32, 0x6a,
-	0x02, 0x4d, 0xf8, 0x69,
+	0x20, 0x19, 0x30, 0x6a,
+	0x02, 0x4d, 0xf6, 0x69,
 	0x40, 0x33, 0x67, 0x02,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x80, 0x33, 0xb1, 0x6a,
+	0x00, 0xe2, 0xf6, 0x41,
+	0x80, 0x33, 0xaf, 0x6a,
 	0x01, 0x44, 0x10, 0x33,
 	0x08, 0xa8, 0x51, 0x03,
-	0x00, 0xe2, 0xf8, 0x41,
+	0x00, 0xe2, 0xf6, 0x41,
 	0x10, 0xea, 0x80, 0x00,
 	0x01, 0x31, 0xc5, 0x31,
-	0x80, 0xe2, 0x60, 0x62,
-	0x10, 0xa8, 0x85, 0x6a,
+	0x80, 0xe2, 0x5e, 0x62,
+	0x10, 0xa8, 0x83, 0x6a,
 	0xc0, 0xaa, 0xc5, 0x01,
-	0x40, 0xa8, 0x51, 0x6a,
+	0x40, 0xa8, 0x4f, 0x6a,
 	0xbf, 0xe2, 0xc4, 0x09,
-	0x20, 0xa8, 0x65, 0x7a,
+	0x20, 0xa8, 0x63, 0x7a,
 	0x01, 0xe2, 0x88, 0x30,
-	0x00, 0xe2, 0xac, 0x5b,
-	0xa0, 0x36, 0x6d, 0x62,
+	0x00, 0xe2, 0xb2, 0x5b,
+	0xa0, 0x36, 0x6b, 0x62,
 	0x23, 0xa8, 0x89, 0x08,
-	0x00, 0xe2, 0xac, 0x5b,
-	0xa0, 0x36, 0x6d, 0x62,
-	0x00, 0xa8, 0x64, 0x42,
-	0xff, 0xe2, 0x64, 0x62,
-	0x00, 0xe2, 0x84, 0x42,
+	0x00, 0xe2, 0xb2, 0x5b,
+	0xa0, 0x36, 0x6b, 0x62,
+	0x00, 0xa8, 0x62, 0x42,
+	0xff, 0xe2, 0x62, 0x62,
+	0x00, 0xe2, 0x82, 0x42,
 	0x40, 0xea, 0x98, 0x00,
 	0x01, 0xe2, 0x88, 0x30,
-	0x00, 0xe2, 0xac, 0x5b,
-	0xa0, 0x36, 0x43, 0x72,
+	0x00, 0xe2, 0xb2, 0x5b,
+	0xa0, 0x36, 0x41, 0x72,
 	0x40, 0xea, 0x98, 0x00,
 	0x01, 0x31, 0x89, 0x32,
 	0x08, 0xea, 0x62, 0x02,
-	0x00, 0xe2, 0xf8, 0x41,
-	0xe0, 0xea, 0xc8, 0x5b,
-	0x80, 0xe0, 0xbc, 0x6a,
-	0x04, 0xe0, 0x5a, 0x73,
-	0x02, 0xe0, 0x8a, 0x73,
-	0x00, 0xea, 0x1a, 0x73,
-	0x03, 0xe0, 0x9a, 0x73,
-	0x23, 0xe0, 0x96, 0x72,
-	0x08, 0xe0, 0xb8, 0x72,
-	0x00, 0xe2, 0xac, 0x5b,
-	0x07, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0xf6, 0x41,
+	0xe0, 0xea, 0xce, 0x5b,
+	0x80, 0xe0, 0xba, 0x6a,
+	0x04, 0xe0, 0x60, 0x73,
+	0x02, 0xe0, 0x90, 0x73,
+	0x00, 0xea, 0x18, 0x73,
+	0x03, 0xe0, 0xa0, 0x73,
+	0x23, 0xe0, 0x94, 0x72,
+	0x08, 0xe0, 0xb6, 0x72,
+	0x00, 0xe2, 0xb2, 0x5b,
+	0x07, 0xea, 0x4e, 0x59,
 	0x07, 0xea, 0x04, 0x00,
-	0x08, 0x42, 0xf9, 0x71,
-	0x04, 0x42, 0x93, 0x62,
+	0x08, 0x42, 0xf7, 0x71,
+	0x04, 0x42, 0x91, 0x62,
 	0x01, 0x43, 0x89, 0x30,
-	0x00, 0xe2, 0x84, 0x42,
+	0x00, 0xe2, 0x82, 0x42,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0x84, 0x42,
+	0x00, 0xe2, 0x82, 0x42,
 	0x01, 0x00, 0x60, 0x32,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x42, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x4c, 0x34, 0xc1, 0x28,
 	0x01, 0x64, 0xc0, 0x31,
-	0x00, 0x30, 0x45, 0x59,
+	0x00, 0x30, 0x43, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x01, 0xe0, 0xb6, 0x7a,
-	0xa0, 0xea, 0xbe, 0x5b,
-	0x01, 0xa0, 0xb6, 0x62,
-	0x01, 0x84, 0xaf, 0x7a,
-	0x01, 0xa7, 0xb8, 0x7a,
-	0x00, 0xe2, 0xb8, 0x42,
-	0x03, 0xea, 0x50, 0x59,
+	0x01, 0xe0, 0xb4, 0x7a,
+	0xa0, 0xea, 0xc4, 0x5b,
+	0x01, 0xa0, 0xb4, 0x62,
+	0x01, 0x84, 0xad, 0x7a,
+	0x01, 0xa7, 0xb6, 0x7a,
+	0x00, 0xe2, 0xb6, 0x42,
+	0x03, 0xea, 0x4e, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xb8, 0x42,
-	0x07, 0xea, 0xd0, 0x5b,
+	0x00, 0xe2, 0xb6, 0x42,
+	0x07, 0xea, 0xd6, 0x5b,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0xf8, 0x41,
+	0x00, 0xe2, 0xf6, 0x41,
 	0x3f, 0xe0, 0x6a, 0x0a,
 	0xc0, 0x34, 0xc1, 0x09,
 	0x00, 0x35, 0x51, 0x01,
@@ -366,78 +365,82 @@
 	0x01, 0xea, 0xc6, 0x01,
 	0x02, 0xe2, 0xc8, 0x31,
 	0x02, 0xec, 0x40, 0x31,
-	0xff, 0xa1, 0xd8, 0x72,
+	0xff, 0xa1, 0xd6, 0x72,
 	0x02, 0xe8, 0xda, 0x31,
 	0x02, 0xa0, 0x50, 0x31,
-	0x00, 0xe2, 0xfa, 0x42,
+	0x00, 0xe2, 0xf8, 0x42,
 	0x80, 0x33, 0x67, 0x02,
 	0x01, 0x44, 0xd4, 0x31,
-	0x00, 0xe2, 0xac, 0x5b,
+	0x00, 0xe2, 0xb2, 0x5b,
 	0x01, 0x33, 0x67, 0x02,
-	0xe0, 0x36, 0x15, 0x63,
+	0xe0, 0x36, 0x13, 0x63,
 	0x02, 0x33, 0x67, 0x02,
-	0x20, 0x46, 0x0e, 0x63,
+	0x20, 0x46, 0x0c, 0x63,
 	0xff, 0xea, 0x52, 0x09,
-	0xa8, 0xea, 0xbe, 0x5b,
-	0x04, 0xa8, 0xf5, 0x7a,
+	0xa8, 0xea, 0xc4, 0x5b,
+	0x04, 0xa8, 0xf3, 0x7a,
 	0x01, 0x34, 0xc1, 0x31,
-	0x00, 0xa9, 0xf5, 0x62,
+	0x00, 0xa9, 0xf3, 0x62,
 	0x01, 0x35, 0xc1, 0x31,
-	0x00, 0xaa, 0xff, 0x72,
+	0x00, 0xaa, 0xfd, 0x72,
 	0x01, 0xa9, 0x52, 0x11,
-	0xff, 0xa9, 0xea, 0x6a,
-	0x00, 0xe2, 0x0e, 0x43,
+	0xff, 0xa9, 0xe8, 0x6a,
+	0x00, 0xe2, 0x0c, 0x43,
 	0x10, 0x33, 0x67, 0x02,
-	0x04, 0xa8, 0x0f, 0x7b,
+	0x04, 0xa8, 0x0d, 0x7b,
 	0xfb, 0xa8, 0x51, 0x0b,
 	0xff, 0xea, 0x66, 0x0a,
-	0x01, 0xa4, 0x09, 0x6b,
+	0x01, 0x9c, 0x07, 0x6b,
 	0x02, 0xa8, 0x90, 0x32,
-	0x00, 0xe2, 0x6a, 0x59,
-	0x10, 0xa8, 0xb9, 0x7a,
-	0xff, 0xea, 0xd0, 0x5b,
-	0x00, 0xe2, 0xb8, 0x42,
-	0x04, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0x68, 0x59,
+	0x10, 0xa8, 0xb7, 0x7a,
+	0xff, 0xea, 0xd6, 0x5b,
+	0x00, 0xe2, 0xb6, 0x42,
+	0x04, 0xea, 0x4e, 0x59,
 	0x04, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xb8, 0x42,
-	0x04, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0xb6, 0x42,
+	0x04, 0xea, 0x4e, 0x59,
 	0x04, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x08, 0xa8, 0xb1, 0x7a,
-	0xc0, 0x33, 0x25, 0x7b,
-	0x80, 0x33, 0xb1, 0x6a,
-	0xff, 0x88, 0x25, 0x6b,
-	0x40, 0x33, 0xb1, 0x6a,
-	0x10, 0xa8, 0x2b, 0x7b,
-	0x0a, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0xf6, 0x41,
+	0x08, 0xa8, 0xaf, 0x7a,
+	0xc0, 0x33, 0x23, 0x7b,
+	0x80, 0x33, 0xaf, 0x6a,
+	0xff, 0x88, 0x23, 0x6b,
+	0x40, 0x33, 0xaf, 0x6a,
+	0x10, 0xa8, 0x29, 0x7b,
+	0x0a, 0xea, 0x4e, 0x59,
 	0x0a, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x44, 0x5b,
-	0x00, 0xe2, 0x76, 0x43,
-	0x50, 0x4b, 0x32, 0x6b,
+	0x00, 0xe2, 0x48, 0x5b,
+	0x00, 0xe2, 0x7c, 0x43,
+	0x50, 0x4b, 0x30, 0x6b,
 	0xbf, 0x3a, 0x74, 0x08,
-	0x01, 0xe0, 0xf8, 0x31,
+	0x01, 0xe0, 0xf4, 0x31,
 	0xff, 0xea, 0xc0, 0x09,
 	0x01, 0x2e, 0x5d, 0x1a,
 	0x00, 0x2f, 0x5f, 0x22,
 	0x04, 0x47, 0x8f, 0x02,
-	0x01, 0xfc, 0xc0, 0x35,
-	0x33, 0xea, 0x44, 0x59,
+	0x01, 0xfa, 0xc0, 0x35,
+	0x02, 0xa8, 0x84, 0x32,
+	0x02, 0xea, 0xb4, 0x00,
+	0x33, 0xea, 0x42, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x02, 0x42, 0x51, 0x31,
-	0xff, 0x88, 0x51, 0x6b,
-	0x01, 0xa4, 0x4d, 0x6b,
-	0x02, 0xa4, 0x55, 0x6b,
-	0x01, 0x84, 0x55, 0x7b,
+	0xff, 0xae, 0x65, 0x68,
+	0xff, 0x88, 0x55, 0x6b,
+	0x01, 0x9c, 0x51, 0x6b,
+	0x02, 0x9c, 0x59, 0x6b,
+	0x01, 0x84, 0x59, 0x7b,
 	0x02, 0x28, 0x19, 0x33,
 	0x02, 0xa8, 0x50, 0x36,
-	0xff, 0x88, 0x55, 0x73,
-	0x00, 0xe2, 0x2e, 0x5b,
+	0xff, 0x88, 0x59, 0x73,
+	0x00, 0xe2, 0x2c, 0x5b,
+	0x02, 0xa8, 0x5c, 0x33,
 	0x02, 0x2c, 0x19, 0x33,
 	0x02, 0xa8, 0x58, 0x32,
-	0x04, 0xa4, 0x49, 0x07,
-	0xc0, 0x33, 0xb1, 0x6a,
+	0x04, 0x9c, 0x39, 0x07,
+	0xc0, 0x33, 0xaf, 0x6a,
 	0x04, 0xa8, 0x51, 0x03,
-	0x20, 0xa8, 0x77, 0x6b,
+	0x20, 0xa8, 0x7d, 0x6b,
 	0x02, 0xa8, 0x40, 0x31,
 	0xc0, 0x34, 0xc1, 0x09,
 	0x00, 0x35, 0x51, 0x01,
@@ -452,73 +455,73 @@
 	0xf7, 0x57, 0xae, 0x08,
 	0x08, 0xea, 0x98, 0x00,
 	0x01, 0x44, 0xd4, 0x31,
-	0xee, 0x00, 0x80, 0x6b,
+	0xee, 0x00, 0x86, 0x6b,
 	0x02, 0xea, 0xb4, 0x00,
-	0x00, 0xe2, 0xa8, 0x5b,
-	0x09, 0x4c, 0x82, 0x7b,
+	0x00, 0xe2, 0xae, 0x5b,
+	0x09, 0x4c, 0x88, 0x7b,
 	0x08, 0x4c, 0x06, 0x68,
-	0x0b, 0xea, 0x50, 0x59,
+	0x0b, 0xea, 0x4e, 0x59,
 	0x0b, 0xea, 0x04, 0x00,
 	0x01, 0x44, 0xd4, 0x31,
-	0x20, 0x33, 0xf9, 0x79,
-	0x00, 0xe2, 0x92, 0x5b,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x01, 0x84, 0x97, 0x7b,
-	0x01, 0xa4, 0x49, 0x07,
-	0x08, 0x60, 0x30, 0x33,
-	0x08, 0x80, 0x41, 0x37,
+	0x20, 0x33, 0xf7, 0x79,
+	0x00, 0xe2, 0x98, 0x5b,
+	0x00, 0xe2, 0xf6, 0x41,
+	0x01, 0x84, 0x9d, 0x7b,
+	0x01, 0x9c, 0x39, 0x07,
+	0x08, 0x60, 0x20, 0x33,
+	0x08, 0x80, 0x31, 0x37,
 	0xdf, 0x33, 0x67, 0x0a,
-	0xee, 0x00, 0xa4, 0x6b,
+	0xee, 0x00, 0xaa, 0x6b,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x42, 0x59,
 	0x33, 0xea, 0x00, 0x00,
-	0x00, 0xe2, 0x6a, 0x59,
-	0x00, 0xe2, 0xb8, 0x42,
+	0x00, 0xe2, 0x68, 0x59,
+	0x00, 0xe2, 0xb6, 0x42,
 	0x01, 0xea, 0x6c, 0x02,
 	0xc0, 0xea, 0x66, 0x06,
-	0xff, 0x42, 0xb8, 0x6b,
-	0x01, 0x41, 0xac, 0x6b,
-	0x02, 0x41, 0xac, 0x7b,
-	0xff, 0x42, 0xb8, 0x6b,
-	0x01, 0x41, 0xac, 0x6b,
-	0x02, 0x41, 0xac, 0x7b,
-	0xff, 0x42, 0xb8, 0x7b,
-	0x04, 0x4c, 0xac, 0x6b,
+	0xff, 0x42, 0xbe, 0x6b,
+	0x01, 0x41, 0xb2, 0x6b,
+	0x02, 0x41, 0xb2, 0x7b,
+	0xff, 0x42, 0xbe, 0x6b,
+	0x01, 0x41, 0xb2, 0x6b,
+	0x02, 0x41, 0xb2, 0x7b,
+	0xff, 0x42, 0xbe, 0x7b,
+	0x04, 0x4c, 0xb2, 0x6b,
 	0xe0, 0x41, 0x6c, 0x0e,
 	0x01, 0x44, 0xd4, 0x31,
-	0xff, 0x42, 0xc0, 0x7b,
-	0x04, 0x4c, 0xc0, 0x6b,
+	0xff, 0x42, 0xc6, 0x7b,
+	0x04, 0x4c, 0xc6, 0x6b,
 	0xe0, 0x41, 0x6c, 0x0a,
-	0xe0, 0x36, 0xf9, 0x61,
+	0xe0, 0x36, 0xf7, 0x61,
 	0xff, 0xea, 0xca, 0x09,
 	0x01, 0xe2, 0xc8, 0x31,
 	0x01, 0x46, 0xda, 0x35,
 	0x01, 0x44, 0xd4, 0x35,
 	0x10, 0xea, 0x80, 0x00,
 	0x01, 0xe2, 0x62, 0x36,
-	0x04, 0xa6, 0xd8, 0x7b,
+	0x04, 0xa6, 0xde, 0x7b,
 	0xff, 0xea, 0x5a, 0x09,
 	0xff, 0xea, 0x4c, 0x0d,
-	0x01, 0xa6, 0xf6, 0x6b,
-	0x10, 0xad, 0x96, 0x7d,
-	0x80, 0xad, 0xee, 0x6b,
-	0x08, 0xad, 0x96, 0x6d,
+	0x01, 0xa6, 0xfc, 0x6b,
+	0x10, 0xad, 0x64, 0x78,
+	0x80, 0xad, 0xf4, 0x6b,
+	0x08, 0xad, 0x64, 0x68,
 	0x04, 0x84, 0xf9, 0x30,
 	0x00, 0xea, 0x08, 0x81,
 	0xff, 0xea, 0xd4, 0x09,
 	0x02, 0x84, 0xf9, 0x88,
 	0x0d, 0xea, 0x5a, 0x01,
 	0x04, 0xa6, 0x4c, 0x05,
-	0x04, 0xa6, 0x96, 0x7d,
+	0x04, 0xa6, 0x64, 0x78,
 	0xff, 0xea, 0x5a, 0x09,
 	0x03, 0x84, 0x59, 0x89,
 	0x03, 0xea, 0x4c, 0x01,
-	0x80, 0x1a, 0x96, 0x7d,
-	0x08, 0x19, 0x96, 0x7d,
+	0x80, 0x1a, 0x64, 0x78,
+	0x08, 0x19, 0x64, 0x78,
 	0x08, 0xb0, 0xe0, 0x30,
 	0x04, 0xb0, 0xe0, 0x30,
 	0x03, 0xb0, 0xf0, 0x30,
-	0x01, 0x78, 0x04, 0x7c,
+	0x01, 0x78, 0x0a, 0x7c,
 	0x01, 0xa7, 0x4e, 0x11,
 	0x01, 0xb0, 0x06, 0x33,
 	0x7f, 0x83, 0xe9, 0x08,
@@ -529,275 +532,268 @@
 	0x00, 0x86, 0x0d, 0x23,
 	0x00, 0x87, 0x0f, 0x23,
 	0x01, 0x84, 0xc5, 0x31,
-	0x01, 0xa7, 0x1a, 0x7c,
+	0x01, 0xa7, 0x20, 0x7c,
 	0x04, 0xe2, 0xc4, 0x01,
-	0x80, 0x83, 0x21, 0x7c,
+	0x80, 0x83, 0x27, 0x7c,
 	0x02, 0xe2, 0xc4, 0x01,
 	0xff, 0xea, 0x4c, 0x09,
 	0x01, 0xe2, 0x36, 0x30,
 	0xc8, 0x19, 0x32, 0x00,
 	0x88, 0x19, 0x32, 0x00,
 	0x01, 0xac, 0xd4, 0x99,
-	0x00, 0xe2, 0x96, 0x55,
+	0x00, 0xe2, 0x64, 0x50,
 	0xfe, 0xa6, 0x4c, 0x0d,
-	0x0b, 0x98, 0xe1, 0x30,
-	0x01, 0xa0, 0x4f, 0x09,
-	0xfd, 0xa4, 0x49, 0x09,
-	0x80, 0xa3, 0x37, 0x7c,
+	0x0b, 0x90, 0xe1, 0x30,
+	0x01, 0x98, 0x4f, 0x09,
+	0xfd, 0x9c, 0x49, 0x09,
+	0x80, 0x9b, 0x3d, 0x7c,
 	0x02, 0xa4, 0x48, 0x01,
-	0x01, 0xa7, 0x3a, 0x7c,
+	0x01, 0xa7, 0x40, 0x7c,
 	0x04, 0xa4, 0x48, 0x01,
 	0x01, 0xa4, 0x36, 0x30,
 	0xa8, 0xea, 0x32, 0x00,
-	0xfd, 0xa4, 0x49, 0x0b,
-	0x05, 0xa3, 0x07, 0x33,
-	0x80, 0x83, 0x47, 0x6c,
+	0xfd, 0x9c, 0x39, 0x0b,
+	0x05, 0x9b, 0x07, 0x33,
+	0x80, 0x83, 0x4d, 0x6c,
 	0x02, 0xea, 0x4c, 0x05,
 	0xff, 0xea, 0x4c, 0x0d,
 	0x00, 0xe2, 0x3c, 0x59,
-	0x02, 0xa6, 0xda, 0x6b,
+	0x02, 0xa6, 0xe0, 0x6b,
 	0x80, 0xf9, 0xf2, 0x05,
-	0xc0, 0x33, 0x55, 0x7c,
-	0x03, 0xea, 0x50, 0x59,
+	0xc0, 0x33, 0x5b, 0x7c,
+	0x03, 0xea, 0x4e, 0x59,
 	0x03, 0xea, 0x04, 0x00,
-	0x20, 0x33, 0x79, 0x7c,
-	0x01, 0x84, 0x5f, 0x6c,
-	0x06, 0xea, 0x50, 0x59,
+	0x20, 0x33, 0x7f, 0x7c,
+	0x01, 0x84, 0x65, 0x6c,
+	0x06, 0xea, 0x4e, 0x59,
 	0x06, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x7c, 0x44,
+	0x00, 0xe2, 0x82, 0x44,
 	0x01, 0x00, 0x60, 0x32,
-	0xee, 0x00, 0x68, 0x6c,
+	0xee, 0x00, 0x6e, 0x6c,
 	0x05, 0xea, 0xb4, 0x00,
-	0x33, 0xea, 0x44, 0x59,
+	0x33, 0xea, 0x42, 0x59,
 	0x33, 0xea, 0x00, 0x00,
 	0x80, 0x3d, 0x7a, 0x00,
-	0xfc, 0x42, 0x6a, 0x7c,
+	0xfc, 0x42, 0x70, 0x7c,
 	0x7f, 0x3d, 0x7a, 0x08,
-	0x00, 0x30, 0x45, 0x59,
+	0x00, 0x30, 0x43, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x09, 0xea, 0x50, 0x59,
+	0x09, 0xea, 0x4e, 0x59,
 	0x09, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x01, 0xa4, 0x5f, 0x6c,
-	0x00, 0xe2, 0x2c, 0x5c,
+	0x00, 0xe2, 0xf6, 0x41,
+	0x01, 0x9c, 0x65, 0x6c,
+	0x00, 0xe2, 0x32, 0x5c,
 	0x20, 0x33, 0x67, 0x02,
 	0x01, 0x00, 0x60, 0x32,
-	0x02, 0xa6, 0x84, 0x7c,
-	0x00, 0xe2, 0x48, 0x5c,
-	0x00, 0xe2, 0x70, 0x58,
-	0x00, 0xe2, 0x80, 0x58,
+	0x02, 0xa6, 0x8a, 0x7c,
+	0x00, 0xe2, 0x4e, 0x5c,
+	0x00, 0xe2, 0x56, 0x58,
+	0x00, 0xe2, 0x66, 0x58,
 	0x00, 0xe2, 0x3a, 0x58,
-	0x00, 0x30, 0x45, 0x59,
+	0x00, 0x30, 0x43, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x20, 0x19, 0x84, 0x6c,
-	0x00, 0xe2, 0xb4, 0x5c,
-	0x04, 0x19, 0x9e, 0x6c,
+	0x20, 0x19, 0x8a, 0x6c,
+	0x00, 0xe2, 0xba, 0x5c,
+	0x04, 0x19, 0xa4, 0x6c,
 	0x02, 0x19, 0x32, 0x00,
-	0x01, 0x84, 0x9f, 0x7c,
-	0x01, 0x1b, 0x98, 0x7c,
-	0x01, 0x1a, 0x9e, 0x6c,
-	0x00, 0xe2, 0x4e, 0x44,
-	0x80, 0x4b, 0xa4, 0x6c,
-	0x01, 0x4c, 0xa0, 0x7c,
-	0x03, 0x42, 0x4e, 0x6c,
-	0x00, 0xe2, 0xd4, 0x5b,
+	0x01, 0x84, 0xa5, 0x7c,
+	0x01, 0x1b, 0x9e, 0x7c,
+	0x01, 0x1a, 0xa4, 0x6c,
+	0x00, 0xe2, 0x54, 0x44,
+	0x80, 0x4b, 0xaa, 0x6c,
+	0x01, 0x4c, 0xa6, 0x7c,
+	0x03, 0x42, 0x54, 0x6c,
+	0x00, 0xe2, 0xda, 0x5b,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x04, 0x33, 0xf9, 0x79,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x08, 0x5d, 0xbc, 0x6c,
-	0x00, 0xe2, 0x70, 0x58,
-	0x00, 0x30, 0x45, 0x59,
+	0x04, 0x33, 0xf7, 0x79,
+	0x00, 0xe2, 0xf6, 0x41,
+	0x08, 0x5d, 0xc2, 0x6c,
+	0x00, 0xe2, 0x56, 0x58,
+	0x00, 0x30, 0x43, 0x59,
 	0x01, 0x30, 0x01, 0x30,
-	0x02, 0x1b, 0xac, 0x7c,
-	0x08, 0x5d, 0xba, 0x7c,
+	0x02, 0x1b, 0xb2, 0x7c,
+	0x08, 0x5d, 0xc0, 0x7c,
 	0x03, 0x68, 0x00, 0x37,
 	0x01, 0x84, 0x09, 0x07,
-	0x80, 0x1b, 0xc6, 0x7c,
-	0x80, 0x84, 0xc7, 0x6c,
+	0x80, 0x1b, 0xcc, 0x7c,
+	0x80, 0x84, 0xcd, 0x6c,
 	0xff, 0x85, 0x0b, 0x1b,
 	0xff, 0x86, 0x0d, 0x23,
 	0xff, 0x87, 0x0f, 0x23,
 	0xf8, 0x1b, 0x08, 0x0b,
 	0xff, 0xea, 0x4e, 0x09,
-	0x04, 0x1b, 0xce, 0x7c,
+	0x04, 0x1b, 0xd4, 0x7c,
 	0x01, 0xa7, 0x4e, 0x01,
 	0xff, 0xea, 0x06, 0x0b,
 	0x03, 0x68, 0x00, 0x37,
-	0x00, 0xe2, 0xc0, 0x58,
+	0x00, 0xe2, 0xc4, 0x58,
 	0x10, 0xea, 0x18, 0x00,
 	0xf9, 0xd9, 0xb2, 0x0d,
 	0x01, 0xd9, 0xb2, 0x05,
 	0x01, 0x52, 0x48, 0x31,
-	0x20, 0xa4, 0xf2, 0x7c,
-	0x20, 0x5b, 0xf2, 0x7c,
-	0x80, 0xf9, 0x00, 0x7d,
+	0x20, 0xa4, 0xfc, 0x7c,
+	0x20, 0x5b, 0xfc, 0x7c,
+	0x80, 0xf9, 0x0a, 0x7d,
+	0x02, 0xea, 0xb4, 0x00,
 	0x11, 0x00, 0x00, 0x10,
-	0x04, 0x19, 0xec, 0x7c,
+	0x04, 0x19, 0x16, 0x7d,
 	0xdf, 0x19, 0x32, 0x08,
-	0x01, 0x4c, 0xe8, 0x7c,
+	0x60, 0x5b, 0xf4, 0x6c,
+	0x01, 0x4c, 0xf0, 0x7c,
 	0x20, 0x19, 0x32, 0x00,
-	0x11, 0x00, 0x00, 0x10,
+	0x01, 0xd9, 0xb2, 0x05,
 	0x02, 0xea, 0xb4, 0x00,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x10, 0x5b, 0x04, 0x6d,
-	0x08, 0x5b, 0x0c, 0x6d,
-	0x20, 0x5b, 0xfe, 0x6c,
-	0x02, 0x5b, 0x2c, 0x6d,
-	0x0e, 0xea, 0x50, 0x59,
+	0x10, 0x5b, 0x0e, 0x6d,
+	0x08, 0x5b, 0x18, 0x6d,
+	0x20, 0x5b, 0x08, 0x6d,
+	0x02, 0x5b, 0x38, 0x6d,
+	0x0e, 0xea, 0x4e, 0x59,
 	0x0e, 0xea, 0x04, 0x00,
-	0x80, 0xf9, 0xee, 0x6c,
+	0x80, 0xf9, 0xf8, 0x6c,
 	0xdf, 0x5c, 0xb8, 0x08,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x01, 0xa4, 0xff, 0x6d,
-	0x00, 0xe2, 0x2c, 0x5c,
-	0x00, 0xe2, 0x36, 0x5d,
+	0x01, 0x9c, 0xf3, 0x6d,
+	0x00, 0xe2, 0x32, 0x5c,
+	0x00, 0xe2, 0x42, 0x5d,
+	0x01, 0xae, 0x5d, 0x1b,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x00, 0xe2, 0x2e, 0x5b,
-	0xf3, 0x92, 0xd5, 0x19,
-	0x00, 0xe2, 0x1a, 0x55,
-	0x80, 0x92, 0x1b, 0x6d,
-	0x0f, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0x2c, 0x5b,
+	0xf3, 0xac, 0xd5, 0x19,
+	0x00, 0xe2, 0x26, 0x55,
+	0x80, 0xac, 0x27, 0x6d,
+	0x0f, 0xea, 0x4e, 0x59,
 	0x0f, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x22, 0x45,
+	0x00, 0xe2, 0x2e, 0x45,
 	0x04, 0x8c, 0xe1, 0x30,
 	0x01, 0xea, 0xf2, 0x00,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0xff, 0x93, 0x29, 0x7d,
-	0x14, 0xea, 0x50, 0x59,
+	0xff, 0xad, 0x35, 0x7d,
+	0x14, 0xea, 0x4e, 0x59,
 	0x14, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xb0, 0x5d,
+	0x00, 0xe2, 0xa4, 0x5d,
 	0x01, 0xd9, 0xb2, 0x05,
 	0x09, 0x80, 0xe1, 0x30,
 	0x02, 0xea, 0x36, 0x00,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0xd8, 0x5d,
+	0x00, 0xe2, 0x9c, 0x5d,
 	0x01, 0xd9, 0xb2, 0x05,
-	0x02, 0xa8, 0xf4, 0x31,
-	0x02, 0xa6, 0x48, 0x7d,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x20, 0x5b, 0x56, 0x6d,
-	0xfc, 0x42, 0x42, 0x7d,
-	0x10, 0x40, 0x44, 0x6d,
-	0x20, 0x4d, 0x46, 0x7d,
-	0x08, 0x5d, 0x56, 0x6d,
-	0x02, 0xa6, 0xda, 0x6b,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x20, 0x5b, 0x56, 0x6d,
-	0x01, 0x1b, 0x76, 0x6d,
-	0xfc, 0x42, 0x52, 0x7d,
-	0x10, 0x40, 0x54, 0x6d,
-	0x20, 0x4d, 0x96, 0x7d,
-	0x08, 0x5d, 0x96, 0x7d,
+	0x02, 0xa6, 0x52, 0x7d,
+	0x00, 0xe2, 0x3c, 0x59,
+	0x20, 0x5b, 0x60, 0x6d,
+	0xfc, 0x42, 0x4c, 0x7d,
+	0x10, 0x40, 0x4e, 0x6d,
+	0x20, 0x4d, 0x50, 0x7d,
+	0x08, 0x5d, 0x60, 0x6d,
+	0x02, 0xa6, 0xe0, 0x6b,
+	0x00, 0xe2, 0x3c, 0x59,
+	0x20, 0x5b, 0x60, 0x6d,
+	0x01, 0x1b, 0x80, 0x6d,
+	0xfc, 0x42, 0x5c, 0x7d,
+	0x10, 0x40, 0x5e, 0x6d,
+	0x20, 0x4d, 0x64, 0x78,
+	0x08, 0x5d, 0x64, 0x78,
 	0x02, 0x19, 0x32, 0x00,
 	0x01, 0x5b, 0x40, 0x31,
-	0x00, 0xe2, 0xb4, 0x5c,
-	0x00, 0xe2, 0x92, 0x5b,
+	0x00, 0xe2, 0xba, 0x5c,
+	0x00, 0xe2, 0x98, 0x5b,
 	0x20, 0xea, 0xb6, 0x00,
-	0x00, 0xe2, 0xd4, 0x5b,
+	0x00, 0xe2, 0xda, 0x5b,
 	0x20, 0x5c, 0xb8, 0x00,
-	0x04, 0x19, 0x6c, 0x6d,
-	0x01, 0x1a, 0x6c, 0x6d,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x01, 0x1a, 0x96, 0x7d,
+	0x04, 0x19, 0x76, 0x6d,
+	0x01, 0x1a, 0x76, 0x6d,
+	0x00, 0xe2, 0x3c, 0x59,
+	0x01, 0x1a, 0x64, 0x78,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x20, 0xa0, 0xe8, 0x7d,
-	0x08, 0xa8, 0x75, 0x7d,
-	0x00, 0xe2, 0x88, 0x45,
+	0x20, 0xa0, 0xda, 0x7d,
+	0xff, 0xae, 0x5d, 0x1b,
+	0x08, 0xa8, 0x3d, 0x6b,
 	0x02, 0xea, 0xb4, 0x04,
-	0x02, 0x19, 0x32, 0x00,
-	0x08, 0xa8, 0x99, 0x7d,
-	0x04, 0x5d, 0xfe, 0x7d,
-	0x01, 0x1a, 0xfe, 0x7d,
-	0x01, 0xa4, 0x49, 0x03,
+	0x01, 0x9c, 0x39, 0x03,
+	0x40, 0x5b, 0x90, 0x6d,
+	0x00, 0xe2, 0x3c, 0x59,
+	0x40, 0x5b, 0x90, 0x6d,
+	0x04, 0x5d, 0xf4, 0x7d,
+	0x01, 0x1a, 0xf4, 0x7d,
+	0x20, 0x4d, 0x64, 0x78,
+	0x40, 0x5b, 0xda, 0x7d,
+	0x04, 0x5d, 0xf4, 0x7d,
+	0x01, 0x1a, 0xf4, 0x7d,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x02, 0xa8, 0x84, 0x32,
-	0x02, 0xea, 0xb4, 0x00,
-	0x00, 0xe2, 0x3e, 0x43,
-	0x02, 0xa8, 0x84, 0x32,
-	0x02, 0xea, 0xb4, 0x00,
-	0xff, 0xea, 0xd4, 0x19,
-	0x00, 0xe2, 0x4a, 0x59,
-	0x11, 0x00, 0x00, 0x10,
-	0x00, 0xe2, 0xcc, 0x5d,
-	0x00, 0xe2, 0x3e, 0x53,
-	0xff, 0xea, 0xd4, 0x0d,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x40, 0x5b, 0xa4, 0x6d,
-	0x04, 0x5d, 0xfe, 0x7d,
-	0x01, 0x1a, 0xfe, 0x7d,
-	0x20, 0x4d, 0x96, 0x7d,
-	0x40, 0x5b, 0xe8, 0x7d,
-	0x04, 0x5d, 0xfe, 0x7d,
-	0x01, 0x1a, 0xfe, 0x7d,
+	0xff, 0xae, 0x5d, 0x1b,
+	0x08, 0xa8, 0x3d, 0x6b,
+	0x02, 0xea, 0xb4, 0x04,
+	0x00, 0xe2, 0x3c, 0x59,
+	0x01, 0x1b, 0x64, 0x78,
 	0x80, 0xf9, 0xf2, 0x01,
-	0x01, 0xa4, 0x49, 0x03,
-	0x08, 0xa8, 0x89, 0x6d,
 	0x02, 0xea, 0xb4, 0x04,
 	0x00, 0xe2, 0x3c, 0x59,
-	0x01, 0x1b, 0xc0, 0x7d,
-	0x40, 0x5b, 0x96, 0x7d,
+	0x01, 0x1b, 0xb8, 0x6d,
+	0x40, 0x5b, 0xc6, 0x7d,
+	0x01, 0x1b, 0xb8, 0x6d,
 	0x02, 0x19, 0x32, 0x00,
+	0x01, 0x1a, 0x64, 0x78,
 	0x80, 0xf9, 0xf2, 0x01,
 	0xff, 0xea, 0x10, 0x03,
 	0x08, 0xa8, 0x51, 0x03,
-	0x00, 0xe2, 0x88, 0x45,
-	0xff, 0x6a, 0xc6, 0x6d,
-	0x40, 0x5b, 0x96, 0x7d,
-	0xff, 0x6a, 0xb6, 0x7d,
-	0x10, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0x3c, 0x43,
+	0x01, 0x1a, 0xc2, 0x7d,
+	0x40, 0x5b, 0xbe, 0x7d,
+	0x01, 0x1a, 0xac, 0x6d,
+	0xfc, 0x42, 0x64, 0x78,
+	0x01, 0x1a, 0xc6, 0x6d,
+	0x10, 0xea, 0x4e, 0x59,
 	0x10, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xb6, 0x45,
-	0x80, 0xf9, 0x96, 0x6d,
-	0x01, 0x43, 0xc1, 0x31,
-	0x00, 0xfb, 0x96, 0x65,
-	0x01, 0x42, 0xc1, 0x31,
-	0x00, 0xfa, 0x96, 0x65,
-	0x01, 0xe8, 0xd4, 0x1d,
-	0x00, 0xe2, 0x3c, 0x59,
-	0x01, 0x1b, 0x96, 0x7d,
-	0x80, 0xf9, 0xf2, 0x01,
-	0x02, 0xea, 0xb4, 0x04,
+	0xfc, 0x42, 0x64, 0x78,
+	0x10, 0x40, 0xcc, 0x6d,
+	0x20, 0x4d, 0x64, 0x78,
+	0x40, 0x5b, 0xac, 0x6d,
+	0x01, 0x1a, 0x64, 0x78,
+	0x01, 0xae, 0x5d, 0x1b,
 	0x30, 0x3f, 0xc0, 0x09,
-	0x30, 0xe0, 0x96, 0x65,
-	0x40, 0x4b, 0x96, 0x6d,
+	0x30, 0xe0, 0x64, 0x60,
+	0x40, 0x4b, 0x64, 0x68,
 	0xff, 0xea, 0x52, 0x01,
-	0xee, 0x00, 0xee, 0x6d,
+	0xee, 0x00, 0xe0, 0x6d,
 	0x80, 0xf9, 0xf2, 0x01,
+	0xff, 0xae, 0x5d, 0x1b,
 	0x02, 0xea, 0xb4, 0x00,
 	0x20, 0xea, 0x9a, 0x00,
-	0xf3, 0x42, 0xf8, 0x6d,
-	0x12, 0xea, 0x50, 0x59,
+	0xf3, 0x42, 0xec, 0x6d,
+	0x12, 0xea, 0x4e, 0x59,
 	0x12, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x0d, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0xf6, 0x41,
+	0x0d, 0xea, 0x4e, 0x59,
 	0x0d, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0xf8, 0x41,
-	0x11, 0xea, 0x50, 0x59,
+	0x00, 0xe2, 0xf6, 0x41,
+	0x01, 0xae, 0x5d, 0x1b,
+	0x11, 0xea, 0x4e, 0x59,
 	0x11, 0xea, 0x04, 0x00,
-	0x00, 0xe2, 0x2e, 0x5b,
+	0x00, 0xe2, 0x2c, 0x5b,
 	0x08, 0x5a, 0xb4, 0x00,
-	0x00, 0xe2, 0x22, 0x5e,
+	0x00, 0xe2, 0x1a, 0x5e,
 	0xa8, 0xea, 0x32, 0x00,
-	0x00, 0xe2, 0x3e, 0x59,
-	0x80, 0x1a, 0x12, 0x7e,
-	0x00, 0xe2, 0x22, 0x5e,
+	0x00, 0xe2, 0x3c, 0x59,
+	0x80, 0x1a, 0x08, 0x7e,
+	0x00, 0xe2, 0x1a, 0x5e,
 	0x80, 0x19, 0x32, 0x00,
-	0x40, 0x5b, 0x18, 0x6e,
-	0x08, 0x5a, 0x18, 0x7e,
-	0x20, 0x4d, 0x96, 0x7d,
+	0x40, 0x5b, 0x0e, 0x6e,
+	0x08, 0x5a, 0x0e, 0x7e,
+	0x20, 0x4d, 0x64, 0x78,
 	0x02, 0x84, 0x09, 0x03,
-	0x40, 0x5b, 0xe8, 0x7d,
-	0x08, 0xa8, 0x81, 0x6d,
+	0x40, 0x5b, 0xda, 0x7d,
+	0xff, 0xae, 0x5d, 0x1b,
 	0x80, 0xf9, 0xf2, 0x01,
+	0x08, 0xa8, 0x3d, 0x6b,
 	0x02, 0xea, 0xb4, 0x04,
 	0x01, 0x38, 0xe1, 0x30,
 	0x05, 0x39, 0xe3, 0x98,
-	0x01, 0xe0, 0xf8, 0x31,
+	0x01, 0xe0, 0xf4, 0x31,
 	0xff, 0xea, 0xc0, 0x09,
 	0x00, 0x3a, 0xe5, 0x20,
 	0x00, 0x3b, 0xe7, 0x20,
-	0x01, 0xfc, 0xc0, 0x31,
+	0x01, 0xfa, 0xc0, 0x31,
 	0x04, 0xea, 0xe8, 0x30,
 	0xff, 0xea, 0xf0, 0x08,
 	0x02, 0xea, 0xf2, 0x00,
@@ -1000,124 +996,121 @@
 	{ ahd_patch0_func, 30, 1, 1 },
 	{ ahd_patch1_func, 37, 1, 2 },
 	{ ahd_patch0_func, 38, 1, 1 },
-	{ ahd_patch2_func, 45, 1, 2 },
-	{ ahd_patch0_func, 46, 1, 1 },
-	{ ahd_patch2_func, 49, 1, 2 },
-	{ ahd_patch0_func, 50, 1, 1 },
-	{ ahd_patch2_func, 53, 1, 2 },
-	{ ahd_patch0_func, 54, 1, 1 },
-	{ ahd_patch2_func, 56, 1, 2 },
-	{ ahd_patch0_func, 57, 1, 1 },
-	{ ahd_patch2_func, 60, 1, 2 },
-	{ ahd_patch0_func, 61, 1, 1 },
-	{ ahd_patch2_func, 64, 1, 2 },
-	{ ahd_patch0_func, 65, 1, 1 },
-	{ ahd_patch2_func, 162, 6, 1 },
-	{ ahd_patch1_func, 168, 2, 1 },
-	{ ahd_patch4_func, 170, 1, 1 },
-	{ ahd_patch2_func, 179, 1, 2 },
-	{ ahd_patch0_func, 180, 1, 1 },
-	{ ahd_patch5_func, 181, 2, 2 },
-	{ ahd_patch0_func, 183, 6, 3 },
-	{ ahd_patch2_func, 186, 1, 2 },
-	{ ahd_patch0_func, 187, 1, 1 },
-	{ ahd_patch2_func, 190, 1, 2 },
-	{ ahd_patch0_func, 191, 1, 1 },
-	{ ahd_patch6_func, 193, 2, 1 },
-	{ ahd_patch4_func, 201, 16, 2 },
-	{ ahd_patch0_func, 217, 1, 1 },
-	{ ahd_patch7_func, 237, 2, 1 },
-	{ ahd_patch1_func, 241, 1, 2 },
-	{ ahd_patch0_func, 242, 1, 1 },
-	{ ahd_patch6_func, 245, 2, 1 },
-	{ ahd_patch1_func, 259, 1, 2 },
-	{ ahd_patch0_func, 260, 1, 1 },
-	{ ahd_patch1_func, 263, 1, 2 },
-	{ ahd_patch0_func, 264, 1, 1 },
-	{ ahd_patch2_func, 267, 1, 2 },
-	{ ahd_patch0_func, 268, 1, 1 },
-	{ ahd_patch1_func, 323, 1, 2 },
-	{ ahd_patch0_func, 324, 1, 1 },
-	{ ahd_patch2_func, 332, 1, 2 },
-	{ ahd_patch0_func, 333, 1, 1 },
-	{ ahd_patch2_func, 336, 1, 2 },
-	{ ahd_patch0_func, 337, 1, 1 },
-	{ ahd_patch1_func, 344, 1, 2 },
-	{ ahd_patch0_func, 345, 1, 1 },
-	{ ahd_patch8_func, 364, 1, 1 },
-	{ ahd_patch8_func, 367, 1, 1 },
-	{ ahd_patch8_func, 369, 1, 1 },
-	{ ahd_patch8_func, 381, 1, 1 },
-	{ ahd_patch1_func, 391, 1, 2 },
-	{ ahd_patch0_func, 392, 1, 1 },
-	{ ahd_patch1_func, 394, 1, 2 },
-	{ ahd_patch0_func, 395, 1, 1 },
-	{ ahd_patch1_func, 403, 1, 2 },
-	{ ahd_patch0_func, 404, 1, 1 },
-	{ ahd_patch2_func, 415, 1, 2 },
-	{ ahd_patch0_func, 416, 1, 1 },
-	{ ahd_patch9_func, 444, 1, 1 },
-	{ ahd_patch1_func, 451, 1, 2 },
-	{ ahd_patch0_func, 452, 1, 1 },
-	{ ahd_patch2_func, 464, 1, 2 },
-	{ ahd_patch0_func, 465, 1, 1 },
-	{ ahd_patch10_func, 470, 6, 2 },
-	{ ahd_patch0_func, 476, 1, 1 },
-	{ ahd_patch11_func, 499, 1, 1 },
-	{ ahd_patch12_func, 508, 1, 1 },
-	{ ahd_patch13_func, 509, 1, 2 },
-	{ ahd_patch0_func, 510, 1, 1 },
-	{ ahd_patch14_func, 515, 1, 1 },
-	{ ahd_patch13_func, 516, 1, 1 },
-	{ ahd_patch15_func, 529, 1, 2 },
-	{ ahd_patch0_func, 530, 1, 1 },
-	{ ahd_patch1_func, 552, 1, 2 },
-	{ ahd_patch0_func, 553, 1, 1 },
-	{ ahd_patch1_func, 556, 1, 2 },
-	{ ahd_patch0_func, 557, 1, 1 },
-	{ ahd_patch2_func, 562, 1, 2 },
-	{ ahd_patch0_func, 563, 1, 1 },
-	{ ahd_patch2_func, 567, 1, 2 },
-	{ ahd_patch0_func, 568, 1, 1 },
-	{ ahd_patch1_func, 569, 1, 2 },
-	{ ahd_patch0_func, 570, 1, 1 },
-	{ ahd_patch2_func, 581, 1, 2 },
-	{ ahd_patch0_func, 582, 1, 1 },
-	{ ahd_patch16_func, 586, 1, 1 },
-	{ ahd_patch17_func, 591, 1, 1 },
-	{ ahd_patch18_func, 592, 2, 1 },
-	{ ahd_patch17_func, 596, 1, 2 },
-	{ ahd_patch0_func, 597, 1, 1 },
-	{ ahd_patch2_func, 600, 1, 2 },
-	{ ahd_patch0_func, 601, 1, 1 },
-	{ ahd_patch2_func, 619, 1, 2 },
-	{ ahd_patch0_func, 620, 1, 1 },
-	{ ahd_patch19_func, 621, 12, 1 },
-	{ ahd_patch1_func, 637, 1, 2 },
-	{ ahd_patch0_func, 638, 1, 1 },
-	{ ahd_patch19_func, 639, 1, 1 },
-	{ ahd_patch1_func, 650, 1, 2 },
-	{ ahd_patch0_func, 651, 1, 1 },
-	{ ahd_patch1_func, 658, 1, 2 },
-	{ ahd_patch0_func, 659, 1, 1 },
-	{ ahd_patch16_func, 683, 1, 1 },
-	{ ahd_patch16_func, 699, 1, 1 },
-	{ ahd_patch2_func, 711, 1, 2 },
-	{ ahd_patch0_func, 712, 1, 1 },
-	{ ahd_patch16_func, 731, 1, 1 },
-	{ ahd_patch1_func, 739, 1, 2 },
-	{ ahd_patch0_func, 740, 1, 1 },
-	{ ahd_patch1_func, 761, 1, 2 },
-	{ ahd_patch0_func, 762, 1, 1 },
-	{ ahd_patch1_func, 764, 1, 2 },
-	{ ahd_patch0_func, 765, 1, 1 },
-	{ ahd_patch1_func, 767, 1, 2 },
-	{ ahd_patch0_func, 768, 1, 1 },
-	{ ahd_patch20_func, 770, 1, 2 },
-	{ ahd_patch0_func, 771, 2, 1 },
-	{ ahd_patch21_func, 774, 4, 2 },
-	{ ahd_patch0_func, 778, 1, 1 },
-	{ ahd_patch21_func, 785, 11, 1 }
+	{ ahd_patch2_func, 43, 1, 2 },
+	{ ahd_patch0_func, 44, 1, 1 },
+	{ ahd_patch2_func, 47, 1, 2 },
+	{ ahd_patch0_func, 48, 1, 1 },
+	{ ahd_patch2_func, 51, 1, 2 },
+	{ ahd_patch0_func, 52, 1, 1 },
+	{ ahd_patch2_func, 65, 1, 2 },
+	{ ahd_patch0_func, 66, 1, 1 },
+	{ ahd_patch2_func, 69, 1, 2 },
+	{ ahd_patch0_func, 70, 1, 1 },
+	{ ahd_patch1_func, 73, 1, 2 },
+	{ ahd_patch0_func, 74, 1, 1 },
+	{ ahd_patch2_func, 161, 6, 1 },
+	{ ahd_patch1_func, 167, 2, 1 },
+	{ ahd_patch4_func, 169, 1, 1 },
+	{ ahd_patch2_func, 178, 1, 2 },
+	{ ahd_patch0_func, 179, 1, 1 },
+	{ ahd_patch5_func, 180, 2, 2 },
+	{ ahd_patch0_func, 182, 6, 3 },
+	{ ahd_patch2_func, 185, 1, 2 },
+	{ ahd_patch0_func, 186, 1, 1 },
+	{ ahd_patch2_func, 189, 1, 2 },
+	{ ahd_patch0_func, 190, 1, 1 },
+	{ ahd_patch6_func, 192, 2, 1 },
+	{ ahd_patch4_func, 200, 16, 2 },
+	{ ahd_patch0_func, 216, 1, 1 },
+	{ ahd_patch7_func, 236, 2, 1 },
+	{ ahd_patch1_func, 240, 1, 2 },
+	{ ahd_patch0_func, 241, 1, 1 },
+	{ ahd_patch6_func, 244, 2, 1 },
+	{ ahd_patch1_func, 258, 1, 2 },
+	{ ahd_patch0_func, 259, 1, 1 },
+	{ ahd_patch1_func, 262, 1, 2 },
+	{ ahd_patch0_func, 263, 1, 1 },
+	{ ahd_patch2_func, 266, 1, 2 },
+	{ ahd_patch0_func, 267, 1, 1 },
+	{ ahd_patch1_func, 322, 1, 2 },
+	{ ahd_patch0_func, 323, 1, 1 },
+	{ ahd_patch2_func, 331, 1, 2 },
+	{ ahd_patch0_func, 332, 1, 1 },
+	{ ahd_patch2_func, 335, 1, 2 },
+	{ ahd_patch0_func, 336, 1, 1 },
+	{ ahd_patch1_func, 343, 1, 2 },
+	{ ahd_patch0_func, 344, 1, 1 },
+	{ ahd_patch8_func, 363, 1, 1 },
+	{ ahd_patch8_func, 366, 1, 1 },
+	{ ahd_patch8_func, 368, 1, 1 },
+	{ ahd_patch8_func, 380, 1, 1 },
+	{ ahd_patch1_func, 390, 1, 2 },
+	{ ahd_patch0_func, 391, 1, 1 },
+	{ ahd_patch1_func, 393, 1, 2 },
+	{ ahd_patch0_func, 394, 1, 1 },
+	{ ahd_patch1_func, 402, 1, 2 },
+	{ ahd_patch0_func, 403, 1, 1 },
+	{ ahd_patch2_func, 416, 1, 2 },
+	{ ahd_patch0_func, 417, 1, 1 },
+	{ ahd_patch9_func, 447, 1, 1 },
+	{ ahd_patch1_func, 454, 1, 2 },
+	{ ahd_patch0_func, 455, 1, 1 },
+	{ ahd_patch2_func, 467, 1, 2 },
+	{ ahd_patch0_func, 468, 1, 1 },
+	{ ahd_patch10_func, 473, 6, 2 },
+	{ ahd_patch0_func, 479, 1, 1 },
+	{ ahd_patch11_func, 502, 1, 1 },
+	{ ahd_patch12_func, 511, 1, 1 },
+	{ ahd_patch13_func, 512, 1, 2 },
+	{ ahd_patch0_func, 513, 1, 1 },
+	{ ahd_patch14_func, 518, 1, 1 },
+	{ ahd_patch13_func, 519, 1, 1 },
+	{ ahd_patch15_func, 532, 1, 2 },
+	{ ahd_patch0_func, 533, 1, 1 },
+	{ ahd_patch1_func, 555, 1, 2 },
+	{ ahd_patch0_func, 556, 1, 1 },
+	{ ahd_patch1_func, 559, 1, 2 },
+	{ ahd_patch0_func, 560, 1, 1 },
+	{ ahd_patch2_func, 565, 1, 2 },
+	{ ahd_patch0_func, 566, 1, 1 },
+	{ ahd_patch2_func, 570, 1, 2 },
+	{ ahd_patch0_func, 571, 1, 1 },
+	{ ahd_patch1_func, 572, 1, 2 },
+	{ ahd_patch0_func, 573, 1, 1 },
+	{ ahd_patch2_func, 584, 1, 2 },
+	{ ahd_patch0_func, 585, 1, 1 },
+	{ ahd_patch16_func, 589, 1, 1 },
+	{ ahd_patch17_func, 594, 1, 1 },
+	{ ahd_patch18_func, 595, 2, 1 },
+	{ ahd_patch17_func, 599, 1, 2 },
+	{ ahd_patch0_func, 600, 1, 1 },
+	{ ahd_patch2_func, 603, 1, 2 },
+	{ ahd_patch0_func, 604, 1, 1 },
+	{ ahd_patch2_func, 622, 1, 2 },
+	{ ahd_patch0_func, 623, 1, 1 },
+	{ ahd_patch19_func, 624, 14, 1 },
+	{ ahd_patch1_func, 642, 1, 2 },
+	{ ahd_patch0_func, 643, 1, 1 },
+	{ ahd_patch19_func, 644, 1, 1 },
+	{ ahd_patch1_func, 656, 1, 2 },
+	{ ahd_patch0_func, 657, 1, 1 },
+	{ ahd_patch1_func, 664, 1, 2 },
+	{ ahd_patch0_func, 665, 1, 1 },
+	{ ahd_patch16_func, 688, 1, 1 },
+	{ ahd_patch16_func, 726, 1, 1 },
+	{ ahd_patch1_func, 737, 1, 2 },
+	{ ahd_patch0_func, 738, 1, 1 },
+	{ ahd_patch1_func, 755, 1, 2 },
+	{ ahd_patch0_func, 756, 1, 1 },
+	{ ahd_patch1_func, 758, 1, 2 },
+	{ ahd_patch0_func, 759, 1, 1 },
+	{ ahd_patch1_func, 762, 1, 2 },
+	{ ahd_patch0_func, 763, 1, 1 },
+	{ ahd_patch20_func, 765, 1, 2 },
+	{ ahd_patch0_func, 766, 2, 1 },
+	{ ahd_patch21_func, 769, 4, 2 },
+	{ ahd_patch0_func, 773, 1, 1 },
+	{ ahd_patch21_func, 781, 11, 1 }
 };
 
 static struct cs {
@@ -1127,18 +1120,15 @@
 	{ 11, 12 },
 	{ 13, 14 },
 	{ 29, 42 },
-	{ 43, 56 },
-	{ 69, 72 },
-	{ 99, 124 },
-	{ 125, 156 },
-	{ 158, 162 },
-	{ 170, 178 },
-	{ 201, 250 },
-	{ 683, 699 },
-	{ 699, 717 },
-	{ 722, 728 },
-	{ 731, 736 },
-	{ 742, 748 }
+	{ 56, 59 },
+	{ 101, 127 },
+	{ 128, 156 },
+	{ 158, 161 },
+	{ 169, 177 },
+	{ 200, 249 },
+	{ 688, 704 },
+	{ 704, 718 },
+	{ 728, 732 }
 };
 
 static const int num_critical_sections = sizeof(critical_sections)
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx.h b/drivers/scsi/aic7xxx/aic7xxx.h
--- a/drivers/scsi/aic7xxx/aic7xxx.h	Mon Mar 10 16:57:17 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx.h	Thu Apr 24 11:10:32 2003
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#74 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.h#75 $
  *
  * $FreeBSD$
  */
@@ -1081,6 +1081,14 @@
 
 	/* PCI cacheline size. */
 	u_int			  pci_cachesize;
+
+	/*
+	 * Count of parity errors we have seen as a target.
+	 * We auto-disable parity error checking after seeing
+	 * AHC_PCI_TARGET_PERR_THRESH number of errors.
+	 */
+	u_int			  pci_target_perr_count;
+#define		AHC_PCI_TARGET_PERR_THRESH	10
 
 	/* Maximum number of sequencer instructions supported. */
 	u_int			  instruction_ram_size;
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_core.c b/drivers/scsi/aic7xxx/aic7xxx_core.c
--- a/drivers/scsi/aic7xxx/aic7xxx_core.c	Tue Mar 25 16:32:22 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_core.c	Wed Apr  9 12:01:02 2003
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#124 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx.c#128 $
  *
  * $FreeBSD$
  */
@@ -3949,7 +3949,6 @@
 {
 	int i;
 
-	ahc_fini_scbdata(ahc);
 	switch (ahc->init_level) {
 	default:
 	case 5:
@@ -3981,6 +3980,7 @@
 	ahc_dma_tag_destroy(ahc, ahc->parent_dmat);
 #endif
 	ahc_platform_free(ahc);
+	ahc_fini_scbdata(ahc);
 	for (i = 0; i < AHC_NUM_TARGETS; i++) {
 		struct ahc_tmode_tstate *tstate;
 
@@ -5100,7 +5100,7 @@
 	} while (--maxloops
 	      && (intstat != 0xFF || (ahc->features & AHC_REMOVABLE) == 0)
 	      && ((intstat & INT_PEND) != 0
-	       || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO))));
+	       || (ahc_inb(ahc, SSTAT0) & (SELDO|SELINGO)) != 0));
 	if (maxloops == 0) {
 		printf("Infinite interrupt loop, INTSTAT = %x",
 		       ahc_inb(ahc, INTSTAT));
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_inline.h b/drivers/scsi/aic7xxx/aic7xxx_inline.h
--- a/drivers/scsi/aic7xxx/aic7xxx_inline.h	Thu Feb 20 14:50:09 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_inline.h	Thu May  1 10:06:05 2003
@@ -37,7 +37,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#40 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_inline.h#42 $
  *
  * $FreeBSD$
  */
@@ -500,7 +500,7 @@
 static __inline void	ahc_sync_qoutfifo(struct ahc_softc *ahc, int op);
 static __inline void	ahc_sync_tqinfifo(struct ahc_softc *ahc, int op);
 static __inline u_int	ahc_check_cmdcmpltqueues(struct ahc_softc *ahc);
-static __inline void	ahc_intr(struct ahc_softc *ahc);
+static __inline int	ahc_intr(struct ahc_softc *ahc);
 
 static __inline void
 ahc_sync_qoutfifo(struct ahc_softc *ahc, int op)
@@ -558,7 +558,7 @@
 /*
  * Catch an interrupt from the adapter
  */
-static __inline void
+static __inline int
 ahc_intr(struct ahc_softc *ahc)
 {
 	u_int	intstat;
@@ -570,7 +570,7 @@
 		 * so just return.  This is likely just a shared
 		 * interrupt.
 		 */
-		return;
+		return (0);
 	}
 	/*
 	 * Instead of directly reading the interrupt status register,
@@ -585,6 +585,20 @@
 		intstat = ahc_inb(ahc, INTSTAT);
 	}
 
+	if ((intstat & INT_PEND) == 0) {
+#if AHC_PCI_CONFIG > 0
+		if (ahc->unsolicited_ints > 500) {
+			ahc->unsolicited_ints = 0;
+			if ((ahc->chip & AHC_PCI) != 0
+			 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
+				ahc->bus_intr(ahc);
+		}
+#endif
+		ahc->unsolicited_ints++;
+		return (0);
+	}
+	ahc->unsolicited_ints = 0;
+
 	if (intstat & CMDCMPLT) {
 		ahc_outb(ahc, CLRINT, CLRCMDINT);
 
@@ -604,38 +618,25 @@
 #endif
 	}
 
-	if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0)
-		/* Hot eject */
-		return;
-
-	if ((intstat & INT_PEND) == 0) {
-#if AHC_PCI_CONFIG > 0
-		if (ahc->unsolicited_ints > 500) {
-			ahc->unsolicited_ints = 0;
-			if ((ahc->chip & AHC_PCI) != 0
-			 && (ahc_inb(ahc, ERROR) & PCIERRSTAT) != 0)
-				ahc->bus_intr(ahc);
-		}
-#endif
-		ahc->unsolicited_ints++;
-		return;
-	}
-	ahc->unsolicited_ints = 0;
-
-	if (intstat & BRKADRINT) {
+	/*
+	 * Handle statuses that may invalidate our cached
+	 * copy of INTSTAT separately.
+	 */
+	if (intstat == 0xFF && (ahc->features & AHC_REMOVABLE) != 0) {
+		/* Hot eject.  Do nothing */
+	} else if (intstat & BRKADRINT) {
 		ahc_handle_brkadrint(ahc);
-		/* Fatal error, no more interrupts to handle. */
-		return;
-	}
+	} else if ((intstat & (SEQINT|SCSIINT)) != 0) {
 
-	if ((intstat & (SEQINT|SCSIINT)) != 0)
 		ahc_pause_bug_fix(ahc);
 
-	if ((intstat & SEQINT) != 0)
-		ahc_handle_seqint(ahc, intstat);
+		if ((intstat & SEQINT) != 0)
+			ahc_handle_seqint(ahc, intstat);
 
-	if ((intstat & SCSIINT) != 0)
-		ahc_handle_scsiint(ahc, intstat);
+		if ((intstat & SCSIINT) != 0)
+			ahc_handle_scsiint(ahc, intstat);
+	}
+	return (1);
 }
 
 #endif  /* _AIC7XXX_INLINE_H_ */
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c	Sun Apr 20 14:14:29 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c	Tue May 13 14:11:12 2003
@@ -1,7 +1,7 @@
 /*
  * Adaptec AIC7xxx device driver for Linux.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#206 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.c#221 $
  *
  * Copyright (c) 1994 John Aycock
  *   The University of Calgary Department of Computer Science.
@@ -146,18 +146,15 @@
 #include <linux/unistd.h>
 static int errno;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
 /*
  * Lock protecting manipulation of the ahc softc list.
  */
 spinlock_t ahc_list_spinlock;
-#endif
 
-/*
- * 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,5,0)
+/* For dynamic sglist size calculation. */
+u_int ahc_linux_nseg;
+#endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
 struct proc_dir_entry proc_scsi_aic7xxx = {
@@ -367,31 +364,26 @@
  * disabled at the very end.  That should fix everyone up unless there are
  * really strange cirumstances.
  */
-static int aic7xxx_reverse_scan = 0;
+static uint32_t aic7xxx_reverse_scan;
 
 /*
  * 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;
+static uint32_t aic7xxx_extended;
 
 /*
  * 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.
+ * chipset configurations where stray PCI transactions with bad parity are
+ * the norm rather than the exception, the error messages can be overwelming.
  * 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.
+ *   0	   = Shut off PCI parity check
+ *   non-0 = reverse polarity pci parity checking
  */
-static int aic7xxx_pci_parity = 0;
+static uint32_t aic7xxx_pci_parity = ~0;
 
 /*
  * Certain newer motherboards have put new PCI based devices into the
@@ -404,12 +396,9 @@
  * would result in never finding any devices :)
  */
 #ifndef CONFIG_AIC7XXX_PROBE_EISA_VL
-#define CONFIG_AIC7XXX_PROBE_EISA_VL n
-#endif
-#if CONFIG_AIC7XXX_PROBE_EISA_VL == n
-static int aic7xxx_no_probe = 1;
+static uint32_t aic7xxx_probe_eisa_vl;
 #else
-static int aic7xxx_no_probe;
+static uint32_t aic7xxx_probe_eisa_vl = ~0;
 #endif
 
 /*
@@ -418,7 +407,7 @@
  * controller.  I/O mapped register access, if allowed by the given
  * platform, will work in almost all cases.
  */
-int aic7xxx_allow_memio = 1;
+uint32_t aic7xxx_allow_memio = ~0;
 
 /*
  * aic7xxx_detect() has been run, so register all device arrivals
@@ -437,7 +426,7 @@
  * We default to 256ms because some older devices need a longer time
  * to respond to initial selection.
  */
-static int aic7xxx_seltime = 0x00;
+static uint32_t aic7xxx_seltime;
 
 /*
  * Certain devices do not perform any aging on commands.  Should the
@@ -447,7 +436,7 @@
  * force all outstanding transactions to be serviced prior to a new
  * transaction.
  */
-int aic7xxx_periodic_otag;
+uint32_t aic7xxx_periodic_otag;
 
 /*
  * Module information and settable options.
@@ -472,7 +461,8 @@
 "	verbose			Enable verbose/diagnostic logging\n"
 "	allow_memio		Allow device registers to be memory mapped\n"
 "	debug			Bitmask of debug values to enable\n"
-"	no_probe		Disable EISA/VLB controller probing\n"
+"	no_probe		Toggle EISA/VLB controller probing\n"
+"	probe_eisa_vl		Toggle EISA/VLB controller probing\n"
 "	no_reset		Supress initial bus resets\n"
 "	extended		Enable extended geometry on all controllers\n"
 "	periodic_otag		Send an ordered tagged transaction\n"
@@ -489,10 +479,10 @@
 "\n"
 "	Sample /etc/modules.conf line:\n"
 "		Toggle EISA/VLB probing\n"
-"		Set tag depth on Controller 1/Target 2 to 10 tags\n"
+"		Set tag depth on Controller 1/Target 1 to 10 tags\n"
 "		Shorten the selection timeout to 128ms\n"
 "\n"
-"	options aic7xxx 'aic7xxx=no_probe.tag_info:{{}.{..10}}.seltime:1'\n"
+"	options aic7xxx 'aic7xxx=probe_eisa_vl.tag_info:{{}.{.10}}.seltime:1'\n"
 );
 #endif
 
@@ -508,6 +498,7 @@
 static void ahc_linux_dev_timed_unfreeze(u_long arg);
 static int  ahc_linux_queue_recovery_cmd(Scsi_Cmnd *cmd, scb_flag flag);
 static void ahc_linux_initialize_scsi_bus(struct ahc_softc *ahc);
+static void ahc_linux_size_nseg(void);
 static void ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc);
 static void ahc_linux_start_dv(struct ahc_softc *ahc);
 static void ahc_linux_dv_timeout(struct scsi_cmnd *cmd);
@@ -571,16 +562,14 @@
 static int  aic7xxx_setup(char *s);
 static int  ahc_linux_next_unit(void);
 static void ahc_runq_tasklet(unsigned long data);
-static int  ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf);
-static void ahc_schedule_completeq(struct ahc_softc *ahc, struct ahc_cmd *acmd);
+static struct ahc_cmd *ahc_linux_run_complete_queue(struct ahc_softc *ahc);
 
 /********************************* Inlines ************************************/
 static __inline void ahc_schedule_runq(struct ahc_softc *ahc);
 static __inline struct ahc_linux_device*
 		     ahc_linux_get_device(struct ahc_softc *ahc, u_int channel,
 					  u_int target, u_int lun, int alloc);
-static struct ahc_cmd *ahc_linux_run_complete_queue(struct ahc_softc *ahc,
-						    struct ahc_cmd *acmd);
+static __inline void ahc_schedule_completeq(struct ahc_softc *ahc);
 static __inline void ahc_linux_check_device_queue(struct ahc_softc *ahc,
 						  struct ahc_linux_device *dev);
 static __inline struct ahc_linux_device *
@@ -592,27 +581,9 @@
 		 		      struct ahc_dma_seg *sg,
 				      bus_addr_t addr, bus_size_t len);
 
-static void
-ahc_schedule_completeq(struct ahc_softc *ahc, struct ahc_cmd *acmd)
+static __inline void
+ahc_schedule_completeq(struct ahc_softc *ahc)
 {
-	while (acmd != NULL) {
-		struct ahc_completeq *completeq;
-		struct ahc_cmd *list_cmd;
-		struct ahc_cmd *next_cmd;
-
-		next_cmd = TAILQ_NEXT(acmd, acmd_links.tqe);
-		completeq = &ahc->platform_data->completeq;
-		list_cmd = TAILQ_FIRST(completeq);
-		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);
-		acmd = next_cmd;
-	}
 	if ((ahc->platform_data->flags & AHC_RUN_CMPLT_Q_TIMER) == 0) {
 		ahc->platform_data->flags |= AHC_RUN_CMPLT_Q_TIMER;
 		ahc->platform_data->completeq_timer.expires = jiffies;
@@ -664,25 +635,17 @@
 
 #define AHC_LINUX_MAX_RETURNED_ERRORS 4
 static struct ahc_cmd *
-ahc_linux_run_complete_queue(struct ahc_softc *ahc, struct ahc_cmd *acmd)
-{	
+ahc_linux_run_complete_queue(struct ahc_softc *ahc)
+{
+	struct	ahc_cmd *acmd;
 	u_long	done_flags;
 	int	with_errors;
 
 	with_errors = 0;
 	ahc_done_lock(ahc, &done_flags);
-	while (acmd != NULL) {
+	while ((acmd = TAILQ_FIRST(&ahc->platform_data->completeq)) != NULL) {
 		Scsi_Cmnd *cmd;
 
-		cmd = &acmd_scsi_cmd(acmd);
-		acmd = TAILQ_NEXT(acmd, acmd_links.tqe);
-		cmd->host_scribble = NULL;
-		if (ahc_cmd_get_transaction_status(cmd) != DID_OK
-		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)
-			with_errors++;
-
-		cmd->scsi_done(cmd);
-
 		if (with_errors > AHC_LINUX_MAX_RETURNED_ERRORS) {
 			/*
 			 * Linux uses stack recursion to requeue
@@ -692,8 +655,18 @@
 			 * the operating system in case they are going
 			 * to be retried. "ick"
 			 */
+			ahc_schedule_completeq(ahc);
 			break;
 		}
+		TAILQ_REMOVE(&ahc->platform_data->completeq,
+			     acmd, acmd_links.tqe);
+		cmd = &acmd_scsi_cmd(acmd);
+		cmd->host_scribble = NULL;
+		if (ahc_cmd_get_transaction_status(cmd) != DID_OK
+		 || (cmd->result & 0xFF) != SCSI_STATUS_OK)
+			with_errors++;
+
+		cmd->scsi_done(cmd);
 	}
 	ahc_done_unlock(ahc, &done_flags);
 	return (acmd);
@@ -811,19 +784,84 @@
 static int	   ahc_linux_slave_alloc(Scsi_Device *);
 static int	   ahc_linux_slave_configure(Scsi_Device *);
 static void	   ahc_linux_slave_destroy(Scsi_Device *);
+#if defined(__i386__)
 static int	   ahc_linux_biosparam(struct scsi_device*,
 				       struct block_device*,
 				       sector_t, int[]);
+#endif
 #else
 static void	   ahc_linux_select_queue_depth(struct Scsi_Host *host,
 						Scsi_Device *scsi_devs);
+#if defined(__i386__)
 static int	   ahc_linux_biosparam(Disk *, kdev_t, int[]);
 #endif
+#endif
 static int	   ahc_linux_bus_reset(Scsi_Cmnd *);
 static int	   ahc_linux_dev_reset(Scsi_Cmnd *);
 static int	   ahc_linux_abort(Scsi_Cmnd *);
 
 /*
+ * Calculate a safe value for AHC_NSEG (as expressed through ahc_linux_nseg).
+ *
+ * In pre-2.5.X...
+ * The midlayer allocates an S/G array dynamically when a command is issued
+ * using SCSI malloc.  This array, which is in an OS dependent format that
+ * must later be copied to our private S/G list, is sized to house just the
+ * number of segments needed for the current transfer.  Since the code that
+ * sizes the SCSI malloc pool does not take into consideration fragmentation
+ * of the pool, executing transactions numbering just a fraction of our
+ * concurrent transaction limit with list lengths aproaching AHC_NSEG will
+ * quickly depleat the SCSI malloc pool of usable space.  Unfortunately, the
+ * mid-layer does not properly handle this scsi malloc failures for the S/G
+ * array and the result can be a lockup of the I/O subsystem.  We try to size
+ * our S/G list so that it satisfies our drivers allocation requirements in
+ * addition to avoiding fragmentation of the SCSI malloc pool.
+ */
+static void
+ahc_linux_size_nseg(void)
+{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	u_int cur_size;
+	u_int best_size;
+
+	/*
+	 * The SCSI allocator rounds to the nearest 512 bytes
+	 * an cannot allocate across a page boundary.  Our algorithm
+	 * is to start at 1K of scsi malloc space per-command and
+	 * loop through all factors of the PAGE_SIZE and pick the best.
+	 */
+	best_size = 0;
+	for (cur_size = 1024; cur_size <= PAGE_SIZE; cur_size *= 2) {
+		u_int nseg;
+
+		nseg = cur_size / sizeof(struct scatterlist);
+		if (nseg < AHC_LINUX_MIN_NSEG)
+			continue;
+
+		if (best_size == 0) {
+			best_size = cur_size;
+			ahc_linux_nseg = nseg;
+		} else {
+			u_int best_rem;
+			u_int cur_rem;
+
+			/*
+			 * Compare the traits of the current "best_size"
+			 * with the current size to determine if the
+			 * current size is a better size.
+			 */
+			best_rem = best_size % sizeof(struct scatterlist);
+			cur_rem = cur_size % sizeof(struct scatterlist);
+			if (cur_rem < best_rem) {
+				best_size = cur_size;
+				ahc_linux_nseg = nseg;
+			}
+		}
+	}
+#endif
+}
+
+/*
  * Try to detect an Adaptec 7XXX controller.
  */
 static int
@@ -851,6 +889,7 @@
 		printf("ahc_linux_detect: Unable to attach\n");
 		return (0);
 	}
+	ahc_linux_size_nseg();
 #ifdef MODULE
 	/*
 	 * If we've been passed any parameters, process them now.
@@ -881,7 +920,7 @@
 	ahc_linux_pci_init();
 #endif
 
-	if (aic7xxx_no_probe == 0)
+	if (aic7xxx_probe_eisa_vl != 0)
 		aic7770_linux_probe(template);
 
 	/*
@@ -991,7 +1030,7 @@
 
 		ahc_cmd_set_transaction_status(cmd, CAM_REQUEUE_REQ);
 		ahc_linux_queue_cmd_complete(ahc, cmd);
-		ahc_schedule_completeq(ahc, NULL);
+		ahc_schedule_completeq(ahc);
 		ahc_midlayer_entrypoint_unlock(ahc, &flags);
 		return (0);
 	}
@@ -1000,7 +1039,7 @@
 	if (dev == NULL) {
 		ahc_cmd_set_transaction_status(cmd, CAM_RESRC_UNAVAIL);
 		ahc_linux_queue_cmd_complete(ahc, cmd);
-		ahc_schedule_completeq(ahc, NULL);
+		ahc_schedule_completeq(ahc);
 		ahc_midlayer_entrypoint_unlock(ahc, &flags);
 		printf("%s: aic7xxx_linux_queue - Unable to allocate device!\n",
 		       ahc_name(ahc));
@@ -1082,7 +1121,8 @@
 	 && (dev->flags & AHC_DEV_SLAVE_CONFIGURED) != 0) {
 		dev->flags |= AHC_DEV_UNCONFIGURED;
 		if (TAILQ_EMPTY(&dev->busyq)
-		 && dev->active == 0)
+		 && dev->active == 0
+	 	 && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0)
 			ahc_linux_free_device(ahc, dev);
 	}
 	ahc_midlayer_entrypoint_unlock(ahc, &flags);
@@ -1093,16 +1133,33 @@
  * off the input host adapter.
  */
 static void
-ahc_linux_select_queue_depth(struct Scsi_Host * host,
-			     Scsi_Device * scsi_devs)
+ahc_linux_select_queue_depth(struct Scsi_Host *host, Scsi_Device *scsi_devs)
 {
 	Scsi_Device *device;
+	Scsi_Device *ldev;
 	struct	ahc_softc *ahc;
 	u_long	flags;
 
 	ahc = *((struct ahc_softc **)host->hostdata);
 	ahc_lock(ahc, &flags);
 	for (device = scsi_devs; device != NULL; device = device->next) {
+
+		/*
+		 * Watch out for duplicate devices.  This works around
+		 * some quirks in how the SCSI scanning code does its
+		 * device management.
+		 */
+		for (ldev = scsi_devs; ldev != device; ldev = ldev->next) {
+			if (ldev->host == device->host
+			 && ldev->channel == device->channel
+			 && ldev->id == device->id
+			 && ldev->lun == device->lun)
+				break;
+		}
+		/* Skip duplicate. */
+		if (ldev != device)
+			continue;
+
 		if (device->host == host) {
 			struct	 ahc_linux_device *dev;
 
@@ -1141,6 +1198,7 @@
 /*
  * Return the disk geometry for the given SCSI device.
  */
+#if defined(__i386__)
 static int
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
 ahc_linux_biosparam(struct scsi_device *sdev, struct block_device *bdev,
@@ -1204,6 +1262,7 @@
 	geom[2] = cylinders;
 	return (0);
 }
+#endif
 
 /*
  * Abort the current SCSI command(s).
@@ -1240,7 +1299,6 @@
 ahc_linux_bus_reset(Scsi_Cmnd *cmd)
 {
 	struct ahc_softc *ahc;
-	struct ahc_cmd *acmd;
 	u_long s;
 	int    found;
 
@@ -1248,14 +1306,7 @@
 	ahc_midlayer_entrypoint_lock(ahc, &s);
 	found = ahc_reset_channel(ahc, cmd->device->channel + 'A',
 				  /*initiate reset*/TRUE);
-	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
-	TAILQ_INIT(&ahc->platform_data->completeq);
-
-	if (acmd != NULL) {
-		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL)
-			ahc_schedule_completeq(ahc, acmd);
-	}
+	ahc_linux_run_complete_queue(ahc);
 	ahc_midlayer_entrypoint_unlock(ahc, &s);
 
 	if (bootverbose)
@@ -1279,7 +1330,6 @@
 #endif
 	.can_queue		= AHC_MAX_QUEUE,
 	.this_id		= -1,
-	.sg_tablesize		= AHC_NSEG,
 	.cmd_per_lun		= 2,
 	.use_clustering		= ENABLE_CLUSTERING,
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,7)
@@ -1337,44 +1387,17 @@
 		TAILQ_REMOVE(&ahc->platform_data->device_runq, dev, links);
 		dev->flags &= ~AHC_DEV_ON_RUN_LIST;
 		ahc_linux_check_device_queue(ahc, dev);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 		/* Yeild to our interrupt handler */
 		ahc_unlock(ahc, &flags);
 		ahc_lock(ahc, &flags);
+#endif
 	}
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	ahc_unlock(ahc, &flags);
 #endif
 }
 
-/************************ Shutdown/halt/reboot hook ***************************/
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-
-static struct notifier_block ahc_linux_notifier = {
-	ahc_linux_halt, NULL, 0
-};
-
-static int ahc_linux_halt(struct notifier_block *nb, u_long event, void *buf)
-{
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
-	struct ahc_softc *ahc;
-
-	/*
-	 * In 2.5.X, this is called prior to the filesystems
-	 * being synced and the SCSI layer being properly
-	 * shutdown.  A different API is required there,
-	 * but the device hooks for this don't quite look
-	 * right.
-	 */
-	if (event == SYS_DOWN || event == SYS_HALT) {
-		TAILQ_FOREACH(ahc, &ahc_tailq, links) {
-			ahc_shutdown(ahc);
-		}
-	}
-#endif
-	return (NOTIFY_OK);
-}
-
 /******************************** Macros **************************************/
 #define BUILD_SCSIID(ahc, cmd)						    \
 	((((cmd)->device->id << TID_SHIFT) & TID)			    \
@@ -1482,6 +1505,7 @@
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
 	stack_sg.ds_addr = map->bus_addr;
 #else
+#define VIRT_TO_BUS(a) (uint32_t)virt_to_bus((void *)(a))
 	stack_sg.ds_addr = VIRT_TO_BUS(buf);
 #endif
 	stack_sg.ds_len = dmat->maxsize;
@@ -1613,7 +1637,7 @@
 }
 
 static void
-ahc_linux_setup_tag_info(void *arg, int instance, int targ, int32_t value)
+ahc_linux_setup_tag_info(u_long arg, int instance, int targ, int32_t value)
 {
 
 	if ((instance >= 0) && (targ >= 0)
@@ -1626,7 +1650,7 @@
 }
 
 static void
-ahc_linux_setup_dv(void *arg, int instance, int targ, int32_t value)
+ahc_linux_setup_dv(u_long arg, int instance, int targ, int32_t value)
 {
 
 	if ((instance >= 0)
@@ -1661,7 +1685,8 @@
 		{ "debug", &ahc_debug },
 #endif
 		{ "reverse_scan", &aic7xxx_reverse_scan },
-		{ "no_probe", &aic7xxx_no_probe },
+		{ "no_probe", &aic7xxx_probe_eisa_vl },
+		{ "probe_eisa_vl", &aic7xxx_probe_eisa_vl },
 		{ "periodic_otag", &aic7xxx_periodic_otag },
 		{ "pci_parity", &aic7xxx_pci_parity },
 		{ "seltime", &aic7xxx_seltime },
@@ -1694,16 +1719,16 @@
 			ahc_linux_setup_tag_info_global(p + n);
 		} else if (strncmp(p, "tag_info", n) == 0) {
 			s = aic_parse_brace_option("tag_info", p + n, end,
-			    2, ahc_linux_setup_tag_info, NULL);
+			    2, ahc_linux_setup_tag_info, 0);
 		} else if (strncmp(p, "dv", n) == 0) {
 			s = aic_parse_brace_option("dv", p + n, end, 1,
-			    ahc_linux_setup_dv, NULL);
+			    ahc_linux_setup_dv, 0);
 		} else if (p[n] == ':') {
 			*(options[i].flag) = simple_strtoul(p + n + 1, NULL, 0);
 		} else if (strncmp(p, "verbose", n) == 0) {
 			*(options[i].flag) = 1;
 		} else {
-			*(options[i].flag) = ~(*(options[i].flag));
+			*(options[i].flag) ^= 0xFFFFFFFF;
 		}
 	}
 	return 1;
@@ -1713,7 +1738,7 @@
 __setup("aic7xxx=", aic7xxx_setup);
 #endif
 
-int aic7xxx_verbose;
+uint32_t aic7xxx_verbose;
 
 int
 ahc_linux_register_host(struct ahc_softc *ahc, Scsi_Host_Template *template)
@@ -1739,13 +1764,13 @@
 	ahc->platform_data->host = host;
 	host->can_queue = AHC_MAX_QUEUE;
 	host->cmd_per_lun = 2;
-	host->sg_tablesize = AHC_NSEG;
 	/* XXX No way to communicate the ID for multiple channels */
 	host->this_id = ahc->our_id;
 	host->irq = ahc->platform_data->irq;
 	host->max_id = (ahc->features & AHC_WIDE) ? 16 : 8;
 	host->max_lun = AHC_NUM_LUNS;
 	host->max_channel = (ahc->features & AHC_TWIN) ? 1 : 0;
+	host->sg_tablesize = AHC_NSEG;
 	ahc_set_unit(ahc, ahc_linux_next_unit());
 	sprintf(buf, "scsi%d", host->host_no);
 	new_name = malloc(strlen(buf) + 1, M_DEVBUF, M_NOWAIT);
@@ -1953,8 +1978,6 @@
 	if (aic7xxx_pci_parity == 0)
 		ahc->flags |= AHC_DISABLE_PCI_PERR;
 
-	if (TAILQ_EMPTY(&ahc_tailq))
-		register_reboot_notifier(&ahc_linux_notifier);
 	return (0);
 }
 
@@ -1966,6 +1989,7 @@
 	int i, j;
 
 	if (ahc->platform_data != NULL) {
+		del_timer_sync(&ahc->platform_data->completeq_timer);
 		ahc_linux_kill_dv_thread(ahc);
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 		tasklet_kill(&ahc->platform_data->runq_tasklet);
@@ -1981,17 +2005,22 @@
 		for (i = 0; i < AHC_NUM_TARGETS; i++) {
 			targ = ahc->platform_data->targets[i];
 			if (targ != NULL) {
+				/* Keep target around through the loop. */
+				targ->refcount++;
 				for (j = 0; j < AHC_NUM_LUNS; j++) {
-					if (targ->devices[j] != NULL) {
-						dev = targ->devices[j];
-						ahc_linux_free_device(ahc, dev);
-					}
-					if (ahc->platform_data->targets[i] ==
-					    NULL)
-						break;
+
+					if (targ->devices[j] == NULL)
+						continue;
+					dev = targ->devices[j];
+					ahc_linux_free_device(ahc, dev);
 				}
-			}
-		}
+				/*
+				 * Forcibly free the target now that
+				 * all devices are gone.
+				 */
+				ahc_linux_free_target(ahc, targ);
+ 			}
+ 		}
 
 		if (ahc->platform_data->irq != AHC_LINUX_NOIRQ)
 			free_irq(ahc->platform_data->irq, ahc);
@@ -2200,19 +2229,12 @@
 static void
 ahc_linux_thread_run_complete_queue(struct ahc_softc *ahc)
 {
-	struct ahc_cmd *acmd;
 	u_long flags;
 
 	ahc_lock(ahc, &flags);
 	del_timer(&ahc->platform_data->completeq_timer);
 	ahc->platform_data->flags &= ~AHC_RUN_CMPLT_Q_TIMER;
-	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
-	TAILQ_INIT(&ahc->platform_data->completeq);
-	if (acmd != NULL) {
-		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL)
-			ahc_schedule_completeq(ahc, acmd);
-	}
+	ahc_linux_run_complete_queue(ahc);
 	ahc_unlock(ahc, &flags);
 }
 
@@ -2575,10 +2597,14 @@
 	}
 
 	ahc_lock(ahc, &s);
-	if (targ->dv_buffer != NULL)
+	if (targ->dv_buffer != NULL) {
 		free(targ->dv_buffer, M_DEVBUF);
-	if (targ->dv_buffer1 != NULL)
+		targ->dv_buffer = NULL;
+	}
+	if (targ->dv_buffer1 != NULL) {
 		free(targ->dv_buffer1, M_DEVBUF);
+		targ->dv_buffer1 = NULL;
+	}
 	targ->flags &= ~AHC_DV_REQUIRED;
 	if (targ->refcount == 0)
 		ahc_linux_free_target(ahc, targ);
@@ -3408,7 +3434,6 @@
 ahc_linux_dv_timeout(struct scsi_cmnd *cmd)
 {
 	struct	ahc_softc *ahc;
-	struct	ahc_cmd *acmd;
 	struct	scb *scb;
 	u_long	flags;
 
@@ -3455,15 +3480,9 @@
 	ahc->platform_data->reset_timer.function =
 	    (ahc_linux_callback_t *)ahc_linux_release_simq;
 	add_timer(&ahc->platform_data->reset_timer);
-	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
-	TAILQ_INIT(&ahc->platform_data->completeq);
 	if (ahc_linux_next_device_to_run(ahc) != NULL)
 		ahc_schedule_runq(ahc);
-	if (acmd != NULL) {
-		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL)
-			ahc_schedule_completeq(ahc, acmd);
-	}
+	ahc_linux_run_complete_queue(ahc);
 	ahc_unlock(ahc, &flags);
 }
 
@@ -3639,9 +3658,8 @@
 	 && dev->scsi_device->tagged_supported != 0) {
 
 		ahc_set_tags(ahc, &devinfo, AHC_QUEUE_TAGGED);
-		printf("scsi%d:%c:%d:%d: Tagged Queuing enabled.  Depth %d\n",
-	       	       ahc->platform_data->host->host_no, devinfo.channel,
-		       devinfo.target, devinfo.lun, tags);
+		ahc_print_devinfo(ahc, &devinfo);
+		printf("Tagged Queuing enabled.  Depth %d\n", tags);
 	} else {
 		ahc_set_tags(ahc, &devinfo, AHC_QUEUE_NONE);
 	}
@@ -3863,39 +3881,29 @@
 /*
  * SCSI controller interrupt handler.
  */
-irqreturn_t
+AIC_LINUX_IRQRETURN_T
 ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct	ahc_softc *ahc;
-	struct	ahc_cmd *acmd;
 	u_long	flags;
+	int	ours;
 
 	ahc = (struct ahc_softc *) dev_id;
 	ahc_lock(ahc, &flags); 
-	ahc_intr(ahc);
-	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
-	TAILQ_INIT(&ahc->platform_data->completeq);
+	ours = ahc_intr(ahc);
 	if (ahc_linux_next_device_to_run(ahc) != NULL)
 		ahc_schedule_runq(ahc);
-	if (acmd != NULL) {
-		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL)
-			ahc_schedule_completeq(ahc, acmd);
-	}
+	ahc_linux_run_complete_queue(ahc);
 	ahc_unlock(ahc, &flags);
-	/* FIXME! Was it really ours? */
-	return IRQ_HANDLED;
+	AIC_LINUX_IRQRETURN(ours);
 }
 
 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);
-	while (acmd != NULL)
-		acmd = ahc_linux_run_complete_queue(ahc, acmd);
+	while (ahc_linux_run_complete_queue(ahc) != NULL)
+		;
 }
 
 static struct ahc_linux_target*
@@ -4081,22 +4089,19 @@
 	}
         case AC_SENT_BDR:
 	{
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+		WARN_ON(lun != CAM_LUN_WILDCARD);
+		scsi_report_device_reset(ahc->platform_data->host,
+					 channel - 'A', target);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
 		Scsi_Device *scsi_dev;
 
 		/*
 		 * Find the SCSI device associated with this
 		 * request and indicate that a UA is expected.
-		 * XXX This should really be handled by the mid-layer.
 		 */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
-		list_for_each_entry(scsi_dev,
-				    &ahc->platform_data->host->my_devices,
-				    siblings) {
-#else
 		for (scsi_dev = ahc->platform_data->host->host_queue;
 		     scsi_dev != NULL; scsi_dev = scsi_dev->next) {
-#endif
 			if (channel - 'A' == scsi_dev->channel
 			 && target == scsi_dev->id
 			 && (lun == CAM_LUN_WILDCARD
@@ -4229,7 +4234,8 @@
 
 	if (TAILQ_EMPTY(&dev->busyq)) {
 		if ((dev->flags & AHC_DEV_UNCONFIGURED) != 0
-		 && dev->active == 0)
+		 && dev->active == 0
+	 	 && (dev->flags & AHC_DEV_TIMER_ACTIVE) == 0)
 			ahc_linux_free_device(ahc, dev);
 	} else if ((dev->flags & AHC_DEV_ON_RUN_LIST) == 0) {
 		TAILQ_INSERT_TAIL(&ahc->platform_data->device_runq, dev, links);
@@ -4709,6 +4715,9 @@
 	if (dev->qfrozen == 0
 	 && (dev->flags & AHC_DEV_ON_RUN_LIST) == 0)
 		ahc_linux_run_device_queue(ahc, dev);
+	if (TAILQ_EMPTY(&dev->busyq)
+	 && dev->active == 0)
+		ahc_linux_free_device(ahc, dev);
 	ahc_unlock(ahc, &s);
 }
 
@@ -4727,6 +4736,7 @@
 	u_int  saved_scsiid;
 	u_int  cdb_byte;
 	int    retval;
+	int    was_paused;
 	int    paused;
 	int    wait;
 	int    disconnected;
@@ -4768,7 +4778,7 @@
 	 * 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.
+	 * command, return success.
 	 */
 	dev = ahc_linux_get_device(ahc, cmd->device->channel, cmd->device->id,
 				   cmd->device->lun, /*alloc*/FALSE);
@@ -4855,11 +4865,10 @@
 	 * behind our back and that we didn't "just" miss
 	 * an interrupt that would affect this cmd.
 	 */
+	was_paused = ahc_is_paused(ahc);
 	ahc_pause_and_flushwork(ahc);
 	paused = TRUE;
 
-	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->device->channel, cmd->device->id,
@@ -4867,6 +4876,10 @@
 		goto no_cmd;
 	}
 
+	printf("%s: At time of recovery, card was %spaused\n",
+	       ahc_name(ahc), was_paused ? "" : "not ");
+	ahc_dump_card_state(ahc);
+
 	disconnected = TRUE;
 	if (flag == SCB_ABORT) {
 		if (ahc_search_qinfifo(ahc, cmd->device->id,
@@ -5026,21 +5039,15 @@
 		printf("Recovery code sleeping\n");
 		down(&ahc->platform_data->eh_sem);
 		printf("Recovery code awake\n");
-        	ret = del_timer(&timer);
+        	ret = del_timer_sync(&timer);
 		if (ret == 0) {
 			printf("Timer Expired\n");
 			retval = FAILED;
 		}
 		spin_lock_irq(&ahc->platform_data->spin_lock);
 	}
-	acmd = TAILQ_FIRST(&ahc->platform_data->completeq);
-	TAILQ_INIT(&ahc->platform_data->completeq);
 	ahc_schedule_runq(ahc);
-	if (acmd != NULL) {
-		acmd = ahc_linux_run_complete_queue(ahc, acmd);
-		if (acmd != NULL)
-			ahc_schedule_completeq(ahc, acmd);
-	}
+	ahc_linux_run_complete_queue(ahc);
 	ahc_midlayer_entrypoint_unlock(ahc, &s);
 	return (retval);
 }
@@ -5140,8 +5147,6 @@
 	 */
 	ahc_linux_pci_exit();
 #endif
-
-	unregister_reboot_notifier(&ahc_linux_notifier);
 }
 
 module_init(ahc_linux_init);
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_osm.h b/drivers/scsi/aic7xxx/aic7xxx_osm.h
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.h	Sun Apr 20 14:14:29 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.h	Mon May 12 20:52:59 2003
@@ -53,7 +53,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#131 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_osm.h#142 $
  *
  */
 #ifndef _AIC7XXX_LINUX_H_
@@ -150,8 +150,8 @@
 #endif /* BYTE_ORDER */
 
 /************************* Configuration Data *********************************/
-extern int aic7xxx_no_probe;
-extern int aic7xxx_allow_memio;
+extern u_int aic7xxx_no_probe;
+extern u_int aic7xxx_allow_memio;
 extern int aic7xxx_detect_complete;
 extern Scsi_Host_Template aic7xxx_driver_template;
 
@@ -258,7 +258,7 @@
 typedef struct timer_list ahc_timer_t;
 
 /********************************** Includes **********************************/
-#if CONFIG_AIC7XXX_REG_PRETTY_PRINT
+#ifdef CONFIG_AIC7XXX_REG_PRETTY_PRINT
 #define AIC_DEBUG_REGISTERS 1
 #else
 #define AIC_DEBUG_REGISTERS 0
@@ -267,7 +267,7 @@
 
 /***************************** Timer Facilities *******************************/
 #define ahc_timer_init init_timer
-#define ahc_timer_stop del_timer
+#define ahc_timer_stop del_timer_sync
 typedef void ahc_linux_callback_t (u_long);  
 static __inline void ahc_timer_reset(ahc_timer_t *timer, int usec,
 				     ahc_callback_t *func, void *arg);
@@ -305,7 +305,7 @@
 #define AHC_SCSI_HAS_HOST_LOCK 0
 #endif
 
-#define AIC7XXX_DRIVER_VERSION "6.2.31"
+#define AIC7XXX_DRIVER_VERSION "6.2.33"
 
 /**************************** Front End Queues ********************************/
 /*
@@ -494,7 +494,18 @@
  * manner and are allocated below 4GB, the number of S/G segments is
  * unrestricted.
  */
-#define        AHC_NSEG 128
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+/*
+ * We dynamically adjust the number of segments in pre-2.5 kernels to
+ * avoid fragmentation issues in the SCSI mid-layer's private memory
+ * allocator.  See aic7xxx_osm.c ahc_linux_size_nseg() for details.
+ */
+extern u_int ahc_linux_nseg;
+#define	AHC_NSEG ahc_linux_nseg
+#define	AHC_LINUX_MIN_NSEG 64
+#else
+#define	AHC_NSEG 128
+#endif
 
 /*
  * Per-SCB OSM storage.
@@ -538,9 +549,7 @@
 	TAILQ_HEAD(, ahc_linux_device) device_runq;
 	struct ahc_completeq	 completeq;
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
 	spinlock_t		 spin_lock;
-#endif
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
 	struct tasklet_struct	 runq_tasklet;
 #endif
@@ -699,7 +708,6 @@
 static __inline void ahc_list_lock(unsigned long *flags);
 static __inline void ahc_list_unlock(unsigned long *flags);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,93)
 static __inline void
 ahc_lockinit(struct ahc_softc *ahc)
 {
@@ -729,7 +737,8 @@
 	 * trade the io_request_lock for our per-softc lock.
 	 */
 #if AHC_SCSI_HAS_HOST_LOCK == 0
-	ahc_lock(ahc, flags);
+	spin_unlock(&io_request_lock);
+	spin_lock(&ahc->platform_data->spin_lock);
 #endif
 }
 
@@ -737,7 +746,8 @@
 ahc_midlayer_entrypoint_unlock(struct ahc_softc *ahc, unsigned long *flags)
 {
 #if AHC_SCSI_HAS_HOST_LOCK == 0
-	ahc_unlock(ahc, flags);
+	spin_unlock(&ahc->platform_data->spin_lock);
+	spin_lock(&io_request_lock);
 #endif
 }
 
@@ -768,7 +778,7 @@
 }
 
 static __inline void
-ahc_list_lockinit()
+ahc_list_lockinit(void)
 {
 	spin_lock_init(&ahc_list_spinlock);
 }
@@ -785,65 +795,6 @@
 	spin_unlock_irqrestore(&ahc_list_spinlock, *flags);
 }
 
-#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,93) */
-
-static __inline void
-ahc_lockinit(struct ahc_softc *ahc)
-{
-}
-
-static __inline void
-ahc_lock(struct ahc_softc *ahc, unsigned long *flags)
-{
-	save_flags(*flags);
-	cli();
-}
-
-static __inline void
-ahc_unlock(struct ahc_softc *ahc, unsigned long *flags)
-{
-	restore_flags(*flags);
-}
-
-static __inline void
-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)
-{
-}
-
-static __inline void
-ahc_list_lockinit()
-{
-}
-
-static __inline void
-ahc_list_lock(unsigned long *flags)
-{
-	save_flags(*flags);
-	cli();
-}
-
-static __inline void
-ahc_list_unlock(unsigned long *flags)
-{
-	restore_flags(*flags);
-}
-#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0) */
-
 /******************************* PCI Definitions ******************************/
 /*
  * PCIM_xxx: mask to locate subfield in register
@@ -902,16 +853,6 @@
 int			 aic7770_map_int(struct ahc_softc *ahc, u_int irq);
 
 /******************************* 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 supported under 2.1.92 and above"
-#endif
-#include <linux/bios32.h>
-#endif
-
 int			 ahc_linux_pci_init(void);
 void			 ahc_linux_pci_exit(void);
 int			 ahc_pci_map_registers(struct ahc_softc *ahc);
@@ -1224,7 +1165,8 @@
 int	ahc_platform_abort_scbs(struct ahc_softc *ahc, int target,
 				char channel, int lun, u_int tag,
 				role_t role, uint32_t status);
-irqreturn_t ahc_linux_isr(int irq, void *dev_id, struct pt_regs * regs);
+AIC_LINUX_IRQRETURN_T
+	ahc_linux_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*);
@@ -1239,5 +1181,5 @@
 #define AHC_PCI_CONFIG 0
 #endif
 #define bootverbose aic7xxx_verbose
-extern int aic7xxx_verbose;
+extern u_int aic7xxx_verbose;
 #endif /* _AIC7XXX_LINUX_H_ */
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_pci.c b/drivers/scsi/aic7xxx/aic7xxx_pci.c
--- a/drivers/scsi/aic7xxx/aic7xxx_pci.c	Tue Mar 25 16:32:23 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_pci.c	Mon May 12 20:53:00 2003
@@ -39,7 +39,7 @@
  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGES.
  *
- * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#62 $
+ * $Id: //depot/aic7xxx/aic7xxx/aic7xxx_pci.c#63 $
  *
  * $FreeBSD$
  */
@@ -837,14 +837,6 @@
 	command = ahc_pci_read_config(ahc->dev_softc, PCIR_COMMAND, /*bytes*/1);
 	command |= PCIM_CMD_BUSMASTEREN;
 
-	/*
-	 * Disable PCI parity error reporting.  Users typically
-	 * do this to work around broken PCI chipsets that get
-	 * the parity timing wrong and thus generate lots of spurious
-	 * errors.
-	 */
-	if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0)
-		command &= ~PCIM_CMD_PERRESPEN;
 	ahc_pci_write_config(ahc->dev_softc, PCIR_COMMAND, command, /*bytes*/1);
 
 	/* On all PCI adapters, we allow SCB paging */
@@ -854,6 +846,19 @@
 	if (error != 0)
 		return (error);
 
+	/*
+	 * Disable PCI parity error checking.  Users typically
+	 * do this to work around broken PCI chipsets that get
+	 * the parity timing wrong and thus generate lots of spurious
+	 * errors.  The chip only allows us to disable *all* parity
+	 * error reporting when doing this, so CIO bus, scb ram, and
+	 * scratch ram parity errors will be ignored too.
+	 */
+	if ((ahc->flags & AHC_DISABLE_PCI_PERR) != 0) {
+		ahc->pause |= FAILDIS;
+		ahc->unpause |= FAILDIS;
+	}
+
 	ahc->bus_intr = ahc_pci_intr;
 	ahc->bus_chip_init = ahc_pci_chip_init;
 	ahc->bus_suspend = ahc_pci_suspend;
@@ -1958,8 +1963,7 @@
 }
 
 static uint8_t
-read_brdctl(ahc)
-	struct 	ahc_softc *ahc;
+read_brdctl(struct ahc_softc *ahc)
 {
 	uint8_t brdctl;
 	uint8_t value;
@@ -1998,6 +2002,7 @@
 	      ahc_inb(ahc, SEQADDR0) | (ahc_inb(ahc, SEQADDR1) << 8));
 
 	if (status1 & DPE) {
+		ahc->pci_target_perr_count++;
 		printf("%s: Data Parity Error Detected during address "
 		       "or write data phase\n", ahc_name(ahc));
 	}
@@ -2029,6 +2034,19 @@
 		ahc_outb(ahc, CLRINT, CLRPARERR);
 	}
 
+	if (ahc->pci_target_perr_count > AHC_PCI_TARGET_PERR_THRESH) {
+		printf(
+"%s: WARNING WARNING WARNING WARNING\n"
+"%s: Too many PCI parity errors observed as a target.\n"
+"%s: Some device on this bus is generating bad parity.\n"
+"%s: This is an error *observed by*, not *generated by*, this controller.\n"
+"%s: PCI parity error checking has been disabled.\n"
+"%s: WARNING WARNING WARNING WARNING\n",
+		       ahc_name(ahc), ahc_name(ahc), ahc_name(ahc),
+		       ahc_name(ahc), ahc_name(ahc), ahc_name(ahc));
+		ahc->pause |= FAILDIS;
+		ahc->unpause |= FAILDIS;
+	}
 	ahc_unpause(ahc);
 }
 
diff -Nru a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c	Thu Feb 20 14:50:09 2003
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c	Thu Apr 24 14:10:07 2003
@@ -37,7 +37,7 @@
  * String handling code courtesy of Gerard Roudier's <groudier@club-internet.fr>
  * sym driver.
  *
- * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#24 $
+ * $Id: //depot/aic7xxx/linux/drivers/scsi/aic7xxx/aic7xxx_proc.c#27 $
  */
 #include "aic7xxx_osm.h"
 #include "aic7xxx_inline.h"
@@ -148,8 +148,9 @@
 
 	tinfo = ahc_fetch_transinfo(ahc, channel, our_id,
 				    target_id, &tstate);
-	copy_info(info, "Channel %c Target %d Negotiation Settings\n",
-		  channel, target_id);
+	if ((ahc->features & AHC_TWIN) != 0)
+		copy_info(info, "Channel %c ", channel);
+	copy_info(info, "Target %d Negotiation Settings\n", target_id);
 	copy_info(info, "\tUser: ");
 	ahc_format_transinfo(info, &tinfo->user);
 	targ = ahc->platform_data->targets[target_offset];
@@ -327,7 +328,10 @@
 		  AIC7XXX_DRIVER_VERSION);
 	copy_info(&info, "%s\n", ahc->description);
 	ahc_controller_info(ahc, ahc_info);
-	copy_info(&info, "%s\n\n", ahc_info);
+	copy_info(&info, "%s\n", ahc_info);
+	copy_info(&info, "Allocated SCBs: %d, SG List Length: %d\n\n",
+		  ahc->scb_data->numscbs, AHC_NSEG);
+
 
 	if (ahc->seep_config == NULL)
 		copy_info(&info, "No Serial EEPROM\n");
diff -Nru a/drivers/scsi/aic7xxx/aiclib.c b/drivers/scsi/aic7xxx/aiclib.c
--- a/drivers/scsi/aic7xxx/aiclib.c	Tue Mar 25 16:03:44 2003
+++ b/drivers/scsi/aic7xxx/aiclib.c	Wed Apr  9 10:56:06 2003
@@ -1335,7 +1335,7 @@
 
 char *
 aic_parse_brace_option(char *opt_name, char *opt_arg, char *end, int depth,
-		       aic_option_callback_t *callback, void *callback_arg)
+		       aic_option_callback_t *callback, u_long callback_arg)
 {
 	char	*tok_end;
 	char	*tok_end2;
diff -Nru a/drivers/scsi/aic7xxx/aiclib.h b/drivers/scsi/aic7xxx/aiclib.h
--- a/drivers/scsi/aic7xxx/aiclib.h	Tue Mar 25 16:03:44 2003
+++ b/drivers/scsi/aic7xxx/aiclib.h	Thu Apr 24 14:12:34 2003
@@ -15,15 +15,58 @@
  * Ported to run under 386BSD by Julian Elischer (julian@tfs.com) Sept 1992
  *
  * $FreeBSD: src/sys/cam/scsi/scsi_all.h,v 1.21 2002/10/08 17:12:44 ken Exp $
+ *
+ * Copyright (c) 2003 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. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    substantially similar to the "NO WARRANTY" disclaimer below
+ *    ("Disclaimer") and any redistribution must be conditioned upon
+ *    including a substantially similar Disclaimer requirement for further
+ *    binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may 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 General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
  * $Id$
  */
 
+#ifndef	_AICLIB_H
+#define _AICLIB_H
+
 /*
- * SCSI general  interface description
+ * Linux Interrupt Support.
  */
-
-#ifndef	_SCSI_SCSI_ALL_H
-#define _SCSI_SCSI_ALL_H 1
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+#define	AIC_LINUX_IRQRETURN_T irqreturn_t
+#define	AIC_LINUX_IRQRETURN(ours) return (IRQ_RETVAL(ours))
+#else
+#define	AIC_LINUX_IRQRETURN_T void
+#define	AIC_LINUX_IRQRETURN(ours)  return
+#endif
 
 /*
  * SCSI command format
@@ -906,10 +949,10 @@
 int		aic_static_inquiry_match(caddr_t /*inqbuffer*/,
 					 caddr_t /*table_entry*/);
 
-typedef void aic_option_callback_t(void *, int, int, int32_t);
+typedef void aic_option_callback_t(u_long, int, int, int32_t);
 char *		aic_parse_brace_option(char *opt_name, char *opt_arg,
 				       char *end, int depth,
-				       aic_option_callback_t *, void *);
+				       aic_option_callback_t *, u_long);
 
 static __inline void	 scsi_extract_sense(struct scsi_sense_data *sense,
 					    int *error_code, int *sense_key,
@@ -1003,4 +1046,4 @@
 	return (rv);
 }
 
-#endif /*_SCSI_SCSI_ALL_H*/
+#endif /*_AICLIB_H */
diff -Nru a/drivers/scsi/aic7xxx_old/aic7xxx.h b/drivers/scsi/aic7xxx_old/aic7xxx.h
--- a/drivers/scsi/aic7xxx_old/aic7xxx.h	Sat Mar  1 07:43:30 2003
+++ b/drivers/scsi/aic7xxx_old/aic7xxx.h	Wed May  7 07:19:49 2003
@@ -25,48 +25,4 @@
 
 #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	{						\
-	.proc_info		= aic7xxx_proc_info,		\
-	.detect			= aic7xxx_detect,		\
-	.release		= aic7xxx_release,		\
-	.info			= aic7xxx_info,			\
-	.queuecommand		= aic7xxx_queue,		\
-	.slave_alloc		= aic7xxx_slave_alloc,		\
-	.slave_configure	= aic7xxx_slave_configure,	\
-	.slave_destroy		= aic7xxx_slave_destroy,	\
-	.bios_param		= aic7xxx_biosparam,		\
-	.eh_abort_handler	= aic7xxx_abort,		\
-	.eh_device_reset_handler	= aic7xxx_bus_device_reset,	\
-	.eh_host_reset_handler	= aic7xxx_reset,			\
-	.can_queue		= 255,	/* max simultaneous cmds      */\
-	.this_id		= -1,	/* scsi id of host adapter    */\
-	.sg_tablesize		= 0,	/* max scatter-gather cmds    */\
-	.max_sectors		= 2048,	/* max physical sectors in 1 cmd */\
-	.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,			\
-}
-
-extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
-extern int aic7xxx_biosparam(struct scsi_device *, struct block_device *,
-		sector_t, int[]);
-extern int aic7xxx_detect(Scsi_Host_Template *);
-extern int aic7xxx_command(Scsi_Cmnd *);
-extern int aic7xxx_release(struct Scsi_Host *);
-static int aic7xxx_slave_alloc(Scsi_Device *);
-static int aic7xxx_slave_configure(Scsi_Device *);
-static void aic7xxx_slave_destroy(Scsi_Device *);
-extern int aic7xxx_abort(Scsi_Cmnd *);
-extern int aic7xxx_bus_device_reset(Scsi_Cmnd *);
-extern int aic7xxx_reset(Scsi_Cmnd *);
-
-extern const char *aic7xxx_info(struct Scsi_Host *);
-
-extern int aic7xxx_proc_info(char *, char **, off_t, int, int, int);
-
 #endif /* _aic7xxx_h */
diff -Nru a/drivers/scsi/aic7xxx_old.c b/drivers/scsi/aic7xxx_old.c
--- a/drivers/scsi/aic7xxx_old.c	Sun Apr 20 23:56:10 2003
+++ b/drivers/scsi/aic7xxx_old.c	Wed May  7 07:38:54 2003
@@ -1270,6 +1270,7 @@
  *
  ***************************************************************************/
 
+static int aic7xxx_release(struct Scsi_Host *host);
 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,
@@ -8361,7 +8362,7 @@
  *   Perform a chip reset on the aic7xxx SCSI controller.  The controller
  *   is paused upon return.
  *-F*************************************************************************/
-int
+static int
 aic7xxx_chip_reset(struct aic7xxx_host *p)
 {
   unsigned char sblkctl;
@@ -8996,7 +8997,7 @@
  *       one do-it-all function.  This may be useful when (and if) the
  *       mid-level SCSI code is overhauled.
  *-F*************************************************************************/
-int
+static int
 aic7xxx_detect(Scsi_Host_Template *template)
 {
   struct aic7xxx_host *temp_p = NULL;
@@ -10293,7 +10294,7 @@
  * Description:
  *   Queue a SCB to the controller.
  *-F*************************************************************************/
-int
+static int
 aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
 {
   struct aic7xxx_host *p;
@@ -10364,7 +10365,7 @@
  *   aborted, then we will reset the channel and have all devices renegotiate.
  *   Returns an enumerated type that indicates the status of the operation.
  *-F*************************************************************************/
-int
+static int
 aic7xxx_bus_device_reset(Scsi_Cmnd *cmd)
 {
   struct aic7xxx_host  *p;
@@ -10566,7 +10567,7 @@
  * Description:
  *   Abort the current SCSI command(s).
  *-F*************************************************************************/
-void
+static void
 aic7xxx_panic_abort(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
 {
 
@@ -10592,7 +10593,7 @@
  * Description:
  *   Abort the current SCSI command(s).
  *-F*************************************************************************/
-int
+static int
 aic7xxx_abort(Scsi_Cmnd *cmd)
 {
   struct aic7xxx_scb  *scb = NULL;
@@ -10820,7 +10821,7 @@
  *   DEVICE RESET message - on the offending target before pulling
  *   the SCSI bus reset line.
  *-F*************************************************************************/
-int
+static int
 aic7xxx_reset(Scsi_Cmnd *cmd)
 {
   struct aic7xxx_scb *scb;
@@ -10905,7 +10906,7 @@
  *   This function is broken for today's really large drives and needs
  *   fixed.
  *-F*************************************************************************/
-int
+static int
 aic7xxx_biosparam(struct scsi_device *sdev, struct block_device *bdev,
 		sector_t capacity, int geom[])
 {
@@ -10955,7 +10956,7 @@
  *   Free the passed in Scsi_Host memory structures prior to unloading the
  *   module.
  *-F*************************************************************************/
-int
+static int
 aic7xxx_release(struct Scsi_Host *host)
 {
   struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
@@ -11141,8 +11142,25 @@
 MODULE_LICENSE("Dual BSD/GPL");
 
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = AIC7XXX;
+static Scsi_Host_Template driver_template = {
+	.proc_info		= aic7xxx_proc_info,
+	.detect			= aic7xxx_detect,
+	.release		= aic7xxx_release,
+	.info			= aic7xxx_info,	
+	.queuecommand		= aic7xxx_queue,
+	.slave_alloc		= aic7xxx_slave_alloc,
+	.slave_configure	= aic7xxx_slave_configure,
+	.slave_destroy		= aic7xxx_slave_destroy,
+	.bios_param		= aic7xxx_biosparam,
+	.eh_abort_handler	= aic7xxx_abort,
+	.eh_device_reset_handler	= aic7xxx_bus_device_reset,
+	.eh_host_reset_handler	= aic7xxx_reset,
+	.can_queue		= 255,
+	.this_id		= -1,
+	.max_sectors		= 2048,
+	.cmd_per_lun		= 3,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
 
 #include "scsi_module.c"
 
diff -Nru a/drivers/scsi/arm/Kconfig b/drivers/scsi/arm/Kconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/Kconfig	Thu May 15 17:33:13 2003
@@ -0,0 +1,89 @@
+#
+# SCSI driver configuration for Acorn
+#
+config SCSI_ACORNSCSI_3
+	tristate "Acorn SCSI card (aka30) support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  This enables support for the Acorn SCSI card (aka30). If you have an
+	  Acorn system with one of these, say Y. If unsure, say N.
+
+config SCSI_ACORNSCSI_TAGGED_QUEUE
+	bool "Support SCSI 2 Tagged queueing"
+	depends on SCSI_ACORNSCSI_3
+	help
+	  Say Y here to enable tagged queuing support on the Acorn SCSI card.
+
+	  This is a feature of SCSI-2 which improves performance: the host
+	  adapter can send several SCSI commands to a device's queue even if
+	  previous commands haven't finished yet. Some SCSI devices don't
+	  implement this properly, so the safe answer is N.
+
+config SCSI_ACORNSCSI_SYNC
+	bool "Support SCSI 2 Synchronous Transfers"
+	depends on SCSI_ACORNSCSI_3
+	help
+	  Say Y here to enable synchronous transfer negotiation with all
+	  targets on the Acorn SCSI card.
+
+	  In general, this improves performance; however some SCSI devices
+	  don't implement it properly, so the safe answer is N.
+
+config SCSI_ARXESCSI
+	tristate "ARXE SCSI support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  Around 1991, Arxe Systems Limited released a high density floppy
+	  disc interface for the Acorn Archimedes range, to allow the use of
+	  HD discs from the then new A5000 on earlier models. This interface
+	  was either sold on its own or with an integral SCSI controller.
+	  Technical details on this NCR53c94-based device are available at
+	  <http://www.cryton.demon.co.uk/acornbits/scsi_arxe.html>
+	  Say Y here to compile in support for the SCSI controller.
+
+config SCSI_CUMANA_2
+	tristate "CumanaSCSI II support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  This enables support for the Cumana SCSI II card. If you have an
+	  Acorn system with one of these, say Y. If unsure, say N.
+
+config SCSI_EESOXSCSI
+	tristate "EESOX support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  This enables support for the EESOX SCSI card. If you have an Acorn
+	  system with one of these, say Y, otherwise say N.
+
+config SCSI_POWERTECSCSI
+	tristate "PowerTec support"
+	depends on ARCH_ACORN && SCSI
+	help
+	  This enables support for the Powertec SCSI card on Acorn systems. If
+	  you have one of these, say Y. If unsure, say N.
+
+comment "The following drivers are not fully supported"
+	depends on ARCH_ACORN && EXPERIMENTAL
+
+config SCSI_CUMANA_1
+	tristate "CumanaSCSI I support (EXPERIMENTAL)"
+	depends on ARCH_ACORN && EXPERIMENTAL && SCSI
+	help
+	  This enables support for the Cumana SCSI I card. If you have an
+	  Acorn system with one of these, say Y. If unsure, say N.
+
+config SCSI_ECOSCSI
+	tristate "EcoScsi support (EXPERIMENTAL)"
+	depends on ARCH_ACORN && EXPERIMENTAL && (ARCH_ARC || ARCH_A5K) && SCSI
+	help
+	  This enables support for the EcoSCSI card -- a small card that sits
+	  in the Econet socket. If you have an Acorn system with one of these,
+	  say Y. If unsure, say N.
+
+config SCSI_OAK1
+	tristate "Oak SCSI support (EXPERIMENTAL)"
+	depends on ARCH_ACORN && EXPERIMENTAL && SCSI
+	help
+	  This enables support for the Oak SCSI card. If you have an Acorn
+	  system with one of these, say Y. If unsure, say N.
+
diff -Nru a/drivers/scsi/arm/Makefile b/drivers/scsi/arm/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/Makefile	Sat May 17 06:52:31 2003
@@ -0,0 +1,14 @@
+#
+# Makefile for drivers/scsi/arm
+#
+
+acornscsi_mod-objs	:= acornscsi.o acornscsi-io.o
+
+obj-$(CONFIG_SCSI_ACORNSCSI_3)	+= acornscsi_mod.o queue.o msgqueue.o
+obj-$(CONFIG_SCSI_ARXESCSI)	+= arxescsi.o fas216.o queue.o msgqueue.o
+obj-$(CONFIG_SCSI_CUMANA_1)	+= cumana_1.o
+obj-$(CONFIG_SCSI_CUMANA_2)	+= cumana_2.o fas216.o queue.o msgqueue.o
+obj-$(CONFIG_SCSI_ECOSCSI)	+= ecoscsi.o
+obj-$(CONFIG_SCSI_OAK1)		+= oak.o
+obj-$(CONFIG_SCSI_POWERTECSCSI)	+= powertec.o fas216.o queue.o msgqueue.o
+obj-$(CONFIG_SCSI_EESOXSCSI)	+= eesox.o fas216.o queue.o msgqueue.o
diff -Nru a/drivers/scsi/arm/acornscsi-io.S b/drivers/scsi/arm/acornscsi-io.S
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/acornscsi-io.S	Thu May 15 17:33:13 2003
@@ -0,0 +1,145 @@
+/*
+ *  linux/drivers/acorn/scsi/acornscsi-io.S: Acorn SCSI card IO
+ *
+ * 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/linkage.h>
+
+#include <asm/assembler.h>
+#include <asm/hardware.h>
+
+#if (IO_BASE == (PCIO_BASE & 0xff000000))
+#define ADDR(off,reg)						\
+		tst	off, $0x80000000			;\
+		mov	reg, $IO_BASE				;\
+		orreq	reg, reg, $(PCIO_BASE & 0x00ff0000)
+#else
+#define ADDR(off,reg)						\
+		tst	off, $0x80000000			;\
+		movne	reg, $IO_BASE				;\
+		moveq	reg, $(PCIO_BASE & 0xff000000)		;\
+		orreq	reg, reg, $(PCIO_BASE & 0x00ff0000)
+#endif
+
+@ Purpose: transfer a block of data from the acorn scsi card to memory
+@ Proto  : void acornscsi_in(unsigned int addr_start, char *buffer, int length)
+@ Returns: nothing
+
+		.align
+ENTRY(__acornscsi_in)
+		stmfd	sp!, {r4 - r7, lr}
+		bic	r0, r0, #3
+		mov	lr, #0xff
+		orr	lr, lr, #0xff00
+acornscsi_in16lp:
+		subs	r2, r2, #16
+		bmi	acornscsi_in8
+		ldmia	r0!, {r3, r4, r5, r6}
+		and	r3, r3, lr
+		orr	r3, r3, r4, lsl #16
+		and 	r4, r5, lr
+		orr	r4, r4, r6, lsl #16
+		ldmia	r0!, {r5, r6, r7, ip}
+		and	r5, r5, lr
+		orr	r5, r5, r6, lsl #16
+		and	r6, r7, lr
+		orr	r6, r6, ip, lsl #16
+		stmia	r1!, {r3 - r6}
+		bne	acornscsi_in16lp
+		LOADREGS(fd, sp!, {r4 - r7, pc})
+
+acornscsi_in8:	adds	r2, r2, #8
+		bmi	acornscsi_in4
+		ldmia	r0!, {r3, r4, r5, r6}
+		and	r3, r3, lr
+		orr	r3, r3, r4, lsl #16
+		and	r4, r5, lr
+		orr	r4, r4, r6, lsl #16
+		stmia	r1!, {r3 - r4}
+		LOADREGS(eqfd, sp!, {r4 - r7, pc})
+		sub	r2, r2, #8
+
+acornscsi_in4:	adds	r2, r2, #4
+		bmi	acornscsi_in2
+		ldmia	r0!, {r3, r4}
+		and	r3, r3, lr
+		orr	r3, r3, r4, lsl #16
+		str	r3, [r1], #4
+		LOADREGS(eqfd, sp!, {r4 - r7, pc})
+		sub	r2, r2, #4
+
+acornscsi_in2:	adds	r2, r2, #2
+		ldr	r3, [r0], #4
+		and	r3, r3, lr
+		strb	r3, [r1], #1
+		mov	r3, r3, lsr #8
+		strplb	r3, [r1], #1
+		LOADREGS(fd, sp!, {r4 - r7, pc})
+
+@ Purpose: transfer a block of data from memory to the acorn scsi card
+@ Proto  : void acornscsi_in(unsigned int addr_start, char *buffer, int length)
+@ Returns: nothing
+
+ENTRY(__acornscsi_out)
+		stmfd	sp!, {r4 - r6, lr}
+		bic	r0, r0, #3
+acornscsi_out16lp:
+		subs	r2, r2, #16
+		bmi	acornscsi_out8
+		ldmia	r1!, {r4, r6, ip, lr}
+		mov	r3, r4, lsl #16
+		orr	r3, r3, r3, lsr #16
+		mov	r4, r4, lsr #16
+		orr	r4, r4, r4, lsl #16
+		mov	r5, r6, lsl #16
+		orr	r5, r5, r5, lsr #16
+		mov	r6, r6, lsr #16
+		orr	r6, r6, r6, lsl #16
+		stmia	r0!, {r3, r4, r5, r6}
+		mov	r3, ip, lsl #16
+		orr	r3, r3, r3, lsr #16
+		mov	r4, ip, lsr #16
+		orr	r4, r4, r4, lsl #16
+		mov	ip, lr, lsl #16
+		orr	ip, ip, ip, lsr #16
+		mov	lr, lr, lsr #16
+		orr	lr, lr, lr, lsl #16
+		stmia	r0!, {r3, r4, ip, lr}
+		bne	acornscsi_out16lp
+		LOADREGS(fd, sp!, {r4 - r6, pc})
+
+acornscsi_out8:	adds	r2, r2, #8
+		bmi	acornscsi_out4
+		ldmia	r1!, {r4, r6}
+		mov	r3, r4, lsl #16
+		orr	r3, r3, r3, lsr #16
+		mov	r4, r4, lsr #16
+		orr	r4, r4, r4, lsl #16
+		mov	r5, r6, lsl #16
+		orr	r5, r5, r5, lsr #16
+		mov	r6, r6, lsr #16
+		orr	r6, r6, r6, lsl #16
+		stmia	r0!, {r3, r4, r5, r6}
+		LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
+		sub	r2, r2, #8
+acornscsi_out4:	adds	r2, r2, #4
+		bmi	acornscsi_out2
+		ldr	r4, [r1], #4
+		mov	r3, r4, lsl #16
+		orr	r3, r3, r3, lsr #16
+		mov	r4, r4, lsr #16
+		orr	r4, r4, r4, lsl #16
+		stmia	r0!, {r3, r4}
+		LOADREGS(eqfd, sp!, {r4 - r6, pc})
+
+		sub	r2, r2, #4
+acornscsi_out2:	adds	r2, r2, #2
+		ldr	r3, [r1], #2
+		strb	r3, [r0], #1
+		mov	r3, r3, lsr #8
+		strplb	r3, [r0], #1
+		LOADREGS(fd, sp!, {r4 - r6, pc})
+
diff -Nru a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/acornscsi.c	Sat May 17 11:00:48 2003
@@ -0,0 +1,3126 @@
+/*
+ *  linux/drivers/acorn/scsi/acornscsi.c
+ *
+ *  Acorn SCSI 3 driver
+ *  By R.M.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.
+ *
+ * Abandoned using the Select and Transfer command since there were
+ * some nasty races between our software and the target devices that
+ * were not easy to solve, and the device errata had a lot of entries
+ * for this command, some of them quite nasty...
+ *
+ * Changelog:
+ *  26-Sep-1997	RMK	Re-jigged to use the queue module.
+ *			Re-coded state machine to be based on driver
+ *			state not scsi state.  Should be easier to debug.
+ *			Added acornscsi_release to clean up properly.
+ *			Updated proc/scsi reporting.
+ *  05-Oct-1997	RMK	Implemented writing to SCSI devices.
+ *  06-Oct-1997	RMK	Corrected small (non-serious) bug with the connect/
+ *			reconnect race condition causing a warning message.
+ *  12-Oct-1997	RMK	Added catch for re-entering interrupt routine.
+ *  15-Oct-1997	RMK	Improved handling of commands.
+ *  27-Jun-1998	RMK	Changed asm/delay.h to linux/delay.h.
+ *  13-Dec-1998	RMK	Better abort code and command handling.  Extra state
+ *			transitions added to allow dodgy devices to work.
+ */
+#define DEBUG_NO_WRITE	1
+#define DEBUG_QUEUES	2
+#define DEBUG_DMA	4
+#define DEBUG_ABORT	8
+#define DEBUG_DISCON	16
+#define DEBUG_CONNECT	32
+#define DEBUG_PHASES	64
+#define DEBUG_WRITE	128
+#define DEBUG_LINK	256
+#define DEBUG_MESSAGES	512
+#define DEBUG_RESET	1024
+#define DEBUG_ALL	(DEBUG_RESET|DEBUG_MESSAGES|DEBUG_LINK|DEBUG_WRITE|\
+			 DEBUG_PHASES|DEBUG_CONNECT|DEBUG_DISCON|DEBUG_ABORT|\
+			 DEBUG_DMA|DEBUG_QUEUES)
+
+/* DRIVER CONFIGURATION
+ *
+ * SCSI-II Tagged queue support.
+ *
+ * I don't have any SCSI devices that support it, so it is totally untested
+ * (except to make sure that it doesn't interfere with any non-tagging
+ * devices).  It is not fully implemented either - what happens when a
+ * tagging device reconnects???
+ *
+ * You can tell if you have a device that supports tagged queueing my
+ * cating (eg) /proc/scsi/acornscsi/0 and see if the SCSI revision is reported
+ * as '2 TAG'.
+ *
+ * Also note that CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE is normally set in the config
+ * scripts, but disabled here.  Once debugged, remove the #undef, otherwise to debug,
+ * comment out the undef.
+ */
+#undef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+/*
+ * SCSI-II Linked command support.
+ *
+ * The higher level code doesn't support linked commands yet, and so the option
+ * is undef'd here.
+ */
+#undef CONFIG_SCSI_ACORNSCSI_LINK
+/*
+ * SCSI-II Synchronous transfer support.
+ *
+ * Tried and tested...
+ *
+ * SDTR_SIZE	  - maximum number of un-acknowledged bytes (0 = off, 12 = max)
+ * SDTR_PERIOD	  - period of REQ signal (min=125, max=1020)
+ * DEFAULT_PERIOD - default REQ period.
+ */
+#define SDTR_SIZE	12
+#define SDTR_PERIOD	125
+#define DEFAULT_PERIOD	500
+
+/*
+ * Debugging information
+ *
+ * DEBUG	  - bit mask from list above
+ * DEBUG_TARGET   - is defined to the target number if you want to debug
+ *		    a specific target. [only recon/write/dma].
+ */
+#define DEBUG (DEBUG_RESET|DEBUG_WRITE|DEBUG_NO_WRITE)
+/* only allow writing to SCSI device 0 */
+#define NO_WRITE 0xFE
+/*#define DEBUG_TARGET 2*/
+/*
+ * Select timeout time (in 10ms units)
+ *
+ * This is the timeout used between the start of selection and the WD33C93
+ * chip deciding that the device isn't responding.
+ */
+#define TIMEOUT_TIME 10
+/*
+ * Define this if you want to have verbose explaination of SCSI
+ * status/messages.
+ */
+#undef CONFIG_ACORNSCSI_CONSTANTS
+/*
+ * Define this if you want to use the on board DMAC [don't remove this option]
+ * If not set, then use PIO mode (not currently supported).
+ */
+#define USE_DMAC
+
+/*
+ * ====================================================================================
+ */
+
+#ifdef DEBUG_TARGET
+#define DBG(cmd,xxx...) \
+  if (cmd->device->id == DEBUG_TARGET) { \
+    xxx; \
+  }
+#else
+#define DBG(cmd,xxx...) xxx
+#endif
+
+#ifndef STRINGIFY
+#define STRINGIFY(x) #x
+#endif
+#define STRx(x) STRINGIFY(x)
+#define NO_WRITE_STR STRx(NO_WRITE)
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/ioport.h>
+#include <linux/blk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ecard.h>
+
+#include "../scsi.h"
+#include "../hosts.h"
+#include "acornscsi.h"
+#include "msgqueue.h"
+#include "scsi.h"
+
+#include <scsi/scsicam.h>
+
+#define VER_MAJOR 2
+#define VER_MINOR 0
+#define VER_PATCH 6
+
+#ifndef ABORT_TAG
+#define ABORT_TAG 0xd
+#else
+#error "Yippee!  ABORT TAG is now defined!  Remove this error!"
+#endif
+
+#ifdef CONFIG_SCSI_ACORNSCSI_LINK
+#error SCSI2 LINKed commands not supported (yet)!
+#endif
+
+#ifdef USE_DMAC
+/*
+ * DMAC setup parameters
+ */ 
+#define INIT_DEVCON0	(DEVCON0_RQL|DEVCON0_EXW|DEVCON0_CMP)
+#define INIT_DEVCON1	(DEVCON1_BHLD)
+#define DMAC_READ	(MODECON_READ)
+#define DMAC_WRITE	(MODECON_WRITE)
+#define INIT_SBICDMA	(CTRL_DMABURST)
+
+#define scsi_xferred	have_data_in
+
+/*
+ * Size of on-board DMA buffer
+ */
+#define DMAC_BUFFER_SIZE	65536
+#endif
+
+#define STATUS_BUFFER_TO_PRINT	24
+
+unsigned int sdtr_period = SDTR_PERIOD;
+unsigned int sdtr_size   = SDTR_SIZE;
+
+static void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result);
+static int acornscsi_reconnect_finish(AS_Host *host);
+static void acornscsi_dma_cleanup(AS_Host *host);
+static void acornscsi_abortcmd(AS_Host *host, unsigned char tag);
+
+/* ====================================================================================
+ * Miscellaneous
+ */
+
+static inline void
+sbic_arm_write(unsigned int io_port, int reg, int value)
+{
+    __raw_writeb(reg, io_port);
+    __raw_writeb(value, io_port + 4);
+}
+
+#define sbic_arm_writenext(io,val) \
+	__raw_writeb((val), (io) + 4)
+
+static inline
+int sbic_arm_read(unsigned int io_port, int reg)
+{
+    if(reg == ASR)
+	   return __raw_readl(io_port) & 255;
+    __raw_writeb(reg, io_port);
+    return __raw_readl(io_port + 4) & 255;
+}
+
+#define sbic_arm_readnext(io) \
+	__raw_readb((io) + 4)
+
+#ifdef USE_DMAC
+#define dmac_read(io_port,reg) \
+	inb((io_port) + (reg))
+
+#define dmac_write(io_port,reg,value) \
+	({ outb((value), (io_port) + (reg)); })
+
+#define dmac_clearintr(io_port) \
+	({ outb(0, (io_port)); })
+
+static inline
+unsigned int dmac_address(unsigned int io_port)
+{
+    return dmac_read(io_port, TXADRHI) << 16 |
+	   dmac_read(io_port, TXADRMD) << 8 |
+	   dmac_read(io_port, TXADRLO);
+}
+
+static
+void acornscsi_dumpdma(AS_Host *host, char *where)
+{
+	unsigned int mode, addr, len;
+
+	mode = dmac_read(host->dma.io_port, MODECON);
+	addr = dmac_address(host->dma.io_port);
+	len  = dmac_read(host->dma.io_port, TXCNTHI) << 8 |
+	       dmac_read(host->dma.io_port, TXCNTLO);
+
+	printk("scsi%d: %s: DMAC %02x @%06x+%04x msk %02x, ",
+		host->host->host_no, where,
+		mode, addr, (len + 1) & 0xffff,
+		dmac_read(host->dma.io_port, MASKREG));
+
+	printk("DMA @%06x, ", host->dma.start_addr);
+	printk("BH @%p +%04x, ", host->scsi.SCp.ptr,
+		host->scsi.SCp.this_residual);
+	printk("DT @+%04x ST @+%04x", host->dma.transferred,
+		host->scsi.SCp.scsi_xferred);
+	printk("\n");
+}
+#endif
+
+static
+unsigned long acornscsi_sbic_xfcount(AS_Host *host)
+{
+    unsigned long length;
+
+    length = sbic_arm_read(host->scsi.io_port, TRANSCNTH) << 16;
+    length |= sbic_arm_readnext(host->scsi.io_port) << 8;
+    length |= sbic_arm_readnext(host->scsi.io_port);
+
+    return length;
+}
+
+static int
+acornscsi_sbic_wait(AS_Host *host, int stat_mask, int stat, int timeout, char *msg)
+{
+	int asr;
+
+	do {
+		asr = sbic_arm_read(host->scsi.io_port, ASR);
+
+		if ((asr & stat_mask) == stat)
+			return 0;
+
+		udelay(1);
+	} while (--timeout);
+
+	printk("scsi%d: timeout while %s\n", host->host->host_no, msg);
+
+	return -1;
+}
+
+static
+int acornscsi_sbic_issuecmd(AS_Host *host, int command)
+{
+    if (acornscsi_sbic_wait(host, ASR_CIP, 0, 1000, "issuing command"))
+	return -1;
+
+    sbic_arm_write(host->scsi.io_port, CMND, command);
+
+    return 0;
+}
+
+static void
+acornscsi_csdelay(unsigned int cs)
+{
+    unsigned long target_jiffies, flags;
+
+    target_jiffies = jiffies + 1 + cs * HZ / 100;
+
+    local_save_flags(flags);
+    local_irq_enable();
+
+    while (time_before(jiffies, target_jiffies)) barrier();
+
+    local_irq_restore(flags);
+}
+
+static
+void acornscsi_resetcard(AS_Host *host)
+{
+    unsigned int i, timeout;
+
+    /* assert reset line */
+    host->card.page_reg = 0x80;
+    outb(host->card.page_reg, host->card.io_page);
+
+    /* wait 3 cs.  SCSI standard says 25ms. */
+    acornscsi_csdelay(3);
+
+    host->card.page_reg = 0;
+    outb(host->card.page_reg, host->card.io_page);
+
+    /*
+     * Should get a reset from the card
+     */
+    timeout = 1000;
+    do {
+	if (inb(host->card.io_intr) & 8)
+	    break;
+	udelay(1);
+    } while (--timeout);
+
+    if (timeout == 0)
+	printk("scsi%d: timeout while resetting card\n",
+		host->host->host_no);
+
+    sbic_arm_read(host->scsi.io_port, ASR);
+    sbic_arm_read(host->scsi.io_port, SSR);
+
+    /* setup sbic - WD33C93A */
+    sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
+    sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
+
+    /*
+     * Command should cause a reset interrupt
+     */
+    timeout = 1000;
+    do {
+	if (inb(host->card.io_intr) & 8)
+	    break;
+	udelay(1);
+    } while (--timeout);
+
+    if (timeout == 0)
+	printk("scsi%d: timeout while resetting card\n",
+		host->host->host_no);
+
+    sbic_arm_read(host->scsi.io_port, ASR);
+    if (sbic_arm_read(host->scsi.io_port, SSR) != 0x01)
+	printk(KERN_CRIT "scsi%d: WD33C93A didn't give enhanced reset interrupt\n",
+		host->host->host_no);
+
+    sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
+    sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
+    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
+    sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+
+    host->card.page_reg = 0x40;
+    outb(host->card.page_reg, host->card.io_page);
+
+    /* setup dmac - uPC71071 */
+    dmac_write(host->dma.io_port, INIT, 0);
+#ifdef USE_DMAC
+    dmac_write(host->dma.io_port, INIT, INIT_8BIT);
+    dmac_write(host->dma.io_port, CHANNEL, CHANNEL_0);
+    dmac_write(host->dma.io_port, DEVCON0, INIT_DEVCON0);
+    dmac_write(host->dma.io_port, DEVCON1, INIT_DEVCON1);
+#endif
+
+    host->SCpnt = NULL;
+    host->scsi.phase = PHASE_IDLE;
+    host->scsi.disconnectable = 0;
+
+    memset(host->busyluns, 0, sizeof(host->busyluns));
+
+    for (i = 0; i < 8; i++) {
+	host->device[i].sync_state = SYNC_NEGOCIATE;
+	host->device[i].disconnect_ok = 1;
+    }
+
+    /* wait 25 cs.  SCSI standard says 250ms. */
+    acornscsi_csdelay(25);
+}
+
+/*=============================================================================================
+ * Utility routines (eg. debug)
+ */
+#ifdef CONFIG_ACORNSCSI_CONSTANTS
+static char *acornscsi_interrupttype[] = {
+  "rst",  "suc",  "p/a",  "3",
+  "term", "5",	  "6",	  "7",
+  "serv", "9",	  "a",	  "b",
+  "c",	  "d",	  "e",	  "f"
+};
+
+static signed char acornscsi_map[] = {
+  0,  1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1,  2, -1, -1,  -1, -1,  3, -1,   4,	5,  6,	7,   8,  9, 10, 11,
+ 12, 13, 14, -1,  -1, -1, -1, -1,   4,	5,  6,	7,   8,  9, 10, 11,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ 15, 16, 17, 18,  19, -1, -1, 20,   4,	5,  6,	7,   8,  9, 10, 11,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ 21, 22, -1, -1,  -1, 23, -1, -1,   4,	5,  6,	7,   8,  9, 10, 11,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,
+ -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1,  -1, -1, -1, -1
+};      
+
+static char *acornscsi_interruptcode[] = {
+    /* 0 */
+    "reset - normal mode",	/* 00 */
+    "reset - advanced mode",	/* 01 */
+
+    /* 2 */
+    "sel",			/* 11 */
+    "sel+xfer", 		/* 16 */
+    "data-out", 		/* 18 */
+    "data-in",			/* 19 */
+    "cmd",			/* 1A */
+    "stat",			/* 1B */
+    "??-out",			/* 1C */
+    "??-in",			/* 1D */
+    "msg-out",			/* 1E */
+    "msg-in",			/* 1F */
+
+    /* 12 */
+    "/ACK asserted",		/* 20 */
+    "save-data-ptr",		/* 21 */
+    "{re}sel",			/* 22 */
+
+    /* 15 */
+    "inv cmd",			/* 40 */
+    "unexpected disconnect",	/* 41 */
+    "sel timeout",		/* 42 */
+    "P err",			/* 43 */
+    "P err+ATN",		/* 44 */
+    "bad status byte",		/* 47 */
+
+    /* 21 */
+    "resel, no id",		/* 80 */
+    "resel",			/* 81 */
+    "discon",			/* 85 */
+};
+
+static
+void print_scsi_status(unsigned int ssr)
+{
+    if (acornscsi_map[ssr] != -1)
+	printk("%s:%s",
+		acornscsi_interrupttype[(ssr >> 4)],
+		acornscsi_interruptcode[acornscsi_map[ssr]]);
+    else
+	printk("%X:%X", ssr >> 4, ssr & 0x0f);    
+}    
+#endif
+
+static
+void print_sbic_status(int asr, int ssr, int cmdphase)
+{
+#ifdef CONFIG_ACORNSCSI_CONSTANTS
+    printk("sbic: %c%c%c%c%c%c ",
+	    asr & ASR_INT ? 'I' : 'i',
+	    asr & ASR_LCI ? 'L' : 'l',
+	    asr & ASR_BSY ? 'B' : 'b',
+	    asr & ASR_CIP ? 'C' : 'c',
+	    asr & ASR_PE  ? 'P' : 'p',
+	    asr & ASR_DBR ? 'D' : 'd');
+    printk("scsi: ");
+    print_scsi_status(ssr);
+    printk(" ph %02X\n", cmdphase);
+#else
+    printk("sbic: %02X scsi: %X:%X ph: %02X\n",
+	    asr, (ssr & 0xf0)>>4, ssr & 0x0f, cmdphase);
+#endif
+}
+
+static void
+acornscsi_dumplogline(AS_Host *host, int target, int line)
+{
+	unsigned long prev;
+	signed int ptr;
+
+	ptr = host->status_ptr[target] - STATUS_BUFFER_TO_PRINT;
+	if (ptr < 0)
+		ptr += STATUS_BUFFER_SIZE;
+
+	printk("%c: %3s:", target == 8 ? 'H' : '0' + target,
+		line == 0 ? "ph" : line == 1 ? "ssr" : "int");
+
+	prev = host->status[target][ptr].when;
+
+	for (; ptr != host->status_ptr[target]; ptr = (ptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
+		unsigned long time_diff;
+
+		if (!host->status[target][ptr].when)
+			continue;
+
+		switch (line) {
+		case 0:
+			printk("%c%02X", host->status[target][ptr].irq ? '-' : ' ',
+					 host->status[target][ptr].ph);
+			break;
+
+		case 1:
+			printk(" %02X", host->status[target][ptr].ssr);
+			break;
+
+		case 2:
+			time_diff = host->status[target][ptr].when - prev;
+			prev = host->status[target][ptr].when;
+			if (time_diff == 0)
+				printk("==^");
+			else if (time_diff >= 100)
+				printk("   ");
+			else
+				printk(" %02ld", time_diff);
+			break;
+		}
+	}
+
+	printk("\n");
+}
+
+static
+void acornscsi_dumplog(AS_Host *host, int target)
+{
+    do {
+	acornscsi_dumplogline(host, target, 0);
+	acornscsi_dumplogline(host, target, 1);
+	acornscsi_dumplogline(host, target, 2);
+
+	if (target == 8)
+	    break;
+
+	target = 8;
+    } while (1);
+}
+
+static
+char acornscsi_target(AS_Host *host)
+{
+	if (host->SCpnt)
+		return '0' + host->SCpnt->device->id;
+	return 'H';
+}
+
+/*
+ * Prototype: cmdtype_t acornscsi_cmdtype(int command)
+ * Purpose  : differentiate READ from WRITE from other commands
+ * Params   : command - command to interpret
+ * Returns  : CMD_READ	- command reads data,
+ *	      CMD_WRITE - command writes data,
+ *	      CMD_MISC	- everything else
+ */
+static inline
+cmdtype_t acornscsi_cmdtype(int command)
+{
+    switch (command) {
+    case WRITE_6:  case WRITE_10:  case WRITE_12:
+	return CMD_WRITE;
+    case READ_6:   case READ_10:   case READ_12:
+	return CMD_READ;
+    default:
+	return CMD_MISC;
+    }
+}
+
+/*
+ * Prototype: int acornscsi_datadirection(int command)
+ * Purpose  : differentiate between commands that have a DATA IN phase
+ *	      and a DATA OUT phase
+ * Params   : command - command to interpret
+ * Returns  : DATADIR_OUT - data out phase expected
+ *	      DATADIR_IN  - data in phase expected
+ */
+static
+datadir_t acornscsi_datadirection(int command)
+{
+    switch (command) {
+    case CHANGE_DEFINITION:	case COMPARE:		case COPY:
+    case COPY_VERIFY:		case LOG_SELECT:	case MODE_SELECT:
+    case MODE_SELECT_10:	case SEND_DIAGNOSTIC:	case WRITE_BUFFER:
+    case FORMAT_UNIT:		case REASSIGN_BLOCKS:	case RESERVE:
+    case SEARCH_EQUAL:		case SEARCH_HIGH:	case SEARCH_LOW:
+    case WRITE_6:		case WRITE_10:		case WRITE_VERIFY:
+    case UPDATE_BLOCK:		case WRITE_LONG:	case WRITE_SAME:
+    case SEARCH_HIGH_12:	case SEARCH_EQUAL_12:	case SEARCH_LOW_12:
+    case WRITE_12:		case WRITE_VERIFY_12:	case SET_WINDOW:
+    case MEDIUM_SCAN:		case SEND_VOLUME_TAG:	case 0xea:
+	return DATADIR_OUT;
+    default:
+	return DATADIR_IN;
+    }
+}
+
+/*
+ * Purpose  : provide values for synchronous transfers with 33C93.
+ * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ *	Modified by Russell King for 8MHz WD33C93A
+ */
+static struct sync_xfer_tbl {
+    unsigned int period_ns;
+    unsigned char reg_value;
+} sync_xfer_table[] = {
+    {	1, 0x20 },    { 249, 0x20 },	{ 374, 0x30 },
+    { 499, 0x40 },    { 624, 0x50 },	{ 749, 0x60 },
+    { 874, 0x70 },    { 999, 0x00 },	{   0,	  0 }
+};
+
+/*
+ * Prototype: int acornscsi_getperiod(unsigned char syncxfer)
+ * Purpose  : period for the synchronous transfer setting
+ * Params   : syncxfer SYNCXFER register value
+ * Returns  : period in ns.
+ */
+static
+int acornscsi_getperiod(unsigned char syncxfer)
+{
+    int i;
+
+    syncxfer &= 0xf0;
+    if (syncxfer == 0x10)
+	syncxfer = 0;
+
+    for (i = 1; sync_xfer_table[i].period_ns; i++)
+	if (syncxfer == sync_xfer_table[i].reg_value)
+	    return sync_xfer_table[i].period_ns;
+    return 0;
+}
+
+/*
+ * Prototype: int round_period(unsigned int period)
+ * Purpose  : return index into above table for a required REQ period
+ * Params   : period - time (ns) for REQ
+ * Returns  : table index
+ * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ */
+static inline
+int round_period(unsigned int period)
+{
+    int i;
+
+    for (i = 1; sync_xfer_table[i].period_ns; i++) {
+	if ((period <= sync_xfer_table[i].period_ns) &&
+	    (period > sync_xfer_table[i - 1].period_ns))
+	    return i;
+    }
+    return 7;
+}
+
+/*
+ * Prototype: unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
+ * Purpose  : calculate value for 33c93s SYNC register
+ * Params   : period - time (ns) for REQ
+ *	      offset - offset in bytes between REQ/ACK
+ * Returns  : value for SYNC register
+ * Copyright: Copyright (c) 1996 John Shifflett, GeoLog Consulting
+ */
+static
+unsigned char calc_sync_xfer(unsigned int period, unsigned int offset)
+{
+    return sync_xfer_table[round_period(period)].reg_value |
+		((offset < SDTR_SIZE) ? offset : SDTR_SIZE);
+}
+
+/* ====================================================================================
+ * Command functions
+ */
+/*
+ * Function: acornscsi_kick(AS_Host *host)
+ * Purpose : kick next command to interface
+ * Params  : host - host to send command to
+ * Returns : INTR_IDLE if idle, otherwise INTR_PROCESSING
+ * Notes   : interrupts are always disabled!
+ */
+static
+intr_ret_t acornscsi_kick(AS_Host *host)
+{
+    int from_queue = 0;
+    Scsi_Cmnd *SCpnt;
+
+    /* first check to see if a command is waiting to be executed */
+    SCpnt = host->origSCpnt;
+    host->origSCpnt = NULL;
+
+    /* retrieve next command */
+    if (!SCpnt) {
+	SCpnt = queue_remove_exclude(&host->queues.issue, host->busyluns);
+	if (!SCpnt)
+	    return INTR_IDLE;
+
+	from_queue = 1;
+    }
+
+    if (host->scsi.disconnectable && host->SCpnt) {
+	queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
+	host->scsi.disconnectable = 0;
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	DBG(host->SCpnt, printk("scsi%d.%c: moved command to disconnected queue\n",
+		host->host->host_no, acornscsi_target(host)));
+#endif
+	host->SCpnt = NULL;
+    }
+
+    /*
+     * If we have an interrupt pending, then we may have been reselected.
+     * In this case, we don't want to write to the registers
+     */
+    if (!(sbic_arm_read(host->scsi.io_port, ASR) & (ASR_INT|ASR_BSY|ASR_CIP))) {
+	sbic_arm_write(host->scsi.io_port, DESTID, SCpnt->device->id);
+	sbic_arm_write(host->scsi.io_port, CMND, CMND_SELWITHATN);
+    }
+
+    /*
+     * claim host busy - all of these must happen atomically wrt
+     * our interrupt routine.  Failure means command loss.
+     */
+    host->scsi.phase = PHASE_CONNECTING;
+    host->SCpnt = SCpnt;
+    host->scsi.SCp = SCpnt->SCp;
+    host->dma.xfer_setup = 0;
+    host->dma.xfer_required = 0;
+    host->dma.xfer_done = 0;
+
+#if (DEBUG & (DEBUG_ABORT|DEBUG_CONNECT))
+    DBG(SCpnt,printk("scsi%d.%c: starting cmd %02X\n",
+	    host->host->host_no, '0' + SCpnt->device->id,
+	    SCpnt->cmnd[0]));
+#endif
+
+    if (from_queue) {
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+	/*
+	 * tagged queueing - allocate a new tag to this command
+	 */
+	if (SCpnt->device->tagged_queue) {
+	    SCpnt->device->current_tag += 1;
+	    if (SCpnt->device->current_tag == 0)
+		SCpnt->device->current_tag = 1;
+	    SCpnt->tag = SCpnt->device->current_tag;
+	} else
+#endif
+	    set_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns);
+
+	host->stats.removes += 1;
+
+	switch (acornscsi_cmdtype(SCpnt->cmnd[0])) {
+	case CMD_WRITE:
+	    host->stats.writes += 1;
+	    break;
+	case CMD_READ:
+	    host->stats.reads += 1;
+	    break;
+	case CMD_MISC:
+	    host->stats.miscs += 1;
+	    break;
+	}
+    }
+
+    return INTR_PROCESSING;
+}    
+
+/*
+ * Function: void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+ * Purpose : complete processing for command
+ * Params  : host   - interface that completed
+ *	     result - driver byte of result
+ */
+static
+void acornscsi_done(AS_Host *host, Scsi_Cmnd **SCpntp, unsigned int result)
+{
+    Scsi_Cmnd *SCpnt = *SCpntp;
+
+    /* clean up */
+    sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+
+    host->stats.fins += 1;
+
+    if (SCpnt) {
+	*SCpntp = NULL;
+
+	acornscsi_dma_cleanup(host);
+
+	SCpnt->result = result << 16 | host->scsi.SCp.Message << 8 | host->scsi.SCp.Status;
+
+	/*
+	 * In theory, this should not happen.  In practice, it seems to.
+	 * Only trigger an error if the device attempts to report all happy
+	 * but with untransferred buffers...  If we don't do something, then
+	 * data loss will occur.  Should we check SCpnt->underflow here?
+	 * It doesn't appear to be set to something meaningful by the higher
+	 * levels all the time.
+	 */
+	if (result == DID_OK) {
+		int xfer_warn = 0;
+
+		if (SCpnt->underflow == 0) {
+			if (host->scsi.SCp.ptr &&
+			    acornscsi_cmdtype(SCpnt->cmnd[0]) != CMD_MISC)
+				xfer_warn = 1;
+		} else {
+			if (host->scsi.SCp.scsi_xferred < SCpnt->underflow ||
+			    host->scsi.SCp.scsi_xferred != host->dma.transferred)
+				xfer_warn = 1;
+		}
+
+		/* ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.6)
+		 *  Targets which break data transfers into multiple
+		 *  connections shall end each successful connection
+		 *  (except possibly the last) with a SAVE DATA
+		 *  POINTER - DISCONNECT message sequence.
+		 *
+		 * This makes it difficult to ensure that a transfer has
+		 * completed.  If we reach the end of a transfer during
+		 * the command, then we can only have finished the transfer.
+		 * therefore, if we seem to have some data remaining, this
+		 * is not a problem.
+		 */
+		if (host->dma.xfer_done)
+			xfer_warn = 0;
+
+		if (xfer_warn) {
+		    switch (status_byte(SCpnt->result)) {
+		    case CHECK_CONDITION:
+		    case COMMAND_TERMINATED:
+		    case BUSY:
+		    case QUEUE_FULL:
+		    case RESERVATION_CONFLICT:
+			break;
+
+		    default:
+			printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
+				host->host->host_no, SCpnt->result);
+			print_command(SCpnt->cmnd);
+			acornscsi_dumpdma(host, "done");
+		 	acornscsi_dumplog(host, SCpnt->device->id);
+			SCpnt->result &= 0xffff;
+			SCpnt->result |= DID_ERROR << 16;
+		    }
+		}
+	}
+
+	if (!SCpnt->scsi_done)
+	    panic("scsi%d.H: null scsi_done function in acornscsi_done", host->host->host_no);
+
+	clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns);
+
+	SCpnt->scsi_done(SCpnt);
+    } else
+	printk("scsi%d: null command in acornscsi_done", host->host->host_no);
+
+    host->scsi.phase = PHASE_IDLE;
+}
+
+/* ====================================================================================
+ * DMA routines
+ */
+/*
+ * Purpose  : update SCSI Data Pointer
+ * Notes    : this will only be one SG entry or less
+ */
+static
+void acornscsi_data_updateptr(AS_Host *host, Scsi_Pointer *SCp, unsigned int length)
+{
+    SCp->ptr += length;
+    SCp->this_residual -= length;
+
+    if (SCp->this_residual == 0 && next_SCp(SCp) == 0)
+	host->dma.xfer_done = 1;
+}
+
+/*
+ * Prototype: void acornscsi_data_read(AS_Host *host, char *ptr,
+ *				unsigned int start_addr, unsigned int length)
+ * Purpose  : read data from DMA RAM
+ * Params   : host - host to transfer from
+ *	      ptr  - DRAM address
+ *	      start_addr - host mem address
+ *	      length - number of bytes to transfer
+ * Notes    : this will only be one SG entry or less
+ */
+static
+void acornscsi_data_read(AS_Host *host, char *ptr,
+				 unsigned int start_addr, unsigned int length)
+{
+    extern void __acornscsi_in(int port, char *buf, int len);
+    unsigned int page, offset, len = length;
+
+    page = (start_addr >> 12);
+    offset = start_addr & ((1 << 12) - 1);
+
+    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
+
+    while (len > 0) {
+	unsigned int this_len;
+
+	if (len + offset > (1 << 12))
+	    this_len = (1 << 12) - offset;
+	else
+	    this_len = len;
+
+	__acornscsi_in(host->card.io_ram + (offset << 1), ptr, this_len);
+
+	offset += this_len;
+	ptr += this_len;
+	len -= this_len;
+
+	if (offset == (1 << 12)) {
+	    offset = 0;
+	    page ++;
+	    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
+	}
+    }
+    outb(host->card.page_reg, host->card.io_page);
+}
+
+/*
+ * Prototype: void acornscsi_data_write(AS_Host *host, char *ptr,
+ *				unsigned int start_addr, unsigned int length)
+ * Purpose  : write data to DMA RAM
+ * Params   : host - host to transfer from
+ *	      ptr  - DRAM address
+ *	      start_addr - host mem address
+ *	      length - number of bytes to transfer
+ * Notes    : this will only be one SG entry or less
+ */
+static
+void acornscsi_data_write(AS_Host *host, char *ptr,
+				 unsigned int start_addr, unsigned int length)
+{
+    extern void __acornscsi_out(int port, char *buf, int len);
+    unsigned int page, offset, len = length;
+
+    page = (start_addr >> 12);
+    offset = start_addr & ((1 << 12) - 1);
+
+    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
+
+    while (len > 0) {
+	unsigned int this_len;
+
+	if (len + offset > (1 << 12))
+	    this_len = (1 << 12) - offset;
+	else
+	    this_len = len;
+
+	__acornscsi_out(host->card.io_ram + (offset << 1), ptr, this_len);
+
+	offset += this_len;
+	ptr += this_len;
+	len -= this_len;
+
+	if (offset == (1 << 12)) {
+	    offset = 0;
+	    page ++;
+	    outb((page & 0x3f) | host->card.page_reg, host->card.io_page);
+	}
+    }
+    outb(host->card.page_reg, host->card.io_page);
+}
+
+/* =========================================================================================
+ * On-board DMA routines
+ */
+#ifdef USE_DMAC
+/*
+ * Prototype: void acornscsi_dmastop(AS_Host *host)
+ * Purpose  : stop all DMA
+ * Params   : host - host on which to stop DMA
+ * Notes    : This is called when leaving DATA IN/OUT phase,
+ *	      or when interface is RESET
+ */
+static inline
+void acornscsi_dma_stop(AS_Host *host)
+{
+    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+    dmac_clearintr(host->dma.io_intr_clear);
+
+#if (DEBUG & DEBUG_DMA)
+    DBG(host->SCpnt, acornscsi_dumpdma(host, "stop"));
+#endif
+}
+
+/*
+ * Function: void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
+ * Purpose : setup DMA controller for data transfer
+ * Params  : host - host to setup
+ *	     direction - data transfer direction
+ * Notes   : This is called when entering DATA I/O phase, not
+ *	     while we're in a DATA I/O phase
+ */
+static
+void acornscsi_dma_setup(AS_Host *host, dmadir_t direction)
+{
+    unsigned int address, length, mode;
+
+    host->dma.direction = direction;
+
+    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+
+    if (direction == DMA_OUT) {
+#if (DEBUG & DEBUG_NO_WRITE)
+	if (NO_WRITE & (1 << host->SCpnt->device->id)) {
+	    printk(KERN_CRIT "scsi%d.%c: I can't handle DMA_OUT!\n",
+		    host->host->host_no, acornscsi_target(host));
+	    return;
+	}
+#endif
+	mode = DMAC_WRITE;
+    } else
+	mode = DMAC_READ;
+
+    /*
+     * Allocate some buffer space, limited to half the buffer size
+     */
+    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
+    if (length) {
+	host->dma.start_addr = address = host->dma.free_addr;
+	host->dma.free_addr = (host->dma.free_addr + length) &
+				(DMAC_BUFFER_SIZE - 1);
+
+	/*
+	 * Transfer data to DMA memory
+	 */
+	if (direction == DMA_OUT)
+	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
+				length);
+
+	length -= 1;
+	dmac_write(host->dma.io_port, TXCNTLO, length);
+	dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
+	dmac_write(host->dma.io_port, TXADRLO, address);
+	dmac_write(host->dma.io_port, TXADRMD, address >> 8);
+	dmac_write(host->dma.io_port, TXADRHI, 0);
+	dmac_write(host->dma.io_port, MODECON, mode);
+	dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
+
+#if (DEBUG & DEBUG_DMA)
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "strt"));
+#endif
+	host->dma.xfer_setup = 1;
+    }
+}
+
+/*
+ * Function: void acornscsi_dma_cleanup(AS_Host *host)
+ * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct
+ * Params  : host - host to finish
+ * Notes   : This is called when a command is:
+ *		terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT
+ *	   : This must not return until all transfers are completed.
+ */
+static
+void acornscsi_dma_cleanup(AS_Host *host)
+{
+    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+    dmac_clearintr(host->dma.io_intr_clear);
+
+    /*
+     * Check for a pending transfer
+     */
+    if (host->dma.xfer_required) {
+	host->dma.xfer_required = 0;
+	if (host->dma.direction == DMA_IN)
+	    acornscsi_data_read(host, host->dma.xfer_ptr,
+				 host->dma.xfer_start, host->dma.xfer_length);
+    }
+
+    /*
+     * Has a transfer been setup?
+     */
+    if (host->dma.xfer_setup) {
+	unsigned int transferred;
+
+	host->dma.xfer_setup = 0;
+
+#if (DEBUG & DEBUG_DMA)
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupi"));
+#endif
+
+	/*
+	 * Calculate number of bytes transferred from DMA.
+	 */
+	transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
+	host->dma.transferred += transferred;
+
+	if (host->dma.direction == DMA_IN)
+	    acornscsi_data_read(host, host->scsi.SCp.ptr,
+				 host->dma.start_addr, transferred);
+
+	/*
+	 * Update SCSI pointers
+	 */
+	acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
+#if (DEBUG & DEBUG_DMA)
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "cupo"));
+#endif
+    }
+}
+
+/*
+ * Function: void acornscsi_dmacintr(AS_Host *host)
+ * Purpose : handle interrupts from DMAC device
+ * Params  : host - host to process
+ * Notes   : If reading, we schedule the read to main memory &
+ *	     allow the transfer to continue.
+ *	   : If writing, we fill the onboard DMA memory from main
+ *	     memory.
+ *	   : Called whenever DMAC finished it's current transfer.
+ */
+static
+void acornscsi_dma_intr(AS_Host *host)
+{
+    unsigned int address, length, transferred;
+
+#if (DEBUG & DEBUG_DMA)
+    DBG(host->SCpnt, acornscsi_dumpdma(host, "inti"));
+#endif
+
+    dmac_write(host->dma.io_port, MASKREG, MASK_ON);
+    dmac_clearintr(host->dma.io_intr_clear);
+
+    /*
+     * Calculate amount transferred via DMA
+     */
+    transferred = dmac_address(host->dma.io_port) - host->dma.start_addr;
+    host->dma.transferred += transferred;
+
+    /*
+     * Schedule DMA transfer off board
+     */
+    if (host->dma.direction == DMA_IN) {
+	host->dma.xfer_start = host->dma.start_addr;
+	host->dma.xfer_length = transferred;
+	host->dma.xfer_ptr = host->scsi.SCp.ptr;
+	host->dma.xfer_required = 1;
+    }
+
+    acornscsi_data_updateptr(host, &host->scsi.SCp, transferred);
+
+    /*
+     * Allocate some buffer space, limited to half the on-board RAM size
+     */
+    length = min_t(unsigned int, host->scsi.SCp.this_residual, DMAC_BUFFER_SIZE / 2);
+    if (length) {
+	host->dma.start_addr = address = host->dma.free_addr;
+	host->dma.free_addr = (host->dma.free_addr + length) &
+				(DMAC_BUFFER_SIZE - 1);
+
+	/*
+	 * Transfer data to DMA memory
+	 */
+	if (host->dma.direction == DMA_OUT)
+	    acornscsi_data_write(host, host->scsi.SCp.ptr, host->dma.start_addr,
+				length);
+
+	length -= 1;
+	dmac_write(host->dma.io_port, TXCNTLO, length);
+	dmac_write(host->dma.io_port, TXCNTHI, length >> 8);
+	dmac_write(host->dma.io_port, TXADRLO, address);
+	dmac_write(host->dma.io_port, TXADRMD, address >> 8);
+	dmac_write(host->dma.io_port, TXADRHI, 0);
+	dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
+
+#if (DEBUG & DEBUG_DMA)
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "into"));
+#endif
+    } else {
+	host->dma.xfer_setup = 0;
+#if 0
+	/*
+	 * If the interface still wants more, then this is an error.
+	 * We give it another byte, but we also attempt to raise an
+	 * attention condition.  We continue giving one byte until
+	 * the device recognises the attention.
+	 */
+	if (dmac_read(host->dma.io_port, STATUS) & STATUS_RQ0) {
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+
+	    dmac_write(host->dma.io_port, TXCNTLO, 0);
+	    dmac_write(host->dma.io_port, TXCNTHI, 0);
+	    dmac_write(host->dma.io_port, TXADRLO, 0);
+	    dmac_write(host->dma.io_port, TXADRMD, 0);
+	    dmac_write(host->dma.io_port, TXADRHI, 0);
+	    dmac_write(host->dma.io_port, MASKREG, MASK_OFF);
+	}
+#endif
+    }
+}
+
+/*
+ * Function: void acornscsi_dma_xfer(AS_Host *host)
+ * Purpose : transfer data between AcornSCSI and memory
+ * Params  : host - host to process
+ */
+static
+void acornscsi_dma_xfer(AS_Host *host)
+{
+    host->dma.xfer_required = 0;
+
+    if (host->dma.direction == DMA_IN)
+	acornscsi_data_read(host, host->dma.xfer_ptr,
+				host->dma.xfer_start, host->dma.xfer_length);
+}
+
+/*
+ * Function: void acornscsi_dma_adjust(AS_Host *host)
+ * Purpose : adjust DMA pointers & count for bytes transferred to
+ *	     SBIC but not SCSI bus.
+ * Params  : host - host to adjust DMA count for
+ */
+static
+void acornscsi_dma_adjust(AS_Host *host)
+{
+    if (host->dma.xfer_setup) {
+	signed long transferred;
+#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
+	DBG(host->SCpnt, acornscsi_dumpdma(host, "adji"));
+#endif
+	/*
+	 * Calculate correct DMA address - DMA is ahead of SCSI bus while
+	 * writing.
+	 *  host->scsi.SCp.scsi_xferred is the number of bytes
+	 *  actually transferred to/from the SCSI bus.
+	 *  host->dma.transferred is the number of bytes transferred
+	 *  over DMA since host->dma.start_addr was last set.
+	 *
+	 * real_dma_addr = host->dma.start_addr + host->scsi.SCp.scsi_xferred
+	 *		   - host->dma.transferred
+	 */
+	transferred = host->scsi.SCp.scsi_xferred - host->dma.transferred;
+	if (transferred < 0)
+	    printk("scsi%d.%c: Ack! DMA write correction %ld < 0!\n",
+		    host->host->host_no, acornscsi_target(host), transferred);
+	else if (transferred == 0)
+	    host->dma.xfer_setup = 0;
+	else {
+	    transferred += host->dma.start_addr;
+	    dmac_write(host->dma.io_port, TXADRLO, transferred);
+	    dmac_write(host->dma.io_port, TXADRMD, transferred >> 8);
+	    dmac_write(host->dma.io_port, TXADRHI, transferred >> 16);
+#if (DEBUG & (DEBUG_DMA|DEBUG_WRITE))
+	    DBG(host->SCpnt, acornscsi_dumpdma(host, "adjo"));
+#endif
+	}
+    }
+}
+#endif
+
+/* =========================================================================================
+ * Data I/O
+ */
+static int
+acornscsi_write_pio(AS_Host *host, char *bytes, int *ptr, int len, unsigned int max_timeout)
+{
+	unsigned int asr, timeout = max_timeout;
+	int my_ptr = *ptr;
+
+	while (my_ptr < len) {
+		asr = sbic_arm_read(host->scsi.io_port, ASR);
+
+		if (asr & ASR_DBR) {
+			timeout = max_timeout;
+
+			sbic_arm_write(host->scsi.io_port, DATA, bytes[my_ptr++]);
+		} else if (asr & ASR_INT)
+			break;
+		else if (--timeout == 0)
+			break;
+		udelay(1);
+	}
+
+	*ptr = my_ptr;
+
+	return (timeout == 0) ? -1 : 0;
+}
+
+/*
+ * Function: void acornscsi_sendcommand(AS_Host *host)
+ * Purpose : send a command to a target
+ * Params  : host - host which is connected to target
+ */
+static void
+acornscsi_sendcommand(AS_Host *host)
+{
+    Scsi_Cmnd *SCpnt = host->SCpnt;
+
+    sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
+    sbic_arm_writenext(host->scsi.io_port, 0);
+    sbic_arm_writenext(host->scsi.io_port, SCpnt->cmd_len - host->scsi.SCp.sent_command);
+
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
+
+    if (acornscsi_write_pio(host, SCpnt->cmnd,
+	(int *)&host->scsi.SCp.sent_command, SCpnt->cmd_len, 1000000))
+	printk("scsi%d: timeout while sending command\n", host->host->host_no);
+
+    host->scsi.phase = PHASE_COMMAND;
+}
+
+static
+void acornscsi_sendmessage(AS_Host *host)
+{
+    unsigned int message_length = msgqueue_msglength(&host->scsi.msgs);
+    unsigned int msgnr;
+    struct message *msg;
+
+#if (DEBUG & DEBUG_MESSAGES)
+    printk("scsi%d.%c: sending message ",
+	    host->host->host_no, acornscsi_target(host));
+#endif
+
+    switch (message_length) {
+    case 0:
+	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+
+	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 1");
+
+	sbic_arm_write(host->scsi.io_port, DATA, NOP);
+
+	host->scsi.last_message = NOP;
+#if (DEBUG & DEBUG_MESSAGES)
+	printk("NOP");
+#endif
+	break;
+
+    case 1:
+	acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+	msg = msgqueue_getmsg(&host->scsi.msgs, 0);
+
+	acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "sending message 2");
+
+	sbic_arm_write(host->scsi.io_port, DATA, msg->msg[0]);
+
+	host->scsi.last_message = msg->msg[0];
+#if (DEBUG & DEBUG_MESSAGES)
+	print_msg(msg->msg);
+#endif
+	break;
+
+    default:
+	/*
+	 * ANSI standard says: (SCSI-2 Rev 10c Sect 5.6.14)
+	 * 'When a target sends this (MESSAGE_REJECT) message, it
+	 *  shall change to MESSAGE IN phase and send this message
+	 *  prior to requesting additional message bytes from the
+	 *  initiator.  This provides an interlock so that the
+	 *  initiator can determine which message byte is rejected.
+	 */
+	sbic_arm_write(host->scsi.io_port, TRANSCNTH, 0);
+	sbic_arm_writenext(host->scsi.io_port, 0);
+	sbic_arm_writenext(host->scsi.io_port, message_length);
+	acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
+
+	msgnr = 0;
+	while ((msg = msgqueue_getmsg(&host->scsi.msgs, msgnr++)) != NULL) {
+	    unsigned int i;
+#if (DEBUG & DEBUG_MESSAGES)
+	    print_msg(msg);
+#endif
+	    i = 0;
+	    if (acornscsi_write_pio(host, msg->msg, &i, msg->length, 1000000))
+		printk("scsi%d: timeout while sending message\n", host->host->host_no);
+
+	    host->scsi.last_message = msg->msg[0];
+	    if (msg->msg[0] == EXTENDED_MESSAGE)
+		host->scsi.last_message |= msg->msg[2] << 8;
+
+	    if (i != msg->length)
+		break;
+	}
+	break;
+    }
+#if (DEBUG & DEBUG_MESSAGES)
+    printk("\n");
+#endif
+}
+
+/*
+ * Function: void acornscsi_readstatusbyte(AS_Host *host)
+ * Purpose : Read status byte from connected target
+ * Params  : host - host connected to target
+ */
+static
+void acornscsi_readstatusbyte(AS_Host *host)
+{
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO|CMND_SBT);
+    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "reading status byte");
+    host->scsi.SCp.Status = sbic_arm_read(host->scsi.io_port, DATA);
+}
+
+/*
+ * Function: unsigned char acornscsi_readmessagebyte(AS_Host *host)
+ * Purpose : Read one message byte from connected target
+ * Params  : host - host connected to target
+ */
+static
+unsigned char acornscsi_readmessagebyte(AS_Host *host)
+{
+    unsigned char message;
+
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO | CMND_SBT);
+
+    acornscsi_sbic_wait(host, ASR_DBR, ASR_DBR, 1000, "for message byte");
+
+    message = sbic_arm_read(host->scsi.io_port, DATA);
+
+    /* wait for MSGIN-XFER-PAUSED */
+    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after message byte");
+
+    sbic_arm_read(host->scsi.io_port, SSR);
+
+    return message;
+}
+
+/*
+ * Function: void acornscsi_message(AS_Host *host)
+ * Purpose : Read complete message from connected target & action message
+ * Params  : host - host connected to target
+ */
+static
+void acornscsi_message(AS_Host *host)
+{
+    unsigned char message[16];
+    unsigned int msgidx = 0, msglen = 1;
+
+    do {
+	message[msgidx] = acornscsi_readmessagebyte(host);
+
+	switch (msgidx) {
+	case 0:
+	    if (message[0] == EXTENDED_MESSAGE ||
+		(message[0] >= 0x20 && message[0] <= 0x2f))
+		msglen = 2;
+	    break;
+
+	case 1:
+	    if (message[0] == EXTENDED_MESSAGE)
+		msglen += message[msgidx];
+	    break;
+	}
+	msgidx += 1;
+	if (msgidx < msglen) {
+	    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
+
+	    /* wait for next msg-in */
+	    acornscsi_sbic_wait(host, ASR_INT, ASR_INT, 1000, "for interrupt after negate ack");
+	    sbic_arm_read(host->scsi.io_port, SSR);
+	}
+    } while (msgidx < msglen);
+
+#if (DEBUG & DEBUG_MESSAGES)
+    printk("scsi%d.%c: message in: ",
+	    host->host->host_no, acornscsi_target(host));
+    print_msg(message);
+    printk("\n");
+#endif
+
+    if (host->scsi.phase == PHASE_RECONNECTED) {
+	/*
+	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)
+	 * 'Whenever a target reconnects to an initiator to continue
+	 *  a tagged I/O process, the SIMPLE QUEUE TAG message shall
+	 *  be sent immediately following the IDENTIFY message...'
+	 */
+	if (message[0] == SIMPLE_QUEUE_TAG)
+	    host->scsi.reconnected.tag = message[1];
+	if (acornscsi_reconnect_finish(host))
+	    host->scsi.phase = PHASE_MSGIN;
+    }
+
+    switch (message[0]) {
+    case ABORT:
+    case ABORT_TAG:
+    case COMMAND_COMPLETE:
+	if (host->scsi.phase != PHASE_STATUSIN) {
+	    printk(KERN_ERR "scsi%d.%c: command complete following non-status in phase?\n",
+		    host->host->host_no, acornscsi_target(host));
+	    acornscsi_dumplog(host, host->SCpnt->device->id);
+	}
+	host->scsi.phase = PHASE_DONE;
+	host->scsi.SCp.Message = message[0];
+	break;
+
+    case SAVE_POINTERS:
+	/*
+	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.20)
+	 * 'The SAVE DATA POINTER message is sent from a target to
+	 *  direct the initiator to copy the active data pointer to
+	 *  the saved data pointer for the current I/O process.
+	 */
+	acornscsi_dma_cleanup(host);
+	host->SCpnt->SCp = host->scsi.SCp;
+	host->SCpnt->SCp.sent_command = 0;
+	host->scsi.phase = PHASE_MSGIN;
+	break;
+
+    case RESTORE_POINTERS:
+	/*
+	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.19)
+	 * 'The RESTORE POINTERS message is sent from a target to
+	 *  direct the initiator to copy the most recently saved
+	 *  command, data, and status pointers for the I/O process
+	 *  to the corresponding active pointers.  The command and
+	 *  status pointers shall be restored to the beginning of
+	 *  the present command and status areas.'
+	 */
+	acornscsi_dma_cleanup(host);
+	host->scsi.SCp = host->SCpnt->SCp;
+	host->scsi.phase = PHASE_MSGIN;
+	break;
+
+    case DISCONNECT:
+	/*
+	 * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 6.4.2)
+	 * 'On those occasions when an error or exception condition occurs
+	 *  and the target elects to repeat the information transfer, the
+	 *  target may repeat the transfer either issuing a RESTORE POINTERS
+	 *  message or by disconnecting without issuing a SAVE POINTERS
+	 *  message.  When reconnection is completed, the most recent
+	 *  saved pointer values are restored.'
+	 */
+	acornscsi_dma_cleanup(host);
+	host->scsi.phase = PHASE_DISCONNECT;
+	break;
+
+    case MESSAGE_REJECT:
+#if 0 /* this isn't needed any more */
+	/*
+	 * If we were negociating sync transfer, we don't yet know if
+	 * this REJECT is for the sync transfer or for the tagged queue/wide
+	 * transfer.  Re-initiate sync transfer negociation now, and if
+	 * we got a REJECT in response to SDTR, then it'll be set to DONE.
+	 */
+	if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST)
+	    host->device[host->SCpnt->device->id].sync_state = SYNC_NEGOCIATE;
+#endif
+
+	/*
+	 * If we have any messages waiting to go out, then assert ATN now
+	 */
+	if (msgqueue_msglength(&host->scsi.msgs))
+	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+
+	switch (host->scsi.last_message) {
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+	case HEAD_OF_QUEUE_TAG:
+	case ORDERED_QUEUE_TAG:
+	case SIMPLE_QUEUE_TAG:
+	    /*
+	     * ANSI standard says: (Section SCSI-2 Rev. 10c Sect 5.6.17)
+	     *  If a target does not implement tagged queuing and a queue tag
+	     *  message is received, it shall respond with a MESSAGE REJECT
+	     *  message and accept the I/O process as if it were untagged.
+	     */
+	    printk(KERN_NOTICE "scsi%d.%c: disabling tagged queueing\n",
+		    host->host->host_no, acornscsi_target(host));
+	    host->SCpnt->device->tagged_queue = 0;
+	    set_bit(host->SCpnt->device->id * 8 + host->SCpnt->device->lun, host->busyluns);
+	    break;
+#endif
+	case EXTENDED_MESSAGE | (EXTENDED_SDTR << 8):
+	    /*
+	     * Target can't handle synchronous transfers
+	     */
+	    printk(KERN_NOTICE "scsi%d.%c: Using asynchronous transfer\n",
+		    host->host->host_no, acornscsi_target(host));
+	    host->device[host->SCpnt->device->id].sync_xfer = SYNCHTRANSFER_2DBA;
+	    host->device[host->SCpnt->device->id].sync_state = SYNC_ASYNCHRONOUS;
+	    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
+	    break;
+
+	default:
+	    break;
+	}
+	break;
+
+    case QUEUE_FULL:
+	/* TODO: target queue is full */
+	break;
+
+    case SIMPLE_QUEUE_TAG:
+	/* tag queue reconnect... message[1] = queue tag.  Print something to indicate something happened! */
+	printk("scsi%d.%c: reconnect queue tag %02X\n",
+		host->host->host_no, acornscsi_target(host),
+		message[1]);
+	break;
+
+    case EXTENDED_MESSAGE:
+	switch (message[2]) {
+#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
+	case EXTENDED_SDTR:
+	    if (host->device[host->SCpnt->device->id].sync_state == SYNC_SENT_REQUEST) {
+		/*
+		 * We requested synchronous transfers.  This isn't quite right...
+		 * We can only say if this succeeded if we proceed on to execute the
+		 * command from this message.  If we get a MESSAGE PARITY ERROR,
+		 * and the target retries fail, then we fallback to asynchronous mode
+		 */
+		host->device[host->SCpnt->device->id].sync_state = SYNC_COMPLETED;
+		printk(KERN_NOTICE "scsi%d.%c: Using synchronous transfer, offset %d, %d ns\n",
+			host->host->host_no, acornscsi_target(host),
+			message[4], message[3] * 4);
+		host->device[host->SCpnt->device->id].sync_xfer =
+			calc_sync_xfer(message[3] * 4, message[4]);
+	    } else {
+		unsigned char period, length;
+		/*
+		 * Target requested synchronous transfers.  The agreement is only
+		 * to be in operation AFTER the target leaves message out phase.
+		 */
+		acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+		period = max_t(unsigned int, message[3], sdtr_period / 4);
+		length = min_t(unsigned int, message[4], sdtr_size);
+		msgqueue_addmsg(&host->scsi.msgs, 5, EXTENDED_MESSAGE, 3,
+				 EXTENDED_SDTR, period, length);
+		host->device[host->SCpnt->device->id].sync_xfer =
+			calc_sync_xfer(period * 4, length);
+	    }
+	    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
+	    break;
+#else
+	    /* We do not accept synchronous transfers.  Respond with a
+	     * MESSAGE_REJECT.
+	     */
+#endif
+
+	case EXTENDED_WDTR:
+	    /* The WD33C93A is only 8-bit.  We respond with a MESSAGE_REJECT
+	     * to a wide data transfer request.
+	     */
+	default:
+	    acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+	    msgqueue_flush(&host->scsi.msgs);
+	    msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
+	    break;
+	}
+	break;
+
+#ifdef CONFIG_SCSI_ACORNSCSI_LINK
+    case LINKED_CMD_COMPLETE:
+    case LINKED_FLG_CMD_COMPLETE:
+	/*
+	 * We don't support linked commands yet
+	 */
+	if (0) {
+#if (DEBUG & DEBUG_LINK)
+	    printk("scsi%d.%c: lun %d tag %d linked command complete\n",
+		    host->host->host_no, acornscsi_target(host), host->SCpnt->tag);
+#endif
+	    /*
+	     * A linked command should only terminate with one of these messages
+	     * if there are more linked commands available.
+	     */
+	    if (!host->SCpnt->next_link) {
+		printk(KERN_WARNING "scsi%d.%c: lun %d tag %d linked command complete, but no next_link\n",
+			instance->host_no, acornscsi_target(host), host->SCpnt->tag);
+		acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+		msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
+	    } else {
+		Scsi_Cmnd *SCpnt = host->SCpnt;
+
+		acornscsi_dma_cleanup(host);
+
+		host->SCpnt = host->SCpnt->next_link;
+		host->SCpnt->tag = SCpnt->tag;
+		SCpnt->result = DID_OK | host->scsi.SCp.Message << 8 | host->Scsi.SCp.Status;
+		SCpnt->done(SCpnt);
+
+		/* initialise host->SCpnt->SCp */
+	    }
+	    break;
+	}
+#endif
+
+    default: /* reject message */
+	printk(KERN_ERR "scsi%d.%c: unrecognised message %02X, rejecting\n",
+		host->host->host_no, acornscsi_target(host),
+		message[0]);
+	acornscsi_sbic_issuecmd(host, CMND_ASSERTATN);
+	msgqueue_flush(&host->scsi.msgs);
+	msgqueue_addmsg(&host->scsi.msgs, 1, MESSAGE_REJECT);
+	host->scsi.phase = PHASE_MSGIN;
+	break;
+    }
+    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
+}
+
+/*
+ * Function: int acornscsi_buildmessages(AS_Host *host)
+ * Purpose : build the connection messages for a host
+ * Params  : host - host to add messages to
+ */
+static
+void acornscsi_buildmessages(AS_Host *host)
+{
+#if 0
+    /* does the device need resetting? */
+    if (cmd_reset) {
+	msgqueue_addmsg(&host->scsi.msgs, 1, BUS_DEVICE_RESET);
+	return;
+    }
+#endif
+
+    msgqueue_addmsg(&host->scsi.msgs, 1,
+		     IDENTIFY(host->device[host->SCpnt->device->id].disconnect_ok,
+			     host->SCpnt->device->lun));
+
+#if 0
+    /* does the device need the current command aborted */
+    if (cmd_aborted) {
+	acornscsi_abortcmd(host->SCpnt->tag);
+	return;
+    }
+#endif
+
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+    if (host->SCpnt->tag) {
+	unsigned int tag_type;
+
+	if (host->SCpnt->cmnd[0] == REQUEST_SENSE ||
+	    host->SCpnt->cmnd[0] == TEST_UNIT_READY ||
+	    host->SCpnt->cmnd[0] == INQUIRY)
+	    tag_type = HEAD_OF_QUEUE_TAG;
+	else
+	    tag_type = SIMPLE_QUEUE_TAG;
+	msgqueue_addmsg(&host->scsi.msgs, 2, tag_type, host->SCpnt->tag);
+    }
+#endif
+
+#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
+    if (host->device[host->SCpnt->device->id].sync_state == SYNC_NEGOCIATE) {
+	host->device[host->SCpnt->device->id].sync_state = SYNC_SENT_REQUEST;
+	msgqueue_addmsg(&host->scsi.msgs, 5,
+			 EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+			 sdtr_period / 4, sdtr_size);
+    }
+#endif
+}
+
+/*
+ * Function: int acornscsi_starttransfer(AS_Host *host)
+ * Purpose : transfer data to/from connected target
+ * Params  : host - host to which target is connected
+ * Returns : 0 if failure
+ */
+static
+int acornscsi_starttransfer(AS_Host *host)
+{
+    int residual;
+
+    if (!host->scsi.SCp.ptr /*&& host->scsi.SCp.this_residual*/) {
+	printk(KERN_ERR "scsi%d.%c: null buffer passed to acornscsi_starttransfer\n",
+		host->host->host_no, acornscsi_target(host));
+	return 0;
+    }
+
+    residual = host->SCpnt->request_bufflen - host->scsi.SCp.scsi_xferred;
+
+    sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, host->device[host->SCpnt->device->id].sync_xfer);
+    sbic_arm_writenext(host->scsi.io_port, residual >> 16);
+    sbic_arm_writenext(host->scsi.io_port, residual >> 8);
+    sbic_arm_writenext(host->scsi.io_port, residual);
+    acornscsi_sbic_issuecmd(host, CMND_XFERINFO);
+    return 1;
+}
+
+/* =========================================================================================
+ * Connection & Disconnection
+ */
+/*
+ * Function : acornscsi_reconnect(AS_Host *host)
+ * Purpose  : reconnect a previously disconnected command
+ * Params   : host - host specific data
+ * Remarks  : SCSI spec says:
+ *		'The set of active pointers is restored from the set
+ *		 of saved pointers upon reconnection of the I/O process'
+ */
+static
+int acornscsi_reconnect(AS_Host *host)
+{
+    unsigned int target, lun, ok = 0;
+
+    target = sbic_arm_read(host->scsi.io_port, SOURCEID);
+
+    if (!(target & 8))
+	printk(KERN_ERR "scsi%d: invalid source id after reselection "
+		"- device fault?\n",
+		host->host->host_no);
+
+    target &= 7;
+
+    if (host->SCpnt && !host->scsi.disconnectable) {
+	printk(KERN_ERR "scsi%d.%d: reconnected while command in "
+		"progress to target %d?\n",
+		host->host->host_no, target, host->SCpnt->device->id);
+	host->SCpnt = NULL;
+    }
+
+    lun = sbic_arm_read(host->scsi.io_port, DATA) & 7;
+
+    host->scsi.reconnected.target = target;
+    host->scsi.reconnected.lun = lun;
+    host->scsi.reconnected.tag = 0;
+
+    if (host->scsi.disconnectable && host->SCpnt &&
+	host->SCpnt->device->id == target && host->SCpnt->device->lun == lun)
+	ok = 1;
+
+    if (!ok && queue_probetgtlun(&host->queues.disconnected, target, lun))
+	ok = 1;
+
+    ADD_STATUS(target, 0x81, host->scsi.phase, 0);
+
+    if (ok) {
+	host->scsi.phase = PHASE_RECONNECTED;
+    } else {
+	/* this doesn't seem to work */
+	printk(KERN_ERR "scsi%d.%c: reselected with no command "
+		"to reconnect with\n",
+		host->host->host_no, '0' + target);
+	acornscsi_dumplog(host, target);
+	acornscsi_abortcmd(host, 0);
+	if (host->SCpnt) {
+	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
+	    host->SCpnt = NULL;
+	}
+    }
+    acornscsi_sbic_issuecmd(host, CMND_NEGATEACK);
+    return !ok;
+}
+
+/*
+ * Function: int acornscsi_reconect_finish(AS_Host *host)
+ * Purpose : finish reconnecting a command
+ * Params  : host - host to complete
+ * Returns : 0 if failed
+ */
+static
+int acornscsi_reconnect_finish(AS_Host *host)
+{
+    if (host->scsi.disconnectable && host->SCpnt) {
+	host->scsi.disconnectable = 0;
+	if (host->SCpnt->device->id  == host->scsi.reconnected.target &&
+	    host->SCpnt->device->lun == host->scsi.reconnected.lun &&
+	    host->SCpnt->tag         == host->scsi.reconnected.tag) {
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	    DBG(host->SCpnt, printk("scsi%d.%c: reconnected",
+		    host->host->host_no, acornscsi_target(host)));
+#endif
+	} else {
+	    queue_add_cmd_tail(&host->queues.disconnected, host->SCpnt);
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	    DBG(host->SCpnt, printk("scsi%d.%c: had to move command "
+		    "to disconnected queue\n",
+		    host->host->host_no, acornscsi_target(host)));
+#endif
+	    host->SCpnt = NULL;
+	}
+    }
+    if (!host->SCpnt) {
+	host->SCpnt = queue_remove_tgtluntag(&host->queues.disconnected,
+				host->scsi.reconnected.target,
+				host->scsi.reconnected.lun,
+				host->scsi.reconnected.tag);
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	DBG(host->SCpnt, printk("scsi%d.%c: had to get command",
+		host->host->host_no, acornscsi_target(host)));
+#endif
+    }
+
+    if (!host->SCpnt)
+	acornscsi_abortcmd(host, host->scsi.reconnected.tag);
+    else {
+	/*
+	 * Restore data pointer from SAVED pointers.
+	 */
+	host->scsi.SCp = host->SCpnt->SCp;
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+	printk(", data pointers: [%p, %X]",
+		host->scsi.SCp.ptr, host->scsi.SCp.this_residual);
+#endif
+    }
+#if (DEBUG & (DEBUG_QUEUES|DEBUG_DISCON))
+    printk("\n");
+#endif
+
+    host->dma.transferred = host->scsi.SCp.scsi_xferred;
+
+    return host->SCpnt != NULL;
+}
+
+/*
+ * Function: void acornscsi_disconnect_unexpected(AS_Host *host)
+ * Purpose : handle an unexpected disconnect
+ * Params  : host - host on which disconnect occurred
+ */
+static
+void acornscsi_disconnect_unexpected(AS_Host *host)
+{
+    printk(KERN_ERR "scsi%d.%c: unexpected disconnect\n",
+	    host->host->host_no, acornscsi_target(host));
+#if (DEBUG & DEBUG_ABORT)
+    acornscsi_dumplog(host, 8);
+#endif
+
+    acornscsi_done(host, &host->SCpnt, DID_ERROR);
+}
+
+/*
+ * Function: void acornscsi_abortcmd(AS_host *host, unsigned char tag)
+ * Purpose : abort a currently executing command
+ * Params  : host - host with connected command to abort
+ *	     tag  - tag to abort
+ */
+static
+void acornscsi_abortcmd(AS_Host *host, unsigned char tag)
+{
+    host->scsi.phase = PHASE_ABORTED;
+    sbic_arm_write(host->scsi.io_port, CMND, CMND_ASSERTATN);
+
+    msgqueue_flush(&host->scsi.msgs);
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+    if (tag)
+	msgqueue_addmsg(&host->scsi.msgs, 2, ABORT_TAG, tag);
+    else
+#endif
+	msgqueue_addmsg(&host->scsi.msgs, 1, ABORT);
+}
+
+/* ==========================================================================================
+ * Interrupt routines.
+ */
+/*
+ * Function: int acornscsi_sbicintr(AS_Host *host)
+ * Purpose : handle interrupts from SCSI device
+ * Params  : host - host to process
+ * Returns : INTR_PROCESS if expecting another SBIC interrupt
+ *	     INTR_IDLE if no interrupt
+ *	     INTR_NEXT_COMMAND if we have finished processing the command
+ */
+static
+intr_ret_t acornscsi_sbicintr(AS_Host *host, int in_irq)
+{
+    unsigned int asr, ssr;
+
+    asr = sbic_arm_read(host->scsi.io_port, ASR);
+    if (!(asr & ASR_INT))
+	return INTR_IDLE;
+
+    ssr = sbic_arm_read(host->scsi.io_port, SSR);
+
+#if (DEBUG & DEBUG_PHASES)
+    print_sbic_status(asr, ssr, host->scsi.phase);
+#endif
+
+    ADD_STATUS(8, ssr, host->scsi.phase, in_irq);
+
+    if (host->SCpnt && !host->scsi.disconnectable)
+	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);
+
+    switch (ssr) {
+    case 0x00:				/* reset state - not advanced			*/
+	printk(KERN_ERR "scsi%d: reset in standard mode but wanted advanced mode.\n",
+		host->host->host_no);
+	/* setup sbic - WD33C93A */
+	sbic_arm_write(host->scsi.io_port, OWNID, OWNID_EAF | host->host->this_id);
+	sbic_arm_write(host->scsi.io_port, CMND, CMND_RESET);
+	return INTR_IDLE;
+
+    case 0x01:				/* reset state - advanced			*/
+	sbic_arm_write(host->scsi.io_port, CTRL, INIT_SBICDMA | CTRL_IDI);
+	sbic_arm_write(host->scsi.io_port, TIMEOUT, TIMEOUT_TIME);
+	sbic_arm_write(host->scsi.io_port, SYNCHTRANSFER, SYNCHTRANSFER_2DBA);
+	sbic_arm_write(host->scsi.io_port, SOURCEID, SOURCEID_ER | SOURCEID_DSP);
+	msgqueue_flush(&host->scsi.msgs);
+	return INTR_IDLE;
+
+    case 0x41:				/* unexpected disconnect aborted command	*/
+	acornscsi_disconnect_unexpected(host);
+	return INTR_NEXT_COMMAND;
+    }
+
+    switch (host->scsi.phase) {
+    case PHASE_CONNECTING:		/* STATE: command removed from issue queue	*/
+	switch (ssr) {
+	case 0x11:			/* -> PHASE_CONNECTED				*/
+	    /* BUS FREE -> SELECTION */
+	    host->scsi.phase = PHASE_CONNECTED;
+	    msgqueue_flush(&host->scsi.msgs);
+	    host->dma.transferred = host->scsi.SCp.scsi_xferred;
+	    /* 33C93 gives next interrupt indicating bus phase */
+	    asr = sbic_arm_read(host->scsi.io_port, ASR);
+	    if (!(asr & ASR_INT))
+		break;
+	    ssr = sbic_arm_read(host->scsi.io_port, SSR);
+	    ADD_STATUS(8, ssr, host->scsi.phase, 1);
+	    ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, 1);
+	    goto connected;
+	    
+	case 0x42:			/* select timed out				*/
+					/* -> PHASE_IDLE				*/
+	    acornscsi_done(host, &host->SCpnt, DID_NO_CONNECT);
+	    return INTR_NEXT_COMMAND;
+
+	case 0x81:			/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/
+	    /* BUS FREE -> RESELECTION */
+	    host->origSCpnt = host->SCpnt;
+	    host->SCpnt = NULL;
+	    msgqueue_flush(&host->scsi.msgs);
+	    acornscsi_reconnect(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTING, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+	}
+	return INTR_PROCESSING;
+
+    connected:
+    case PHASE_CONNECTED:		/* STATE: device selected ok			*/
+	switch (ssr) {
+#ifdef NONSTANDARD
+	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
+	    /* SELECTION -> COMMAND */
+	    acornscsi_sendcommand(host);
+	    break;
+
+	case 0x8b:			/* -> PHASE_STATUS				*/
+	    /* SELECTION -> STATUS */
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+#endif
+
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* SELECTION ->MESSAGE OUT */
+	    host->scsi.phase = PHASE_MSGOUT;
+	    acornscsi_buildmessages(host);
+	    acornscsi_sendmessage(host);
+	    break;
+
+	/* these should not happen */
+	case 0x85:			/* target disconnected				*/
+	    acornscsi_done(host, &host->SCpnt, DID_ERROR);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_CONNECTED, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_MSGOUT:			/* STATE: connected & sent IDENTIFY message	*/
+	/*
+	 * SCSI standard says that MESSAGE OUT phases can be followed by a
+	 * DATA phase, STATUS phase, MESSAGE IN phase or COMMAND phase
+	 */
+	switch (ssr) {
+	case 0x8a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
+	case 0x1a:			/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
+	    /* MESSAGE OUT -> COMMAND */
+	    acornscsi_sendcommand(host);
+	    break;
+
+	case 0x8b:			/* -> PHASE_STATUS				*/
+	case 0x1b:			/* -> PHASE_STATUS				*/
+	    /* MESSAGE OUT -> STATUS */
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* MESSAGE_OUT(MESSAGE_IN) ->MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x4f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    /* MESSAGE OUT -> MESSAGE IN */
+	    acornscsi_message(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_MSGOUT, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_COMMAND: 		/* STATE: connected & command sent		*/
+	switch (ssr) {
+	case 0x18:			/* -> PHASE_DATAOUT				*/
+	    /* COMMAND -> DATA OUT */
+	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    acornscsi_dma_setup(host, DMA_OUT);
+	    if (!acornscsi_starttransfer(host))
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    host->scsi.phase = PHASE_DATAOUT;
+	    return INTR_IDLE;
+
+	case 0x19:			/* -> PHASE_DATAIN				*/
+	    /* COMMAND -> DATA IN */
+	    if (host->scsi.SCp.sent_command != host->SCpnt->cmd_len)
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    acornscsi_dma_setup(host, DMA_IN);
+	    if (!acornscsi_starttransfer(host))
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    host->scsi.phase = PHASE_DATAIN;
+	    return INTR_IDLE;
+
+	case 0x1b:			/* -> PHASE_STATUS				*/
+	    /* COMMAND -> STATUS */
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	    /* COMMAND -> MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    /* COMMAND -> MESSAGE IN */
+	    acornscsi_message(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_COMMAND, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_DISCONNECT:		/* STATE: connected, received DISCONNECT msg	*/
+	if (ssr == 0x85) {		/* -> PHASE_IDLE				*/
+	    host->scsi.disconnectable = 1;
+	    host->scsi.reconnected.tag = 0;
+	    host->scsi.phase = PHASE_IDLE;
+	    host->stats.disconnects += 1;
+	} else {
+	    printk(KERN_ERR "scsi%d.%c: PHASE_DISCONNECT, SSR %02X instead of disconnect?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_NEXT_COMMAND;
+
+    case PHASE_IDLE:			/* STATE: disconnected				*/
+	if (ssr == 0x81)		/* -> PHASE_RECONNECTED or PHASE_ABORTED	*/
+	    acornscsi_reconnect(host);
+	else {
+	    printk(KERN_ERR "scsi%d.%c: PHASE_IDLE, SSR %02X while idle?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_RECONNECTED:		/* STATE: device reconnected to initiator	*/
+	/*
+	 * Command reconnected - if MESGIN, get message - it may be
+	 * the tag.  If not, get command out of disconnected queue
+	 */
+	/*
+	 * If we reconnected and we're not in MESSAGE IN phase after IDENTIFY,
+	 * reconnect I_T_L command
+	 */
+	if (ssr != 0x8f && !acornscsi_reconnect_finish(host))
+	    return INTR_IDLE;
+	ADD_STATUS(host->SCpnt->device->id, ssr, host->scsi.phase, in_irq);
+	switch (ssr) {
+	case 0x88:			/* data out phase				*/
+					/* -> PHASE_DATAOUT				*/
+	    /* MESSAGE IN -> DATA OUT */
+	    acornscsi_dma_setup(host, DMA_OUT);
+	    if (!acornscsi_starttransfer(host))
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    host->scsi.phase = PHASE_DATAOUT;
+	    return INTR_IDLE;
+
+	case 0x89:			/* data in phase				*/
+					/* -> PHASE_DATAIN				*/
+	    /* MESSAGE IN -> DATA IN */
+	    acornscsi_dma_setup(host, DMA_IN);
+	    if (!acornscsi_starttransfer(host))
+		acornscsi_abortcmd(host, host->SCpnt->tag);
+	    host->scsi.phase = PHASE_DATAIN;
+	    return INTR_IDLE;
+
+	case 0x8a:			/* command out					*/
+	    /* MESSAGE IN -> COMMAND */
+	    acornscsi_sendcommand(host);/* -> PHASE_COMMAND, PHASE_COMMANDPAUSED	*/
+	    break;
+
+	case 0x8b:			/* status in					*/
+					/* -> PHASE_STATUSIN				*/
+	    /* MESSAGE IN -> STATUS */
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x8e:			/* message out					*/
+					/* -> PHASE_MSGOUT				*/
+	    /* MESSAGE IN -> MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x8f:			/* message in					*/
+	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_RECONNECTED, SSR %02X after reconnect?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_DATAIN:			/* STATE: transferred data in			*/
+	/*
+	 * This is simple - if we disconnect then the DMA address & count is
+	 * correct.
+	 */
+	switch (ssr) {
+	case 0x19:			/* -> PHASE_DATAIN				*/
+	case 0x89:			/* -> PHASE_DATAIN				*/
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+	    return INTR_IDLE;
+
+	case 0x1b:			/* -> PHASE_STATUSIN				*/
+	case 0x4b:			/* -> PHASE_STATUSIN				*/
+	case 0x8b:			/* -> PHASE_STATUSIN				*/
+	    /* DATA IN -> STATUS */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	case 0x4e:			/* -> PHASE_MSGOUT				*/
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* DATA IN -> MESSAGE OUT */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x1f:			/* message in					*/
+	case 0x4f:			/* message in					*/
+	case 0x8f:			/* message in					*/
+	    /* DATA IN -> MESSAGE IN */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_DATAIN, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_DATAOUT: 		/* STATE: transferred data out			*/
+	/*
+	 * This is more complicated - if we disconnect, the DMA could be 12
+	 * bytes ahead of us.  We need to correct this.
+	 */
+	switch (ssr) {
+	case 0x18:			/* -> PHASE_DATAOUT				*/
+	case 0x88:			/* -> PHASE_DATAOUT				*/
+	    acornscsi_abortcmd(host, host->SCpnt->tag);
+	    return INTR_IDLE;
+
+	case 0x1b:			/* -> PHASE_STATUSIN				*/
+	case 0x4b:			/* -> PHASE_STATUSIN				*/
+	case 0x8b:			/* -> PHASE_STATUSIN				*/
+	    /* DATA OUT -> STATUS */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_dma_adjust(host);
+	    acornscsi_readstatusbyte(host);
+	    host->scsi.phase = PHASE_STATUSIN;
+	    break;
+
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	case 0x4e:			/* -> PHASE_MSGOUT				*/
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* DATA OUT -> MESSAGE OUT */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_dma_adjust(host);
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x1f:			/* message in					*/
+	case 0x4f:			/* message in					*/
+	case 0x8f:			/* message in					*/
+	    /* DATA OUT -> MESSAGE IN */
+	    host->scsi.SCp.scsi_xferred = host->SCpnt->request_bufflen -
+					  acornscsi_sbic_xfcount(host);
+	    acornscsi_dma_stop(host);
+	    acornscsi_dma_adjust(host);
+	    acornscsi_message(host);	/* -> PHASE_MSGIN, PHASE_DISCONNECT		*/
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_DATAOUT, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_STATUSIN:		/* STATE: status in complete			*/
+	switch (ssr) {
+	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+	case 0x8f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+	    /* STATUS -> MESSAGE IN */
+	    acornscsi_message(host);
+	    break;
+
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* STATUS -> MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_STATUSIN, SSR %02X instead of MESSAGE_IN?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_MSGIN:			/* STATE: message in				*/
+	switch (ssr) {
+	case 0x1e:			/* -> PHASE_MSGOUT				*/
+	case 0x4e:			/* -> PHASE_MSGOUT				*/
+	case 0x8e:			/* -> PHASE_MSGOUT				*/
+	    /* MESSAGE IN -> MESSAGE OUT */
+	    acornscsi_sendmessage(host);
+	    break;
+
+	case 0x1f:			/* -> PHASE_MSGIN, PHASE_DONE, PHASE_DISCONNECT */
+	case 0x2f:
+	case 0x4f:
+	case 0x8f:
+	    acornscsi_message(host);
+	    break;
+
+	case 0x85:
+	    printk("scsi%d.%c: strange message in disconnection\n",
+		host->host->host_no, acornscsi_target(host));
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	    acornscsi_done(host, &host->SCpnt, DID_ERROR);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_MSGIN, SSR %02X after message in?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_DONE:			/* STATE: received status & message		*/
+	switch (ssr) {
+	case 0x85:			/* -> PHASE_IDLE				*/
+	    acornscsi_done(host, &host->SCpnt, DID_OK);
+	    return INTR_NEXT_COMMAND;
+
+	case 0x1e:
+	case 0x8e:
+	    acornscsi_sendmessage(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_DONE, SSR %02X instead of disconnect?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    case PHASE_ABORTED:
+	switch (ssr) {
+	case 0x85:
+	    if (host->SCpnt)
+		acornscsi_done(host, &host->SCpnt, DID_ABORT);
+	    else {
+		clear_bit(host->scsi.reconnected.target * 8 + host->scsi.reconnected.lun,
+			  host->busyluns);
+		host->scsi.phase = PHASE_IDLE;
+	    }
+	    return INTR_NEXT_COMMAND;
+
+	case 0x1e:
+	case 0x2e:
+	case 0x4e:
+	case 0x8e:
+	    acornscsi_sendmessage(host);
+	    break;
+
+	default:
+	    printk(KERN_ERR "scsi%d.%c: PHASE_ABORTED, SSR %02X?\n",
+		    host->host->host_no, acornscsi_target(host), ssr);
+	    acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+	}
+	return INTR_PROCESSING;
+
+    default:
+	printk(KERN_ERR "scsi%d.%c: unknown driver phase %d\n",
+		host->host->host_no, acornscsi_target(host), ssr);
+	acornscsi_dumplog(host, host->SCpnt ? host->SCpnt->device->id : 8);
+    }
+    return INTR_PROCESSING;
+}
+
+/*
+ * Prototype: void acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+ * Purpose  : handle interrupts from Acorn SCSI card
+ * Params   : irq    - interrupt number
+ *	      dev_id - device specific data (AS_Host structure)
+ *	      regs   - processor registers when interrupt occurred
+ */
+static irqreturn_t
+acornscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+    AS_Host *host = (AS_Host *)dev_id;
+    intr_ret_t ret;
+    int iostatus;
+    int in_irq = 0;
+
+    do {
+	ret = INTR_IDLE;
+
+	iostatus = inb(host->card.io_intr);
+
+	if (iostatus & 2) {
+	    acornscsi_dma_intr(host);
+	    iostatus = inb(host->card.io_intr);
+	}
+
+	if (iostatus & 8)
+	    ret = acornscsi_sbicintr(host, in_irq);
+
+	/*
+	 * If we have a transfer pending, start it.
+	 * Only start it if the interface has already started transferring
+	 * it's data
+	 */
+	if (host->dma.xfer_required)
+	    acornscsi_dma_xfer(host);
+
+	if (ret == INTR_NEXT_COMMAND)
+	    ret = acornscsi_kick(host);
+
+	in_irq = 1;
+    } while (ret != INTR_IDLE);
+
+    return IRQ_HANDLED;
+}
+
+/*=============================================================================================
+ * Interfaces between interrupt handler and rest of scsi code
+ */
+
+/*
+ * Function : acornscsi_queuecmd(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+ * Purpose  : queues a SCSI command
+ * Params   : cmd  - SCSI command
+ *	      done - function called on completion, with pointer to command descriptor
+ * Returns  : 0, or < 0 on error.
+ */
+int acornscsi_queuecmd(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+    AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
+
+    if (!done) {
+	/* there should be some way of rejecting errors like this without panicing... */
+	panic("scsi%d: queuecommand called with NULL done function [cmd=%p]",
+		host->host->host_no, SCpnt);
+	return -EINVAL;
+    }
+
+#if (DEBUG & DEBUG_NO_WRITE)
+    if (acornscsi_cmdtype(SCpnt->cmnd[0]) == CMD_WRITE && (NO_WRITE & (1 << SCpnt->device->id))) {
+	printk(KERN_CRIT "scsi%d.%c: WRITE attempted with NO_WRITE flag set\n",
+	    host->host->host_no, '0' + SCpnt->device->id);
+	SCpnt->result = DID_NO_CONNECT << 16;
+	done(SCpnt);
+	return 0;
+    }
+#endif
+
+    SCpnt->scsi_done = done;
+    SCpnt->host_scribble = NULL;
+    SCpnt->result = 0;
+    SCpnt->tag = 0;
+    SCpnt->SCp.phase = (int)acornscsi_datadirection(SCpnt->cmnd[0]);
+    SCpnt->SCp.sent_command = 0;
+    SCpnt->SCp.scsi_xferred = 0;
+
+    init_SCp(SCpnt);
+
+    host->stats.queues += 1;
+
+    {
+	unsigned long flags;
+
+	if (!queue_add_cmd_ordered(&host->queues.issue, SCpnt)) {
+	    SCpnt->result = DID_ERROR << 16;
+	    done(SCpnt);
+	    return 0;
+	}
+	local_irq_save(flags);
+	if (host->scsi.phase == PHASE_IDLE)
+	    acornscsi_kick(host);
+	local_irq_restore(flags);
+    }
+    return 0;
+}
+
+/*
+ * Prototype: void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+ * Purpose  : pass a result to *SCpntp1, and check if *SCpntp1 = *SCpntp2
+ * Params   : SCpntp1 - pointer to command to return
+ *	      SCpntp2 - pointer to command to check
+ *	      result  - result to pass back to mid-level done function
+ * Returns  : *SCpntp2 = NULL if *SCpntp1 is the same command structure as *SCpntp2.
+ */
+static inline
+void acornscsi_reportstatus(Scsi_Cmnd **SCpntp1, Scsi_Cmnd **SCpntp2, int result)
+{
+    Scsi_Cmnd *SCpnt = *SCpntp1;
+
+    if (SCpnt) {
+	*SCpntp1 = NULL;
+
+	SCpnt->result = result;
+	SCpnt->scsi_done(SCpnt);
+    }
+
+    if (SCpnt == *SCpntp2)
+	*SCpntp2 = NULL;
+}
+
+enum res_abort { res_not_running, res_success, res_success_clear, res_snooze };
+
+/*
+ * Prototype: enum res acornscsi_do_abort(Scsi_Cmnd *SCpnt)
+ * Purpose  : abort a command on this host
+ * Params   : SCpnt - command to abort
+ * Returns  : our abort status
+ */
+static enum res_abort
+acornscsi_do_abort(AS_Host *host, Scsi_Cmnd *SCpnt)
+{
+	enum res_abort res = res_not_running;
+
+	if (queue_remove_cmd(&host->queues.issue, SCpnt)) {
+		/*
+		 * The command was on the issue queue, and has not been
+		 * issued yet.  We can remove the command from the queue,
+		 * and acknowledge the abort.  Neither the devices nor the
+		 * interface know about the command.
+		 */
+//#if (DEBUG & DEBUG_ABORT)
+		printk("on issue queue ");
+//#endif
+		res = res_success;
+	} else if (queue_remove_cmd(&host->queues.disconnected, SCpnt)) {
+		/*
+		 * The command was on the disconnected queue.  Simply
+		 * acknowledge the abort condition, and when the target
+		 * reconnects, we will give it an ABORT message.  The
+		 * target should then disconnect, and we will clear
+		 * the busylun bit.
+		 */
+//#if (DEBUG & DEBUG_ABORT)
+		printk("on disconnected queue ");
+//#endif
+		res = res_success;
+	} else if (host->SCpnt == SCpnt) {
+		unsigned long flags;
+
+//#if (DEBUG & DEBUG_ABORT)
+		printk("executing ");
+//#endif
+
+		local_irq_save(flags);
+		switch (host->scsi.phase) {
+		/*
+		 * If the interface is idle, and the command is 'disconnectable',
+		 * then it is the same as on the disconnected queue.  We simply
+		 * remove all traces of the command.  When the target reconnects,
+		 * we will give it an ABORT message since the command could not
+		 * be found.  When the target finally disconnects, we will clear
+		 * the busylun bit.
+		 */
+		case PHASE_IDLE:
+			if (host->scsi.disconnectable) {
+				host->scsi.disconnectable = 0;
+				host->SCpnt = NULL;
+				res = res_success;
+			}
+			break;
+
+		/*
+		 * If the command has connected and done nothing further,
+		 * simply force a disconnect.  We also need to clear the
+		 * busylun bit.
+		 */
+		case PHASE_CONNECTED:
+			sbic_arm_write(host->scsi.io_port, CMND, CMND_DISCONNECT);
+			host->SCpnt = NULL;
+			res = res_success_clear;
+			break;
+
+		default:
+			acornscsi_abortcmd(host, host->SCpnt->tag);
+			res = res_snooze;
+		}
+		local_irq_restore(flags);
+	} else if (host->origSCpnt == SCpnt) {
+		/*
+		 * The command will be executed next, but a command
+		 * is currently using the interface.  This is similar to
+		 * being on the issue queue, except the busylun bit has
+		 * been set.
+		 */
+		host->origSCpnt = NULL;
+//#if (DEBUG & DEBUG_ABORT)
+		printk("waiting for execution ");
+//#endif
+		res = res_success_clear;
+	} else
+		printk("unknown ");
+
+	return res;
+}
+
+/*
+ * Prototype: int acornscsi_abort(Scsi_Cmnd *SCpnt)
+ * Purpose  : abort a command on this host
+ * Params   : SCpnt - command to abort
+ * Returns  : one of SCSI_ABORT_ macros
+ */
+int acornscsi_abort(Scsi_Cmnd *SCpnt)
+{
+	AS_Host *host = (AS_Host *) SCpnt->device->host->hostdata;
+	int result;
+
+	host->stats.aborts += 1;
+
+#if (DEBUG & DEBUG_ABORT)
+	{
+		int asr, ssr;
+		asr = sbic_arm_read(host->scsi.io_port, ASR);
+		ssr = sbic_arm_read(host->scsi.io_port, SSR);
+
+		printk(KERN_WARNING "acornscsi_abort: ");
+		print_sbic_status(asr, ssr, host->scsi.phase);
+		acornscsi_dumplog(host, SCpnt->device->id);
+	}
+#endif
+
+	printk("scsi%d: ", host->host->host_no);
+
+	switch (acornscsi_do_abort(host, SCpnt)) {
+	/*
+	 * We managed to find the command and cleared it out.
+	 * We do not expect the command to be executing on the
+	 * target, but we have set the busylun bit.
+	 */
+	case res_success_clear:
+//#if (DEBUG & DEBUG_ABORT)
+		printk("clear ");
+//#endif
+		clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, host->busyluns);
+
+	/*
+	 * We found the command, and cleared it out.  Either
+	 * the command is still known to be executing on the
+	 * target, or the busylun bit is not set.
+	 */
+	case res_success:
+//#if (DEBUG & DEBUG_ABORT)
+		printk("success\n");
+//#endif
+		SCpnt->result = DID_ABORT << 16;
+		SCpnt->scsi_done(SCpnt);
+		result = SCSI_ABORT_SUCCESS;
+		break;
+
+	/*
+	 * We did find the command, but unfortunately we couldn't
+	 * unhook it from ourselves.  Wait some more, and if it
+	 * still doesn't complete, reset the interface.
+	 */
+	case res_snooze:
+//#if (DEBUG & DEBUG_ABORT)
+		printk("snooze\n");
+//#endif
+		result = SCSI_ABORT_SNOOZE;
+		break;
+
+	/*
+	 * The command could not be found (either because it completed,
+	 * or it got dropped.
+	 */
+	default:
+	case res_not_running:
+		acornscsi_dumplog(host, SCpnt->device->id);
+#if (DEBUG & DEBUG_ABORT)
+		result = SCSI_ABORT_SNOOZE;
+#else
+		result = SCSI_ABORT_NOT_RUNNING;
+#endif
+//#if (DEBUG & DEBUG_ABORT)
+		printk("not running\n");
+//#endif
+		break;
+	}
+
+	return result;
+}
+
+/*
+ * Prototype: int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+ * Purpose  : reset a command on this host/reset this host
+ * Params   : SCpnt  - command causing reset
+ *	      result - what type of reset to perform
+ * Returns  : one of SCSI_RESET_ macros
+ */
+int acornscsi_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags)
+{
+    AS_Host *host = (AS_Host *)SCpnt->device->host->hostdata;
+    Scsi_Cmnd *SCptr;
+    
+    host->stats.resets += 1;
+
+#if (DEBUG & DEBUG_RESET)
+    {
+	int asr, ssr;
+
+	asr = sbic_arm_read(host->scsi.io_port, ASR);
+	ssr = sbic_arm_read(host->scsi.io_port, SSR);
+
+	printk(KERN_WARNING "acornscsi_reset: ");
+	print_sbic_status(asr, ssr, host->scsi.phase);
+	acornscsi_dumplog(host, SCpnt->device->id);
+    }
+#endif
+
+    acornscsi_dma_stop(host);
+
+    SCptr = host->SCpnt;
+
+    /*
+     * do hard reset.  This resets all devices on this host, and so we
+     * must set the reset status on all commands.
+     */
+    acornscsi_resetcard(host);
+
+    /*
+     * report reset on commands current connected/disconnected
+     */
+    acornscsi_reportstatus(&host->SCpnt, &SCptr, DID_RESET);
+
+    while ((SCptr = queue_remove(&host->queues.disconnected)) != NULL)
+	acornscsi_reportstatus(&SCptr, &SCpnt, DID_RESET);
+
+    if (SCpnt) {
+	SCpnt->result = DID_RESET << 16;
+	SCpnt->scsi_done(SCpnt);
+    }
+
+    return SCSI_RESET_BUS_RESET | SCSI_RESET_HOST_RESET | SCSI_RESET_SUCCESS;
+}
+
+/*==============================================================================================
+ * initialisation & miscellaneous support
+ */
+
+/*
+ * Function: char *acornscsi_info(struct Scsi_Host *host)
+ * Purpose : return a string describing this interface
+ * Params  : host - host to give information on
+ * Returns : a constant string
+ */
+const
+char *acornscsi_info(struct Scsi_Host *host)
+{
+    static char string[100], *p;
+
+    p = string;
+    
+    p += sprintf(string, "%s at port %08lX irq %d v%d.%d.%d"
+#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
+    " SYNC"
+#endif
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+    " TAG"
+#endif
+#ifdef CONFIG_SCSI_ACORNSCSI_LINK
+    " LINK"
+#endif
+#if (DEBUG & DEBUG_NO_WRITE)
+    " NOWRITE ("NO_WRITE_STR")"
+#endif
+		, host->hostt->name, host->io_port, host->irq,
+		VER_MAJOR, VER_MINOR, VER_PATCH);
+    return string;
+}
+
+int acornscsi_proc_info(char *buffer, char **start, off_t offset,
+			int length, int host_no, int inout)
+{
+    int pos, begin = 0, devidx;
+    struct Scsi_Host *instance;
+    Scsi_Device *scd;
+    AS_Host *host;
+    char *p = buffer;
+
+    instance = scsi_host_hn_get(host_no);
+
+    if (inout == 1 || !instance)
+	return -EINVAL;
+
+    host  = (AS_Host *)instance->hostdata;
+    
+    p += sprintf(p, "AcornSCSI driver v%d.%d.%d"
+#ifdef CONFIG_SCSI_ACORNSCSI_SYNC
+    " SYNC"
+#endif
+#ifdef CONFIG_SCSI_ACORNSCSI_TAGGED_QUEUE
+    " TAG"
+#endif
+#ifdef CONFIG_SCSI_ACORNSCSI_LINK
+    " LINK"
+#endif
+#if (DEBUG & DEBUG_NO_WRITE)
+    " NOWRITE ("NO_WRITE_STR")"
+#endif
+		"\n\n", VER_MAJOR, VER_MINOR, VER_PATCH);
+
+    p += sprintf(p,	"SBIC: WD33C93A  Address: %08X  IRQ : %d\n",
+			host->scsi.io_port, host->scsi.irq);
+#ifdef USE_DMAC
+    p += sprintf(p,	"DMAC: uPC71071  Address: %08X  IRQ : %d\n\n",
+			host->dma.io_port, host->scsi.irq);
+#endif
+
+    p += sprintf(p,	"Statistics:\n"
+			"Queued commands: %-10u    Issued commands: %-10u\n"
+			"Done commands  : %-10u    Reads          : %-10u\n"
+			"Writes         : %-10u    Others         : %-10u\n"
+			"Disconnects    : %-10u    Aborts         : %-10u\n"
+			"Resets         : %-10u\n\nLast phases:",
+			host->stats.queues,		host->stats.removes,
+			host->stats.fins,		host->stats.reads,
+			host->stats.writes,		host->stats.miscs,
+			host->stats.disconnects,	host->stats.aborts,
+			host->stats.resets);
+
+    for (devidx = 0; devidx < 9; devidx ++) {
+	unsigned int statptr, prev;
+
+	p += sprintf(p, "\n%c:", devidx == 8 ? 'H' : ('0' + devidx));
+	statptr = host->status_ptr[devidx] - 10;
+
+	if ((signed int)statptr < 0)
+	    statptr += STATUS_BUFFER_SIZE;
+
+	prev = host->status[devidx][statptr].when;
+
+	for (; statptr != host->status_ptr[devidx]; statptr = (statptr + 1) & (STATUS_BUFFER_SIZE - 1)) {
+	    if (host->status[devidx][statptr].when) {
+		p += sprintf(p, "%c%02X:%02X+%2ld",
+			host->status[devidx][statptr].irq ? '-' : ' ',
+			host->status[devidx][statptr].ph,
+			host->status[devidx][statptr].ssr,
+			(host->status[devidx][statptr].when - prev) < 100 ?
+				(host->status[devidx][statptr].when - prev) : 99);
+		prev = host->status[devidx][statptr].when;
+	    }
+	}
+    }
+
+    p += sprintf(p, "\nAttached devices:\n");
+
+    list_for_each_entry(scd, &instance->my_devices, siblings) {
+	p += sprintf(p, "Device/Lun TaggedQ      Sync\n");
+	p += sprintf(p, "     %d/%d   ", scd->id, scd->lun);
+	if (scd->tagged_supported)
+		p += sprintf(p, "%3sabled(%3d) ",
+			     scd->tagged_queue ? "en" : "dis",
+			     scd->current_tag);
+	else
+		p += sprintf(p, "unsupported  ");
+
+	if (host->device[scd->id].sync_xfer & 15)
+		p += sprintf(p, "offset %d, %d ns\n",
+			     host->device[scd->id].sync_xfer & 15,
+			     acornscsi_getperiod(host->device[scd->id].sync_xfer));
+	else
+		p += sprintf(p, "async\n");
+
+	pos = p - buffer;
+	if (pos + begin < offset) {
+	    begin += pos;
+	    p = buffer;
+	}
+	pos = p - buffer;
+	if (pos + begin > offset + length)
+	    break;
+    }
+
+    pos = p - buffer;
+
+    *start = buffer + (offset - begin);
+    pos -= offset - begin;
+
+    if (pos > length)
+	pos = length;
+
+    return pos;
+}
+
+static Scsi_Host_Template acornscsi_template = {
+	.module			= THIS_MODULE,
+	.proc_info		= acornscsi_proc_info,
+	.name			= "AcornSCSI",
+	.info			= acornscsi_info,
+	.queuecommand		= acornscsi_queuecmd,
+#warning fixme
+	.abort			= acornscsi_abort,
+	.reset			= acornscsi_reset,
+	.can_queue		= 16,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 2,
+	.unchecked_isa_dma	= 0,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.proc_name		= "acornscsi",
+};
+
+static int __devinit
+acornscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	AS_Host *ashost;
+	int ret = -ENOMEM;
+
+	host = scsi_register(&acornscsi_template, sizeof(AS_Host));
+	if (!host)
+		goto out;
+
+	ashost = (AS_Host *)host->hostdata;
+
+	host->io_port = ecard_address(ec, ECARD_MEMC, 0);
+	host->irq = ec->irq;
+
+	ashost->host		= host;
+	ashost->scsi.io_port	= ioaddr(host->io_port + 0x800);
+	ashost->scsi.irq	= host->irq;
+	ashost->card.io_intr	= POD_SPACE(host->io_port) + 0x800;
+	ashost->card.io_page	= POD_SPACE(host->io_port) + 0xc00;
+	ashost->card.io_ram	= ioaddr(host->io_port);
+	ashost->dma.io_port	= host->io_port + 0xc00;
+	ashost->dma.io_intr_clear = POD_SPACE(host->io_port) + 0x800;
+
+	ec->irqaddr	= (char *)ioaddr(ashost->card.io_intr);
+	ec->irqmask	= 0x0a;
+
+	ret = -EBUSY;
+	if (!request_region(host->io_port + 0x800, 2, "acornscsi(sbic)"))
+		goto err_1;
+	if (!request_region(ashost->card.io_intr, 1, "acornscsi(intr)"))
+		goto err_2;
+	if (!request_region(ashost->card.io_page, 1, "acornscsi(page)"))
+		goto err_3;
+#ifdef USE_DMAC
+	if (!request_region(ashost->dma.io_port, 256, "acornscsi(dmac)"))
+		goto err_4;
+#endif
+	if (!request_region(host->io_port, 2048, "acornscsi(ram)"))
+		goto err_5;
+
+	ret = request_irq(host->irq, acornscsi_intr, SA_INTERRUPT, "acornscsi", ashost);
+	if (ret) {
+		printk(KERN_CRIT "scsi%d: IRQ%d not free: %d\n",
+			host->host_no, ashost->scsi.irq, ret);
+		goto err_6;
+	}
+
+	memset(&ashost->stats, 0, sizeof (ashost->stats));
+	queue_initialise(&ashost->queues.issue);
+	queue_initialise(&ashost->queues.disconnected);
+	msgqueue_initialise(&ashost->scsi.msgs);
+
+	acornscsi_resetcard(ashost);
+
+	ret = scsi_add_host(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	free_irq(host->irq, ashost);
+ err_6:
+	release_region(host->io_port, 2048);
+ err_5:
+#ifdef USE_DMAC
+	release_region(ashost->dma.io_port, 256);
+#endif
+ err_4:
+	release_region(ashost->card.io_page, 1);
+ err_3:
+	release_region(ashost->card.io_intr, 1);    
+ err_2:
+	release_region(host->io_port + 0x800, 2);
+ err_1:
+	scsi_unregister(host);
+ out:
+	return ret;
+}
+
+static void __devexit acornscsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	AS_Host *ashost = (AS_Host *)host->hostdata;
+
+	ecard_set_drvdata(ec, NULL);
+	scsi_remove_host(host);
+
+	/*
+	 * Put card into RESET state
+	 */
+	outb(0x80, ashost->card.io_page);
+
+	free_irq(host->irq, ashost);
+
+	release_region(host->io_port + 0x800, 2);
+	release_region(ashost->card.io_intr, 1);
+	release_region(ashost->card.io_page, 1);
+	release_region(ashost->dma.io_port, 256);
+	release_region(host->io_port, 2048);
+
+	msgqueue_free(&ashost->scsi.msgs);
+	queue_free(&ashost->queues.disconnected);
+	queue_free(&ashost->queues.issue);
+}
+
+static const struct ecard_id acornscsi_cids[] = {
+	{ MANU_ACORN, PROD_ACORN_SCSI },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver acornscsi_driver = {
+	.probe		= acornscsi_probe,
+	.remove		= __devexit_p(acornscsi_remove),
+	.id_table	= acornscsi_cids,
+	.drv = {
+		.name		= "acornscsi",
+	},
+};
+
+static int __init acornscsi_init(void)
+{
+	return ecard_register_driver(&acornscsi_driver);
+}
+
+static void __exit acornscsi_exit(void)
+{
+	ecard_remove_driver(&acornscsi_driver);
+}
+
+module_init(acornscsi_init);
+module_exit(acornscsi_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("AcornSCSI driver");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/arm/acornscsi.h b/drivers/scsi/arm/acornscsi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/acornscsi.h	Thu May 15 17:33:14 2003
@@ -0,0 +1,358 @@
+/*
+ *  linux/drivers/acorn/scsi/acornscsi.h
+ *
+ *  Copyright (C) 1997 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.
+ *
+ *  Acorn SCSI driver
+ */
+#ifndef ACORNSCSI_H
+#define ACORNSCSI_H
+
+/* SBIC registers */
+#define OWNID			0
+#define OWNID_FS1		(1<<7)
+#define OWNID_FS2		(1<<6)
+#define OWNID_EHP		(1<<4)
+#define OWNID_EAF		(1<<3)
+
+#define CTRL			1
+#define CTRL_DMAMODE		(1<<7)
+#define CTRL_DMADBAMODE		(1<<6)
+#define CTRL_DMABURST		(1<<5)
+#define CTRL_DMAPOLLED		0
+#define CTRL_HHP		(1<<4)
+#define CTRL_EDI		(1<<3)
+#define CTRL_IDI		(1<<2)
+#define CTRL_HA			(1<<1)
+#define CTRL_HSP		(1<<0)
+
+#define TIMEOUT			2
+#define TOTSECTS		3
+#define TOTHEADS		4
+#define TOTCYLH			5
+#define TOTCYLL			6
+#define LOGADDRH		7
+#define LOGADDRM2		8
+#define LOGADDRM1		9
+#define LOGADDRL		10
+#define SECTORNUM		11
+#define HEADNUM			12
+#define CYLH			13
+#define CYLL			14
+#define TARGETLUN		15
+#define TARGETLUN_TLV		(1<<7)
+#define TARGETLUN_DOK		(1<<6)
+
+#define CMNDPHASE		16
+#define SYNCHTRANSFER		17
+#define SYNCHTRANSFER_OF0	0x00
+#define SYNCHTRANSFER_OF1	0x01
+#define SYNCHTRANSFER_OF2	0x02
+#define SYNCHTRANSFER_OF3	0x03
+#define SYNCHTRANSFER_OF4	0x04
+#define SYNCHTRANSFER_OF5	0x05
+#define SYNCHTRANSFER_OF6	0x06
+#define SYNCHTRANSFER_OF7	0x07
+#define SYNCHTRANSFER_OF8	0x08
+#define SYNCHTRANSFER_OF9	0x09
+#define SYNCHTRANSFER_OF10	0x0A
+#define SYNCHTRANSFER_OF11	0x0B
+#define SYNCHTRANSFER_OF12	0x0C
+#define SYNCHTRANSFER_8DBA	0x00
+#define SYNCHTRANSFER_2DBA	0x20
+#define SYNCHTRANSFER_3DBA	0x30
+#define SYNCHTRANSFER_4DBA	0x40
+#define SYNCHTRANSFER_5DBA	0x50
+#define SYNCHTRANSFER_6DBA	0x60
+#define SYNCHTRANSFER_7DBA	0x70
+
+#define TRANSCNTH		18
+#define TRANSCNTM		19
+#define TRANSCNTL		20
+#define DESTID			21
+#define DESTID_SCC		(1<<7)
+#define DESTID_DPD		(1<<6)
+
+#define SOURCEID		22
+#define SOURCEID_ER		(1<<7)
+#define SOURCEID_ES		(1<<6)
+#define SOURCEID_DSP		(1<<5)
+#define SOURCEID_SIV		(1<<4)
+
+#define SSR			23
+#define CMND			24
+#define CMND_RESET		0x00
+#define CMND_ABORT		0x01
+#define CMND_ASSERTATN		0x02
+#define CMND_NEGATEACK		0x03
+#define CMND_DISCONNECT		0x04
+#define CMND_RESELECT		0x05
+#define CMND_SELWITHATN		0x06
+#define CMND_SELECT		0x07
+#define CMND_SELECTATNTRANSFER	0x08
+#define CMND_SELECTTRANSFER	0x09
+#define CMND_RESELECTRXDATA	0x0A
+#define CMND_RESELECTTXDATA	0x0B
+#define CMND_WAITFORSELRECV	0x0C
+#define CMND_SENDSTATCMD	0x0D
+#define CMND_SENDDISCONNECT	0x0E
+#define CMND_SETIDI		0x0F
+#define CMND_RECEIVECMD		0x10
+#define CMND_RECEIVEDTA		0x11
+#define CMND_RECEIVEMSG		0x12
+#define CMND_RECEIVEUSP		0x13
+#define CMND_SENDCMD		0x14
+#define CMND_SENDDATA		0x15
+#define CMND_SENDMSG		0x16
+#define CMND_SENDUSP		0x17
+#define CMND_TRANSLATEADDR	0x18
+#define CMND_XFERINFO		0x20
+#define CMND_SBT		(1<<7)
+
+#define DATA			25
+#define ASR			26
+#define ASR_INT			(1<<7)
+#define ASR_LCI			(1<<6)
+#define ASR_BSY			(1<<5)
+#define ASR_CIP			(1<<4)
+#define ASR_PE			(1<<1)
+#define ASR_DBR			(1<<0)
+
+/* DMAC registers */
+#define INIT			0x00
+#define INIT_8BIT		(1)
+
+#define CHANNEL			0x80
+#define CHANNEL_0		0x00
+#define CHANNEL_1		0x01
+#define CHANNEL_2		0x02
+#define CHANNEL_3		0x03
+
+#define TXCNTLO			0x01
+#define TXCNTHI			0x81
+#define TXADRLO			0x02
+#define TXADRMD			0x82
+#define TXADRHI			0x03
+
+#define DEVCON0			0x04
+#define DEVCON0_AKL		(1<<7)
+#define DEVCON0_RQL		(1<<6)
+#define DEVCON0_EXW		(1<<5)
+#define DEVCON0_ROT		(1<<4)
+#define DEVCON0_CMP		(1<<3)
+#define DEVCON0_DDMA		(1<<2)
+#define DEVCON0_AHLD		(1<<1)
+#define DEVCON0_MTM		(1<<0)
+
+#define DEVCON1			0x84
+#define DEVCON1_WEV		(1<<1)
+#define DEVCON1_BHLD		(1<<0)
+
+#define MODECON			0x05
+#define MODECON_WOED		0x01
+#define MODECON_VERIFY		0x00
+#define MODECON_READ		0x04
+#define MODECON_WRITE		0x08
+#define MODECON_AUTOINIT	0x10
+#define MODECON_ADDRDIR		0x20
+#define MODECON_DEMAND		0x00
+#define MODECON_SINGLE		0x40
+#define MODECON_BLOCK		0x80
+#define MODECON_CASCADE		0xC0
+
+#define STATUS			0x85
+#define STATUS_TC0		(1<<0)
+#define STATUS_RQ0		(1<<4)
+
+#define TEMPLO			0x06
+#define TEMPHI			0x86
+#define REQREG			0x07
+#define MASKREG			0x87
+#define MASKREG_M0		0x01
+#define MASKREG_M1		0x02
+#define MASKREG_M2		0x04
+#define MASKREG_M3		0x08
+
+/* miscellaneous internal variables */
+
+#define POD_SPACE(x)	((x) + 0xd0000)
+#define MASK_ON		(MASKREG_M3|MASKREG_M2|MASKREG_M1|MASKREG_M0)
+#define MASK_OFF	(MASKREG_M3|MASKREG_M2|MASKREG_M1)
+
+/*
+ * SCSI driver phases
+ */
+typedef enum {
+    PHASE_IDLE,					/* we're not planning on doing anything	 */
+    PHASE_CONNECTING,				/* connecting to a target		 */
+    PHASE_CONNECTED,				/* connected to a target		 */
+    PHASE_MSGOUT,				/* message out to device		 */
+    PHASE_RECONNECTED,				/* reconnected				 */
+    PHASE_COMMANDPAUSED,			/* command partly sent			 */
+    PHASE_COMMAND,				/* command all sent			 */
+    PHASE_DATAOUT,				/* data out to device			 */
+    PHASE_DATAIN,				/* data in from device			 */
+    PHASE_STATUSIN,				/* status in from device		 */
+    PHASE_MSGIN,				/* message in from device		 */
+    PHASE_DONE,					/* finished				 */
+    PHASE_ABORTED,				/* aborted				 */
+    PHASE_DISCONNECT,				/* disconnecting			 */
+} phase_t;
+
+/*
+ * After interrupt, what to do now
+ */
+typedef enum {
+    INTR_IDLE,					/* not expecting another IRQ		 */
+    INTR_NEXT_COMMAND,				/* start next command			 */
+    INTR_PROCESSING,				/* interrupt routine still processing	 */
+} intr_ret_t;
+
+/*
+ * DMA direction
+ */
+typedef enum {
+    DMA_OUT,					/* DMA from memory to chip		*/
+    DMA_IN					/* DMA from chip to memory		*/
+} dmadir_t;
+
+/*
+ * Synchronous transfer state
+ */
+typedef enum {					/* Synchronous transfer state		*/
+    SYNC_ASYNCHRONOUS,				/* don't negociate synchronous transfers*/
+    SYNC_NEGOCIATE,				/* start negociation			*/
+    SYNC_SENT_REQUEST,				/* sent SDTR message			*/
+    SYNC_COMPLETED,				/* received SDTR reply			*/
+} syncxfer_t;
+
+/*
+ * Command type
+ */
+typedef enum {					/* command type				*/
+    CMD_READ,					/* READ_6, READ_10, READ_12		*/
+    CMD_WRITE,					/* WRITE_6, WRITE_10, WRITE_12		*/
+    CMD_MISC,					/* Others				*/
+} cmdtype_t;
+
+/*
+ * Data phase direction
+ */
+typedef enum {					/* Data direction			*/
+    DATADIR_IN,					/* Data in phase expected		*/
+    DATADIR_OUT					/* Data out phase expected		*/
+} datadir_t;
+
+#include "queue.h"
+#include "msgqueue.h"
+
+#define STATUS_BUFFER_SIZE	32
+/*
+ * This is used to dump the previous states of the SBIC
+ */
+struct status_entry {
+	unsigned long	when;
+	unsigned char	ssr;
+	unsigned char	ph;
+	unsigned char	irq;
+	unsigned char	unused;
+};
+
+#define ADD_STATUS(_q,_ssr,_ph,_irq) \
+({									\
+	host->status[(_q)][host->status_ptr[(_q)]].when = jiffies;	\
+	host->status[(_q)][host->status_ptr[(_q)]].ssr  = (_ssr);	\
+	host->status[(_q)][host->status_ptr[(_q)]].ph   = (_ph);	\
+	host->status[(_q)][host->status_ptr[(_q)]].irq  = (_irq);	\
+	host->status_ptr[(_q)] = (host->status_ptr[(_q)] + 1) & (STATUS_BUFFER_SIZE - 1); \
+})
+
+/*
+ * AcornSCSI host specific data
+ */
+typedef struct acornscsi_hostdata {
+    /* miscellaneous */
+    struct Scsi_Host	*host;			/* host					*/
+    Scsi_Cmnd		*SCpnt;			/* currently processing command		*/
+    Scsi_Cmnd		*origSCpnt;		/* original connecting command		*/
+
+    /* driver information */
+    struct {
+	unsigned int	io_port;		/* base address of WD33C93		*/
+	unsigned int	irq;			/* interrupt				*/
+	phase_t		phase;			/* current phase			*/
+
+	struct {
+	    unsigned char	target;		/* reconnected target			*/
+	    unsigned char	lun;		/* reconnected lun			*/
+	    unsigned char	tag;		/* reconnected tag			*/
+	} reconnected;
+
+	Scsi_Pointer	SCp;			/* current commands data pointer	*/
+
+	MsgQueue_t	msgs;
+
+	unsigned short	last_message;		/* last message to be sent		*/
+	unsigned char	disconnectable:1;	/* this command can be disconnected	*/
+    } scsi;
+
+    /* statistics information */
+    struct {
+	unsigned int	queues;
+	unsigned int	removes;
+	unsigned int	fins;
+	unsigned int	reads;
+	unsigned int	writes;
+	unsigned int	miscs;
+	unsigned int	disconnects;
+	unsigned int	aborts;
+	unsigned int	resets;
+    } stats;
+
+    /* queue handling */
+    struct {
+	Queue_t		issue;			/* issue queue				*/
+	Queue_t		disconnected;		/* disconnected command queue		*/
+    } queues;
+
+    /* per-device info */
+    struct {
+	unsigned char	sync_xfer;		/* synchronous transfer (SBIC value)	*/
+	syncxfer_t	sync_state;		/* sync xfer negociation state		*/
+	unsigned char	disconnect_ok:1;	/* device can disconnect		*/
+    } device[8];
+    unsigned long	busyluns[64 / sizeof(unsigned long)];/* array of bits indicating LUNs busy	*/
+
+    /* DMA info */
+    struct {
+	unsigned int	io_port;		/* base address of DMA controller	*/
+	unsigned int	io_intr_clear;		/* address of DMA interrupt clear	*/
+	unsigned int	free_addr;		/* next free address			*/
+	unsigned int	start_addr;		/* start address of current transfer	*/
+	dmadir_t	direction;		/* dma direction			*/
+	unsigned int	transferred;		/* number of bytes transferred		*/
+	unsigned int	xfer_start;		/* scheduled DMA transfer start		*/
+	unsigned int	xfer_length;		/* scheduled DMA transfer length	*/
+	char		*xfer_ptr;		/* pointer to area			*/
+	unsigned char	xfer_required:1;	/* set if we need to transfer something	*/
+	unsigned char	xfer_setup:1;		/* set if DMA is setup			*/
+	unsigned char	xfer_done:1;		/* set if DMA reached end of BH list	*/
+    } dma;
+
+    /* card info */
+    struct {
+	unsigned int	io_intr;		/* base address of interrupt id reg	*/
+	unsigned int	io_page;		/* base address of page reg		*/
+	unsigned int	io_ram;			/* base address of RAM access		*/
+	unsigned char	page_reg;		/* current setting of page reg		*/
+    } card;
+
+    unsigned char status_ptr[9];
+    struct status_entry status[9][STATUS_BUFFER_SIZE];
+} AS_Host;
+
+#endif /* ACORNSCSI_H */
diff -Nru a/drivers/scsi/arm/arxescsi.c b/drivers/scsi/arm/arxescsi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/arxescsi.c	Sat May 17 08:48:41 2003
@@ -0,0 +1,408 @@
+/*
+ * linux/arch/arm/drivers/scsi/arxescsi.c
+ *
+ * Copyright (C) 1997-2000 Russell King, Stefan Hanske
+ *
+ * This driver is based on experimentation.  Hence, it may have made
+ * assumptions about the particular card that I have available, and
+ * may not be reliable!
+ *
+ * Changelog:
+ *  30-08-1997	RMK	0.0.0	Created, READONLY version as cumana_2.c
+ *  22-01-1998	RMK	0.0.1	Updated to 2.1.80
+ *  15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
+ *  11-06-1998 	SH	0.0.2   Changed to support ARXE 16-bit SCSI card
+ *				enabled writing
+ *  01-01-2000	SH	0.1.0   Added *real* pseudo dma writing
+ *				(arxescsi_pseudo_dma_write)
+ *  02-04-2000	RMK	0.1.1	Updated for new error handling code.
+ *  22-10-2000  SH		Updated for new registering scheme.
+ */
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/unistd.h>
+#include <linux/stat.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ecard.h>
+
+#include "../scsi.h"
+#include "../hosts.h"
+#include "fas216.h"
+
+struct arxescsi_info {
+	FAS216_Info		info;
+	struct expansion_card	*ec;
+};
+
+#define DMADATA_OFFSET	(0x200)
+
+#define DMASTAT_OFFSET	(0x600)
+#define DMASTAT_DRQ	(1 << 0)
+
+#define CSTATUS_IRQ	(1 << 0)
+
+#define VERSION "1.10 (23/01/2003 2.5.57)"
+
+/*
+ * Function: int arxescsi_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose : initialises DMA/PIO
+ * Params  : host      - host
+ *	     SCpnt     - command
+ *	     direction - DMA on to/off of card
+ *	     min_type  - minimum DMA support that we must have for this transfer
+ * Returns : 0 if we should not set CMD_WITHDMA for transfer info command
+ */
+static fasdmatype_t
+arxescsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		       fasdmadir_t direction, fasdmatype_t min_type)
+{
+	/*
+	 * We don't do real DMA
+	 */
+	return fasdma_pseudo;
+}
+
+static void arxescsi_pseudo_dma_write(unsigned char *addr, unsigned char *base)
+{
+       __asm__ __volatile__(
+       "               stmdb   sp!, {r0-r12}\n"
+       "               mov     r3, %0\n"
+       "               mov     r1, %1\n"
+       "               add     r2, r1, #512\n"
+       "               mov     r4, #256\n"
+       ".loop_1:       ldmia   r3!, {r6, r8, r10, r12}\n"
+       "               mov     r5, r6, lsl #16\n"
+       "               mov     r7, r8, lsl #16\n"
+       ".loop_2:       ldrb    r0, [r1, #1536]\n"
+       "               tst     r0, #1\n"
+       "               beq     .loop_2\n"
+       "               stmia   r2, {r5-r8}\n\t"
+       "               mov     r9, r10, lsl #16\n"
+       "               mov     r11, r12, lsl #16\n"
+       ".loop_3:       ldrb    r0, [r1, #1536]\n"
+       "               tst     r0, #1\n"
+       "               beq     .loop_3\n"
+       "               stmia   r2, {r9-r12}\n"
+       "               subs    r4, r4, #16\n"
+       "               bne     .loop_1\n"
+       "               ldmia   sp!, {r0-r12}\n"
+       :
+       : "r" (addr), "r" (base));
+}
+
+/*
+ * Function: int arxescsi_dma_pseudo(host, SCpnt, direction, transfer)
+ * Purpose : handles pseudo DMA
+ * Params  : host      - host
+ *	     SCpnt     - command
+ *	     direction - DMA on to/off of card
+ *	     transfer  - minimum number of bytes we expect to transfer
+ */
+static void
+arxescsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		    fasdmadir_t direction, int transfer)
+{
+	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
+	unsigned int length, error = 0;
+	unsigned char *base = info->info.scsi.io_base;
+	unsigned char *addr;
+
+	length = SCp->this_residual;
+	addr = SCp->ptr;
+
+	if (direction == DMA_OUT) {
+		unsigned int word;
+		while (length > 256) {
+			if (readb(base + 0x80) & STAT_INT) {
+				error = 1;
+				break;
+			}
+			arxescsi_pseudo_dma_write(addr, base);
+			addr += 256;
+			length -= 256;
+		}
+
+		if (!error)
+			while (length > 0) {
+				if (readb(base + 0x80) & STAT_INT)
+					break;
+	 
+				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
+					continue;
+
+				word = *addr | *(addr + 1) << 8;
+
+				writew(word, base + DMADATA_OFFSET);
+				if (length > 1) {
+					addr += 2;
+					length -= 2;
+				} else {
+					addr += 1;
+					length -= 1;
+				}
+			}
+	}
+	else {
+		if (transfer && (transfer & 255)) {
+			while (length >= 256) {
+				if (readb(base + 0x80) & STAT_INT) {
+					error = 1;
+					break;
+				}
+	    
+				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
+					continue;
+
+				readsw(base + DMADATA_OFFSET, addr, 256 >> 1);
+				addr += 256;
+				length -= 256;
+			}
+		}
+
+		if (!(error))
+			while (length > 0) {
+				unsigned long word;
+
+				if (readb(base + 0x80) & STAT_INT)
+					break;
+
+				if (!(readb(base + DMASTAT_OFFSET) & DMASTAT_DRQ))
+					continue;
+
+				word = readw(base + DMADATA_OFFSET);
+				*addr++ = word;
+				if (--length > 0) {
+					*addr++ = word >> 8;
+					length --;
+				}
+			}
+	}
+}
+
+/*
+ * Function: int arxescsi_dma_stop(host, SCpnt)
+ * Purpose : stops DMA/PIO
+ * Params  : host  - host
+ *	     SCpnt - command
+ */
+static void arxescsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+	/*
+	 * no DMA to stop
+	 */
+}
+
+/*
+ * Function: const char *arxescsi_info(struct Scsi_Host * host)
+ * Purpose : returns a descriptive string about this interface,
+ * Params  : host - driver host structure to return info for.
+ * Returns : pointer to a static buffer containing null terminated string.
+ */
+static const char *arxescsi_info(struct Scsi_Host *host)
+{
+	struct arxescsi_info *info = (struct arxescsi_info *)host->hostdata;
+	static char string[150];
+
+	sprintf(string, "%s (%s) in slot %d v%s",
+		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
+		VERSION);
+
+	return string;
+}
+
+/*
+ * Function: int arxescsi_proc_info(char *buffer, char **start, off_t offset,
+ *					 int length, int host_no, int inout)
+ * Purpose : Return information about the driver to a user process accessing
+ *	     the /proc filesystem.
+ * Params  : buffer - a buffer to write information to
+ *	     start  - a pointer into this buffer set by this routine to the start
+ *		      of the required information.
+ *	     offset - offset into information that we have read upto.
+ *	     length - length of buffer
+ *	     host_no - host number to return information for
+ *	     inout  - 0 for reading, 1 for writing.
+ * Returns : length of data written to buffer.
+ */
+static int
+arxescsi_proc_info(char *buffer, char **start, off_t offset, int length,
+		   int host_no, int inout)
+{
+	struct Scsi_Host *host;
+	struct arxescsi_info *info;
+	char *p = buffer;
+	int pos;
+
+	host = scsi_host_hn_get(host_no);
+	if (!host)
+		return 0;
+
+	info = (struct arxescsi_info *)host->hostdata;
+	if (inout == 1)
+		return -EINVAL;
+
+	p += sprintf(p, "ARXE 16-bit SCSI driver v%s\n", VERSION);
+	p += fas216_print_host(&info->info, p);
+	p += fas216_print_stats(&info->info, p);
+	p += fas216_print_devices(&info->info, p);
+
+	*start = buffer + offset;
+	pos = p - buffer - offset;
+	if (pos > length)
+		pos = length;
+
+	return pos;
+}
+
+static Scsi_Host_Template arxescsi_template = {
+	.proc_info			= arxescsi_proc_info,
+	.name				= "ARXE SCSI card",
+	.info				= arxescsi_info,
+	.command			= fas216_command,
+	.queuecommand			= fas216_queue_command,
+	.eh_host_reset_handler		= fas216_eh_host_reset,
+	.eh_bus_reset_handler		= fas216_eh_bus_reset,
+	.eh_device_reset_handler	= fas216_eh_device_reset,
+	.eh_abort_handler		= fas216_eh_abort,
+	.can_queue			= 0,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= DISABLE_CLUSTERING,
+	.proc_name			= "arxescsi",
+};
+
+static int __devinit
+arxescsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	struct arxescsi_info *info;
+	unsigned long resbase, reslen;
+	unsigned char *base;
+	int ret;
+
+	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
+	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
+
+	if (!request_mem_region(resbase, reslen, "arxescsi")) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	base = ioremap(resbase, reslen);
+	if (!base) {
+		ret = -ENOMEM;
+		goto out_region;
+	}
+
+	host = scsi_register(&arxescsi_template, sizeof(struct arxescsi_info));
+	if (!host) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	host->base = (unsigned long)base;
+	host->irq = NO_IRQ;
+	host->dma_channel = NO_DMA;
+
+	info = (struct arxescsi_info *)host->hostdata;
+	info->ec = ec;
+
+	info->info.scsi.io_base		= base + 0x2000;
+	info->info.scsi.irq		= host->irq;
+	info->info.scsi.io_shift	= 5;
+	info->info.ifcfg.clockrate	= 24; /* MHz */
+	info->info.ifcfg.select_timeout = 255;
+	info->info.ifcfg.asyncperiod	= 200; /* ns */
+	info->info.ifcfg.sync_max_depth	= 0;
+	info->info.ifcfg.cntl3		= CNTL3_FASTSCSI | CNTL3_FASTCLK;
+	info->info.ifcfg.disconnect_ok	= 0;
+	info->info.ifcfg.wide_max_size	= 0;
+	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
+	info->info.dma.setup		= arxescsi_dma_setup;
+	info->info.dma.pseudo		= arxescsi_dma_pseudo;
+	info->info.dma.stop		= arxescsi_dma_stop;
+		
+	ec->irqaddr = base;
+	ec->irqmask = CSTATUS_IRQ;
+
+	ret = fas216_init(host);
+	if (ret)
+		goto out_unregister;
+
+	ret = fas216_add(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	fas216_release(host);
+ out_unregister:
+	scsi_unregister(host);
+ out_unmap:
+	iounmap(base);
+ out_region:
+	release_mem_region(resbase, reslen);
+ out:
+	return ret;
+}
+
+static void __devexit arxescsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	unsigned long resbase, reslen;
+
+	ecard_set_drvdata(ec, NULL);
+	fas216_remove(host);
+
+	iounmap((void *)host->base);
+
+	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
+	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
+
+	release_mem_region(resbase, reslen);
+
+	fas216_release(host);
+	scsi_unregister(host);
+}
+
+static const struct ecard_id arxescsi_cids[] = {
+	{ MANU_ARXE, PROD_ARXE_SCSI },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver arxescsi_driver = {
+	.probe		= arxescsi_probe,
+	.remove		= __devexit_p(arxescsi_remove),
+	.id_table	= arxescsi_cids,
+	.drv = {
+		.name		= "arxescsi",
+	},
+};
+
+static int __init init_arxe_scsi_driver(void)
+{
+	return ecard_register_driver(&arxescsi_driver);
+}
+
+static void __exit exit_arxe_scsi_driver(void)
+{
+	ecard_remove_driver(&arxescsi_driver);
+}
+
+module_init(init_arxe_scsi_driver);
+module_exit(exit_arxe_scsi_driver);
+
+MODULE_AUTHOR("Stefan Hanske");
+MODULE_DESCRIPTION("ARXESCSI driver for Acorn machines");
+MODULE_LICENSE("GPL");
+
diff -Nru a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/cumana_1.c	Sat May 17 08:48:41 2003
@@ -0,0 +1,355 @@
+/*
+ * Generic Generic NCR5380 driver
+ *
+ * Copyright 1995-2002, Russell King
+ */
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "../scsi.h"
+#include "../hosts.h"
+
+#include <scsi/scsicam.h>
+
+#define AUTOSENSE
+#define PSEUDO_DMA
+
+#define CUMANASCSI_PUBLIC_RELEASE 1
+
+#define NCR5380_implementation_fields	int port, ctrl
+#define NCR5380_local_declare()		struct Scsi_Host *_instance
+#define NCR5380_setup(instance)		_instance = instance
+#define NCR5380_read(reg)		cumanascsi_read(_instance, reg)
+#define NCR5380_write(reg, value)	cumanascsi_write(_instance, reg, value)
+#define NCR5380_intr			cumanascsi_intr
+#define NCR5380_queue_command		cumanascsi_queue_command
+#define NCR5380_proc_info		cumanascsi_proc_info
+
+int NCR5380_proc_info(char *buffer, char **start, off_t offset,
+		      int length, int hostno, int inout);
+
+#define BOARD_NORMAL	0
+#define BOARD_NCR53C400	1
+
+#include "../NCR5380.h"
+
+void cumanascsi_setup(char *str, int *ints)
+{
+}
+
+const char *cumanascsi_info(struct Scsi_Host *spnt)
+{
+	return "";
+}
+
+#ifdef NOT_EFFICIENT
+#define CTRL(p,v)     outb(*ctrl = (v), (p) - 577)
+#define STAT(p)       inb((p)+1)
+#define IN(p)         inb((p))
+#define OUT(v,p)      outb((v), (p))
+#else
+#define CTRL(p,v)	(p[-2308] = (*ctrl = (v)))
+#define STAT(p)		(p[4])
+#define IN(p)		(*(p))
+#define IN2(p)		((unsigned short)(*(volatile unsigned long *)(p)))
+#define OUT(v,p)	(*(p) = (v))
+#define OUT2(v,p)	(*((volatile unsigned long *)(p)) = (v))
+#endif
+#define L(v)		(((v)<<16)|((v) & 0x0000ffff))
+#define H(v)		(((v)>>16)|((v) & 0xffff0000))
+
+static inline int
+NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr, int len)
+{
+  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+  int oldctrl = *ctrl;
+  unsigned long *laddr;
+#ifdef NOT_EFFICIENT
+  int iobase = instance->io_port;
+  int dma_io = iobase & ~(0x3C0000>>2);
+#else
+  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
+  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
+#endif
+
+  if(!len) return 0;
+
+  CTRL(iobase, 0x02);
+  laddr = (unsigned long *)addr;
+  while(len >= 32)
+  {
+    int status;
+    unsigned long v;
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(!(status & 0x40))
+      continue;
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    v=*laddr++; OUT2(L(v),dma_io); OUT2(H(v),dma_io);
+    len -= 32;
+    if(len == 0)
+      break;
+  }
+
+  addr = (unsigned char *)laddr;
+  CTRL(iobase, 0x12);
+  while(len > 0)
+  {
+    int status;
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(status & 0x40)
+    {
+      OUT(*addr++, dma_io);
+      if(--len == 0)
+        break;
+    }
+
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(status & 0x40)
+    {
+      OUT(*addr++, dma_io);
+      if(--len == 0)
+        break;
+    }
+  }
+end:
+  CTRL(iobase, oldctrl|0x40);
+  return len;
+}
+
+static inline int
+NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr, int len)
+{
+  int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+  int oldctrl = *ctrl;
+  unsigned long *laddr;
+#ifdef NOT_EFFICIENT
+  int iobase = instance->io_port;
+  int dma_io = iobase & ~(0x3C0000>>2);
+#else
+  volatile unsigned char *iobase = (unsigned char *)ioaddr(instance->io_port);
+  volatile unsigned char *dma_io = (unsigned char *)((int)iobase & ~0x3C0000);
+#endif
+
+  if(!len) return 0;
+
+  CTRL(iobase, 0x00);
+  laddr = (unsigned long *)addr;
+  while(len >= 32)
+  {
+    int status;
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(!(status & 0x40))
+      continue;
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    *laddr++ = IN2(dma_io)|(IN2(dma_io)<<16);
+    len -= 32;
+    if(len == 0)
+      break;
+  }
+
+  addr = (unsigned char *)laddr;
+  CTRL(iobase, 0x10);
+  while(len > 0)
+  {
+    int status;
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(status & 0x40)
+    {
+      *addr++ = IN(dma_io);
+      if(--len == 0)
+        break;
+    }
+
+    status = STAT(iobase);
+    if(status & 0x80)
+      goto end;
+    if(status & 0x40)
+    {
+      *addr++ = IN(dma_io);
+      if(--len == 0)
+        break;
+    }
+  }
+end:
+  CTRL(iobase, oldctrl|0x40);
+  return len;
+}
+
+#undef STAT
+#undef CTRL
+#undef IN
+#undef OUT
+
+#define CTRL(p,v) outb(*ctrl = (v), (p) - 577)
+
+static char cumanascsi_read(struct Scsi_Host *instance, int reg)
+{
+	unsigned int iobase = instance->io_port;
+	int i;
+	int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+
+	CTRL(iobase, 0);
+	i = inb(iobase + 64 + reg);
+	CTRL(iobase, 0x40);
+
+	return i;
+}
+
+static void cumanascsi_write(struct Scsi_Host *instance, int reg, int value)
+{
+	int iobase = instance->io_port;
+	int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
+
+	CTRL(iobase, 0);
+	outb(value, iobase + 64 + reg);
+	CTRL(iobase, 0x40);
+}
+
+#undef CTRL
+
+#include "../NCR5380.c"
+
+static Scsi_Host_Template cumanascsi_template = {
+	.module			= THIS_MODULE,
+	.name			= "Cumana 16-bit SCSI",
+	.info			= cumanascsi_info,
+	.queuecommand		= cumanascsi_queue_command,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
+	.can_queue		= 16,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 2,
+	.unchecked_isa_dma	= 0,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.proc_name		= "CumanaSCSI-1",
+};
+
+static int __devinit
+cumanascsi1_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	int ret = -ENOMEM;
+
+	host = scsi_register(&cumanascsi_template, sizeof(struct NCR5380_hostdata));
+	if (!host)
+		goto out;
+
+        host->io_port = ecard_address(ec, ECARD_IOC, ECARD_SLOW) + 0x800;
+	host->irq = ec->irq;
+
+	NCR5380_init(host, 0);
+
+	host->n_io_port = 255;
+	if (!(request_region(host->io_port, host->n_io_port, "CumanaSCSI-1"))) {
+		ret = -EBUSY;
+		goto out_free;
+	}
+
+        ((struct NCR5380_hostdata *)host->hostdata)->ctrl = 0;
+        outb(0x00, host->io_port - 577);
+
+	ret = request_irq(host->irq, cumanascsi_intr, SA_INTERRUPT,
+			  "CumanaSCSI-1", host);
+	if (ret) {
+		printk("scsi%d: IRQ%d not free: %d\n",
+		    host->host_no, host->irq, ret);
+		goto out_release;
+	}
+
+	printk("scsi%d: at port 0x%08lx irq %d",
+		host->host_no, host->io_port, host->irq);
+	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+		host->can_queue, host->cmd_per_lun, CUMANASCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", host->host_no);
+	NCR5380_print_options(host);
+	printk("\n");
+
+	ret = scsi_add_host(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	free_irq(host->irq, host);
+ out_release:
+	release_region(host->io_port, host->n_io_port);
+ out_free:
+	scsi_unregister(host);
+ out:
+	return ret;
+}
+
+static void __devexit cumanascsi1_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+
+	ecard_set_drvdata(ec, NULL);
+
+	scsi_remove_host(host);
+	free_irq(host->irq, host);
+	release_region(host->io_port, host->n_io_port);
+	scsi_unregister(host);
+}
+
+static const struct ecard_id cumanascsi1_cids[] = {
+	{ MANU_CUMANA, PROD_CUMANA_SCSI_1 },
+	{ 0xffff, 0xffff }
+};
+
+static struct ecard_driver cumanascsi1_driver = {
+	.probe		= cumanascsi1_probe,
+	.remove		= __devexit_p(cumanascsi1_remove),
+	.id_table	= cumanascsi1_cids,
+	.drv = {
+		.name		= "cumanascsi1",
+	},
+};
+
+static int __init cumanascsi_init(void)
+{
+	return ecard_register_driver(&cumanascsi1_driver);
+}
+
+static void __exit cumanascsi_exit(void)
+{
+	ecard_remove_driver(&cumanascsi1_driver);
+}
+
+module_init(cumanascsi_init);
+module_exit(cumanascsi_exit);
+
+MODULE_DESCRIPTION("Cumana SCSI-1 driver for Acorn machines");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/arm/cumana_2.c b/drivers/scsi/arm/cumana_2.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/cumana_2.c	Sat May 17 11:02:30 2003
@@ -0,0 +1,574 @@
+/*
+ *  linux/drivers/acorn/scsi/cumana_2.c
+ *
+ *  Copyright (C) 1997-2002 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.
+ *
+ *  Changelog:
+ *   30-08-1997	RMK	0.0.0	Created, READONLY version.
+ *   22-01-1998	RMK	0.0.1	Updated to 2.1.80.
+ *   15-04-1998	RMK	0.0.1	Only do PIO if FAS216 will allow it.
+ *   02-05-1998	RMK	0.0.2	Updated & added DMA support.
+ *   27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
+ *   18-08-1998	RMK	0.0.3	Fixed synchronous transfer depth.
+ *   02-04-2000	RMK	0.0.4	Updated for new error handling code.
+ */
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+
+#include "../scsi.h"
+#include "../hosts.h"
+#include "fas216.h"
+#include "scsi.h"
+
+#include <scsi/scsicam.h>
+
+#define CUMANASCSI2_STATUS		(0x0000)
+#define STATUS_INT			(1 << 0)
+#define STATUS_DRQ			(1 << 1)
+#define STATUS_LATCHED			(1 << 3)
+
+#define CUMANASCSI2_ALATCH		(0x0014)
+#define ALATCH_ENA_INT			(3)
+#define ALATCH_DIS_INT			(2)
+#define ALATCH_ENA_TERM			(5)
+#define ALATCH_DIS_TERM			(4)
+#define ALATCH_ENA_BIT32		(11)
+#define ALATCH_DIS_BIT32		(10)
+#define ALATCH_ENA_DMA			(13)
+#define ALATCH_DIS_DMA			(12)
+#define ALATCH_DMA_OUT			(15)
+#define ALATCH_DMA_IN			(14)
+
+#define CUMANASCSI2_PSEUDODMA		(0x0200)
+
+#define CUMANASCSI2_FAS216_OFFSET	(0x0300)
+#define CUMANASCSI2_FAS216_SHIFT	2
+
+/*
+ * Version
+ */
+#define VERSION "1.00 (13/11/2002 2.5.47)"
+
+/*
+ * Use term=0,1,0,0,0 to turn terminators on/off
+ */
+static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+#define NR_SG	256
+
+struct cumanascsi2_info {
+	FAS216_Info		info;
+	struct expansion_card	*ec;
+
+	void			*status;	/* card status register	*/
+	void			*alatch;	/* Control register	*/
+	unsigned int		terms;		/* Terminator state	*/
+	void			*dmaarea;	/* Pseudo DMA area	*/
+	struct scatterlist	sg[NR_SG];	/* Scatter DMA list	*/
+};
+
+#define CSTATUS_IRQ	(1 << 0)
+#define CSTATUS_DRQ	(1 << 1)
+
+/* Prototype: void cumanascsi_2_irqenable(ec, irqnr)
+ * Purpose  : Enable interrupts on Cumana SCSI 2 card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+cumanascsi_2_irqenable(struct expansion_card *ec, int irqnr)
+{
+	writeb(ALATCH_ENA_INT, ec->irq_data);
+}
+
+/* Prototype: void cumanascsi_2_irqdisable(ec, irqnr)
+ * Purpose  : Disable interrupts on Cumana SCSI 2 card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+cumanascsi_2_irqdisable(struct expansion_card *ec, int irqnr)
+{
+	writeb(ALATCH_DIS_INT, ec->irq_data);
+}
+
+static const expansioncard_ops_t cumanascsi_2_ops = {
+	.irqenable	= cumanascsi_2_irqenable,
+	.irqdisable	= cumanascsi_2_irqdisable,
+};
+
+/* Prototype: void cumanascsi_2_terminator_ctl(host, on_off)
+ * Purpose  : Turn the Cumana SCSI 2 terminators on or off
+ * Params   : host   - card to turn on/off
+ *          : on_off - !0 to turn on, 0 to turn off
+ */
+static void
+cumanascsi_2_terminator_ctl(struct Scsi_Host *host, int on_off)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+
+	if (on_off) {
+		info->terms = 1;
+		writeb(ALATCH_ENA_TERM, info->alatch);
+	} else {
+		info->terms = 0;
+		writeb(ALATCH_DIS_TERM, info->alatch);
+	}
+}
+
+/* Prototype: void cumanascsi_2_intr(irq, *dev_id, *regs)
+ * Purpose  : handle interrupts from Cumana SCSI 2 card
+ * Params   : irq    - interrupt number
+ *	      dev_id - user-defined (Scsi_Host structure)
+ *	      regs   - processor registers at interrupt
+ */
+static irqreturn_t
+cumanascsi_2_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct cumanascsi2_info *info = dev_id;
+
+	return fas216_intr(&info->info);
+}
+
+/* Prototype: fasdmatype_t cumanascsi_2_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose  : initialises DMA/PIO
+ * Params   : host      - host
+ *	      SCpnt     - command
+ *	      direction - DMA on to/off of card
+ *	      min_type  - minimum DMA support that we must have for this transfer
+ * Returns  : type of transfer to be performed
+ */
+static fasdmatype_t
+cumanascsi_2_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		       fasdmadir_t direction, fasdmatype_t min_type)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+	struct device *dev = scsi_get_device(host);
+	int dmach = host->dma_channel;
+
+	writeb(ALATCH_DIS_DMA, info->alatch);
+
+	if (dmach != NO_DMA &&
+	    (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
+		int bufs, map_dir, dma_dir, alatch_dir;
+
+		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
+
+		if (direction == DMA_OUT)
+			map_dir = DMA_TO_DEVICE,
+			dma_dir = DMA_MODE_WRITE,
+			alatch_dir = ALATCH_DMA_OUT;
+		else
+			map_dir = DMA_FROM_DEVICE,
+			dma_dir = DMA_MODE_READ,
+			alatch_dir = ALATCH_DMA_IN;
+
+		dma_map_sg(dev, info->sg, bufs + 1, map_dir);
+
+		disable_dma(dmach);
+		set_dma_sg(dmach, info->sg, bufs + 1);
+		writeb(alatch_dir, info->alatch);
+		set_dma_mode(dmach, dma_dir);
+		enable_dma(dmach);
+		writeb(ALATCH_ENA_DMA, info->alatch);
+		writeb(ALATCH_DIS_BIT32, info->alatch);
+		return fasdma_real_all;
+	}
+
+	/*
+	 * If we're not doing DMA,
+	 *  we'll do pseudo DMA
+	 */
+	return fasdma_pio;
+}
+
+/*
+ * Prototype: void cumanascsi_2_dma_pseudo(host, SCpnt, direction, transfer)
+ * Purpose  : handles pseudo DMA
+ * Params   : host      - host
+ *	      SCpnt     - command
+ *	      direction - DMA on to/off of card
+ *	      transfer  - minimum number of bytes we expect to transfer
+ */
+static void
+cumanascsi_2_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+			fasdmadir_t direction, int transfer)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+	unsigned int length;
+	unsigned char *addr;
+
+	length = SCp->this_residual;
+	addr = SCp->ptr;
+
+	if (direction == DMA_OUT)
+#if 0
+		while (length > 1) {
+			unsigned long word;
+			unsigned int status = readb(info->status);
+
+			if (status & STATUS_INT)
+				goto end;
+
+			if (!(status & STATUS_DRQ))
+				continue;
+
+			word = *addr | *(addr + 1) << 8;
+			writew(word, info->dmaarea);
+			addr += 2;
+			length -= 2;
+		}
+#else
+		printk ("PSEUDO_OUT???\n");
+#endif
+	else {
+		if (transfer && (transfer & 255)) {
+			while (length >= 256) {
+				unsigned int status = readb(info->status);
+
+				if (status & STATUS_INT)
+					return;
+	    
+				if (!(status & STATUS_DRQ))
+					continue;
+
+				readsw(info->dmaarea, addr, 256 >> 1);
+				addr += 256;
+				length -= 256;
+			}
+		}
+
+		while (length > 0) {
+			unsigned long word;
+			unsigned int status = readb(info->status);
+
+			if (status & STATUS_INT)
+				return;
+
+			if (!(status & STATUS_DRQ))
+				continue;
+
+			word = readw(info->dmaarea);
+			*addr++ = word;
+			if (--length > 0) {
+				*addr++ = word >> 8;
+				length --;
+			}
+		}
+	}
+}
+
+/* Prototype: int cumanascsi_2_dma_stop(host, SCpnt)
+ * Purpose  : stops DMA/PIO
+ * Params   : host  - host
+ *	      SCpnt - command
+ */
+static void
+cumanascsi_2_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+	if (host->dma_channel != NO_DMA) {
+		writeb(ALATCH_DIS_DMA, info->alatch);
+		disable_dma(host->dma_channel);
+	}
+}
+
+/* Prototype: const char *cumanascsi_2_info(struct Scsi_Host * host)
+ * Purpose  : returns a descriptive string about this interface,
+ * Params   : host - driver host structure to return info for.
+ * Returns  : pointer to a static buffer containing null terminated string.
+ */
+const char *cumanascsi_2_info(struct Scsi_Host *host)
+{
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+	static char string[150];
+
+	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
+		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
+		VERSION, info->terms ? "n" : "ff");
+
+	return string;
+}
+
+/* Prototype: int cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+ * Purpose  : Set a driver specific function
+ * Params   : host   - host to setup
+ *          : buffer - buffer containing string describing operation
+ *          : length - length of string
+ * Returns  : -EINVAL, or 0
+ */
+static int
+cumanascsi_2_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+{
+	int ret = length;
+
+	if (length >= 11 && strcmp(buffer, "CUMANASCSI2") == 0) {
+		buffer += 11;
+		length -= 11;
+
+		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
+			if (buffer[5] == '1')
+				cumanascsi_2_terminator_ctl(host, 1);
+			else if (buffer[5] == '0')
+				cumanascsi_2_terminator_ctl(host, 0);
+			else
+				ret = -EINVAL;
+		} else
+			ret = -EINVAL;
+	} else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/* Prototype: int cumanascsi_2_proc_info(char *buffer, char **start, off_t offset,
+ *					 int length, int host_no, int inout)
+ * Purpose  : Return information about the driver to a user process accessing
+ *	      the /proc filesystem.
+ * Params   : buffer - a buffer to write information to
+ *	      start  - a pointer into this buffer set by this routine to the start
+ *		       of the required information.
+ *	      offset - offset into information that we have read upto.
+ *	      length - length of buffer
+ *	      host_no - host number to return information for
+ *	      inout  - 0 for reading, 1 for writing.
+ * Returns  : length of data written to buffer.
+ */
+int cumanascsi_2_proc_info (char *buffer, char **start, off_t offset,
+			    int length, int host_no, int inout)
+{
+	struct Scsi_Host *host;
+	struct cumanascsi2_info *info;
+	char *p = buffer;
+	int pos;
+
+	host = scsi_host_hn_get(host_no);
+	if (!host)
+		return 0;
+
+	if (inout == 1)
+		return cumanascsi_2_set_proc_info(host, buffer, length);
+
+	info = (struct cumanascsi2_info *)host->hostdata;
+
+	p += sprintf(p, "Cumana SCSI II driver v%s\n", VERSION);
+	p += fas216_print_host(&info->info, p);
+	p += sprintf(p, "Term    : o%s\n",
+			info->terms ? "n" : "ff");
+
+	p += fas216_print_stats(&info->info, p);
+	p += fas216_print_devices(&info->info, p);
+
+	*start = buffer + offset;
+	pos = p - buffer - offset;
+	if (pos > length)
+		pos = length;
+
+	return pos;
+}
+
+static Scsi_Host_Template cumanascsi2_template = {
+	.module				= THIS_MODULE,
+	.proc_info			= cumanascsi_2_proc_info,
+	.name				= "Cumana SCSI II",
+	.info				= cumanascsi_2_info,
+	.command			= fas216_command,
+	.queuecommand			= fas216_queue_command,
+	.eh_host_reset_handler		= fas216_eh_host_reset,
+	.eh_bus_reset_handler		= fas216_eh_bus_reset,
+	.eh_device_reset_handler	= fas216_eh_device_reset,
+	.eh_abort_handler		= fas216_eh_abort,
+	.can_queue			= 1,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= DISABLE_CLUSTERING,
+	.proc_name			= "cumanascsi2",
+};
+
+static int __devinit
+cumanascsi2_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	struct cumanascsi2_info *info;
+	unsigned long resbase, reslen;
+	unsigned char *base;
+	int ret;
+
+	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
+	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
+
+	if (!request_mem_region(resbase, reslen, "cumanascsi2")) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	base = ioremap(resbase, reslen);
+	if (!base) {
+		ret = -ENOMEM;
+		goto out_region;
+	}
+
+	host = scsi_register(&cumanascsi2_template,
+			     sizeof(struct cumanascsi2_info));
+	if (!host) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	host->base	  = (unsigned long)base;
+	host->irq	  = ec->irq;
+	host->dma_channel = ec->dma;
+
+	ecard_set_drvdata(ec, host);
+
+	info = (struct cumanascsi2_info *)host->hostdata;
+	info->ec	= ec;
+	info->dmaarea	= base + CUMANASCSI2_PSEUDODMA;
+	info->status	= base + CUMANASCSI2_STATUS;
+	info->alatch	= base + CUMANASCSI2_ALATCH;
+
+	ec->irqaddr	= info->status;
+	ec->irqmask	= STATUS_INT;
+	ec->irq_data	= base + CUMANASCSI2_ALATCH;
+	ec->ops		= &cumanascsi_2_ops;
+
+	cumanascsi_2_terminator_ctl(host, term[ec->slot_no]);
+
+	info->info.scsi.io_base		= base + CUMANASCSI2_FAS216_OFFSET;
+	info->info.scsi.io_shift	= CUMANASCSI2_FAS216_SHIFT;
+	info->info.scsi.irq		= host->irq;
+	info->info.ifcfg.clockrate	= 40; /* MHz */
+	info->info.ifcfg.select_timeout	= 255;
+	info->info.ifcfg.asyncperiod	= 200; /* ns */
+	info->info.ifcfg.sync_max_depth	= 7;
+	info->info.ifcfg.cntl3		= CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
+	info->info.ifcfg.disconnect_ok	= 1;
+	info->info.ifcfg.wide_max_size	= 0;
+	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
+	info->info.dma.setup		= cumanascsi_2_dma_setup;
+	info->info.dma.pseudo		= cumanascsi_2_dma_pseudo;
+	info->info.dma.stop		= cumanascsi_2_dma_stop;
+
+	ret = fas216_init(host);
+	if (ret)
+		goto out_free;
+
+	ret = request_irq(host->irq, cumanascsi_2_intr,
+			  SA_INTERRUPT, "cumanascsi2", info);
+	if (ret) {
+		printk("scsi%d: IRQ%d not free: %d\n",
+		       host->host_no, host->irq, ret);
+		goto out_release;
+	}
+
+	if (host->dma_channel != NO_DMA) {
+		if (request_dma(host->dma_channel, "cumanascsi2")) {
+			printk("scsi%d: DMA%d not free, using PIO\n",
+			       host->host_no, host->dma_channel);
+			host->dma_channel = NO_DMA;
+		} else {
+			set_dma_speed(host->dma_channel, 180);
+			info->info.ifcfg.capabilities |= FASCAP_DMA;
+		}
+	}
+
+	ret = fas216_add(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	if (host->dma_channel != NO_DMA)
+		free_dma(host->dma_channel);
+	free_irq(host->irq, host);
+
+ out_release:
+	fas216_release(host);
+
+ out_free:
+	scsi_unregister(host);
+
+ out_unmap:
+	iounmap(base);
+
+ out_region:
+	release_mem_region(resbase, reslen);
+
+ out:
+	return ret;
+}
+
+static void __devexit cumanascsi2_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct cumanascsi2_info *info = (struct cumanascsi2_info *)host->hostdata;
+	unsigned long resbase, reslen;
+
+	ecard_set_drvdata(ec, NULL);
+	fas216_remove(host);
+
+	if (host->dma_channel != NO_DMA)
+		free_dma(host->dma_channel);
+	free_irq(host->irq, info);
+
+	iounmap((void *)host->base);
+
+	resbase = ecard_resource_start(ec, ECARD_RES_MEMC);
+	reslen = ecard_resource_len(ec, ECARD_RES_MEMC);
+
+	release_mem_region(resbase, reslen);
+
+	fas216_release(host);
+	scsi_unregister(host);
+}
+
+static const struct ecard_id cumanascsi2_cids[] = {
+	{ MANU_CUMANA, PROD_CUMANA_SCSI_2 },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver cumanascsi2_driver = {
+	.probe		= cumanascsi2_probe,
+	.remove		= __devexit_p(cumanascsi2_remove),
+	.id_table	= cumanascsi2_cids,
+	.drv = {
+		.name		= "cumanascsi2",
+	},
+};
+
+static int __init cumanascsi2_init(void)
+{
+	return ecard_register_driver(&cumanascsi2_driver);
+}
+
+static void __exit cumanascsi2_exit(void)
+{
+	ecard_remove_driver(&cumanascsi2_driver);
+}
+
+module_init(cumanascsi2_init);
+module_exit(cumanascsi2_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Cumana SCSI-2 driver for Acorn machines");
+MODULE_PARM(term, "1-8i");
+MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/arm/ecoscsi.c b/drivers/scsi/arm/ecoscsi.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/ecoscsi.c	Sat May 17 06:52:32 2003
@@ -0,0 +1,283 @@
+#define AUTOSENSE
+/* #define PSEUDO_DMA */
+
+/*
+ * EcoSCSI Generic NCR5380 driver
+ *
+ * Copyright 1995, Russell King
+ *
+ * ALPHA RELEASE 1.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * Options :
+ *
+ * PARITY - enable parity checking.  Not supported.
+ *
+ * SCSI2 - enable support for SCSI-II tagged queueing.  Untested.
+ *
+ * USLEEP - enable support for devices that don't disconnect.  Untested.
+ */
+
+/*
+ * $Log: ecoscsi.c,v $
+ * Revision 1.2  1998/03/08 05:49:47  davem
+ * Merge to 2.1.89
+ *
+ * Revision 1.1  1998/02/23 02:45:24  davem
+ * Merge to 2.1.88
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/blk.h>
+
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include "../scsi.h"
+#include "../hosts.h"
+
+#define NCR5380_implementation_fields	int port, ctrl
+#define NCR5380_local_declare()		struct Scsi_Host *_instance
+#define NCR5380_setup(instance)		_instance = instance
+
+#define NCR5380_read(reg)		ecoscsi_read(_instance, reg)
+#define NCR5380_write(reg, value)	ecoscsi_write(_instance, reg, value)
+
+#define NCR5380_intr			ecoscsi_intr
+#define NCR5380_queue_command		ecoscsi_queue_command
+#define NCR5380_proc_info		ecoscsi_proc_info
+
+#include "../NCR5380.h"
+
+#define ECOSCSI_PUBLIC_RELEASE 1
+
+static char ecoscsi_read(struct Scsi_Host *instance, int reg)
+{
+  int iobase = instance->io_port;
+  outb(reg | 8, iobase);
+  return inb(iobase + 1);
+}
+
+static void ecoscsi_write(struct Scsi_Host *instance, int reg, int value)
+{
+  int iobase = instance->io_port;
+  outb(reg | 8, iobase);
+  outb(value, iobase + 1);
+}
+
+/*
+ * Function : ecoscsi_setup(char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ *
+ * Inputs : str - unused, ints - array of integer parameters with ints[0]
+ *	equal to the number of ints.
+ *
+ */
+
+void ecoscsi_setup(char *str, int *ints) {
+}
+
+/*
+ * Function : int ecoscsi_detect(Scsi_Host_Template * tpnt)
+ *
+ * Purpose : initializes ecoscsi NCR5380 driver based on the
+ *	command line / compile time port and irq definitions.
+ *
+ * Inputs : tpnt - template for this SCSI adapter.
+ *
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+
+int ecoscsi_detect(Scsi_Host_Template * tpnt)
+{
+	struct Scsi_Host *host;
+
+	tpnt->proc_name = "ecoscsi";
+
+	host = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
+	if (!host)
+		return 0;
+
+	host->io_port = 0x80ce8000;
+	host->n_io_port = 144;
+	host->irq = IRQ_NONE;
+
+	if ( !(request_region(host->io_port, host->n_io_port, "ecoscsi")) )
+		goto unregister_scsi;
+
+	ecoscsi_write (host, MODE_REG, 0x20);		/* Is it really SCSI? */
+	if (ecoscsi_read (host, MODE_REG) != 0x20) /* Write to a reg.    */
+		goto release_reg;
+
+	ecoscsi_write( host, MODE_REG, 0x00 );		/* it back.	      */
+	if (ecoscsi_read (host, MODE_REG) != 0x00)
+		goto release_reg;
+
+	NCR5380_init(host, 0);
+
+	printk("scsi%d: at port 0x%08lx irqs disabled", host->host_no, host->io_port);
+	printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+		host->can_queue, host->cmd_per_lun, ECOSCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", host->host_no);
+	NCR5380_print_options(host);
+	printk("\n");
+
+	return 1;
+
+release_reg:
+	release_region(host->io_port, host->n_io_port);
+unregister_scsi:
+	scsi_unregister(host);
+	return 0;
+}
+
+int ecoscsi_release (struct Scsi_Host *shpnt)
+{
+	if (shpnt->irq != IRQ_NONE)
+		free_irq (shpnt->irq, NULL);
+	if (shpnt->io_port)
+		release_region (shpnt->io_port, shpnt->n_io_port);
+	return 0;
+}
+
+const char * ecoscsi_info (struct Scsi_Host *spnt)
+{
+	return "";
+}
+
+#if 0
+#define STAT(p) inw(p + 144)
+
+static inline int NCR5380_pwrite(struct Scsi_Host *host, unsigned char *addr,
+              int len)
+{
+  int iobase = host->io_port;
+printk("writing %p len %d\n",addr, len);
+  if(!len) return -1;
+
+  while(1)
+  {
+    int status;
+    while(((status = STAT(iobase)) & 0x100)==0);
+  }
+}
+
+static inline int NCR5380_pread(struct Scsi_Host *host, unsigned char *addr,
+              int len)
+{
+  int iobase = host->io_port;
+  int iobase2= host->io_port + 0x100;
+  unsigned char *start = addr;
+  int s;
+printk("reading %p len %d\n",addr, len);
+  outb(inb(iobase + 128), iobase + 135);
+  while(len > 0)
+  {
+    int status,b,i, timeout;
+    timeout = 0x07FFFFFF;
+    while(((status = STAT(iobase)) & 0x100)==0)
+    {
+      timeout--;
+      if(status & 0x200 || !timeout)
+      {
+        printk("status = %p\n",status);
+        outb(0, iobase + 135);
+        return 1;
+      }
+    }
+    if(len >= 128)
+    {
+      for(i=0; i<64; i++)
+      {
+        b = inw(iobase + 136);
+        *addr++ = b;
+        *addr++ = b>>8;
+      }
+      len -= 128;
+    }
+    else
+    {
+      b = inw(iobase + 136);
+      *addr ++ = b;
+      len -= 1;
+      if(len)
+        *addr ++ = b>>8;
+      len -= 1;
+    }
+  }
+  outb(0, iobase + 135);
+  printk("first bytes = %02X %02X %02X %20X %02X %02X %02X\n",*start, start[1], start[2], start[3], start[4], start[5], start[6]);
+  return 1;
+}
+#endif
+#undef STAT
+
+int NCR5380_proc_info(char *buffer, char **start, off_t offset,
+		      int length, int hostno, int inout);
+
+#define BOARD_NORMAL	0
+#define BOARD_NCR53C400	1
+
+#include "../NCR5380.c"
+
+static Scsi_Host_Template ecoscsi_template =  {
+	.module		= THIS_MODULE,
+	.name		= "Serial Port EcoSCSI NCR5380",
+	.detect		= ecoscsi_detect,
+	.release	= ecoscsi_release,
+	.info		= ecoscsi_info,
+	.queuecommand	= ecoscsi_queue_command,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
+	.can_queue	= 16,
+	.this_id	= 7,
+	.sg_tablesize	= SG_ALL,
+	.cmd_per_lun	= 2,
+	.use_clustering	= DISABLE_CLUSTERING
+};
+
+static int __init ecoscsi_init(void)
+{
+	scsi_register_host(&ecoscsi_template);
+	if (ecoscsi_template.present)
+		return 0;
+
+	scsi_unregister_host(&ecoscsi_template);
+	return -ENODEV;
+}
+
+static void __exit ecoscsi_exit(void)
+{
+	scsi_unregister_host(&ecoscsi_template);
+}
+
+module_init(ecoscsi_init);
+module_exit(ecoscsi_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Econet-SCSI driver for Acorn machines");
+MODULE_LICENSE("GPL");
+
diff -Nru a/drivers/scsi/arm/eesox.c b/drivers/scsi/arm/eesox.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/eesox.c	Sat May 17 11:00:49 2003
@@ -0,0 +1,684 @@
+/*
+ *  linux/drivers/acorn/scsi/eesox.c
+ *
+ *  Copyright (C) 1997-2003 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.
+ *
+ *  This driver is based on experimentation.  Hence, it may have made
+ *  assumptions about the particular card that I have available, and
+ *  may not be reliable!
+ *
+ *  Changelog:
+ *   01-10-1997	RMK		Created, READONLY version
+ *   15-02-1998	RMK		READ/WRITE version
+ *				added DMA support and hardware definitions
+ *   14-03-1998	RMK		Updated DMA support
+ *				Added terminator control
+ *   15-04-1998	RMK		Only do PIO if FAS216 will allow it.
+ *   27-06-1998	RMK		Changed asm/delay.h to linux/delay.h
+ *   02-04-2000	RMK	0.0.3	Fixed NO_IRQ/NO_DMA problem, updated for new
+ *				error handling code.
+ */
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/pgtable.h>
+
+#include "../scsi.h"
+#include "../hosts.h"
+#include "fas216.h"
+#include "scsi.h"
+
+#include <scsi/scsicam.h>
+
+#define EESOX_FAS216_OFFSET	0x3000
+#define EESOX_FAS216_SHIFT	5
+
+#define EESOX_DMASTAT		0x2800
+#define EESOX_STAT_INTR		0x01
+#define EESOX_STAT_DMA		0x02
+
+#define EESOX_CONTROL		0x2800
+#define EESOX_INTR_ENABLE	0x04
+#define EESOX_TERM_ENABLE	0x02
+#define EESOX_RESET		0x01
+
+#define EESOX_DMADATA		0x3800
+
+#define VERSION "1.10 (17/01/2003 2.5.59)"
+
+/*
+ * Use term=0,1,0,0,0 to turn terminators on/off
+ */
+static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+#define NR_SG	256
+
+struct eesoxscsi_info {
+	FAS216_Info		info;
+	struct expansion_card	*ec;
+
+	void			*ctl_port;
+	unsigned int		control;
+	struct scatterlist	sg[NR_SG];	/* Scatter DMA list	*/
+};
+
+/* Prototype: void eesoxscsi_irqenable(ec, irqnr)
+ * Purpose  : Enable interrupts on EESOX SCSI card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+eesoxscsi_irqenable(struct expansion_card *ec, int irqnr)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
+
+	info->control |= EESOX_INTR_ENABLE;
+
+	writeb(info->control, info->ctl_port);
+}
+
+/* Prototype: void eesoxscsi_irqdisable(ec, irqnr)
+ * Purpose  : Disable interrupts on EESOX SCSI card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+eesoxscsi_irqdisable(struct expansion_card *ec, int irqnr)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)ec->irq_data;
+
+	info->control &= ~EESOX_INTR_ENABLE;
+
+	writeb(info->control, info->ctl_port);
+}
+
+static const expansioncard_ops_t eesoxscsi_ops = {
+	.irqenable	= eesoxscsi_irqenable,
+	.irqdisable	= eesoxscsi_irqdisable,
+};
+
+/* Prototype: void eesoxscsi_terminator_ctl(*host, on_off)
+ * Purpose  : Turn the EESOX SCSI terminators on or off
+ * Params   : host   - card to turn on/off
+ *          : on_off - !0 to turn on, 0 to turn off
+ */
+static void
+eesoxscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	unsigned long flags;
+
+	spin_lock_irqsave(host->host_lock, flags);
+	if (on_off)
+		info->control |= EESOX_TERM_ENABLE;
+	else
+		info->control &= ~EESOX_TERM_ENABLE;
+
+	writeb(info->control, info->ctl_port);
+	spin_unlock_irqrestore(host->host_lock, flags);
+}
+
+/* Prototype: void eesoxscsi_intr(irq, *dev_id, *regs)
+ * Purpose  : handle interrupts from EESOX SCSI card
+ * Params   : irq    - interrupt number
+ *	      dev_id - user-defined (Scsi_Host structure)
+ *	      regs   - processor registers at interrupt
+ */
+static irqreturn_t
+eesoxscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct eesoxscsi_info *info = dev_id;
+
+	return fas216_intr(&info->info);
+}
+
+/* Prototype: fasdmatype_t eesoxscsi_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose  : initialises DMA/PIO
+ * Params   : host      - host
+ *	      SCpnt     - command
+ *	      direction - DMA on to/off of card
+ *	      min_type  - minimum DMA support that we must have for this transfer
+ * Returns  : type of transfer to be performed
+ */
+static fasdmatype_t
+eesoxscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		       fasdmadir_t direction, fasdmatype_t min_type)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	struct device *dev = scsi_get_device(host);
+	int dmach = host->dma_channel;
+
+	if (dmach != NO_DMA &&
+	    (min_type == fasdma_real_all || SCp->this_residual >= 512)) {
+		int bufs, map_dir, dma_dir;
+
+		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
+
+		if (direction == DMA_OUT)
+			map_dir = DMA_TO_DEVICE,
+			dma_dir = DMA_MODE_WRITE;
+		else
+			map_dir = DMA_FROM_DEVICE,
+			dma_dir = DMA_MODE_READ;
+
+		dma_map_sg(dev, info->sg, bufs + 1, map_dir);
+
+		disable_dma(dmach);
+		set_dma_sg(dmach, info->sg, bufs + 1);
+		set_dma_mode(dmach, dma_dir);
+		enable_dma(dmach);
+		return fasdma_real_all;
+	}
+	/*
+	 * We don't do DMA, we only do slow PIO
+	 *
+	 * Some day, we will do Pseudo DMA
+	 */
+	return fasdma_pseudo;
+}
+
+static void eesoxscsi_buffer_in(void *buf, int length, void *base)
+{
+	const void *reg_fas = base + EESOX_FAS216_OFFSET;
+	const void *reg_dmastat = base + EESOX_DMASTAT;
+	const void *reg_dmadata = base + EESOX_DMADATA;
+	const register unsigned long mask = 0xffff;
+
+	do {
+		unsigned int status;
+
+		/*
+		 * Interrupt request?
+		 */
+		status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
+		if (status & STAT_INT)
+			break;
+
+		/*
+		 * DMA request active?
+		 */
+		status = readb(reg_dmastat);
+		if (!(status & EESOX_STAT_DMA))
+			continue;
+
+		/*
+		 * Get number of bytes in FIFO
+		 */
+		status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
+		if (status > 16)
+			status = 16;
+		if (status > length)
+			status = length;
+
+		/*
+		 * Align buffer.
+		 */
+		if (((u32)buf) & 2 && status >= 2) {
+			*((u16 *)buf)++ = readl(reg_dmadata);
+			status -= 2;
+			length -= 2;
+		}
+
+		if (status >= 8) {
+			unsigned long l1, l2;
+
+			l1 = readl(reg_dmadata) & mask;
+			l1 |= readl(reg_dmadata) << 16;
+			l2 = readl(reg_dmadata) & mask;
+			l2 |= readl(reg_dmadata) << 16;
+			*((u32 *)buf)++ = l1;
+			*((u32 *)buf)++ = l2;
+			length -= 8;
+			continue;
+		}
+
+		if (status >= 4) {
+			unsigned long l1;
+
+			l1 = readl(reg_dmadata) & mask;
+			l1 |= readl(reg_dmadata) << 16;
+
+			*((u32 *)buf)++ = l1;
+			length -= 4;
+			continue;
+		}
+
+		if (status >= 2) {
+			*((u16 *)buf)++ = readl(reg_dmadata);
+			length -= 2;
+		}
+	} while (length);
+}
+
+static void eesoxscsi_buffer_out(void *buf, int length, void *base)
+{
+	const void *reg_fas = base + EESOX_FAS216_OFFSET;
+	const void *reg_dmastat = base + EESOX_DMASTAT;
+	const void *reg_dmadata = base + EESOX_DMADATA;
+
+	do {
+		unsigned int status;
+
+		/*
+		 * Interrupt request?
+		 */
+		status = readb(reg_fas + (REG_STAT << EESOX_FAS216_SHIFT));
+		if (status & STAT_INT)
+			break;
+
+		/*
+		 * DMA request active?
+		 */
+		status = readb(reg_dmastat);
+		if (!(status & EESOX_STAT_DMA))
+			continue;
+
+		/*
+		 * Get number of bytes in FIFO
+		 */
+		status = readb(reg_fas + (REG_CFIS << EESOX_FAS216_SHIFT)) & CFIS_CF;
+		if (status > 16)
+			status = 16;
+		status = 16 - status;
+		if (status > length)
+			status = length;
+		status &= ~1;
+
+		/*
+		 * Align buffer.
+		 */
+		if (((u32)buf) & 2 && status >= 2) {
+			writel(*((u16 *)buf)++ << 16, reg_dmadata);
+			status -= 2;
+			length -= 2;
+		}
+
+		if (status >= 8) {
+			unsigned long l1, l2;
+
+			l1 = *((u32 *)buf)++;
+			l2 = *((u32 *)buf)++;
+
+			writel(l1 << 16, reg_dmadata);
+			writel(l1, reg_dmadata);
+			writel(l2 << 16, reg_dmadata);
+			writel(l2, reg_dmadata);
+			length -= 8;
+			continue;
+		}
+
+		if (status >= 4) {
+			unsigned long l1;
+
+			l1 = *((u32 *)buf)++;
+
+			writel(l1 << 16, reg_dmadata);
+			writel(l1, reg_dmadata);
+			length -= 4;
+			continue;
+		}
+
+		if (status >= 2) {
+			writel(*((u16 *)buf)++ << 16, reg_dmadata);
+			length -= 2;
+		}
+	} while (length);
+}
+
+static void
+eesoxscsi_dma_pseudo(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		     fasdmadir_t dir, int transfer_size)
+{
+	void *base = (void *)host->base;
+	if (dir == DMA_IN) {
+		eesoxscsi_buffer_in(SCp->ptr, SCp->this_residual, base);
+	} else {
+		eesoxscsi_buffer_out(SCp->ptr, SCp->this_residual, base);
+	}
+}
+
+/* Prototype: int eesoxscsi_dma_stop(host, SCpnt)
+ * Purpose  : stops DMA/PIO
+ * Params   : host  - host
+ *	      SCpnt - command
+ */
+static void
+eesoxscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+	if (host->dma_channel != NO_DMA)
+		disable_dma(host->dma_channel);
+}
+
+/* Prototype: const char *eesoxscsi_info(struct Scsi_Host * host)
+ * Purpose  : returns a descriptive string about this interface,
+ * Params   : host - driver host structure to return info for.
+ * Returns  : pointer to a static buffer containing null terminated string.
+ */
+const char *eesoxscsi_info(struct Scsi_Host *host)
+{
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	static char string[150];
+
+	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
+		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
+		VERSION, info->control & EESOX_TERM_ENABLE ? "n" : "ff");
+
+	return string;
+}
+
+/* Prototype: int eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+ * Purpose  : Set a driver specific function
+ * Params   : host   - host to setup
+ *          : buffer - buffer containing string describing operation
+ *          : length - length of string
+ * Returns  : -EINVAL, or 0
+ */
+static int
+eesoxscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+{
+	int ret = length;
+
+	if (length >= 9 && strncmp(buffer, "EESOXSCSI", 9) == 0) {
+		buffer += 9;
+		length -= 9;
+
+		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
+			if (buffer[5] == '1')
+				eesoxscsi_terminator_ctl(host, 1);
+			else if (buffer[5] == '0')
+				eesoxscsi_terminator_ctl(host, 0);
+			else
+				ret = -EINVAL;
+		} else
+			ret = -EINVAL;
+	} else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/* Prototype: int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
+ *				      int length, int host_no, int inout)
+ * Purpose  : Return information about the driver to a user process accessing
+ *	      the /proc filesystem.
+ * Params   : buffer - a buffer to write information to
+ *	      start  - a pointer into this buffer set by this routine to the start
+ *		       of the required information.
+ *	      offset - offset into information that we have read upto.
+ *	      length - length of buffer
+ *	      host_no - host number to return information for
+ *	      inout  - 0 for reading, 1 for writing.
+ * Returns  : length of data written to buffer.
+ */
+int eesoxscsi_proc_info(char *buffer, char **start, off_t offset,
+			    int length, int host_no, int inout)
+{
+	struct Scsi_Host *host;
+	struct eesoxscsi_info *info;
+	char *p = buffer;
+	int pos;
+
+	host = scsi_host_hn_get(host_no);
+	if (!host)
+		return 0;
+
+	if (inout == 1)
+		return eesoxscsi_set_proc_info(host, buffer, length);
+
+	info = (struct eesoxscsi_info *)host->hostdata;
+
+	p += sprintf(p, "EESOX SCSI driver v%s\n", VERSION);
+	p += fas216_print_host(&info->info, p);
+	p += sprintf(p, "Term    : o%s\n",
+			info->control & EESOX_TERM_ENABLE ? "n" : "ff");
+
+	pos += fas216_print_stats(&info->info, buffer + pos);
+	p += fas216_print_stats(&info->info, p);
+	p += fas216_print_devices(&info->info, p);
+
+	if (pos > length)
+		pos = length;
+
+	return pos;
+}
+
+static ssize_t eesoxscsi_show_term(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+
+	return sprintf(buf, "%d\n", info->control & EESOX_TERM_ENABLE ? 1 : 0);
+}
+
+static ssize_t eesoxscsi_store_term(struct device *dev, const char *buf, size_t len)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	unsigned long flags;
+
+	if (len > 1) {
+		spin_lock_irqsave(host->host_lock, flags);
+		if (buf[0] != '0') {
+			info->control |= EESOX_TERM_ENABLE;
+		} else {
+			info->control &= ~EESOX_TERM_ENABLE;
+		}
+		writeb(info->control, info->ctl_port);
+		spin_unlock_irqrestore(host->host_lock, flags);
+	}
+
+	return len;
+}
+
+static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
+		   eesoxscsi_show_term, eesoxscsi_store_term);
+
+static Scsi_Host_Template eesox_template = {
+	.module				= THIS_MODULE,
+	.proc_info			= eesoxscsi_proc_info,
+	.name				= "EESOX SCSI",
+	.info				= eesoxscsi_info,
+	.command			= fas216_command,
+	.queuecommand			= fas216_queue_command,
+	.eh_host_reset_handler		= fas216_eh_host_reset,
+	.eh_bus_reset_handler		= fas216_eh_bus_reset,
+	.eh_device_reset_handler	= fas216_eh_device_reset,
+	.eh_abort_handler		= fas216_eh_abort,
+	.can_queue			= 1,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= DISABLE_CLUSTERING,
+	.proc_name			= "eesox",
+};
+
+static int __devinit
+eesoxscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	struct eesoxscsi_info *info;
+	unsigned long resbase, reslen;
+	unsigned char *base;
+	int ret;
+
+	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
+
+	if (!request_mem_region(resbase, reslen, "eesoxscsi")) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	base = ioremap(resbase, reslen);
+	if (!base) {
+		ret = -ENOMEM;
+		goto out_region;
+	}
+
+	host = scsi_register(&eesox_template,
+			     sizeof(struct eesoxscsi_info));
+	if (!host) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	host->base	  = (unsigned long)base;
+	host->irq	  = ec->irq;
+	host->dma_channel = ec->dma;
+
+	ecard_set_drvdata(ec, host);
+
+	info = (struct eesoxscsi_info *)host->hostdata;
+	info->ec	= ec;
+	info->ctl_port	= base + EESOX_CONTROL;
+	info->control	= term[ec->slot_no] ? EESOX_TERM_ENABLE : 0;
+	writeb(info->control, info->ctl_port);
+
+	ec->irqaddr	= base + EESOX_DMASTAT;
+	ec->irqmask	= EESOX_STAT_INTR;
+	ec->irq_data	= info;
+	ec->ops		= &eesoxscsi_ops;
+
+	info->info.scsi.io_base		= base + EESOX_FAS216_OFFSET;
+	info->info.scsi.io_shift	= EESOX_FAS216_SHIFT;
+	info->info.scsi.irq		= host->irq;
+	info->info.ifcfg.clockrate	= 40; /* MHz */
+	info->info.ifcfg.select_timeout	= 255;
+	info->info.ifcfg.asyncperiod	= 200; /* ns */
+	info->info.ifcfg.sync_max_depth	= 7;
+	info->info.ifcfg.cntl3		= CNTL3_FASTSCSI | CNTL3_FASTCLK;
+	info->info.ifcfg.disconnect_ok	= 1;
+	info->info.ifcfg.wide_max_size	= 0;
+	info->info.ifcfg.capabilities	= FASCAP_PSEUDODMA;
+	info->info.dma.setup		= eesoxscsi_dma_setup;
+	info->info.dma.pseudo		= eesoxscsi_dma_pseudo;
+	info->info.dma.stop		= eesoxscsi_dma_stop;
+
+	device_create_file(&ec->dev, &dev_attr_bus_term);
+
+	ret = fas216_init(host);
+	if (ret)
+		goto out_free;
+
+	ret = request_irq(host->irq, eesoxscsi_intr, 0, "eesoxscsi", info);
+	if (ret) {
+		printk("scsi%d: IRQ%d not free: %d\n",
+		       host->host_no, host->irq, ret);
+		goto out_remove;
+	}
+
+	if (host->dma_channel != NO_DMA) {
+		if (request_dma(host->dma_channel, "eesox")) {
+			printk("scsi%d: DMA%d not free, DMA disabled\n",
+			       host->host_no, host->dma_channel);
+			host->dma_channel = NO_DMA;
+		} else {
+			set_dma_speed(host->dma_channel, 180);
+			info->info.ifcfg.capabilities |= FASCAP_DMA;
+			info->info.ifcfg.cntl3 |= CNTL3_BS8;
+		}
+	}
+
+	ret = fas216_add(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	if (host->dma_channel != NO_DMA)
+		free_dma(host->dma_channel);
+	free_irq(host->irq, host);
+
+ out_remove:
+	fas216_remove(host);
+
+ out_free:
+	device_remove_file(&ec->dev, &dev_attr_bus_term);
+	scsi_unregister(host);
+
+ out_unmap:
+	iounmap(base);
+
+ out_region:
+	release_mem_region(resbase, reslen);
+
+ out:
+	return ret;
+}
+
+static void __devexit eesoxscsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct eesoxscsi_info *info = (struct eesoxscsi_info *)host->hostdata;
+	unsigned long resbase, reslen;
+
+	ecard_set_drvdata(ec, NULL);
+	fas216_remove(host);
+
+	if (host->dma_channel != NO_DMA)
+		free_dma(host->dma_channel);
+	free_irq(host->irq, info);
+
+	device_remove_file(&ec->dev, &dev_attr_bus_term);
+
+	iounmap((void *)host->base);
+
+	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
+
+	release_mem_region(resbase, reslen);
+
+	fas216_release(host);
+	scsi_unregister(host);
+}
+
+static const struct ecard_id eesoxscsi_cids[] = {
+	{ MANU_EESOX, PROD_EESOX_SCSI2 },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver eesoxscsi_driver = {
+	.probe		= eesoxscsi_probe,
+	.remove		= __devexit_p(eesoxscsi_remove),
+	.id_table	= eesoxscsi_cids,
+	.drv = {
+		.name		= "eesoxscsi",
+	},
+};
+
+static int __init eesox_init(void)
+{
+	return ecard_register_driver(&eesoxscsi_driver);
+}
+
+static void __exit eesox_exit(void)
+{
+	ecard_remove_driver(&eesoxscsi_driver);
+}
+
+module_init(eesox_init);
+module_exit(eesox_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("EESOX 'Fast' SCSI driver for Acorn machines");
+MODULE_PARM(term, "1-8i");
+MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
+
diff -Nru a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/fas216.c	Sat May 17 06:52:33 2003
@@ -0,0 +1,3045 @@
+/*
+ *  linux/drivers/acorn/scsi/fas216.c
+ *
+ *  Copyright (C) 1997-2003 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.
+ *
+ * Based on information in qlogicfas.c by Tom Zerucha, Michael Griffith, and
+ * other sources, including:
+ *   the AMD Am53CF94 data sheet
+ *   the AMD Am53C94 data sheet
+ *
+ * This is a generic driver.  To use it, have a look at cumana_2.c.  You
+ * should define your own structure that overlays FAS216_Info, eg:
+ * struct my_host_data {
+ *    FAS216_Info info;
+ *    ... my host specific data ...
+ * };
+ *
+ * Changelog:
+ *  30-08-1997	RMK	Created
+ *  14-09-1997	RMK	Started disconnect support
+ *  08-02-1998	RMK	Corrected real DMA support
+ *  15-02-1998	RMK	Started sync xfer support
+ *  06-04-1998	RMK	Tightened conditions for printing incomplete
+ *			transfers
+ *  02-05-1998	RMK	Added extra checks in fas216_reset
+ *  24-05-1998	RMK	Fixed synchronous transfers with period >= 200ns
+ *  27-06-1998	RMK	Changed asm/delay.h to linux/delay.h
+ *  26-08-1998	RMK	Improved message support wrt MESSAGE_REJECT
+ *  02-04-2000	RMK	Converted to use the new error handling, and
+ *			automatically request sense data upon check
+ *			condition status from targets.
+ */
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/ecard.h>
+
+#include "../scsi.h"
+#include "../hosts.h"
+#include "fas216.h"
+#include "scsi.h"
+
+/* NOTE: SCSI2 Synchronous transfers *require* DMA according to
+ *  the data sheet.  This restriction is crazy, especially when
+ *  you only want to send 16 bytes!  What were the guys who
+ *  designed this chip on at that time?  Did they read the SCSI2
+ *  spec at all?  The following sections are taken from the SCSI2
+ *  standard (s2r10) concerning this:
+ *
+ * > IMPLEMENTORS NOTES:
+ * >   (1)  Re-negotiation at every selection is not recommended, since a
+ * >   significant performance impact is likely.
+ *
+ * >  The implied synchronous agreement shall remain in effect until a BUS DEVICE
+ * >  RESET message is received, until a hard reset condition occurs, or until one
+ * >  of the two SCSI devices elects to modify the agreement.  The default data
+ * >  transfer mode is asynchronous data transfer mode.  The default data transfer
+ * >  mode is entered at power on, after a BUS DEVICE RESET message, or after a hard
+ * >  reset condition.
+ *
+ *  In total, this means that once you have elected to use synchronous
+ *  transfers, you must always use DMA.
+ *
+ *  I was thinking that this was a good chip until I found this restriction ;(
+ */
+#define SCSI2_SYNC
+#undef  SCSI2_TAG
+
+#undef DEBUG_CONNECT
+#undef DEBUG_MESSAGES
+
+#undef CHECK_STRUCTURE
+
+#define LOG_CONNECT		(1 << 0)
+#define LOG_BUSSERVICE		(1 << 1)
+#define LOG_FUNCTIONDONE	(1 << 2)
+#define LOG_MESSAGES		(1 << 3)
+#define LOG_BUFFER		(1 << 4)
+#define LOG_ERROR		(1 << 8)
+
+static int level_mask = LOG_ERROR;
+
+MODULE_PARM(level_mask, "i");
+
+static int __init fas216_log_setup(char *str)
+{
+	char *s;
+
+	level_mask = 0;
+
+	while ((s = strsep(&str, ",")) != NULL) {
+		switch (s[0]) {
+		case 'a':
+			if (strcmp(s, "all") == 0)
+				level_mask |= -1;
+			break;
+		case 'b':
+			if (strncmp(s, "bus", 3) == 0)
+				level_mask |= LOG_BUSSERVICE;
+			if (strncmp(s, "buf", 3) == 0)
+				level_mask |= LOG_BUFFER;
+			break;
+		case 'c':
+			level_mask |= LOG_CONNECT;
+			break;
+		case 'e':
+			level_mask |= LOG_ERROR;
+			break;
+		case 'm':
+			level_mask |= LOG_MESSAGES;
+			break;
+		case 'n':
+			if (strcmp(s, "none") == 0)
+				level_mask = 0;
+			break;
+		case 's':
+			level_mask |= LOG_FUNCTIONDONE;
+			break;
+		}
+	}
+	return 1;
+}
+
+__setup("fas216_logging=", fas216_log_setup);
+
+static inline unsigned char fas216_readb(FAS216_Info *info, unsigned int reg)
+{
+	unsigned int off = reg << info->scsi.io_shift;
+	if (info->scsi.io_base)
+		return readb(info->scsi.io_base + off);
+	else
+		return inb(info->scsi.io_port + off);
+}
+
+static inline void fas216_writeb(FAS216_Info *info, unsigned int reg, unsigned int val)
+{
+	unsigned int off = reg << info->scsi.io_shift;
+	if (info->scsi.io_base)
+		writeb(val, info->scsi.io_base + off);
+	else
+		outb(val, info->scsi.io_port + off);
+}
+
+static void fas216_dumpstate(FAS216_Info *info)
+{
+	unsigned char is, stat, inst;
+
+	is   = fas216_readb(info, REG_IS);
+	stat = fas216_readb(info, REG_STAT);
+	inst = fas216_readb(info, REG_INST);
+	
+	printk("FAS216: CTCL=%02X CTCM=%02X CMD=%02X STAT=%02X"
+	       " INST=%02X IS=%02X CFIS=%02X",
+		fas216_readb(info, REG_CTCL),
+		fas216_readb(info, REG_CTCM),
+		fas216_readb(info, REG_CMD),  stat, inst, is,
+		fas216_readb(info, REG_CFIS));
+	printk(" CNTL1=%02X CNTL2=%02X CNTL3=%02X CTCH=%02X\n",
+		fas216_readb(info, REG_CNTL1),
+		fas216_readb(info, REG_CNTL2),
+		fas216_readb(info, REG_CNTL3),
+		fas216_readb(info, REG_CTCH));
+}
+
+static void print_SCp(Scsi_Pointer *SCp, const char *prefix, const char *suffix)
+{
+	printk("%sptr %p this_residual 0x%x buffer %p buffers_residual 0x%x%s",
+		prefix, SCp->ptr, SCp->this_residual, SCp->buffer,
+		SCp->buffers_residual, suffix);
+}
+
+static void fas216_dumpinfo(FAS216_Info *info)
+{
+	static int used = 0;
+	int i;
+
+	if (used++)
+		return;
+
+	printk("FAS216_Info=\n");
+	printk("  { magic_start=%lX host=%p SCpnt=%p origSCpnt=%p\n",
+		info->magic_start, info->host, info->SCpnt,
+		info->origSCpnt);
+	printk("    scsi={ io_port=%X io_shift=%X irq=%X cfg={ %X %X %X %X }\n",
+		info->scsi.io_port, info->scsi.io_shift, info->scsi.irq,
+		info->scsi.cfg[0], info->scsi.cfg[1], info->scsi.cfg[2],
+		info->scsi.cfg[3]);
+	printk("           type=%p phase=%X\n",
+		info->scsi.type, info->scsi.phase);
+	print_SCp(&info->scsi.SCp, "           SCp={ ", " }\n");
+	printk("      msgs async_stp=%X disconnectable=%d aborting=%d }\n",
+		info->scsi.async_stp,
+		info->scsi.disconnectable, info->scsi.aborting);
+	printk("    stats={ queues=%X removes=%X fins=%X reads=%X writes=%X miscs=%X\n"
+	       "            disconnects=%X aborts=%X bus_resets=%X host_resets=%X}\n",
+		info->stats.queues, info->stats.removes, info->stats.fins,
+		info->stats.reads, info->stats.writes, info->stats.miscs,
+		info->stats.disconnects, info->stats.aborts, info->stats.bus_resets,
+		info->stats.host_resets);
+	printk("    ifcfg={ clockrate=%X select_timeout=%X asyncperiod=%X sync_max_depth=%X }\n",
+		info->ifcfg.clockrate, info->ifcfg.select_timeout,
+		info->ifcfg.asyncperiod, info->ifcfg.sync_max_depth);
+	for (i = 0; i < 8; i++) {
+		printk("    busyluns[%d]=%08lx dev[%d]={ disconnect_ok=%d stp=%X sof=%X sync_state=%X }\n",
+			i, info->busyluns[i], i,
+			info->device[i].disconnect_ok, info->device[i].stp,
+			info->device[i].sof, info->device[i].sync_state);
+	}
+	printk("    dma={ transfer_type=%X setup=%p pseudo=%p stop=%p }\n",
+		info->dma.transfer_type, info->dma.setup,
+		info->dma.pseudo, info->dma.stop);
+	printk("    internal_done=%X magic_end=%lX }\n",
+		info->internal_done, info->magic_end);
+}
+
+#ifdef CHECK_STRUCTURE
+static void __fas216_checkmagic(FAS216_Info *info, const char *func)
+{
+	int corruption = 0;
+	if (info->magic_start != MAGIC) {
+		printk(KERN_CRIT "FAS216 Error: magic at start corrupted\n");
+		corruption++;
+	}
+	if (info->magic_end != MAGIC) {
+		printk(KERN_CRIT "FAS216 Error: magic at end corrupted\n");
+		corruption++;
+	}
+	if (corruption) {
+		fas216_dumpinfo(info);
+		panic("scsi memory space corrupted in %s", func);
+	}
+}
+#define fas216_checkmagic(info) __fas216_checkmagic((info), __FUNCTION__)
+#else
+#define fas216_checkmagic(info)
+#endif
+
+static const char *fas216_bus_phase(int stat)
+{
+	static const char *phases[] = {
+		"DATA OUT", "DATA IN",
+		"COMMAND", "STATUS",
+		"MISC OUT", "MISC IN",
+		"MESG OUT", "MESG IN"
+	};
+
+	return phases[stat & STAT_BUSMASK];
+}
+
+static const char *fas216_drv_phase(FAS216_Info *info)
+{
+	static const char *phases[] = {
+		[PHASE_IDLE]		= "idle",
+		[PHASE_SELECTION]	= "selection",
+		[PHASE_COMMAND]		= "command",
+		[PHASE_DATAOUT]		= "data out",
+		[PHASE_DATAIN]		= "data in",
+		[PHASE_MSGIN]		= "message in",
+		[PHASE_MSGIN_DISCONNECT]= "disconnect",
+		[PHASE_MSGOUT_EXPECT]	= "expect message out",
+		[PHASE_MSGOUT]		= "message out",
+		[PHASE_STATUS]		= "status",
+		[PHASE_DONE]		= "done",
+	};
+
+	if (info->scsi.phase < ARRAY_SIZE(phases) &&
+	    phases[info->scsi.phase])
+		return phases[info->scsi.phase];
+	return "???";
+}
+
+static char fas216_target(FAS216_Info *info)
+{
+	if (info->SCpnt)
+		return '0' + info->SCpnt->device->id;
+	else
+		return 'H';
+}
+
+static void
+fas216_do_log(FAS216_Info *info, char target, char *fmt, va_list ap)
+{
+	static char buf[1024];
+
+	vsnprintf(buf, sizeof(buf), fmt, ap);
+	printk("scsi%d.%c: %s", info->host->host_no, target, buf);
+}
+
+static void
+fas216_log_command(FAS216_Info *info, int level, Scsi_Cmnd *SCpnt, char *fmt, ...)
+{
+	va_list args;
+
+	if (level != 0 && !(level & level_mask))
+		return;
+
+	va_start(args, fmt);
+	fas216_do_log(info, '0' + SCpnt->device->id, fmt, args);
+	va_end(args);
+
+	printk(" CDB: ");
+	print_command(SCpnt->cmnd);
+}
+
+static void
+fas216_log_target(FAS216_Info *info, int level, int target, char *fmt, ...)
+{
+	va_list args;
+
+	if (level != 0 && !(level & level_mask))
+		return;
+
+	if (target < 0)
+		target = 'H';
+	else
+		target += '0';
+
+	va_start(args, fmt);
+	fas216_do_log(info, target, fmt, args);
+	va_end(args);
+
+	printk("\n");
+}
+
+static void fas216_log(FAS216_Info *info, int level, char *fmt, ...)
+{
+	va_list args;
+
+	if (level != 0 && !(level & level_mask))
+		return;
+
+	va_start(args, fmt);
+	fas216_do_log(info, fas216_target(info), fmt, args);
+	va_end(args);
+
+	printk("\n");
+}
+
+#define PH_SIZE	32
+
+static struct { int stat, ssr, isr, ph; } ph_list[PH_SIZE];
+static int ph_ptr;
+
+static void add_debug_list(int stat, int ssr, int isr, int ph)
+{
+	ph_list[ph_ptr].stat = stat;
+	ph_list[ph_ptr].ssr = ssr;
+	ph_list[ph_ptr].isr = isr;
+	ph_list[ph_ptr].ph = ph;
+
+	ph_ptr = (ph_ptr + 1) & (PH_SIZE-1);
+}
+
+static struct { int command; void *from; } cmd_list[8];
+static int cmd_ptr;
+
+static void fas216_cmd(FAS216_Info *info, unsigned int command)
+{
+	cmd_list[cmd_ptr].command = command;
+	cmd_list[cmd_ptr].from = __builtin_return_address(0);
+
+	cmd_ptr = (cmd_ptr + 1) & 7;
+
+	fas216_writeb(info, REG_CMD, command);
+}
+
+static void print_debug_list(void)
+{
+	int i;
+
+	i = ph_ptr;
+
+	printk(KERN_ERR "SCSI IRQ trail\n");
+	do {
+		printk(" %02x:%02x:%02x:%1x",
+			ph_list[i].stat, ph_list[i].ssr,
+			ph_list[i].isr, ph_list[i].ph);
+		i = (i + 1) & (PH_SIZE - 1);
+		if (((i ^ ph_ptr) & 7) == 0)
+			printk("\n");
+	} while (i != ph_ptr);
+	if ((i ^ ph_ptr) & 7)
+		printk("\n");
+
+	i = cmd_ptr;
+	printk(KERN_ERR "FAS216 commands: ");
+	do {
+		printk("%02x:%p ", cmd_list[i].command, cmd_list[i].from);
+		i = (i + 1) & 7;
+	} while (i != cmd_ptr);
+	printk("\n");
+}
+
+static void fas216_done(FAS216_Info *info, unsigned int result);
+
+/**
+ * fas216_get_last_msg - retrive last message from the list
+ * @info: interface to search
+ * @pos: current fifo position
+ *
+ * Retrieve a last message from the list, using position in fifo.
+ */
+static inline unsigned short
+fas216_get_last_msg(FAS216_Info *info, int pos)
+{
+	unsigned short packed_msg = NOP;
+	struct message *msg;
+	int msgnr = 0;
+
+	while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+		if (pos >= msg->fifo)
+			break;
+	}
+
+	if (msg) {
+		if (msg->msg[0] == EXTENDED_MESSAGE)
+			packed_msg = EXTENDED_MESSAGE | msg->msg[2] << 8;
+		else
+			packed_msg = msg->msg[0];
+	}
+
+	fas216_log(info, LOG_MESSAGES,
+		"Message: %04x found at position %02x\n", packed_msg, pos);
+
+	return packed_msg;
+}
+
+/**
+ * fas216_syncperiod - calculate STP register value
+ * @info: state structure for interface connected to device
+ * @ns: period in ns (between subsequent bytes)
+ *
+ * Calculate value to be loaded into the STP register for a given period
+ * in ns. Returns a value suitable for REG_STP.
+ */
+static int fas216_syncperiod(FAS216_Info *info, int ns)
+{
+	int value = (info->ifcfg.clockrate * ns) / 1000;
+
+	fas216_checkmagic(info);
+
+	if (value < 4)
+		value = 4;
+	else if (value > 35)
+		value = 35;
+
+	return value & 31;
+}
+
+/**
+ * fas216_set_sync - setup FAS216 chip for specified transfer period.
+ * @info: state structure for interface connected to device
+ * @target: target
+ *
+ * Correctly setup FAS216 chip for specified transfer period.
+ * Notes   : we need to switch the chip out of FASTSCSI mode if we have
+ *           a transfer period >= 200ns - otherwise the chip will violate
+ *           the SCSI timings.
+ */
+static void fas216_set_sync(FAS216_Info *info, int target)
+{
+	unsigned int cntl3;
+
+	fas216_writeb(info, REG_SOF, info->device[target].sof);
+	fas216_writeb(info, REG_STP, info->device[target].stp);
+
+	cntl3 = info->scsi.cfg[2];
+	if (info->device[target].period >= (200 / 4))
+		cntl3 = cntl3 & ~CNTL3_FASTSCSI;
+
+	fas216_writeb(info, REG_CNTL3, cntl3);
+}
+
+/* Synchronous transfer support
+ *
+ * Note: The SCSI II r10 spec says (5.6.12):
+ *
+ *  (2)  Due to historical problems with early host adapters that could
+ *  not accept an SDTR message, some targets may not initiate synchronous
+ *  negotiation after a power cycle as required by this standard.  Host
+ *  adapters that support synchronous mode may avoid the ensuing failure
+ *  modes when the target is independently power cycled by initiating a
+ *  synchronous negotiation on each REQUEST SENSE and INQUIRY command.
+ *  This approach increases the SCSI bus overhead and is not recommended
+ *  for new implementations.  The correct method is to respond to an
+ *  SDTR message with a MESSAGE REJECT message if the either the
+ *  initiator or target devices does not support synchronous transfers
+ *  or does not want to negotiate for synchronous transfers at the time.
+ *  Using the correct method assures compatibility with wide data
+ *  transfers and future enhancements.
+ *
+ * We will always initiate a synchronous transfer negotiation request on
+ * every INQUIRY or REQUEST SENSE message, unless the target itself has
+ * at some point performed a synchronous transfer negotiation request, or
+ * we have synchronous transfers disabled for this device.
+ */
+
+/**
+ * fas216_handlesync - Handle a synchronous transfer message
+ * @info: state structure for interface
+ * @msg: message from target
+ *
+ * Handle a synchronous transfer message from the target
+ */
+static void fas216_handlesync(FAS216_Info *info, char *msg)
+{
+	struct fas216_device *dev = &info->device[info->SCpnt->device->id];
+	enum { sync, async, none, reject } res = none;
+
+#ifdef SCSI2_SYNC
+	switch (msg[0]) {
+	case MESSAGE_REJECT:
+		/* Synchronous transfer request failed.
+		 * Note: SCSI II r10:
+		 *
+		 *  SCSI devices that are capable of synchronous
+		 *  data transfers shall not respond to an SDTR
+		 *  message with a MESSAGE REJECT message.
+		 *
+		 * Hence, if we get this condition, we disable
+		 * negotiation for this device.
+		 */
+		if (dev->sync_state == neg_inprogress) {
+			dev->sync_state = neg_invalid;
+			res = async;
+		}
+		break;
+
+	case EXTENDED_MESSAGE:
+		switch (dev->sync_state) {
+		/* We don't accept synchronous transfer requests.
+		 * Respond with a MESSAGE_REJECT to prevent a
+		 * synchronous transfer agreement from being reached.
+		 */
+		case neg_invalid:
+			res = reject;
+			break;
+
+		/* We were not negotiating a synchronous transfer,
+		 * but the device sent us a negotiation request.
+		 * Honour the request by sending back a SDTR
+		 * message containing our capability, limited by
+		 * the targets capability.
+		 */
+		default:
+			fas216_cmd(info, CMD_SETATN);
+			if (msg[4] > info->ifcfg.sync_max_depth)
+				msg[4] = info->ifcfg.sync_max_depth;
+			if (msg[3] < 1000 / info->ifcfg.clockrate)
+				msg[3] = 1000 / info->ifcfg.clockrate;
+
+			msgqueue_flush(&info->scsi.msgs);
+			msgqueue_addmsg(&info->scsi.msgs, 5,
+					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+					msg[3], msg[4]);
+			info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+			/* This is wrong.  The agreement is not in effect
+			 * until this message is accepted by the device
+			 */
+			dev->sync_state = neg_targcomplete;
+			res = sync;
+			break;
+
+		/* We initiated the synchronous transfer negotiation,
+		 * and have successfully received a response from the
+		 * target.  The synchronous transfer agreement has been
+		 * reached.  Note: if the values returned are out of our
+		 * bounds, we must reject the message.
+		 */
+		case neg_inprogress:
+			res = reject;
+			if (msg[4] <= info->ifcfg.sync_max_depth &&
+			    msg[3] >= 1000 / info->ifcfg.clockrate) {
+				dev->sync_state = neg_complete;
+				res = sync;
+			}
+			break;
+		}
+	}
+#else
+	res = reject;
+#endif
+
+	switch (res) {
+	case sync:
+		dev->period = msg[3];
+		dev->sof    = msg[4];
+		dev->stp    = fas216_syncperiod(info, msg[3] * 4);
+		fas216_set_sync(info, info->SCpnt->device->id);
+		break;
+
+	case reject:
+		fas216_cmd(info, CMD_SETATN);
+		msgqueue_flush(&info->scsi.msgs);
+		msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+
+	case async:
+		dev->period = info->ifcfg.asyncperiod / 4;
+		dev->sof    = 0;
+		dev->stp    = info->scsi.async_stp;
+		fas216_set_sync(info, info->SCpnt->device->id);
+		break;
+
+	case none:
+		break;
+	}
+}
+
+/**
+ * fas216_updateptrs - update data pointers after transfer suspended/paused
+ * @info: interface's local pointer to update
+ * @bytes_transferred: number of bytes transferred
+ *
+ * Update data pointers after transfer suspended/paused
+ */
+static void fas216_updateptrs(FAS216_Info *info, int bytes_transferred)
+{
+	Scsi_Pointer *SCp = &info->scsi.SCp;
+
+	fas216_checkmagic(info);
+
+	BUG_ON(bytes_transferred < 0);
+
+	info->SCpnt->request_bufflen -= bytes_transferred;
+
+	while (bytes_transferred != 0) {
+		if (SCp->this_residual > bytes_transferred)
+			break;
+		/*
+		 * We have used up this buffer.  Move on to the
+		 * next buffer.
+		 */
+		bytes_transferred -= SCp->this_residual;
+		if (!next_SCp(SCp) && bytes_transferred) {
+			printk(KERN_WARNING "scsi%d.%c: out of buffers\n",
+				info->host->host_no, '0' + info->SCpnt->device->id);
+			return;
+		}
+	}
+
+	SCp->this_residual -= bytes_transferred;
+	if (SCp->this_residual)
+		SCp->ptr += bytes_transferred;
+	else
+		SCp->ptr = NULL;
+}
+
+/**
+ * fas216_pio - transfer data off of/on to card using programmed IO
+ * @info: interface to transfer data to/from
+ * @direction: direction to transfer data (DMA_OUT/DMA_IN)
+ *
+ * Transfer data off of/on to card using programmed IO.
+ * Notes: this is incredibly slow.
+ */
+static void fas216_pio(FAS216_Info *info, fasdmadir_t direction)
+{
+	Scsi_Pointer *SCp = &info->scsi.SCp;
+
+	fas216_checkmagic(info);
+
+	if (direction == DMA_OUT)
+		fas216_writeb(info, REG_FF, get_next_SCp_byte(SCp));
+	else
+		put_next_SCp_byte(SCp, fas216_readb(info, REG_FF));
+
+	if (SCp->this_residual == 0)
+		next_SCp(SCp);
+}
+
+static void fas216_set_stc(FAS216_Info *info, unsigned int length)
+{
+	fas216_writeb(info, REG_STCL, length);
+	fas216_writeb(info, REG_STCM, length >> 8);
+	fas216_writeb(info, REG_STCH, length >> 16);
+}
+
+static unsigned int fas216_get_ctc(FAS216_Info *info)
+{
+	return fas216_readb(info, REG_CTCL) +
+	       (fas216_readb(info, REG_CTCM) << 8) +
+	       (fas216_readb(info, REG_CTCH) << 16);
+}
+
+/**
+ * fas216_cleanuptransfer - clean up after a transfer has completed.
+ * @info: interface to clean up
+ *
+ * Update the data pointers according to the number of bytes transferred
+ * on the SCSI bus.
+ */
+static void fas216_cleanuptransfer(FAS216_Info *info)
+{
+	unsigned long total, residual, fifo;
+	fasdmatype_t dmatype = info->dma.transfer_type;
+
+	info->dma.transfer_type = fasdma_none;
+
+	/*
+	 * PIO transfers do not need to be cleaned up.
+	 */
+	if (dmatype == fasdma_pio || dmatype == fasdma_none)
+		return;
+
+	if (dmatype == fasdma_real_all)
+		total = info->SCpnt->request_bufflen;
+	else
+		total = info->scsi.SCp.this_residual;
+
+	residual = fas216_get_ctc(info);
+
+	fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
+
+	fas216_log(info, LOG_BUFFER, "cleaning up from previous "
+		   "transfer: length 0x%06x, residual 0x%x, fifo %d",
+		   total, residual, fifo);
+
+	/*
+	 * If we were performing Data-Out, the transfer counter
+	 * counts down each time a byte is transferred by the
+	 * host to the FIFO.  This means we must include the
+	 * bytes left in the FIFO from the transfer counter.
+	 */
+	if (info->scsi.phase == PHASE_DATAOUT)
+		residual += fifo;
+
+	fas216_updateptrs(info, total - residual);
+}
+
+/**
+ * fas216_transfer - Perform a DMA/PIO transfer off of/on to card
+ * @info: interface from which device disconnected from
+ *
+ * Start a DMA/PIO transfer off of/on to card
+ */
+static void fas216_transfer(FAS216_Info *info)
+{
+	fasdmadir_t direction;
+	fasdmatype_t dmatype;
+
+	fas216_log(info, LOG_BUFFER,
+		   "starttransfer: buffer %p length 0x%06x reqlen 0x%06x",
+		   info->scsi.SCp.ptr, info->scsi.SCp.this_residual,
+		   info->SCpnt->request_bufflen);
+
+	if (!info->scsi.SCp.ptr) {
+		fas216_log(info, LOG_ERROR, "null buffer passed to "
+			   "fas216_starttransfer");
+		print_SCp(&info->scsi.SCp, "SCp: ", "\n");
+		print_SCp(&info->SCpnt->SCp, "Cmnd SCp: ", "\n");
+		return;
+	}
+
+	/*
+	 * If we have a synchronous transfer agreement in effect, we must
+	 * use DMA mode.  If we are using asynchronous transfers, we may
+	 * use DMA mode or PIO mode.
+	 */
+	if (info->device[info->SCpnt->device->id].sof)
+		dmatype = fasdma_real_all;
+	else
+		dmatype = fasdma_pio;
+
+	if (info->scsi.phase == PHASE_DATAOUT)
+		direction = DMA_OUT;
+	else
+		direction = DMA_IN;
+
+	if (info->dma.setup)
+		dmatype = info->dma.setup(info->host, &info->scsi.SCp,
+					  direction, dmatype);
+	info->dma.transfer_type = dmatype;
+
+	if (dmatype == fasdma_real_all)
+		fas216_set_stc(info, info->SCpnt->request_bufflen);
+	else
+		fas216_set_stc(info, info->scsi.SCp.this_residual);
+
+	switch (dmatype) {
+	case fasdma_pio:
+		fas216_log(info, LOG_BUFFER, "PIO transfer");
+		fas216_writeb(info, REG_SOF, 0);
+		fas216_writeb(info, REG_STP, info->scsi.async_stp);
+		fas216_cmd(info, CMD_TRANSFERINFO);
+		fas216_pio(info, direction);
+		break;
+
+	case fasdma_pseudo:
+		fas216_log(info, LOG_BUFFER, "pseudo transfer");
+		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);
+		info->dma.pseudo(info->host, &info->scsi.SCp,
+				 direction, info->SCpnt->transfersize);
+		break;
+
+	case fasdma_real_block:
+		fas216_log(info, LOG_BUFFER, "block dma transfer");
+		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);
+		break;
+
+	case fasdma_real_all:
+		fas216_log(info, LOG_BUFFER, "total dma transfer");
+		fas216_cmd(info, CMD_TRANSFERINFO | CMD_WITHDMA);
+		break;
+
+	default:
+		fas216_log(info, LOG_BUFFER | LOG_ERROR,
+			   "invalid FAS216 DMA type");
+		break;
+	}
+}
+
+/**
+ * fas216_stoptransfer - Stop a DMA transfer onto / off of the card
+ * @info: interface from which device disconnected from
+ *
+ * Called when we switch away from DATA IN or DATA OUT phases.
+ */
+static void fas216_stoptransfer(FAS216_Info *info)
+{
+	fas216_checkmagic(info);
+
+	if (info->dma.transfer_type == fasdma_real_all ||
+	    info->dma.transfer_type == fasdma_real_block)
+		info->dma.stop(info->host, &info->scsi.SCp);
+
+	fas216_cleanuptransfer(info);
+
+	if (info->scsi.phase == PHASE_DATAIN) {
+		unsigned int fifo;
+
+		/*
+		 * If we were performing Data-In, then the FIFO counter
+		 * contains the number of bytes not transferred via DMA
+		 * from the on-board FIFO.  Read them manually.
+		 */
+		fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
+		while (fifo && info->scsi.SCp.ptr) {
+			*info->scsi.SCp.ptr = fas216_readb(info, REG_FF);
+			fas216_updateptrs(info, 1);
+			fifo--;
+		}
+	} else {
+		/*
+		 * After a Data-Out phase, there may be unsent
+		 * bytes left in the FIFO.  Flush them out.
+		 */
+		fas216_cmd(info, CMD_FLUSHFIFO);
+	}
+}
+
+static void fas216_aborttransfer(FAS216_Info *info)
+{
+	fas216_checkmagic(info);
+
+	if (info->dma.transfer_type == fasdma_real_all ||
+	    info->dma.transfer_type == fasdma_real_block)
+		info->dma.stop(info->host, &info->scsi.SCp);
+
+	info->dma.transfer_type = fasdma_none;
+	fas216_cmd(info, CMD_FLUSHFIFO);
+}
+
+static void fas216_kick(FAS216_Info *info);
+
+/**
+ * fas216_disconnected_intr - handle device disconnection
+ * @info: interface from which device disconnected from
+ *
+ * Handle device disconnection
+ */
+static void fas216_disconnect_intr(FAS216_Info *info)
+{
+	unsigned long flags;
+
+	fas216_checkmagic(info);
+
+	fas216_log(info, LOG_CONNECT, "disconnect phase=%02x",
+		   info->scsi.phase);
+
+	msgqueue_flush(&info->scsi.msgs);
+
+	switch (info->scsi.phase) {
+	case PHASE_SELECTION:			/* while selecting - no target		*/
+	case PHASE_SELSTEPS:
+		fas216_done(info, DID_NO_CONNECT);
+		break;
+
+	case PHASE_MSGIN_DISCONNECT:		/* message in - disconnecting		*/
+		info->scsi.disconnectable = 1;
+		info->scsi.phase = PHASE_IDLE;
+		info->stats.disconnects += 1;
+		spin_lock_irqsave(&info->host_lock, flags);
+		if (info->scsi.phase == PHASE_IDLE)
+			fas216_kick(info);
+		spin_unlock_irqrestore(&info->host_lock, flags);
+		break;
+
+	case PHASE_DONE:			/* at end of command - complete		*/
+		fas216_done(info, DID_OK);
+		break;
+
+	case PHASE_MSGOUT:			/* message out - possible ABORT message	*/
+		if (fas216_get_last_msg(info, info->scsi.msgin_fifo) == ABORT) {
+			info->scsi.aborting = 0;
+			fas216_done(info, DID_ABORT);
+			break;
+		}
+
+	default:				/* huh?					*/
+		printk(KERN_ERR "scsi%d.%c: unexpected disconnect in phase %s\n",
+			info->host->host_no, fas216_target(info), fas216_drv_phase(info));
+		print_debug_list();
+		fas216_stoptransfer(info);
+		fas216_done(info, DID_ERROR);
+		break;
+	}
+}
+
+/**
+ * fas216_reselected_intr - start reconnection of a device
+ * @info: interface which was reselected
+ *
+ * Start reconnection of a device
+ */
+static void
+fas216_reselected_intr(FAS216_Info *info)
+{
+	unsigned int cfis, i;
+	unsigned char msg[4];
+	unsigned char target, lun, tag;
+
+	fas216_checkmagic(info);
+
+	WARN_ON(info->scsi.phase == PHASE_SELECTION ||
+		info->scsi.phase == PHASE_SELSTEPS);
+
+	cfis = fas216_readb(info, REG_CFIS);
+
+	fas216_log(info, LOG_CONNECT, "reconnect phase=%02x cfis=%02x",
+		   info->scsi.phase, cfis);
+
+	cfis &= CFIS_CF;
+
+	if (cfis < 2 || cfis > 4) {
+		printk(KERN_ERR "scsi%d.H: incorrect number of bytes after reselect\n",
+			info->host->host_no);
+		goto bad_message;
+	}
+
+	for (i = 0; i < cfis; i++)
+		msg[i] = fas216_readb(info, REG_FF);
+
+	if (!(msg[0] & (1 << info->host->this_id)) ||
+	    !(msg[1] & 0x80))
+		goto initiator_error;
+
+	target = msg[0] & ~(1 << info->host->this_id);
+	target = ffs(target) - 1;
+	lun = msg[1] & 7;
+	tag = 0;
+
+	if (cfis >= 3) {
+		if (msg[2] != SIMPLE_QUEUE_TAG)
+			goto initiator_error;
+
+		tag = msg[3];
+	}
+
+	/* set up for synchronous transfers */
+	fas216_writeb(info, REG_SDID, target);
+	fas216_set_sync(info, target);
+	msgqueue_flush(&info->scsi.msgs);
+
+	fas216_log(info, LOG_CONNECT, "Reconnected: target %1x lun %1x tag %02x",
+		   target, lun, tag);
+
+	if (info->scsi.disconnectable && info->SCpnt) {
+		info->scsi.disconnectable = 0;
+		if (info->SCpnt->device->id  == target &&
+		    info->SCpnt->device->lun == lun &&
+		    info->SCpnt->tag         == tag) {
+			fas216_log(info, LOG_CONNECT, "reconnected previously executing command");
+		} else {
+			queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);
+			fas216_log(info, LOG_CONNECT, "had to move command to disconnected queue");
+			info->SCpnt = NULL;
+		}
+	}
+	if (!info->SCpnt) {
+		info->SCpnt = queue_remove_tgtluntag(&info->queues.disconnected,
+					target, lun, tag);
+		fas216_log(info, LOG_CONNECT, "had to get command");
+	}
+
+	if (info->SCpnt) {
+		/*
+		 * Restore data pointer from SAVED data pointer
+		 */
+		info->scsi.SCp = info->SCpnt->SCp;
+
+		fas216_log(info, LOG_CONNECT, "data pointers: [%p, %X]",
+			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+		info->scsi.phase = PHASE_MSGIN;
+	} else {
+		/*
+		 * Our command structure not found - abort the
+		 * command on the target.  Since we have no
+		 * record of this command, we can't send
+		 * an INITIATOR DETECTED ERROR message.
+		 */
+		fas216_cmd(info, CMD_SETATN);
+
+#if 0
+		if (tag)
+			msgqueue_addmsg(&info->scsi.msgs, 2, ABORT_TAG, tag);
+		else
+#endif
+			msgqueue_addmsg(&info->scsi.msgs, 1, ABORT);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+		info->scsi.aborting = 1;
+	}
+
+	fas216_cmd(info, CMD_MSGACCEPTED);
+	return;
+
+ initiator_error:
+	printk(KERN_ERR "scsi%d.H: error during reselection: bytes",
+		info->host->host_no);
+	for (i = 0; i < cfis; i++)
+		printk(" %02x", msg[i]);
+	printk("\n");
+ bad_message:
+	fas216_cmd(info, CMD_SETATN);
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+	info->scsi.phase = PHASE_MSGOUT_EXPECT;
+	fas216_cmd(info, CMD_MSGACCEPTED);
+}
+
+static void fas216_parse_message(FAS216_Info *info, unsigned char *message, int msglen)
+{
+	int i;
+
+	switch (message[0]) {
+	case COMMAND_COMPLETE:
+		if (msglen != 1)
+			goto unrecognised;
+
+		printk(KERN_ERR "scsi%d.%c: command complete with no "
+			"status in MESSAGE_IN?\n",
+			info->host->host_no, fas216_target(info));
+		break;
+
+	case SAVE_POINTERS:
+		if (msglen != 1)
+			goto unrecognised;
+
+		/*
+		 * Save current data pointer to SAVED data pointer
+		 * SCSI II standard says that we must not acknowledge
+		 * this until we have really saved pointers.
+		 * NOTE: we DO NOT save the command nor status pointers
+		 * as required by the SCSI II standard.  These always
+		 * point to the start of their respective areas.
+		 */
+		info->SCpnt->SCp = info->scsi.SCp;
+		info->SCpnt->SCp.sent_command = 0;
+		fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER,
+			"save data pointers: [%p, %X]",
+			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+		break;
+
+	case RESTORE_POINTERS:
+		if (msglen != 1)
+			goto unrecognised;
+
+		/*
+		 * Restore current data pointer from SAVED data pointer
+		 */
+		info->scsi.SCp = info->SCpnt->SCp;
+		fas216_log(info, LOG_CONNECT | LOG_MESSAGES | LOG_BUFFER,
+			"restore data pointers: [%p, 0x%x]",
+			info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+		break;
+
+	case DISCONNECT:
+		if (msglen != 1)
+			goto unrecognised;
+
+		info->scsi.phase = PHASE_MSGIN_DISCONNECT;
+		break;
+
+	case MESSAGE_REJECT:
+		if (msglen != 1)
+			goto unrecognised;
+
+		switch (fas216_get_last_msg(info, info->scsi.msgin_fifo)) {
+		case EXTENDED_MESSAGE | EXTENDED_SDTR << 8:
+			fas216_handlesync(info, message);
+			break;
+
+		default:
+			fas216_log(info, 0, "reject, last message 0x%04x",
+				fas216_get_last_msg(info, info->scsi.msgin_fifo));
+		}
+		break;
+
+	case NOP:
+		break;
+
+	case EXTENDED_MESSAGE:
+		if (msglen < 3)
+			goto unrecognised;
+
+		switch (message[2]) {
+		case EXTENDED_SDTR:	/* Sync transfer negotiation request/reply */
+			fas216_handlesync(info, message);
+			break;
+
+		default:
+			goto unrecognised;
+		}
+		break;
+
+	default:
+		goto unrecognised;
+	}
+	return;
+
+unrecognised:
+	fas216_log(info, 0, "unrecognised message, rejecting");
+	printk("scsi%d.%c: message was", info->host->host_no, fas216_target(info));
+	for (i = 0; i < msglen; i++)
+		printk("%s%02X", i & 31 ? " " : "\n  ", message[i]);
+	printk("\n");
+
+	/*
+	 * Something strange seems to be happening here -
+	 * I can't use SETATN since the chip gives me an
+	 * invalid command interrupt when I do.  Weird.
+	 */
+fas216_cmd(info, CMD_NOP);
+fas216_dumpstate(info);
+	fas216_cmd(info, CMD_SETATN);
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, MESSAGE_REJECT);
+	info->scsi.phase = PHASE_MSGOUT_EXPECT;
+fas216_dumpstate(info);
+}
+
+static int fas216_wait_cmd(FAS216_Info *info, int cmd)
+{
+	int tout;
+	int stat;
+
+	fas216_cmd(info, cmd);
+
+	for (tout = 1000; tout; tout -= 1) {
+		stat = fas216_readb(info, REG_STAT);
+		if (stat & (STAT_INT|STAT_PARITYERROR))
+			break;
+		udelay(1);
+	}
+
+	return stat;
+}
+
+static int fas216_get_msg_byte(FAS216_Info *info)
+{
+	unsigned int stat = fas216_wait_cmd(info, CMD_MSGACCEPTED);
+
+	if ((stat & STAT_INT) == 0)
+		goto timedout;
+
+	if ((stat & STAT_BUSMASK) != STAT_MESGIN)
+		goto unexpected_phase_change;
+
+	fas216_readb(info, REG_INST);
+
+	stat = fas216_wait_cmd(info, CMD_TRANSFERINFO);
+
+	if ((stat & STAT_INT) == 0)
+		goto timedout;
+
+	if (stat & STAT_PARITYERROR)
+		goto parity_error;
+
+	if ((stat & STAT_BUSMASK) != STAT_MESGIN)
+		goto unexpected_phase_change;
+
+	fas216_readb(info, REG_INST);
+
+	return fas216_readb(info, REG_FF);
+
+timedout:
+	fas216_log(info, LOG_ERROR, "timed out waiting for message byte");
+	return -1;
+
+unexpected_phase_change:
+	fas216_log(info, LOG_ERROR, "unexpected phase change: status = %02x", stat);
+	return -2;
+
+parity_error:
+	fas216_log(info, LOG_ERROR, "parity error during message in phase");
+	return -3;
+}
+
+/**
+ * fas216_message - handle a function done interrupt from FAS216 chip
+ * @info: interface which caused function done interrupt
+ *
+ * Handle a function done interrupt from FAS216 chip
+ */
+static void fas216_message(FAS216_Info *info)
+{
+	unsigned char *message = info->scsi.message;
+	unsigned int msglen = 1;
+	int msgbyte = 0;
+
+	fas216_checkmagic(info);
+
+	message[0] = fas216_readb(info, REG_FF);
+
+	if (message[0] == EXTENDED_MESSAGE) {
+		msgbyte = fas216_get_msg_byte(info);
+
+		if (msgbyte >= 0) {
+			message[1] = msgbyte;
+
+			for (msglen = 2; msglen < message[1] + 2; msglen++) {
+				msgbyte = fas216_get_msg_byte(info);
+
+				if (msgbyte >= 0)
+					message[msglen] = msgbyte;
+				else
+					break;
+			}
+		}
+	}
+
+	if (msgbyte == -3)
+		goto parity_error;
+
+#ifdef DEBUG_MESSAGES
+	{
+		int i;
+
+		printk("scsi%d.%c: message in: ",
+			info->host->host_no, fas216_target(info));
+		for (i = 0; i < msglen; i++)
+			printk("%02X ", message[i]);
+		printk("\n");
+	}
+#endif
+
+	fas216_parse_message(info, message, msglen);
+	fas216_cmd(info, CMD_MSGACCEPTED);
+	return;
+
+parity_error:
+	fas216_cmd(info, CMD_SETATN);
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, MSG_PARITY_ERROR);
+	info->scsi.phase = PHASE_MSGOUT_EXPECT;
+	fas216_cmd(info, CMD_MSGACCEPTED);
+	return;
+}
+
+/**
+ * fas216_send_command - send command after all message bytes have been sent
+ * @info: interface which caused bus service
+ *
+ * Send a command to a target after all message bytes have been sent
+ */
+static void fas216_send_command(FAS216_Info *info)
+{
+	int i;
+
+	fas216_checkmagic(info);
+
+	fas216_cmd(info, CMD_NOP|CMD_WITHDMA);
+	fas216_cmd(info, CMD_FLUSHFIFO);
+
+	/* load command */
+	for (i = info->scsi.SCp.sent_command; i < info->SCpnt->cmd_len; i++)
+		fas216_writeb(info, REG_FF, info->SCpnt->cmnd[i]);
+
+	fas216_cmd(info, CMD_TRANSFERINFO);
+
+	info->scsi.phase = PHASE_COMMAND;
+}
+
+/**
+ * fas216_send_messageout - handle bus service to send a message
+ * @info: interface which caused bus service
+ *
+ * Handle bus service to send a message.
+ * Note: We do not allow the device to change the data direction!
+ */
+static void fas216_send_messageout(FAS216_Info *info, int start)
+{
+	unsigned int tot_msglen = msgqueue_msglength(&info->scsi.msgs);
+
+	fas216_checkmagic(info);
+
+	fas216_cmd(info, CMD_FLUSHFIFO);
+
+	if (tot_msglen) {
+		struct message *msg;
+		int msgnr = 0;
+
+		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+			int i;
+
+			for (i = start; i < msg->length; i++)
+				fas216_writeb(info, REG_FF, msg->msg[i]);
+
+			msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF);
+			start = 0;
+		}
+	} else
+		fas216_writeb(info, REG_FF, NOP);
+
+	fas216_cmd(info, CMD_TRANSFERINFO);
+
+	info->scsi.phase = PHASE_MSGOUT;
+}
+
+/**
+ * fas216_busservice_intr - handle bus service interrupt from FAS216 chip
+ * @info: interface which caused bus service interrupt
+ * @stat: Status register contents
+ * @is: SCSI Status register contents
+ *
+ * Handle a bus service interrupt from FAS216 chip
+ */
+static void fas216_busservice_intr(FAS216_Info *info, unsigned int stat, unsigned int is)
+{
+	fas216_checkmagic(info);
+
+	fas216_log(info, LOG_BUSSERVICE,
+		   "bus service: stat=%02x is=%02x phase=%02x",
+		   stat, is, info->scsi.phase);
+
+	switch (info->scsi.phase) {
+	case PHASE_SELECTION:
+		if ((is & IS_BITS) != IS_MSGBYTESENT)
+			goto bad_is;
+		break;
+
+	case PHASE_SELSTEPS:
+		switch (is & IS_BITS) {
+		case IS_SELARB:
+		case IS_MSGBYTESENT:
+			goto bad_is;
+
+		case IS_NOTCOMMAND:
+		case IS_EARLYPHASE:
+			if ((stat & STAT_BUSMASK) == STAT_MESGIN)
+				break;
+			goto bad_is;
+
+		case IS_COMPLETE:
+			break;
+		}
+
+	default:
+		break;
+	}
+
+	fas216_cmd(info, CMD_NOP);
+
+#define STATE(st,ph) ((ph) << 3 | (st))
+	/* This table describes the legal SCSI state transitions,
+	 * as described by the SCSI II spec.
+	 */
+	switch (STATE(stat & STAT_BUSMASK, info->scsi.phase)) {
+	case STATE(STAT_DATAIN, PHASE_SELSTEPS):/* Sel w/ steps -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_MSGOUT):  /* Message Out  -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_COMMAND): /* Command      -> Data In      */
+	case STATE(STAT_DATAIN, PHASE_MSGIN):   /* Message In   -> Data In      */
+		info->scsi.phase = PHASE_DATAIN;
+		fas216_transfer(info);
+		return;
+
+	case STATE(STAT_DATAIN, PHASE_DATAIN):  /* Data In      -> Data In      */
+	case STATE(STAT_DATAOUT, PHASE_DATAOUT):/* Data Out     -> Data Out     */
+		fas216_cleanuptransfer(info);
+		fas216_transfer(info);
+		return;
+
+	case STATE(STAT_DATAOUT, PHASE_SELSTEPS):/* Sel w/ steps-> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_MSGOUT): /* Message Out  -> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_COMMAND):/* Command      -> Data Out     */
+	case STATE(STAT_DATAOUT, PHASE_MSGIN):  /* Message In   -> Data Out     */
+		fas216_cmd(info, CMD_FLUSHFIFO);
+		info->scsi.phase = PHASE_DATAOUT;
+		fas216_transfer(info);
+		return;
+
+	case STATE(STAT_STATUS, PHASE_DATAOUT): /* Data Out     -> Status       */
+	case STATE(STAT_STATUS, PHASE_DATAIN):  /* Data In      -> Status       */
+		fas216_stoptransfer(info);
+	case STATE(STAT_STATUS, PHASE_SELSTEPS):/* Sel w/ steps -> Status       */
+	case STATE(STAT_STATUS, PHASE_MSGOUT):  /* Message Out  -> Status       */
+	case STATE(STAT_STATUS, PHASE_COMMAND): /* Command      -> Status       */
+	case STATE(STAT_STATUS, PHASE_MSGIN):   /* Message In   -> Status       */
+		fas216_cmd(info, CMD_INITCMDCOMPLETE);
+		info->scsi.phase = PHASE_STATUS;
+		return;
+
+	case STATE(STAT_MESGIN, PHASE_DATAOUT): /* Data Out     -> Message In   */
+	case STATE(STAT_MESGIN, PHASE_DATAIN):  /* Data In      -> Message In   */
+		fas216_stoptransfer(info);
+	case STATE(STAT_MESGIN, PHASE_COMMAND):	/* Command	-> Message In	*/
+	case STATE(STAT_MESGIN, PHASE_SELSTEPS):/* Sel w/ steps -> Message In   */
+	case STATE(STAT_MESGIN, PHASE_MSGOUT):  /* Message Out  -> Message In   */
+		info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
+		fas216_cmd(info, CMD_FLUSHFIFO);
+		fas216_cmd(info, CMD_TRANSFERINFO);
+		info->scsi.phase = PHASE_MSGIN;
+		return;
+
+	case STATE(STAT_MESGIN, PHASE_MSGIN):
+		info->scsi.msgin_fifo = fas216_readb(info, REG_CFIS) & CFIS_CF;
+		fas216_cmd(info, CMD_TRANSFERINFO);
+		return;
+
+	case STATE(STAT_COMMAND, PHASE_MSGOUT): /* Message Out  -> Command      */
+	case STATE(STAT_COMMAND, PHASE_MSGIN):  /* Message In   -> Command      */
+		fas216_send_command(info);
+		info->scsi.phase = PHASE_COMMAND;
+		return;
+
+
+	/*
+	 * Selection    -> Message Out
+	 */
+	case STATE(STAT_MESGOUT, PHASE_SELECTION):
+		fas216_send_messageout(info, 1);
+		return;
+
+	/*
+	 * Message Out  -> Message Out
+	 */
+	case STATE(STAT_MESGOUT, PHASE_SELSTEPS):
+	case STATE(STAT_MESGOUT, PHASE_MSGOUT):
+		/*
+		 * If we get another message out phase, this usually
+		 * means some parity error occurred.  Resend complete
+		 * set of messages.  If we have more than one byte to
+		 * send, we need to assert ATN again.
+		 */
+		if (info->device[info->SCpnt->device->id].parity_check) {
+			/*
+			 * We were testing... good, the device
+			 * supports parity checking.
+			 */
+			info->device[info->SCpnt->device->id].parity_check = 0;
+			info->device[info->SCpnt->device->id].parity_enabled = 1;
+			fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+		}
+
+		if (msgqueue_msglength(&info->scsi.msgs) > 1)
+			fas216_cmd(info, CMD_SETATN);
+		/*FALLTHROUGH*/
+
+	/*
+	 * Any          -> Message Out
+	 */
+	case STATE(STAT_MESGOUT, PHASE_MSGOUT_EXPECT):
+		fas216_send_messageout(info, 0);
+		return;
+
+	/* Error recovery rules.
+	 *   These either attempt to abort or retry the operation.
+	 * TODO: we need more of these
+	 */
+	case STATE(STAT_COMMAND, PHASE_COMMAND):/* Command      -> Command      */
+		/* error - we've sent out all the command bytes
+		 * we have.
+		 * NOTE: we need SAVE DATA POINTERS/RESTORE DATA POINTERS
+		 * to include the command bytes sent for this to work
+		 * correctly.
+		 */
+		printk(KERN_ERR "scsi%d.%c: "
+			"target trying to receive more command bytes\n",
+			info->host->host_no, fas216_target(info));
+		fas216_cmd(info, CMD_SETATN);
+		fas216_set_stc(info, 15);
+		fas216_cmd(info, CMD_PADBYTES | CMD_WITHDMA);
+		msgqueue_flush(&info->scsi.msgs);
+		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+		return;
+	}
+
+	if (info->scsi.phase == PHASE_MSGIN_DISCONNECT) {
+		printk(KERN_ERR "scsi%d.%c: disconnect message received, but bus service %s?\n",
+			info->host->host_no, fas216_target(info),
+			fas216_bus_phase(stat));
+		msgqueue_flush(&info->scsi.msgs);
+		fas216_cmd(info, CMD_SETATN);
+		msgqueue_addmsg(&info->scsi.msgs, 1, INITIATOR_ERROR);
+		info->scsi.phase = PHASE_MSGOUT_EXPECT;
+		info->scsi.aborting = 1;
+		fas216_cmd(info, CMD_TRANSFERINFO);
+		return;
+	}
+	printk(KERN_ERR "scsi%d.%c: bus phase %s after %s?\n",
+		info->host->host_no, fas216_target(info),
+		fas216_bus_phase(stat),
+		fas216_drv_phase(info));
+	print_debug_list();
+	return;
+
+bad_is:
+	fas216_log(info, 0, "bus service at step %d?", is & IS_BITS);
+	fas216_dumpstate(info);
+	print_debug_list();
+
+	fas216_done(info, DID_ERROR);
+}
+
+/**
+ * fas216_funcdone_intr - handle a function done interrupt from FAS216 chip
+ * @info: interface which caused function done interrupt
+ * @stat: Status register contents
+ * @is: SCSI Status register contents
+ *
+ * Handle a function done interrupt from FAS216 chip
+ */
+static void fas216_funcdone_intr(FAS216_Info *info, unsigned int stat, unsigned int is)
+{
+	unsigned int fifo_len = fas216_readb(info, REG_CFIS) & CFIS_CF;
+
+	fas216_checkmagic(info);
+
+	fas216_log(info, LOG_FUNCTIONDONE,
+		   "function done: stat=%02x is=%02x phase=%02x",
+		   stat, is, info->scsi.phase);
+
+	switch (info->scsi.phase) {
+	case PHASE_STATUS:			/* status phase - read status and msg	*/
+		if (fifo_len != 2) {
+			fas216_log(info, 0, "odd number of bytes in FIFO: %d", fifo_len);
+		}
+		/*
+		 * Read status then message byte.
+		 */
+		info->scsi.SCp.Status = fas216_readb(info, REG_FF);
+		info->scsi.SCp.Message = fas216_readb(info, REG_FF);
+		info->scsi.phase = PHASE_DONE;
+		fas216_cmd(info, CMD_MSGACCEPTED);
+		break;
+
+	case PHASE_IDLE:
+	case PHASE_SELECTION:
+	case PHASE_SELSTEPS:
+		break;
+
+	case PHASE_MSGIN:			/* message in phase			*/
+		if ((stat & STAT_BUSMASK) == STAT_MESGIN) {
+			info->scsi.msgin_fifo = fifo_len;
+			fas216_message(info);
+			break;
+		}
+
+	default:
+		fas216_log(info, 0, "internal phase %s for function done?"
+			"  What do I do with this?",
+			fas216_target(info), fas216_drv_phase(info));
+	}
+}
+
+static void fas216_bus_reset(FAS216_Info *info)
+{
+	neg_t sync_state;
+	int i;
+
+	msgqueue_flush(&info->scsi.msgs);
+
+	sync_state = neg_invalid;
+
+#ifdef SCSI2_SYNC
+	if (info->ifcfg.capabilities & (FASCAP_DMA|FASCAP_PSEUDODMA))
+		sync_state = neg_wait;
+#endif
+
+	info->scsi.phase = PHASE_IDLE;
+	info->SCpnt = NULL; /* bug! */
+	memset(&info->scsi.SCp, 0, sizeof(info->scsi.SCp));
+
+	for (i = 0; i < 8; i++) {
+		info->device[i].disconnect_ok	= info->ifcfg.disconnect_ok;
+		info->device[i].sync_state	= sync_state;
+		info->device[i].period		= info->ifcfg.asyncperiod / 4;
+		info->device[i].stp		= info->scsi.async_stp;
+		info->device[i].sof		= 0;
+		info->device[i].wide_xfer	= 0;
+	}
+
+	info->rst_bus_status = 1;
+	wake_up(&info->eh_wait);
+}
+
+/**
+ * fas216_intr - handle interrupts to progress a command
+ * @info: interface to service
+ *
+ * Handle interrupts from the interface to progress a command
+ */
+irqreturn_t fas216_intr(FAS216_Info *info)
+{
+	unsigned char inst, is, stat;
+	int handled = IRQ_NONE;
+
+	fas216_checkmagic(info);
+
+	stat = fas216_readb(info, REG_STAT);
+	is = fas216_readb(info, REG_IS);
+	inst = fas216_readb(info, REG_INST);
+
+	add_debug_list(stat, is, inst, info->scsi.phase);
+
+	if (stat & STAT_INT) {
+		if (inst & INST_BUSRESET) {
+			fas216_log(info, 0, "bus reset detected");
+			fas216_bus_reset(info);
+			scsi_report_bus_reset(info->host, 0);
+		} else if (inst & INST_ILLEGALCMD) {
+			fas216_log(info, LOG_ERROR, "illegal command given\n");
+			fas216_dumpstate(info);
+			print_debug_list();
+		} else if (inst & INST_DISCONNECT)
+			fas216_disconnect_intr(info);
+		else if (inst & INST_RESELECTED)	/* reselected			*/
+			fas216_reselected_intr(info);
+		else if (inst & INST_BUSSERVICE)	/* bus service request		*/
+			fas216_busservice_intr(info, stat, is);
+		else if (inst & INST_FUNCDONE)		/* function done		*/
+			fas216_funcdone_intr(info, stat, is);
+		else
+		    	fas216_log(info, 0, "unknown interrupt received:"
+				" phase %s inst %02X is %02X stat %02X",
+				fas216_drv_phase(info), inst, is, stat);
+		handled = IRQ_HANDLED;
+	}
+	return handled;
+}
+
+static void __fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+	int tot_msglen;
+
+	/* following what the ESP driver says */
+	fas216_set_stc(info, 0);
+	fas216_cmd(info, CMD_NOP | CMD_WITHDMA);
+
+	/* flush FIFO */
+	fas216_cmd(info, CMD_FLUSHFIFO);
+
+	/* load bus-id and timeout */
+	fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id));
+	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);
+
+	/* synchronous transfers */
+	fas216_set_sync(info, SCpnt->device->id);
+
+	tot_msglen = msgqueue_msglength(&info->scsi.msgs);
+
+#ifdef DEBUG_MESSAGES
+	{
+		struct message *msg;
+		int msgnr = 0, i;
+
+		printk("scsi%d.%c: message out: ",
+			info->host->host_no, '0' + SCpnt->device->id);
+		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+			printk("{ ");
+			for (i = 0; i < msg->length; i++)
+				printk("%02x ", msg->msg[i]);
+			printk("} ");
+		}
+		printk("\n");
+	}
+#endif
+
+	if (tot_msglen == 1 || tot_msglen == 3) {
+		/*
+		 * We have an easy message length to send...
+		 */
+		struct message *msg;
+		int msgnr = 0, i;
+
+		info->scsi.phase = PHASE_SELSTEPS;
+
+		/* load message bytes */
+		while ((msg = msgqueue_getmsg(&info->scsi.msgs, msgnr++)) != NULL) {
+			for (i = 0; i < msg->length; i++)
+				fas216_writeb(info, REG_FF, msg->msg[i]);
+			msg->fifo = tot_msglen - (fas216_readb(info, REG_CFIS) & CFIS_CF);
+		}
+
+		/* load command */
+		for (i = 0; i < SCpnt->cmd_len; i++)
+			fas216_writeb(info, REG_FF, SCpnt->cmnd[i]);
+
+		if (tot_msglen == 1)
+			fas216_cmd(info, CMD_SELECTATN);
+		else
+			fas216_cmd(info, CMD_SELECTATN3);
+	} else {
+		/*
+		 * We have an unusual number of message bytes to send.
+		 *  Load first byte into fifo, and issue SELECT with ATN and
+		 *  stop steps.
+		 */
+		struct message *msg = msgqueue_getmsg(&info->scsi.msgs, 0);
+
+		fas216_writeb(info, REG_FF, msg->msg[0]);
+		msg->fifo = 1;
+
+		fas216_cmd(info, CMD_SELECTATNSTOP);
+	}
+}
+
+/*
+ * Decide whether we need to perform a parity test on this device.
+ * Can also be used to force parity error conditions during initial
+ * information transfer phase (message out) for test purposes.
+ */
+static int parity_test(FAS216_Info *info, int target)
+{
+#if 0
+	if (target == 3) {
+		info->device[target].parity_check = 0;
+		return 1;
+	}
+#endif
+	return info->device[target].parity_check;
+}
+
+static void fas216_start_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+	int disconnect_ok;
+
+	/*
+	 * claim host busy
+	 */
+	info->scsi.phase = PHASE_SELECTION;
+	info->scsi.SCp = SCpnt->SCp;
+	info->SCpnt = SCpnt;
+	info->dma.transfer_type = fasdma_none;
+
+	if (parity_test(info, SCpnt->device->id))
+		fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_PTE);
+	else
+		fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+
+	/*
+	 * Don't allow request sense commands to disconnect.
+	 */
+	disconnect_ok = SCpnt->cmnd[0] != REQUEST_SENSE &&
+			info->device[SCpnt->device->id].disconnect_ok;
+
+	/*
+	 * build outgoing message bytes
+	 */
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, IDENTIFY(disconnect_ok, SCpnt->device->lun));
+
+	/*
+	 * add tag message if required
+	 */
+	if (SCpnt->tag)
+		msgqueue_addmsg(&info->scsi.msgs, 2, SIMPLE_QUEUE_TAG, SCpnt->tag);
+
+	do {
+#ifdef SCSI2_SYNC
+		if ((info->device[SCpnt->device->id].sync_state == neg_wait ||
+		     info->device[SCpnt->device->id].sync_state == neg_complete) &&
+		    (SCpnt->cmnd[0] == REQUEST_SENSE ||
+		     SCpnt->cmnd[0] == INQUIRY)) {
+			info->device[SCpnt->device->id].sync_state = neg_inprogress;
+			msgqueue_addmsg(&info->scsi.msgs, 5,
+					EXTENDED_MESSAGE, 3, EXTENDED_SDTR,
+					1000 / info->ifcfg.clockrate,
+					info->ifcfg.sync_max_depth);
+			break;
+		}
+#endif
+	} while (0);
+
+	__fas216_start_command(info, SCpnt);
+}
+
+static void fas216_allocate_tag(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+#ifdef SCSI2_TAG
+	/*
+	 * tagged queuing - allocate a new tag to this command
+	 */
+	if (SCpnt->device->tagged_queue && SCpnt->cmnd[0] != REQUEST_SENSE &&
+	    SCpnt->cmnd[0] != INQUIRY) {
+	    SCpnt->device->current_tag += 1;
+		if (SCpnt->device->current_tag == 0)
+		    SCpnt->device->current_tag = 1;
+			SCpnt->tag = SCpnt->device->current_tag;
+	} else
+#endif
+		set_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
+
+	info->stats.removes += 1;
+	switch (SCpnt->cmnd[0]) {
+	case WRITE_6:
+	case WRITE_10:
+	case WRITE_12:
+		info->stats.writes += 1;
+		break;
+	case READ_6:
+	case READ_10:
+	case READ_12:
+		info->stats.reads += 1;
+		break;
+	default:
+		info->stats.miscs += 1;
+		break;
+	}
+}
+
+static void fas216_do_bus_device_reset(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+	struct message *msg;
+
+	/*
+	 * claim host busy
+	 */
+	info->scsi.phase = PHASE_SELECTION;
+	info->scsi.SCp = SCpnt->SCp;
+	info->SCpnt = SCpnt;
+	info->dma.transfer_type = fasdma_none;
+
+	fas216_log(info, LOG_ERROR, "sending bus device reset");
+
+	msgqueue_flush(&info->scsi.msgs);
+	msgqueue_addmsg(&info->scsi.msgs, 1, BUS_DEVICE_RESET);
+
+	/* following what the ESP driver says */
+	fas216_set_stc(info, 0);
+	fas216_cmd(info, CMD_NOP | CMD_WITHDMA);
+
+	/* flush FIFO */
+	fas216_cmd(info, CMD_FLUSHFIFO);
+
+	/* load bus-id and timeout */
+	fas216_writeb(info, REG_SDID, BUSID(SCpnt->device->id));
+	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);
+
+	/* synchronous transfers */
+	fas216_set_sync(info, SCpnt->device->id);
+
+	msg = msgqueue_getmsg(&info->scsi.msgs, 0);
+
+	fas216_writeb(info, REG_FF, BUS_DEVICE_RESET);
+	msg->fifo = 1;
+
+	fas216_cmd(info, CMD_SELECTATNSTOP);
+}
+
+/**
+ * fas216_kick - kick a command to the interface
+ * @info: our host interface to kick
+ *
+ * Kick a command to the interface, interface should be idle.
+ * Notes: Interrupts are always disabled!
+ */
+static void fas216_kick(FAS216_Info *info)
+{
+	Scsi_Cmnd *SCpnt = NULL;
+#define TYPE_OTHER	0
+#define TYPE_RESET	1
+#define TYPE_QUEUE	2
+	int where_from = TYPE_OTHER;
+
+	fas216_checkmagic(info);
+
+	/*
+	 * Obtain the next command to process.
+	 */
+	do {
+		if (info->rstSCpnt) {
+			SCpnt = info->rstSCpnt;
+			/* don't remove it */
+			where_from = TYPE_RESET;
+			break;
+		}
+
+		if (info->reqSCpnt) {
+			SCpnt = info->reqSCpnt;
+			info->reqSCpnt = NULL;
+			break;
+		}
+
+		if (info->origSCpnt) {
+			SCpnt = info->origSCpnt;
+			info->origSCpnt = NULL;
+			break;
+		}
+
+		/* retrieve next command */
+		if (!SCpnt) {
+			SCpnt = queue_remove_exclude(&info->queues.issue,
+						     info->busyluns);
+			where_from = TYPE_QUEUE;
+			break;
+		}
+	} while (0);
+
+	if (!SCpnt) {
+		/*
+		 * no command pending, so enable reselection.
+		 */
+		fas216_cmd(info, CMD_ENABLESEL);
+		return;
+	}
+
+	/*
+	 * We're going to start a command, so disable reselection
+	 */
+	fas216_cmd(info, CMD_DISABLESEL);
+
+	if (info->scsi.disconnectable && info->SCpnt) {
+		fas216_log(info, LOG_CONNECT,
+			"moved command for %d to disconnected queue",
+			info->SCpnt->device->id);
+		queue_add_cmd_tail(&info->queues.disconnected, info->SCpnt);
+		info->scsi.disconnectable = 0;
+		info->SCpnt = NULL;
+	}
+
+	fas216_log_command(info, LOG_CONNECT | LOG_MESSAGES, SCpnt,
+			   "starting");
+
+	switch (where_from) {
+	case TYPE_QUEUE:
+		fas216_allocate_tag(info, SCpnt);
+	case TYPE_OTHER:
+		fas216_start_command(info, SCpnt);
+		break;
+	case TYPE_RESET:
+		fas216_do_bus_device_reset(info, SCpnt);
+		break;
+	}
+
+	fas216_log(info, LOG_CONNECT, "select: data pointers [%p, %X]",
+		info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+
+	/*
+	 * should now get either DISCONNECT or
+	 * (FUNCTION DONE with BUS SERVICE) interrupt
+	 */
+}
+
+/*
+ * Clean up from issuing a BUS DEVICE RESET message to a device.
+ */
+static void
+fas216_devicereset_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+	fas216_log(info, LOG_ERROR, "fas216 device reset complete");
+
+	info->rstSCpnt = NULL;
+	info->rst_dev_status = 1;
+	wake_up(&info->eh_wait);
+}
+
+/**
+ * fas216_rq_sns_done - Finish processing automatic request sense command
+ * @info: interface that completed
+ * @SCpnt: command that completed
+ * @result: driver byte of result
+ *
+ * Finish processing automatic request sense command
+ */
+static void
+fas216_rq_sns_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+	fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
+		   "request sense complete, result=0x%04x%02x%02x",
+		   result, SCpnt->SCp.Message, SCpnt->SCp.Status);
+
+	if (result != DID_OK || SCpnt->SCp.Status != GOOD)
+		/*
+		 * Something went wrong.  Make sure that we don't
+		 * have valid data in the sense buffer that could
+		 * confuse the higher levels.
+		 */
+		memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
+//printk("scsi%d.%c: sense buffer: ", info->host->host_no, '0' + SCpnt->device->id);
+//{ int i; for (i = 0; i < 32; i++) printk("%02x ", SCpnt->sense_buffer[i]); printk("\n"); }
+	/*
+	 * Note that we don't set SCpnt->result, since that should
+	 * reflect the status of the command that we were asked by
+	 * the upper layers to process.  This would have been set
+	 * correctly by fas216_std_done.
+	 */
+	SCpnt->scsi_done(SCpnt);
+}
+
+/**
+ * fas216_std_done - finish processing of standard command
+ * @info: interface that completed
+ * @SCpnt: command that completed
+ * @result: driver byte of result
+ *
+ * Finish processing of standard command
+ */
+static void
+fas216_std_done(FAS216_Info *info, Scsi_Cmnd *SCpnt, unsigned int result)
+{
+	info->stats.fins += 1;
+
+	SCpnt->result = result << 16 | info->scsi.SCp.Message << 8 |
+			info->scsi.SCp.Status;
+
+	fas216_log_command(info, LOG_CONNECT, SCpnt,
+		"command complete, result=0x%08x", SCpnt->result);
+
+	/*
+	 * If the driver detected an error, we're all done.
+	 */
+	if (host_byte(SCpnt->result) != DID_OK ||
+	    msg_byte(SCpnt->result) != COMMAND_COMPLETE)
+		goto done;
+
+	/*
+	 * If the command returned CHECK_CONDITION or COMMAND_TERMINATED
+	 * status, request the sense information.
+	 */
+	if (status_byte(SCpnt->result) == CHECK_CONDITION ||
+	    status_byte(SCpnt->result) == COMMAND_TERMINATED)
+		goto request_sense;
+
+	/*
+	 * If the command did not complete with GOOD status,
+	 * we are all done here.
+	 */
+	if (status_byte(SCpnt->result) != GOOD)
+		goto done;
+
+	/*
+	 * We have successfully completed a command.  Make sure that
+	 * we do not have any buffers left to transfer.  The world
+	 * is not perfect, and we seem to occasionally hit this.
+	 * It can be indicative of a buggy driver, target or the upper
+	 * levels of the SCSI code.
+	 */
+	if (info->scsi.SCp.ptr) {
+		switch (SCpnt->cmnd[0]) {
+		case INQUIRY:
+		case START_STOP:
+		case MODE_SENSE:
+			break;
+
+		default:
+			printk(KERN_ERR "scsi%d.%c: incomplete data transfer "
+				"detected: res=%08X ptr=%p len=%X CDB: ",
+				info->host->host_no, '0' + SCpnt->device->id,
+				SCpnt->result, info->scsi.SCp.ptr,
+				info->scsi.SCp.this_residual);
+			print_command(SCpnt->cmnd);
+			SCpnt->result &= ~(255 << 16);
+			SCpnt->result |= DID_BAD_TARGET << 16;
+			goto request_sense;
+		}
+	}
+
+done:
+	if (SCpnt->scsi_done) {
+		SCpnt->scsi_done(SCpnt);
+		return;
+	}
+
+	panic("scsi%d.H: null scsi_done function in fas216_done",
+		info->host->host_no);
+
+
+request_sense:
+	if (SCpnt->cmnd[0] == REQUEST_SENSE)
+		goto done;
+
+	fas216_log_target(info, LOG_CONNECT, SCpnt->device->id,
+			  "requesting sense");
+	memset(SCpnt->cmnd, 0, sizeof (SCpnt->cmnd));
+	SCpnt->cmnd[0] = REQUEST_SENSE;
+	SCpnt->cmnd[1] = SCpnt->device->lun << 5;
+	SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+	SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+	SCpnt->SCp.buffer = NULL;
+	SCpnt->SCp.buffers_residual = 0;
+	SCpnt->SCp.ptr = (char *)SCpnt->sense_buffer;
+	SCpnt->SCp.this_residual = sizeof(SCpnt->sense_buffer);
+	SCpnt->SCp.Message = 0;
+	SCpnt->SCp.Status = 0;
+	SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+	SCpnt->sc_data_direction = SCSI_DATA_READ;
+	SCpnt->use_sg = 0;
+	SCpnt->tag = 0;
+	SCpnt->host_scribble = (void *)fas216_rq_sns_done;
+
+	/*
+	 * Place this command into the high priority "request
+	 * sense" slot.  This will be the very next command
+	 * executed, unless a target connects to us.
+	 */
+	if (info->reqSCpnt)
+		printk(KERN_WARNING "scsi%d.%c: loosing request command\n",
+			info->host->host_no, '0' + SCpnt->device->id);
+	info->reqSCpnt = SCpnt;
+}
+
+/**
+ * fas216_done - complete processing for current command
+ * @info: interface that completed
+ * @result: driver byte of result
+ *
+ * Complete processing for current command
+ */
+static void fas216_done(FAS216_Info *info, unsigned int result)
+{
+	void (*fn)(FAS216_Info *, Scsi_Cmnd *, unsigned int);
+	Scsi_Cmnd *SCpnt;
+	unsigned long flags;
+
+	fas216_checkmagic(info);
+
+	if (!info->SCpnt)
+		goto no_command;
+
+	SCpnt = info->SCpnt;
+	info->SCpnt = NULL;
+    	info->scsi.phase = PHASE_IDLE;
+
+	if (info->scsi.aborting) {
+		fas216_log(info, 0, "uncaught abort - returning DID_ABORT");
+		result = DID_ABORT;
+		info->scsi.aborting = 0;
+	}
+
+	/*
+	 * Sanity check the completion - if we have zero bytes left
+	 * to transfer, we should not have a valid pointer.
+	 */
+	if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) {
+		printk("scsi%d.%c: zero bytes left to transfer, but "
+		       "buffer pointer still valid: ptr=%p len=%08x CDB: ",
+		       info->host->host_no, '0' + SCpnt->device->id,
+		       info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+		info->scsi.SCp.ptr = NULL;
+		print_command(SCpnt->cmnd);
+	}
+
+	/*
+	 * Clear down this command as completed.  If we need to request
+	 * the sense information, fas216_kick will re-assert the busy
+	 * status.
+	 */
+	info->device[SCpnt->device->id].parity_check = 0;
+	clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
+
+	fn = (void (*)(FAS216_Info *, Scsi_Cmnd *, unsigned int))SCpnt->host_scribble;
+	fn(info, SCpnt, result);
+
+	if (info->scsi.irq != NO_IRQ) {
+		spin_lock_irqsave(&info->host_lock, flags);
+		if (info->scsi.phase == PHASE_IDLE)
+			fas216_kick(info);
+		spin_unlock_irqrestore(&info->host_lock, flags);
+	}
+	return;
+
+no_command:
+	panic("scsi%d.H: null command in fas216_done",
+		info->host->host_no);
+}
+
+/**
+ * fas216_queue_command - queue a command for adapter to process.
+ * @SCpnt: Command to queue
+ * @done: done function to call once command is complete
+ *
+ * Queue a command for adapter to process.
+ * Returns: 0 on success, else error.
+ * Notes: io_request_lock is held, interrupts are disabled.
+ */
+int fas216_queue_command(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+	int result;
+
+	fas216_checkmagic(info);
+
+	fas216_log_command(info, LOG_CONNECT, SCpnt,
+			   "received command (%p)", SCpnt);
+
+	SCpnt->scsi_done = done;
+	SCpnt->host_scribble = (void *)fas216_std_done;
+	SCpnt->result = 0;
+
+	init_SCp(SCpnt);
+
+	info->stats.queues += 1;
+	SCpnt->tag = 0;
+
+	spin_lock(&info->host_lock);
+
+	/*
+	 * Add command into execute queue and let it complete under
+	 * whatever scheme we're using.
+	 */
+	result = !queue_add_cmd_ordered(&info->queues.issue, SCpnt);
+
+	/*
+	 * If we successfully added the command,
+	 * kick the interface to get it moving.
+	 */
+	if (result == 0 && info->scsi.phase == PHASE_IDLE)
+		fas216_kick(info);
+	spin_unlock(&info->host_lock);
+
+	fas216_log_target(info, LOG_CONNECT, -1, "queue %s",
+		result ? "failure" : "success");
+
+	return result;
+}
+
+/**
+ * fas216_internal_done - trigger restart of a waiting thread in fas216_command
+ * @SCpnt: Command to wake
+ *
+ * Trigger restart of a waiting thread in fas216_command
+ */
+static void fas216_internal_done(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+
+	fas216_checkmagic(info);
+
+	info->internal_done = 1;
+}
+
+/**
+ * fas216_command - queue a command for adapter to process.
+ * @SCpnt: Command to queue
+ *
+ * Queue a command for adapter to process.
+ * Returns: scsi result code.
+ * Notes: io_request_lock is held, interrupts are disabled.
+ */
+int fas216_command(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+
+	fas216_checkmagic(info);
+
+	/*
+	 * We should only be using this if we don't have an interrupt.
+	 * Provide some "incentive" to use the queueing code.
+	 */
+	if (info->scsi.irq != NO_IRQ)
+		BUG();
+
+	info->internal_done = 0;
+	fas216_queue_command(SCpnt, fas216_internal_done);
+
+	/*
+	 * This wastes time, since we can't return until the command is
+	 * complete. We can't sleep either since we may get re-entered!
+	 * However, we must re-enable interrupts, or else we'll be
+	 * waiting forever.
+	 */
+	spin_unlock_irq(info->host->host_lock);
+
+	while (!info->internal_done) {
+		/*
+		 * If we don't have an IRQ, then we must poll the card for
+		 * it's interrupt, and use that to call this driver's
+		 * interrupt routine.  That way, we keep the command
+		 * progressing.  Maybe we can add some inteligence here
+		 * and go to sleep if we know that the device is going
+		 * to be some time (eg, disconnected).
+		 */
+		if (fas216_readb(info, REG_STAT) & STAT_INT) {
+			spin_lock_irq(info->host->host_lock);
+			fas216_intr(info);
+			spin_unlock_irq(info->host->host_lock);
+		}
+	}
+
+	spin_lock_irq(info->host->host_lock);
+
+	return SCpnt->result;
+}
+
+/*
+ * Error handler timeout function.  Indicate that we timed out,
+ * and wake up any error handler process so it can continue.
+ */
+static void fas216_eh_timer(unsigned long data)
+{
+	FAS216_Info *info = (FAS216_Info *)data;
+
+	fas216_log(info, LOG_ERROR, "error handling timed out\n");
+
+	del_timer(&info->eh_timer);
+
+	if (info->rst_bus_status == 0)
+		info->rst_bus_status = -1;
+	if (info->rst_dev_status == 0)
+		info->rst_dev_status = -1;
+
+	wake_up(&info->eh_wait);
+}
+
+enum res_find {
+	res_failed,		/* not found			*/
+	res_success,		/* command on issue queue	*/
+	res_hw_abort		/* command on disconnected dev	*/
+};
+
+/**
+ * fas216_do_abort - decide how to abort a command
+ * @SCpnt: command to abort
+ *
+ * Decide how to abort a command.
+ * Returns: abort status
+ */
+static enum res_find fas216_find_command(FAS216_Info *info, Scsi_Cmnd *SCpnt)
+{
+	enum res_find res = res_failed;
+
+	if (queue_remove_cmd(&info->queues.issue, SCpnt)) {
+		/*
+		 * The command was on the issue queue, and has not been
+		 * issued yet.  We can remove the command from the queue,
+		 * and acknowledge the abort.  Neither the device nor the
+		 * interface know about the command.
+		 */
+		printk("on issue queue ");
+
+		res = res_success;
+	} else if (queue_remove_cmd(&info->queues.disconnected, SCpnt)) {
+		/*
+		 * The command was on the disconnected queue.  We must
+		 * reconnect with the device if possible, and send it
+		 * an abort message.
+		 */
+		printk("on disconnected queue ");
+
+		res = res_hw_abort;
+	} else if (info->SCpnt == SCpnt) {
+		printk("executing ");
+
+		switch (info->scsi.phase) {
+		/*
+		 * If the interface is idle, and the command is 'disconnectable',
+		 * then it is the same as on the disconnected queue.
+		 */
+		case PHASE_IDLE:
+			if (info->scsi.disconnectable) {
+				info->scsi.disconnectable = 0;
+				info->SCpnt = NULL;
+				res = res_hw_abort;
+			}
+			break;
+
+		default:
+			break;
+		}
+	} else if (info->origSCpnt == SCpnt) {
+		/*
+		 * The command will be executed next, but a command
+		 * is currently using the interface.  This is similar to
+		 * being on the issue queue, except the busylun bit has
+		 * been set.
+		 */
+		info->origSCpnt = NULL;
+		clear_bit(SCpnt->device->id * 8 + SCpnt->device->lun, info->busyluns);
+		printk("waiting for execution ");
+		res = res_success;
+	} else
+		printk("unknown ");
+
+	return res;
+}
+
+/**
+ * fas216_eh_abort - abort this command
+ * @SCpnt: command to abort
+ *
+ * Abort this command.
+ * Returns: FAILED if unable to abort
+ * Notes: io_request_lock is taken, and irqs are disabled
+ */
+int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+	int result = FAILED;
+
+	fas216_checkmagic(info);
+
+	info->stats.aborts += 1;
+
+	printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no);
+	print_command(SCpnt->data_cmnd);
+
+	print_debug_list();
+	fas216_dumpstate(info);
+
+	printk(KERN_WARNING "scsi%d: abort %p ", info->host->host_no, SCpnt);
+
+	switch (fas216_find_command(info, SCpnt)) {
+	/*
+	 * We found the command, and cleared it out.  Either
+	 * the command is still known to be executing on the
+	 * target, or the busylun bit is not set.
+	 */
+	case res_success:
+		printk("success\n");
+		result = SUCCESS;
+		break;
+
+	/*
+	 * We need to reconnect to the target and send it an
+	 * ABORT or ABORT_TAG message.  We can only do this
+	 * if the bus is free.
+	 */
+	case res_hw_abort:
+		
+
+	/*
+	 * We are unable to abort the command for some reason.
+	 */
+	default:
+	case res_failed:
+		printk("failed\n");
+		break;
+	}
+
+	return result;
+}
+
+/**
+ * fas216_eh_device_reset - Reset the device associated with this command
+ * @SCpnt: command specifing device to reset
+ *
+ * Reset the device associated with this command.
+ * Returns: FAILED if unable to reset.
+ * Notes: We won't be re-entered, so we'll only have one device
+ * reset on the go at one time.
+ */
+int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+	unsigned long flags;
+	int i, res = FAILED, target = SCpnt->device->id;
+
+	fas216_log(info, LOG_ERROR, "device reset for target %d", target);
+
+	spin_lock_irqsave(&info->host_lock, flags);
+
+	do {
+		/*
+		 * If we are currently connected to a device, and
+		 * it is the device we want to reset, there is
+		 * nothing we can do here.  Chances are it is stuck,
+		 * and we need a bus reset.
+		 */
+		if (info->SCpnt && !info->scsi.disconnectable &&
+		    info->SCpnt->device->id == SCpnt->device->id)
+			break;
+
+		/*
+		 * We're going to be resetting this device.  Remove
+		 * all pending commands from the driver.  By doing
+		 * so, we guarantee that we won't touch the command
+		 * structures except to process the reset request.
+		 */
+		queue_remove_all_target(&info->queues.issue, target);
+		queue_remove_all_target(&info->queues.disconnected, target);
+		if (info->origSCpnt && info->origSCpnt->device->id == target)
+			info->origSCpnt = NULL;
+		if (info->reqSCpnt && info->reqSCpnt->device->id == target)
+			info->reqSCpnt = NULL;
+		for (i = 0; i < 8; i++)
+			clear_bit(target * 8 + i, info->busyluns);
+
+		/*
+		 * Hijack this SCSI command structure to send
+		 * a bus device reset message to this device.
+		 */
+		SCpnt->host_scribble = (void *)fas216_devicereset_done;
+
+		info->rst_dev_status = 0;
+		info->rstSCpnt = SCpnt;
+
+		if (info->scsi.phase == PHASE_IDLE)
+			fas216_kick(info);
+
+		mod_timer(&info->eh_timer, 30 * HZ);
+		spin_unlock_irqrestore(&info->host_lock, flags);
+
+		/*
+		 * Wait up to 30 seconds for the reset to complete.
+		 */
+		wait_event(info->eh_wait, info->rst_dev_status);
+
+		del_timer_sync(&info->eh_timer);
+		spin_lock_irqsave(&info->host_lock, flags);
+		info->rstSCpnt = NULL;
+
+		if (info->rst_dev_status == 1)
+			res = SUCCESS;
+	} while (0);
+
+	SCpnt->host_scribble = NULL;
+	spin_unlock_irqrestore(&info->host_lock, flags);
+
+	fas216_log(info, LOG_ERROR, "device reset complete: %s\n",
+		   res == SUCCESS ? "success" : "failed");
+
+	return res;
+}
+
+/**
+ * fas216_eh_bus_reset - Reset the bus associated with the command
+ * @SCpnt: command specifing bus to reset
+ *
+ * Reset the bus associated with the command.
+ * Returns: FAILED if unable to reset.
+ * Notes: Further commands are blocked.
+ */
+int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+	unsigned long flags;
+	Scsi_Device *SDpnt;
+
+	fas216_checkmagic(info);
+	fas216_log(info, LOG_ERROR, "resetting bus");
+
+	info->stats.bus_resets += 1;
+
+	spin_lock_irqsave(&info->host_lock, flags);
+
+	/*
+	 * Stop all activity on this interface.
+	 */
+	fas216_aborttransfer(info);
+	fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]);
+
+	/*
+	 * Clear any pending interrupts.
+	 */
+	while (fas216_readb(info, REG_STAT) & STAT_INT)
+		fas216_readb(info, REG_INST);
+
+	info->rst_bus_status = 0;
+
+	/*
+	 * For each attached hard-reset device, clear out
+	 * all command structures.  Leave the running
+	 * command in place.
+	 */
+	list_for_each_entry(SDpnt, &info->host->my_devices, siblings) {
+		int i;
+
+		if (SDpnt->soft_reset)
+			continue;
+
+		queue_remove_all_target(&info->queues.issue, SDpnt->id);
+		queue_remove_all_target(&info->queues.disconnected, SDpnt->id);
+		if (info->origSCpnt && info->origSCpnt->device->id == SDpnt->id)
+			info->origSCpnt = NULL;
+		if (info->reqSCpnt && info->reqSCpnt->device->id == SDpnt->id)
+			info->reqSCpnt = NULL;
+		info->SCpnt = NULL;
+
+		for (i = 0; i < 8; i++)
+			clear_bit(SDpnt->id * 8 + i, info->busyluns);
+	}
+
+	info->scsi.phase = PHASE_IDLE;
+
+	/*
+	 * Reset the SCSI bus.  Device cleanup happens in
+	 * the interrupt handler.
+	 */
+	fas216_cmd(info, CMD_RESETSCSI);
+
+	mod_timer(&info->eh_timer, jiffies + HZ);
+	spin_unlock_irqrestore(&info->host_lock, flags);
+
+	/*
+	 * Wait one second for the interrupt.
+	 */
+	wait_event(info->eh_wait, info->rst_bus_status);
+	del_timer_sync(&info->eh_timer);
+
+	fas216_log(info, LOG_ERROR, "bus reset complete: %s\n",
+		   info->rst_bus_status == 1 ? "success" : "failed");
+
+	return info->rst_bus_status == 1 ? SUCCESS : FAILED;
+}
+
+/**
+ * fas216_init_chip - Initialise FAS216 state after reset
+ * @info: state structure for interface
+ *
+ * Initialise FAS216 state after reset
+ */
+static void fas216_init_chip(FAS216_Info *info)
+{
+	unsigned int clock = ((info->ifcfg.clockrate - 1) / 5 + 1) & 7;
+	fas216_writeb(info, REG_CLKF, clock);
+	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+	fas216_writeb(info, REG_CNTL2, info->scsi.cfg[1]);
+	fas216_writeb(info, REG_CNTL3, info->scsi.cfg[2]);
+	fas216_writeb(info, REG_STIM, info->ifcfg.select_timeout);
+	fas216_writeb(info, REG_SOF, 0);
+	fas216_writeb(info, REG_STP, info->scsi.async_stp);
+	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+}
+
+/**
+ * fas216_eh_host_reset - Reset the host associated with this command
+ * @SCpnt: command specifing host to reset
+ *
+ * Reset the host associated with this command.
+ * Returns: FAILED if unable to reset.
+ * Notes: io_request_lock is taken, and irqs are disabled
+ */
+int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+{
+	FAS216_Info *info = (FAS216_Info *)SCpnt->device->host->hostdata;
+
+	fas216_checkmagic(info);
+
+	printk("scsi%d.%c: %s: resetting host\n",
+		info->host->host_no, '0' + SCpnt->device->id, __FUNCTION__);
+
+	/*
+	 * Reset the SCSI chip.
+	 */
+	fas216_cmd(info, CMD_RESETCHIP);
+
+	/*
+	 * Ugly ugly ugly!
+	 * We need to release the host_lock and enable
+	 * IRQs if we sleep, but we must relock and disable
+	 * IRQs after the sleep.
+	 */
+	spin_unlock_irq(info->host->host_lock);
+	scsi_sleep(50 * HZ/100);
+	spin_lock_irq(info->host->host_lock);
+
+	/*
+	 * Release the SCSI reset.
+	 */
+	fas216_cmd(info, CMD_NOP);
+
+	fas216_init_chip(info);
+
+	return SUCCESS;
+}
+
+#define TYPE_UNKNOWN	0
+#define TYPE_NCR53C90	1
+#define TYPE_NCR53C90A	2
+#define TYPE_NCR53C9x	3
+#define TYPE_Am53CF94	4
+#define TYPE_EmFAS216	5
+#define TYPE_QLFAS216	6
+
+static char *chip_types[] = {
+	"unknown",
+	"NS NCR53C90",
+	"NS NCR53C90A",
+	"NS NCR53C9x",
+	"AMD Am53CF94",
+	"Emulex FAS216",
+	"QLogic FAS216"
+};
+
+static int fas216_detect_type(FAS216_Info *info)
+{
+	int family, rev;
+
+	/*
+	 * Reset the chip.
+	 */
+	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+	udelay(50);
+	fas216_writeb(info, REG_CMD, CMD_NOP);
+
+	/*
+	 * Check to see if control reg 2 is present.
+	 */
+	fas216_writeb(info, REG_CNTL3, 0);
+	fas216_writeb(info, REG_CNTL2, CNTL2_S2FE);
+
+	/*
+	 * If we are unable to read back control reg 2
+	 * correctly, it is not present, and we have a
+	 * NCR53C90.
+	 */
+	if ((fas216_readb(info, REG_CNTL2) & (~0xe0)) != CNTL2_S2FE)
+		return TYPE_NCR53C90;
+
+	/*
+	 * Now, check control register 3
+	 */
+	fas216_writeb(info, REG_CNTL2, 0);
+	fas216_writeb(info, REG_CNTL3, 0);
+	fas216_writeb(info, REG_CNTL3, 5);
+
+	/*
+	 * If we are unable to read the register back
+	 * correctly, we have a NCR53C90A
+	 */
+	if (fas216_readb(info, REG_CNTL3) != 5)
+		return TYPE_NCR53C90A;
+
+	/*
+	 * Now read the ID from the chip.
+	 */
+	fas216_writeb(info, REG_CNTL3, 0);
+
+	fas216_writeb(info, REG_CNTL3, CNTL3_ADIDCHK);
+	fas216_writeb(info, REG_CNTL3, 0);
+
+	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+	udelay(50);
+	fas216_writeb(info, REG_CMD, CMD_WITHDMA | CMD_NOP);
+
+	fas216_writeb(info, REG_CNTL2, CNTL2_ENF);
+	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+	udelay(50);
+	fas216_writeb(info, REG_CMD, CMD_NOP);
+
+	rev     = fas216_readb(info, REG_ID);
+	family  = rev >> 3;
+	rev    &= 7;
+
+	switch (family) {
+	case 0x01:
+		if (rev == 4)
+			return TYPE_Am53CF94;
+		break;
+
+	case 0x02:
+		switch (rev) {
+		case 2:
+			return TYPE_EmFAS216;
+		case 3:
+			return TYPE_QLFAS216;
+		}
+		break;
+
+	default:
+		break;
+	}
+	printk("family %x rev %x\n", family, rev);
+	return TYPE_NCR53C9x;
+}
+
+/**
+ * fas216_reset_state - Initialise driver internal state
+ * @info: state to initialise
+ *
+ * Initialise driver internal state
+ */
+static void fas216_reset_state(FAS216_Info *info)
+{
+	int i;
+
+	fas216_checkmagic(info);
+
+	fas216_bus_reset(info);
+
+	/*
+	 * Clear out all stale info in our state structure
+	 */
+	memset(info->busyluns, 0, sizeof(info->busyluns));
+	info->scsi.disconnectable = 0;
+	info->scsi.aborting = 0;
+
+	for (i = 0; i < 8; i++) {
+		info->device[i].parity_enabled	= 0;
+		info->device[i].parity_check	= 1;
+	}
+
+	/*
+	 * Drain all commands on disconnected queue
+	 */
+	while (queue_remove(&info->queues.disconnected) != NULL);
+
+	/*
+	 * Remove executing commands.
+	 */
+	info->SCpnt     = NULL;
+	info->reqSCpnt  = NULL;
+	info->rstSCpnt  = NULL;
+	info->origSCpnt = NULL;
+}
+
+/**
+ * fas216_init - initialise FAS/NCR/AMD SCSI structures.
+ * @host: a driver-specific filled-out structure
+ *
+ * Initialise FAS/NCR/AMD SCSI structures.
+ * Returns: 0 on success
+ */
+int fas216_init(struct Scsi_Host *host)
+{
+	FAS216_Info *info = (FAS216_Info *)host->hostdata;
+
+	info->magic_start    = MAGIC;
+	info->magic_end      = MAGIC;
+	info->host           = host;
+	info->scsi.cfg[0]    = host->this_id | CNTL1_PERE;
+	info->scsi.cfg[1]    = CNTL2_ENF | CNTL2_S2FE;
+	info->scsi.cfg[2]    = info->ifcfg.cntl3 |
+			       CNTL3_ADIDCHK | CNTL3_QTAG | CNTL3_G2CB | CNTL3_LBTM;
+	info->scsi.async_stp = fas216_syncperiod(info, info->ifcfg.asyncperiod);
+
+	info->rst_dev_status = -1;
+	info->rst_bus_status = -1;
+	init_waitqueue_head(&info->eh_wait);
+	init_timer(&info->eh_timer);
+	info->eh_timer.data  = (unsigned long)info;
+	info->eh_timer.function = fas216_eh_timer;
+	
+	spin_lock_init(&info->host_lock);
+
+	memset(&info->stats, 0, sizeof(info->stats));
+
+	msgqueue_initialise(&info->scsi.msgs);
+
+	if (!queue_initialise(&info->queues.issue))
+		return -ENOMEM;
+
+	if (!queue_initialise(&info->queues.disconnected)) {
+		queue_free(&info->queues.issue);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ * fas216_add - initialise FAS/NCR/AMD SCSI ic.
+ * @host: a driver-specific filled-out structure
+ * @dev: parent device
+ *
+ * Initialise FAS/NCR/AMD SCSI ic.
+ * Returns: 0 on success
+ */
+int fas216_add(struct Scsi_Host *host, struct device *dev)
+{
+	FAS216_Info *info = (FAS216_Info *)host->hostdata;
+	int type, ret;
+
+	if (info->ifcfg.clockrate <= 10 || info->ifcfg.clockrate > 40) {
+		printk(KERN_CRIT "fas216: invalid clock rate %u MHz\n",
+			info->ifcfg.clockrate);
+		return -EINVAL;
+	}
+
+	fas216_reset_state(info);
+	type = fas216_detect_type(info);
+	info->scsi.type = chip_types[type];
+
+	udelay(300);
+
+	/*
+	 * Initialise the chip correctly.
+	 */
+	fas216_init_chip(info);
+
+	/*
+	 * Reset the SCSI bus.  We don't want to see
+	 * the resulting reset interrupt, so mask it
+	 * out.
+	 */
+	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0] | CNTL1_DISR);
+	fas216_writeb(info, REG_CMD, CMD_RESETSCSI);
+
+	/*
+	 * scsi standard says wait 250ms
+	 */
+	spin_unlock_irq(info->host->host_lock);
+	scsi_sleep(100*HZ/100);
+	spin_lock_irq(info->host->host_lock);
+
+	fas216_writeb(info, REG_CNTL1, info->scsi.cfg[0]);
+	fas216_readb(info, REG_INST);
+
+	fas216_checkmagic(info);
+
+	ret = scsi_add_host(host, dev);
+	if (ret)
+		fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+
+	return ret;
+}
+
+void fas216_remove(struct Scsi_Host *host)
+{
+	FAS216_Info *info = (FAS216_Info *)host->hostdata;
+
+	fas216_checkmagic(info);
+	scsi_remove_host(host);
+
+	fas216_writeb(info, REG_CMD, CMD_RESETCHIP);
+}
+
+/**
+ * fas216_release - release all resources for FAS/NCR/AMD SCSI ic.
+ * @host: a driver-specific filled-out structure
+ *
+ * release all resources and put everything to bed for FAS/NCR/AMD SCSI ic.
+ */
+void fas216_release(struct Scsi_Host *host)
+{
+	FAS216_Info *info = (FAS216_Info *)host->hostdata;
+
+	queue_free(&info->queues.disconnected);
+	queue_free(&info->queues.issue);
+}
+
+int fas216_print_host(FAS216_Info *info, char *buffer)
+{
+	return sprintf(buffer,
+			"\n"
+			"Chip    : %s\n"
+			" Address: 0x%08lx\n"
+			" IRQ    : %d\n"
+			" DMA    : %d\n",
+			info->scsi.type, info->host->io_port,
+			info->host->irq, info->host->dma_channel);
+}
+
+int fas216_print_stats(FAS216_Info *info, char *buffer)
+{
+	char *p = buffer;
+
+	p += sprintf(p, "\n"
+			"Command Statistics:\n"
+			" Queued     : %u\n"
+			" Issued     : %u\n"
+			" Completed  : %u\n"
+			" Reads      : %u\n"
+			" Writes     : %u\n"
+			" Others     : %u\n"
+			" Disconnects: %u\n"
+			" Aborts     : %u\n"
+			" Bus resets : %u\n"
+			" Host resets: %u\n",
+			info->stats.queues,	 info->stats.removes,
+			info->stats.fins,	 info->stats.reads,
+			info->stats.writes,	 info->stats.miscs,
+			info->stats.disconnects, info->stats.aborts,
+			info->stats.bus_resets,	 info->stats.host_resets);
+
+	return p - buffer;
+}
+
+int fas216_print_devices(FAS216_Info *info, char *buffer)
+{
+	struct fas216_device *dev;
+	Scsi_Device *scd;
+	char *p = buffer;
+
+	p += sprintf(p, "Device/Lun TaggedQ       Parity   Sync\n");
+
+	list_for_each_entry(scd, &info->host->my_devices, siblings) {
+		dev = &info->device[scd->id];
+		p += sprintf(p, "     %d/%d   ", scd->id, scd->lun);
+		if (scd->tagged_supported)
+			p += sprintf(p, "%3sabled(%3d) ",
+				     scd->tagged_queue ? "en" : "dis",
+				     scd->current_tag);
+		else
+			p += sprintf(p, "unsupported   ");
+
+		p += sprintf(p, "%3sabled ", dev->parity_enabled ? "en" : "dis");
+
+		if (dev->sof)
+			p += sprintf(p, "offset %d, %d ns\n",
+				     dev->sof, dev->period * 4);
+		else
+			p += sprintf(p, "async\n");
+	}
+
+	return p - buffer;
+}
+
+EXPORT_SYMBOL(fas216_init);
+EXPORT_SYMBOL(fas216_add);
+EXPORT_SYMBOL(fas216_queue_command);
+EXPORT_SYMBOL(fas216_command);
+EXPORT_SYMBOL(fas216_intr);
+EXPORT_SYMBOL(fas216_remove);
+EXPORT_SYMBOL(fas216_release);
+EXPORT_SYMBOL(fas216_eh_abort);
+EXPORT_SYMBOL(fas216_eh_device_reset);
+EXPORT_SYMBOL(fas216_eh_bus_reset);
+EXPORT_SYMBOL(fas216_eh_host_reset);
+EXPORT_SYMBOL(fas216_print_host);
+EXPORT_SYMBOL(fas216_print_stats);
+EXPORT_SYMBOL(fas216_print_devices);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Generic FAS216/NCR53C9x driver core");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/arm/fas216.h b/drivers/scsi/arm/fas216.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/fas216.h	Thu May 15 17:33:17 2003
@@ -0,0 +1,394 @@
+/*
+ *  linux/drivers/acorn/scsi/fas216.h
+ *
+ *  Copyright (C) 1997-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.
+ *
+ *  FAS216 generic driver
+ */
+#ifndef FAS216_H
+#define FAS216_H
+
+#ifndef NO_IRQ
+#define NO_IRQ 255
+#endif
+
+#include "queue.h"
+#include "msgqueue.h"
+
+/* FAS register definitions */
+
+/* transfer count low */
+#define REG_CTCL		(0)
+#define REG_STCL		(0)
+
+/* transfer count medium */
+#define REG_CTCM		(1)
+#define REG_STCM		(1)
+
+/* fifo data */
+#define REG_FF			(2)
+
+/* command */
+#define REG_CMD			(3)
+#define CMD_NOP			0x00
+#define CMD_FLUSHFIFO		0x01
+#define CMD_RESETCHIP		0x02
+#define CMD_RESETSCSI		0x03
+
+#define CMD_TRANSFERINFO	0x10
+#define CMD_INITCMDCOMPLETE	0x11
+#define CMD_MSGACCEPTED		0x12
+#define CMD_PADBYTES		0x18
+#define CMD_SETATN		0x1a
+#define CMD_RSETATN		0x1b
+
+#define CMD_SELECTWOATN		0x41
+#define CMD_SELECTATN		0x42
+#define CMD_SELECTATNSTOP	0x43
+#define CMD_ENABLESEL		0x44
+#define CMD_DISABLESEL		0x45
+#define CMD_SELECTATN3		0x46
+#define CMD_RESEL3		0x47
+
+#define CMD_WITHDMA		0x80
+
+/* status register (read) */
+#define REG_STAT		(4)
+#define STAT_IO			(1 << 0)			/* IO phase		*/
+#define STAT_CD			(1 << 1)			/* CD phase		*/
+#define STAT_MSG		(1 << 2)			/* MSG phase		*/
+#define STAT_TRANSFERDONE	(1 << 3)			/* Transfer completed	*/
+#define STAT_TRANSFERCNTZ	(1 << 4)			/* Transfer counter is zero */
+#define STAT_PARITYERROR	(1 << 5)			/* Parity error		*/
+#define STAT_REALBAD		(1 << 6)			/* Something bad	*/
+#define STAT_INT		(1 << 7)			/* Interrupt		*/
+
+#define STAT_BUSMASK		(STAT_MSG|STAT_CD|STAT_IO)
+#define STAT_DATAOUT		(0)				/* Data out		*/
+#define STAT_DATAIN		(STAT_IO)			/* Data in		*/
+#define STAT_COMMAND		(STAT_CD)			/* Command out		*/
+#define STAT_STATUS		(STAT_CD|STAT_IO)		/* Status In		*/
+#define STAT_MESGOUT		(STAT_MSG|STAT_CD)		/* Message out		*/
+#define STAT_MESGIN		(STAT_MSG|STAT_CD|STAT_IO)	/* Message In		*/
+
+/* bus ID for select / reselect */
+#define REG_SDID		(4)
+#define BUSID(target)		((target) & 7)
+
+/* Interrupt status register (read) */
+#define REG_INST		(5)
+#define INST_SELWOATN		(1 << 0)			/* Select w/o ATN	*/
+#define INST_SELATN		(1 << 1)			/* Select w/ATN		*/
+#define INST_RESELECTED		(1 << 2)			/* Reselected		*/
+#define INST_FUNCDONE		(1 << 3)			/* Function done	*/
+#define INST_BUSSERVICE		(1 << 4)			/* Bus service		*/
+#define INST_DISCONNECT		(1 << 5)			/* Disconnect		*/
+#define INST_ILLEGALCMD		(1 << 6)			/* Illegal command	*/
+#define INST_BUSRESET		(1 << 7)			/* SCSI Bus reset	*/
+
+/* Timeout register (write) */
+#define REG_STIM		(5)
+
+/* Sequence step register (read) */
+#define REG_IS			(6)
+#define IS_BITS			0x07
+#define IS_SELARB		0x00				/* Select & Arb ok	*/
+#define IS_MSGBYTESENT		0x01				/* One byte message sent*/
+#define IS_NOTCOMMAND		0x02				/* Not in command state	*/
+#define IS_EARLYPHASE		0x03				/* Early phase change	*/
+#define IS_COMPLETE		0x04				/* Command ok		*/
+#define IS_SOF			0x08				/* Sync off flag	*/
+
+/* Transfer period step (write) */
+#define REG_STP			(6)
+
+/* Synchronous Offset (write) */
+#define REG_SOF			(7)
+
+/* Fifo state register (read) */
+#define REG_CFIS		(7)
+#define CFIS_CF			0x1f				/* Num bytes in FIFO	*/
+#define CFIS_IS			0xe0				/* Step			*/
+
+/* config register 1 */
+#define REG_CNTL1		(8)
+#define CNTL1_CID		(7 << 0)			/* Chip ID			*/
+#define CNTL1_STE		(1 << 3)			/* Self test enable		*/
+#define CNTL1_PERE		(1 << 4)			/* Parity enable reporting en.	*/
+#define CNTL1_PTE		(1 << 5)			/* Parity test enable		*/
+#define CNTL1_DISR		(1 << 6)			/* Disable Irq on SCSI reset	*/
+#define CNTL1_ETM		(1 << 7)			/* Extended Timing Mode		*/
+
+/* Clock conversion factor (read) */
+#define REG_CLKF		(9)
+#define CLKF_F37MHZ		0x00				/* 35.01 - 40 MHz		*/
+#define CLKF_F10MHZ		0x02				/* 10 MHz			*/
+#define CLKF_F12MHZ		0x03				/* 10.01 - 15 MHz		*/
+#define CLKF_F17MHZ		0x04				/* 15.01 - 20 MHz		*/
+#define CLKF_F22MHZ		0x05				/* 20.01 - 25 MHz		*/
+#define CLKF_F27MHZ		0x06				/* 25.01 - 30 MHz		*/
+#define CLKF_F32MHZ		0x07				/* 30.01 - 35 MHz		*/
+
+/* Chip test register (write) */
+#define REG_FTM			(10)
+#define TEST_FTM		0x01				/* Force target mode		*/
+#define TEST_FIM		0x02				/* Force initiator mode		*/
+#define TEST_FHI		0x04				/* Force high impedance mode	*/
+
+/* Configuration register 2 (read/write) */
+#define REG_CNTL2		(11)
+#define CNTL2_PGDP		(1 << 0)			/* Pass Th/Generate Data Parity	*/
+#define CNTL2_PGRP		(1 << 1)			/* Pass Th/Generate Reg Parity	*/
+#define CNTL2_ACDPE		(1 << 2)			/* Abort on Cmd/Data Parity Err	*/
+#define CNTL2_S2FE		(1 << 3)			/* SCSI2 Features Enable	*/
+#define CNTL2_TSDR		(1 << 4)			/* Tristate DREQ		*/
+#define CNTL2_SBO		(1 << 5)			/* Select Byte Order		*/
+#define CNTL2_ENF		(1 << 6)			/* Enable features		*/
+#define CNTL2_DAE		(1 << 7)			/* Data Alignment Enable	*/
+
+/* Configuration register 3 (read/write) */
+#define REG_CNTL3		(12)
+#define CNTL3_BS8		(1 << 0)			/* Burst size 8			*/
+#define CNTL3_MDM		(1 << 1)			/* Modify DMA mode		*/
+#define CNTL3_LBTM		(1 << 2)			/* Last Byte Transfer mode	*/
+#define CNTL3_FASTCLK		(1 << 3)			/* Fast SCSI clocking		*/
+#define CNTL3_FASTSCSI		(1 << 4)			/* Fast SCSI			*/
+#define CNTL3_G2CB		(1 << 5)			/* Group2 SCSI support		*/
+#define CNTL3_QTAG		(1 << 6)			/* Enable 3 byte msgs		*/
+#define CNTL3_ADIDCHK		(1 << 7)			/* Additional ID check		*/
+
+/* High transfer count (read/write) */
+#define REG_CTCH		(14)
+#define REG_STCH		(14)
+
+/* ID register (read only) */
+#define REG_ID			(14)
+
+/* Data alignment */
+#define REG_DAL			(15)
+
+typedef enum {
+	PHASE_IDLE,					/* we're not planning on doing anything	*/
+	PHASE_SELECTION,				/* selecting a device			*/
+	PHASE_SELSTEPS,					/* selection with command steps		*/
+	PHASE_COMMAND,					/* command sent				*/
+	PHASE_MESSAGESENT,				/* selected, and we're sending cmd	*/
+	PHASE_DATAOUT,					/* data out to device			*/
+	PHASE_DATAIN,					/* data in from device			*/
+	PHASE_MSGIN,					/* message in from device		*/
+	PHASE_MSGIN_DISCONNECT,				/* disconnecting from bus		*/
+	PHASE_MSGOUT,					/* after message out phase		*/
+	PHASE_MSGOUT_EXPECT,				/* expecting message out		*/
+	PHASE_STATUS,					/* status from device			*/
+	PHASE_DONE					/* Command complete			*/
+} phase_t;
+
+typedef enum {
+	DMA_OUT,					/* DMA from memory to chip		*/
+	DMA_IN						/* DMA from chip to memory		*/
+} fasdmadir_t;
+
+typedef enum {
+	fasdma_none,					/* No dma				*/
+	fasdma_pio,					/* PIO mode				*/
+	fasdma_pseudo,					/* Pseudo DMA				*/
+	fasdma_real_block,				/* Real DMA, on block by block basis	*/
+	fasdma_real_all					/* Real DMA, on request by request	*/
+} fasdmatype_t;
+
+typedef enum {
+	neg_wait,					/* Negociate with device		*/
+	neg_inprogress,					/* Negociation sent			*/
+	neg_complete,					/* Negociation complete			*/
+	neg_targcomplete,				/* Target completed negociation		*/
+	neg_invalid					/* Negociation not supported		*/
+} neg_t;
+
+#define MAGIC	0x441296bdUL
+#define NR_MSGS	8
+
+#define FASCAP_DMA		(1 << 0)
+#define FASCAP_PSEUDODMA	(1 << 1)
+
+typedef struct {
+	unsigned long		magic_start;
+	spinlock_t		host_lock;
+	struct Scsi_Host	*host;			/* host					*/
+	Scsi_Cmnd		*SCpnt;			/* currently processing command		*/
+	Scsi_Cmnd		*origSCpnt;		/* original connecting command		*/
+	Scsi_Cmnd		*reqSCpnt;		/* request sense command		*/
+	Scsi_Cmnd		*rstSCpnt;		/* reset command			*/
+	Scsi_Cmnd		*pending_SCpnt[8];	/* per-device pending commands		*/
+	int			next_pending;		/* next pending device			*/
+
+	/*
+	 * Error recovery
+	 */
+	wait_queue_head_t	eh_wait;
+	struct timer_list	eh_timer;
+	unsigned int		rst_dev_status;
+	unsigned int		rst_bus_status;
+
+	/* driver information */
+	struct {
+		phase_t		phase;			/* current phase			*/
+		void		*io_base;		/* iomem base of FAS216			*/
+		unsigned int	io_port;		/* base address of FAS216		*/
+		unsigned int	io_shift;		/* shift to adjust reg offsets by	*/
+		unsigned char	cfg[4];			/* configuration registers		*/
+		const char	*type;			/* chip type				*/
+		unsigned int	irq;			/* interrupt				*/
+
+		Scsi_Pointer	SCp;			/* current commands data pointer	*/
+
+		MsgQueue_t	msgs;			/* message queue for connected device	*/
+
+		unsigned int	async_stp;		/* Async transfer STP value		*/
+		unsigned char	msgin_fifo;		/* bytes in fifo at time of message in	*/
+		unsigned char	message[256];		/* last message received from device	*/
+
+		unsigned char	disconnectable:1;	/* this command can be disconnected	*/
+		unsigned char	aborting:1;		/* aborting command			*/
+	} scsi;
+
+	/* statistics information */
+	struct {
+		unsigned int	queues;
+		unsigned int	removes;
+		unsigned int	fins;
+		unsigned int	reads;
+		unsigned int	writes;
+		unsigned int	miscs;
+		unsigned int	disconnects;
+		unsigned int	aborts;
+		unsigned int	bus_resets;
+		unsigned int	host_resets;
+	} stats;
+
+	/* configuration information */
+	struct {
+		unsigned char	clockrate;		/* clock rate of FAS device (MHz)	*/
+		unsigned char	select_timeout;		/* timeout (R5)				*/
+		unsigned char	sync_max_depth;		/* Synchronous xfer max fifo depth	*/
+		unsigned char	wide_max_size;		/* Maximum wide transfer size		*/
+		unsigned char	cntl3;			/* Control Reg 3			*/
+		unsigned int	asyncperiod;		/* Async transfer period (ns)		*/
+		unsigned int	capabilities;		/* driver capabilities			*/
+		unsigned int	disconnect_ok:1;	/* Disconnects allowed?			*/
+	} ifcfg;
+
+	/* queue handling */
+	struct {
+	    	Queue_t		issue;			/* issue queue				*/
+    		Queue_t		disconnected;		/* disconnected command queue		*/
+	} queues;
+
+	/* per-device info */
+	struct fas216_device {
+		unsigned char	disconnect_ok:1;	/* device can disconnect		*/
+		unsigned char	parity_enabled:1;	/* parity checking enabled		*/
+		unsigned char	parity_check:1;		/* need to check parity checking	*/
+		unsigned char	period;			/* sync xfer period in (*4ns)		*/
+		unsigned char	stp;			/* synchronous transfer period		*/
+		unsigned char	sof;			/* synchronous offset register		*/
+		unsigned char	wide_xfer;		/* currently negociated wide transfer	*/
+		neg_t		sync_state;		/* synchronous transfer mode		*/
+		neg_t		wide_state;		/* wide transfer mode			*/
+	} device[8];
+	unsigned long	busyluns[64/sizeof(unsigned long)];/* array of bits indicating LUNs busy	*/
+
+	/* dma */
+	struct {
+		fasdmatype_t	transfer_type;		/* current type of DMA transfer		*/
+		fasdmatype_t	(*setup) (struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, fasdmatype_t min_dma);
+		void		(*pseudo)(struct Scsi_Host *host, Scsi_Pointer *SCp, fasdmadir_t direction, int transfer);
+		void		(*stop)  (struct Scsi_Host *host, Scsi_Pointer *SCp);
+	} dma;
+
+	/* miscellaneous */
+	int			internal_done;		/* flag to indicate request done */
+
+	unsigned long		magic_end;
+} FAS216_Info;
+
+/* Function: int fas216_init (struct Scsi_Host *instance)
+ * Purpose : initialise FAS/NCR/AMD SCSI structures.
+ * Params  : instance - a driver-specific filled-out structure
+ * Returns : 0 on success
+ */
+extern int fas216_init (struct Scsi_Host *instance);
+
+/* Function: int fas216_add (struct Scsi_Host *instance, struct device *dev)
+ * Purpose : initialise FAS/NCR/AMD SCSI ic.
+ * Params  : instance - a driver-specific filled-out structure
+ * Returns : 0 on success
+ */
+extern int fas216_add (struct Scsi_Host *instance, struct device *dev);
+
+/* Function: int fas216_queue_command (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+ * Purpose : queue a command for adapter to process.
+ * Params  : SCpnt - Command to queue
+ *	     done  - done function to call once command is complete
+ * Returns : 0 - success, else error
+ */
+extern int fas216_queue_command (Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+
+/* Function: int fas216_command (Scsi_Cmnd *SCpnt)
+ * Purpose : queue a command for adapter to process.
+ * Params  : SCpnt - Command to queue
+ * Returns : scsi result code
+ */
+extern int fas216_command (Scsi_Cmnd *);
+
+/* Function: irqreturn_t fas216_intr (FAS216_Info *info)
+ * Purpose : handle interrupts from the interface to progress a command
+ * Params  : info - interface to service
+ */
+extern irqreturn_t fas216_intr (FAS216_Info *info);
+
+extern void fas216_remove (struct Scsi_Host *instance);
+
+/* Function: void fas216_release (struct Scsi_Host *instance)
+ * Purpose : release all resources and put everything to bed for FAS/NCR/AMD SCSI ic.
+ * Params  : instance - a driver-specific filled-out structure
+ * Returns : 0 on success
+ */
+extern void fas216_release (struct Scsi_Host *instance);
+
+extern int fas216_print_host(FAS216_Info *info, char *buffer);
+extern int fas216_print_stats(FAS216_Info *info, char *buffer);
+extern int fas216_print_devices(FAS216_Info *info, char *buffer);
+
+/* Function: int fas216_eh_abort(Scsi_Cmnd *SCpnt)
+ * Purpose : abort this command
+ * Params  : SCpnt - command to abort
+ * Returns : FAILED if unable to abort
+ */
+extern int fas216_eh_abort(Scsi_Cmnd *SCpnt);
+
+/* Function: int fas216_eh_device_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the device associated with this command
+ * Params  : SCpnt - command specifing device to reset
+ * Returns : FAILED if unable to reset
+ */
+extern int fas216_eh_device_reset(Scsi_Cmnd *SCpnt);
+
+/* Function: int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the complete bus associated with this command
+ * Params  : SCpnt - command specifing bus to reset
+ * Returns : FAILED if unable to reset
+ */
+extern int fas216_eh_bus_reset(Scsi_Cmnd *SCpnt);
+
+/* Function: int fas216_eh_host_reset(Scsi_Cmnd *SCpnt)
+ * Purpose : Reset the host associated with this command
+ * Params  : SCpnt - command specifing host to reset
+ * Returns : FAILED if unable to reset
+ */
+extern int fas216_eh_host_reset(Scsi_Cmnd *SCpnt);
+
+#endif /* FAS216_H */
diff -Nru a/drivers/scsi/arm/msgqueue.c b/drivers/scsi/arm/msgqueue.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/msgqueue.c	Thu May 15 17:33:17 2003
@@ -0,0 +1,171 @@
+/*
+ *  linux/drivers/acorn/scsi/msgqueue.c
+ *
+ *  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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ *  message queue handling
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/stddef.h>
+#include <linux/init.h>
+
+#include "msgqueue.h"
+
+/*
+ * Function: struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
+ * Purpose : Allocate a message queue entry
+ * Params  : msgq - message queue to claim entry for
+ * Returns : message queue entry or NULL.
+ */
+static struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
+{
+	struct msgqueue_entry *mq;
+
+	if ((mq = msgq->free) != NULL)
+		msgq->free = mq->next;
+
+	return mq;
+}
+
+/*
+ * Function: void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq)
+ * Purpose : free a message queue entry
+ * Params  : msgq - message queue to free entry from
+ *	     mq   - message queue entry to free
+ */
+static void mqe_free(MsgQueue_t *msgq, struct msgqueue_entry *mq)
+{
+	if (mq) {
+		mq->next = msgq->free;
+		msgq->free = mq;
+	}
+}
+
+/*
+ * Function: void msgqueue_initialise(MsgQueue_t *msgq)
+ * Purpose : initialise a message queue
+ * Params  : msgq - queue to initialise
+ */
+void msgqueue_initialise(MsgQueue_t *msgq)
+{
+	int i;
+
+	msgq->qe = NULL;
+	msgq->free = &msgq->entries[0];
+
+	for (i = 0; i < NR_MESSAGES; i++)
+		msgq->entries[i].next = &msgq->entries[i + 1];
+
+	msgq->entries[NR_MESSAGES - 1].next = NULL;
+}
+
+
+/*
+ * Function: void msgqueue_free(MsgQueue_t *msgq)
+ * Purpose : free a queue
+ * Params  : msgq - queue to free
+ */
+void msgqueue_free(MsgQueue_t *msgq)
+{
+}
+
+/*
+ * Function: int msgqueue_msglength(MsgQueue_t *msgq)
+ * Purpose : calculate the total length of all messages on the message queue
+ * Params  : msgq - queue to examine
+ * Returns : number of bytes of messages in queue
+ */
+int msgqueue_msglength(MsgQueue_t *msgq)
+{
+	struct msgqueue_entry *mq = msgq->qe;
+	int length = 0;
+
+	for (mq = msgq->qe; mq; mq = mq->next)
+		length += mq->msg.length;
+
+	return length;
+}
+
+/*
+ * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+ * Purpose : return a message
+ * Params  : msgq   - queue to obtain message from
+ *	   : msgno  - message number
+ * Returns : pointer to message string, or NULL
+ */
+struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+{
+	struct msgqueue_entry *mq;
+
+	for (mq = msgq->qe; mq && msgno; mq = mq->next, msgno--);
+
+	return mq ? &mq->msg : NULL;
+}
+
+/*
+ * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
+ * Purpose : add a message onto a message queue
+ * Params  : msgq   - queue to add message on
+ *	     length - length of message
+ *	     ...    - message bytes
+ * Returns : != 0 if successful
+ */
+int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
+{
+	struct msgqueue_entry *mq = mqe_alloc(msgq);
+	va_list ap;
+
+	if (mq) {
+		struct msgqueue_entry **mqp;
+		int i;
+
+		va_start(ap, length);
+		for (i = 0; i < length; i++)
+			mq->msg.msg[i] = va_arg(ap, unsigned int);
+		va_end(ap);
+
+		mq->msg.length = length;
+		mq->msg.fifo = 0;
+		mq->next = NULL;
+
+		mqp = &msgq->qe;
+		while (*mqp)
+			mqp = &(*mqp)->next;
+
+		*mqp = mq;
+	}
+
+	return mq != NULL;
+}
+
+/*
+ * Function: void msgqueue_flush(MsgQueue_t *msgq)
+ * Purpose : flush all messages from message queue
+ * Params  : msgq - queue to flush
+ */
+void msgqueue_flush(MsgQueue_t *msgq)
+{
+	struct msgqueue_entry *mq, *mqnext;
+
+	for (mq = msgq->qe; mq; mq = mqnext) {
+		mqnext = mq->next;
+		mqe_free(msgq, mq);
+	}
+	msgq->qe = NULL;
+}
+
+EXPORT_SYMBOL(msgqueue_initialise);
+EXPORT_SYMBOL(msgqueue_free);
+EXPORT_SYMBOL(msgqueue_msglength);
+EXPORT_SYMBOL(msgqueue_getmsg);
+EXPORT_SYMBOL(msgqueue_addmsg);
+EXPORT_SYMBOL(msgqueue_flush);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SCSI message queue handling");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/arm/msgqueue.h b/drivers/scsi/arm/msgqueue.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/msgqueue.h	Thu May 15 17:33:17 2003
@@ -0,0 +1,82 @@
+/*
+ *  linux/drivers/acorn/scsi/msgqueue.h
+ *
+ *  Copyright (C) 1997 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.
+ *
+ *  message queue handling
+ */
+#ifndef MSGQUEUE_H
+#define MSGQUEUE_H
+
+struct message {
+    char msg[8];
+    int length;
+    int fifo;
+};
+
+struct msgqueue_entry {
+    struct message msg;
+    struct msgqueue_entry *next;
+};
+
+#define NR_MESSAGES 4
+
+typedef struct {
+    struct msgqueue_entry *qe;
+    struct msgqueue_entry *free;
+    struct msgqueue_entry entries[NR_MESSAGES];
+} MsgQueue_t;
+
+/*
+ * Function: void msgqueue_initialise(MsgQueue_t *msgq)
+ * Purpose : initialise a message queue
+ * Params  : msgq - queue to initialise
+ */
+extern void msgqueue_initialise(MsgQueue_t *msgq);
+
+/*
+ * Function: void msgqueue_free(MsgQueue_t *msgq)
+ * Purpose : free a queue
+ * Params  : msgq - queue to free
+ */
+extern void msgqueue_free(MsgQueue_t *msgq);
+
+/*
+ * Function: int msgqueue_msglength(MsgQueue_t *msgq)
+ * Purpose : calculate the total length of all messages on the message queue
+ * Params  : msgq - queue to examine
+ * Returns : number of bytes of messages in queue
+ */
+extern int msgqueue_msglength(MsgQueue_t *msgq);
+
+/*
+ * Function: struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno)
+ * Purpose : return a message & its length
+ * Params  : msgq   - queue to obtain message from
+ *         : msgno  - message number
+ * Returns : pointer to message string, or NULL
+ */
+extern struct message *msgqueue_getmsg(MsgQueue_t *msgq, int msgno);
+
+/*
+ * Function: int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...)
+ * Purpose : add a message onto a message queue
+ * Params  : msgq   - queue to add message on
+ *	     length - length of message
+ *	     ...    - message bytes
+ * Returns : != 0 if successful
+ */
+extern int msgqueue_addmsg(MsgQueue_t *msgq, int length, ...);
+
+/*
+ * Function: void msgqueue_flush(MsgQueue_t *msgq)
+ * Purpose : flush all messages from message queue
+ * Params  : msgq - queue to flush
+ */
+extern void msgqueue_flush(MsgQueue_t *msgq);
+
+#endif
diff -Nru a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/oak.c	Sat May 17 08:48:42 2003
@@ -0,0 +1,215 @@
+/*
+ * Oak Generic NCR5380 driver
+ *
+ * Copyright 1995-2002, Russell King
+ */
+
+#include <linux/module.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/blk.h>
+#include <linux/init.h>
+
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include "../scsi.h"
+#include "../hosts.h"
+
+#define AUTOSENSE
+/*#define PSEUDO_DMA*/
+
+#define OAKSCSI_PUBLIC_RELEASE 1
+
+#define NCR5380_read(reg)		oakscsi_read(_instance, reg)
+#define NCR5380_write(reg, value)	oakscsi_write(_instance, reg, value)
+#define NCR5380_intr			oakscsi_intr
+#define NCR5380_queue_command		oakscsi_queue_command
+#define NCR5380_proc_info		oakscsi_proc_info
+
+int NCR5380_proc_info(char *buffer, char **start, off_t offset,
+		      int length, int hostno, int inout);
+
+#define NCR5380_implementation_fields	int port, ctrl
+#define NCR5380_local_declare()		struct Scsi_Host *_instance
+#define NCR5380_setup(instance)		_instance = instance
+
+#define BOARD_NORMAL	0
+#define BOARD_NCR53C400	1
+
+#include "../NCR5380.h"
+
+#undef START_DMA_INITIATOR_RECEIVE_REG
+#define START_DMA_INITIATOR_RECEIVE_REG (7 + 128)
+
+const char * oakscsi_info (struct Scsi_Host *spnt)
+{
+	return "";
+}
+
+#define STAT(p)   inw(p + 144)
+extern void inswb(int from, void *to, int len);
+
+static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *addr,
+              int len)
+{
+  int iobase = instance->io_port;
+printk("writing %p len %d\n",addr, len);
+  if(!len) return -1;
+
+  while(1)
+  {
+    int status;
+    while(((status = STAT(iobase)) & 0x100)==0);
+  }
+}
+
+static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *addr,
+              int len)
+{
+  int iobase = instance->io_port;
+printk("reading %p len %d\n", addr, len);
+  while(len > 0)
+  {
+    int status, timeout;
+    unsigned long b;
+    
+    timeout = 0x01FFFFFF;
+    
+    while(((status = STAT(iobase)) & 0x100)==0)
+    {
+      timeout--;
+      if(status & 0x200 || !timeout)
+      {
+        printk("status = %08X\n",status);
+        return 1;
+      }
+    }
+    if(len >= 128)
+    {
+      inswb(iobase + 136, addr, 128);
+      addr += 128;
+      len -= 128;
+    }
+    else
+    {
+      b = (unsigned long) inw(iobase + 136);
+      *addr ++ = b;
+      len -= 1;
+      if(len)
+        *addr ++ = b>>8;
+      len -= 1;
+    }
+  }
+  return 0;
+}
+
+#define oakscsi_read(instance,reg)	(inb((instance)->io_port + (reg)))
+#define oakscsi_write(instance,reg,val)	(outb((val), (instance)->io_port + (reg)))
+
+#undef STAT
+
+#include "../NCR5380.c"
+
+static Scsi_Host_Template oakscsi_template = {
+	.module			= THIS_MODULE,
+	.proc_info		= oakscsi_proc_info,
+	.name			= "Oak 16-bit SCSI",
+	.info			= oakscsi_info,
+	.queuecommand		= oakscsi_queue_command,
+	.eh_abort_handler	= NCR5380_abort,
+	.eh_device_reset_handler= NCR5380_device_reset,
+	.eh_bus_reset_handler	= NCR5380_bus_reset,
+	.eh_host_reset_handler	= NCR5380_host_reset,
+	.can_queue		= 16,
+	.this_id		= 7,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 2,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.proc_name		= "oakscsi",
+};
+
+static int __devinit
+oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	int ret = -ENOMEM;
+
+	host = scsi_register(&oakscsi_template, sizeof(struct NCR5380_hostdata));
+	if (!host)
+		goto out;
+
+	host->io_port = ecard_address(ec, ECARD_MEMC, 0);
+	host->irq = IRQ_NONE;
+	host->n_io_port = 255;
+
+	ret = -EBUSY;
+	if (!request_region (host->io_port, host->n_io_port, "Oak SCSI"))
+		goto unreg;
+
+	NCR5380_init(host, 0);
+
+	printk("scsi%d: at port 0x%08lx irqs disabled",
+		host->host_no, host->io_port);
+	printk(" options CAN_QUEUE=%d  CMD_PER_LUN=%d release=%d",
+		host->can_queue, host->cmd_per_lun, OAKSCSI_PUBLIC_RELEASE);
+	printk("\nscsi%d:", host->host_no);
+	NCR5380_print_options(host);
+	printk("\n");
+
+	ret = scsi_add_host(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	release_region(host->io_port, host->n_io_port);
+ unreg:
+	scsi_unregister(host);
+ out:
+	return ret;
+}
+
+static void __devexit oakscsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+
+	ecard_set_drvdata(ec, NULL);
+	scsi_remove_host(host);
+
+	release_region(host->io_port, host->n_io_port);
+	scsi_unregister(host);
+}
+
+static const struct ecard_id oakscsi_cids[] = {
+	{ MANU_OAK, PROD_OAK_SCSI },
+	{ 0xffff, 0xffff }
+};
+
+static struct ecard_driver oakscsi_driver = {
+	.probe		= oakscsi_probe,
+	.remove		= __devexit_p(oakscsi_remove),
+	.id_table	= oakscsi_cids,
+	.drv = {
+		.name		= "oakscsi",
+	},
+};
+
+static int __init oakscsi_init(void)
+{
+	return ecard_register_driver(&oakscsi_driver);
+}
+
+static void __exit oakscsi_exit(void)
+{
+	ecard_remove_driver(&oakscsi_driver);
+}
+
+module_init(oakscsi_init);
+module_exit(oakscsi_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Oak SCSI driver");
+MODULE_LICENSE("GPL");
+
diff -Nru a/drivers/scsi/arm/powertec.c b/drivers/scsi/arm/powertec.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/powertec.c	Sat May 17 08:48:43 2003
@@ -0,0 +1,486 @@
+/*
+ *  linux/drivers/acorn/scsi/powertec.c
+ *
+ *  Copyright (C) 1997-2003 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/module.h>
+#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+
+#include <asm/dma.h>
+#include <asm/ecard.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/pgtable.h>
+
+#include "../scsi.h"
+#include "../hosts.h"
+#include "fas216.h"
+#include "scsi.h"
+
+#include <scsi/scsicam.h>
+
+#define POWERTEC_FAS216_OFFSET	0x3000
+#define POWERTEC_FAS216_SHIFT	6
+
+#define POWERTEC_INTR_STATUS	0x2000
+#define POWERTEC_INTR_BIT	0x80
+
+#define POWERTEC_RESET_CONTROL	0x1018
+#define POWERTEC_RESET_BIT	1
+
+#define POWERTEC_TERM_CONTROL	0x2018
+#define POWERTEC_TERM_ENABLE	1
+
+#define POWERTEC_INTR_CONTROL	0x101c
+#define POWERTEC_INTR_ENABLE	1
+#define POWERTEC_INTR_DISABLE	0
+
+#define VERSION	"1.10 (19/01/2003 2.5.59)"
+
+/*
+ * Use term=0,1,0,0,0 to turn terminators on/off.
+ * One entry per slot.
+ */
+static int term[MAX_ECARDS] = { 1, 1, 1, 1, 1, 1, 1, 1 };
+
+#define NR_SG	256
+
+struct powertec_info {
+	FAS216_Info		info;
+	struct expansion_card	*ec;
+	void			*term_port;
+	unsigned int		term_ctl;
+	struct scatterlist	sg[NR_SG];
+};
+
+/* Prototype: void powertecscsi_irqenable(ec, irqnr)
+ * Purpose  : Enable interrupts on Powertec SCSI card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+powertecscsi_irqenable(struct expansion_card *ec, int irqnr)
+{
+	writeb(POWERTEC_INTR_ENABLE, ec->irq_data);
+}
+
+/* Prototype: void powertecscsi_irqdisable(ec, irqnr)
+ * Purpose  : Disable interrupts on Powertec SCSI card
+ * Params   : ec    - expansion card structure
+ *          : irqnr - interrupt number
+ */
+static void
+powertecscsi_irqdisable(struct expansion_card *ec, int irqnr)
+{
+	writeb(POWERTEC_INTR_DISABLE, ec->irq_data);
+}
+
+static const expansioncard_ops_t powertecscsi_ops = {
+	.irqenable	= powertecscsi_irqenable,
+	.irqdisable	= powertecscsi_irqdisable,
+};
+
+/* Prototype: void powertecscsi_terminator_ctl(host, on_off)
+ * Purpose  : Turn the Powertec SCSI terminators on or off
+ * Params   : host   - card to turn on/off
+ *          : on_off - !0 to turn on, 0 to turn off
+ */
+static void
+powertecscsi_terminator_ctl(struct Scsi_Host *host, int on_off)
+{
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+
+	info->term_ctl = on_off ? POWERTEC_TERM_ENABLE : 0;
+	writeb(info->term_ctl, info->term_port);
+}
+
+/* Prototype: void powertecscsi_intr(irq, *dev_id, *regs)
+ * Purpose  : handle interrupts from Powertec SCSI card
+ * Params   : irq    - interrupt number
+ *	      dev_id - user-defined (Scsi_Host structure)
+ *	      regs   - processor registers at interrupt
+ */
+static irqreturn_t
+powertecscsi_intr(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct powertec_info *info = dev_id;
+
+	return fas216_intr(&info->info);
+}
+
+/* Prototype: fasdmatype_t powertecscsi_dma_setup(host, SCpnt, direction, min_type)
+ * Purpose  : initialises DMA/PIO
+ * Params   : host      - host
+ *	      SCpnt     - command
+ *	      direction - DMA on to/off of card
+ *	      min_type  - minimum DMA support that we must have for this transfer
+ * Returns  : type of transfer to be performed
+ */
+static fasdmatype_t
+powertecscsi_dma_setup(struct Scsi_Host *host, Scsi_Pointer *SCp,
+		       fasdmadir_t direction, fasdmatype_t min_type)
+{
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+	struct device *dev = scsi_get_device(host);
+	int dmach = host->dma_channel;
+
+	if (info->info.ifcfg.capabilities & FASCAP_DMA &&
+	    min_type == fasdma_real_all) {
+		int bufs, map_dir, dma_dir;
+
+		bufs = copy_SCp_to_sg(&info->sg[0], SCp, NR_SG);
+
+		if (direction == DMA_OUT)
+			map_dir = DMA_TO_DEVICE,
+			dma_dir = DMA_MODE_WRITE;
+		else
+			map_dir = DMA_FROM_DEVICE,
+			dma_dir = DMA_MODE_READ;
+
+		dma_map_sg(dev, info->sg, bufs + 1, map_dir);
+
+		disable_dma(dmach);
+		set_dma_sg(dmach, info->sg, bufs + 1);
+		set_dma_mode(dmach, dma_dir);
+		enable_dma(dmach);
+		return fasdma_real_all;
+	}
+
+	/*
+	 * If we're not doing DMA,
+	 *  we'll do slow PIO
+	 */
+	return fasdma_pio;
+}
+
+/* Prototype: int powertecscsi_dma_stop(host, SCpnt)
+ * Purpose  : stops DMA/PIO
+ * Params   : host  - host
+ *	      SCpnt - command
+ */
+static void
+powertecscsi_dma_stop(struct Scsi_Host *host, Scsi_Pointer *SCp)
+{
+	if (host->dma_channel != NO_DMA)
+		disable_dma(host->dma_channel);
+}
+
+/* Prototype: const char *powertecscsi_info(struct Scsi_Host * host)
+ * Purpose  : returns a descriptive string about this interface,
+ * Params   : host - driver host structure to return info for.
+ * Returns  : pointer to a static buffer containing null terminated string.
+ */
+const char *powertecscsi_info(struct Scsi_Host *host)
+{
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+	static char string[150];
+
+	sprintf(string, "%s (%s) in slot %d v%s terminators o%s",
+		host->hostt->name, info->info.scsi.type, info->ec->slot_no,
+		VERSION, info->term_ctl ? "n" : "ff");
+
+	return string;
+}
+
+/* Prototype: int powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+ * Purpose  : Set a driver specific function
+ * Params   : host   - host to setup
+ *          : buffer - buffer containing string describing operation
+ *          : length - length of string
+ * Returns  : -EINVAL, or 0
+ */
+static int
+powertecscsi_set_proc_info(struct Scsi_Host *host, char *buffer, int length)
+{
+	int ret = length;
+
+	if (length >= 12 && strncmp(buffer, "POWERTECSCSI", 12) == 0) {
+		buffer += 12;
+		length -= 12;
+
+		if (length >= 5 && strncmp(buffer, "term=", 5) == 0) {
+			if (buffer[5] == '1')
+				powertecscsi_terminator_ctl(host, 1);
+			else if (buffer[5] == '0')
+				powertecscsi_terminator_ctl(host, 0);
+			else
+				ret = -EINVAL;
+		} else
+			ret = -EINVAL;
+	} else
+		ret = -EINVAL;
+
+	return ret;
+}
+
+/* Prototype: int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
+ *					int length, int host_no, int inout)
+ * Purpose  : Return information about the driver to a user process accessing
+ *	      the /proc filesystem.
+ * Params   : buffer  - a buffer to write information to
+ *	      start   - a pointer into this buffer set by this routine to the start
+ *		        of the required information.
+ *	      offset  - offset into information that we have read upto.
+ *	      length  - length of buffer
+ *	      host_no - host number to return information for
+ *	      inout   - 0 for reading, 1 for writing.
+ * Returns  : length of data written to buffer.
+ */
+int powertecscsi_proc_info(char *buffer, char **start, off_t offset,
+			    int length, int host_no, int inout)
+{
+	struct Scsi_Host *host;
+	struct powertec_info *info;
+	char *p = buffer;
+	int pos;
+
+	host = scsi_host_hn_get(host_no);
+	if (!host)
+		return 0;
+
+	if (inout == 1)
+		return powertecscsi_set_proc_info(host, buffer, length);
+
+	info = (struct powertec_info *)host->hostdata;
+
+	p += sprintf(p, "PowerTec SCSI driver v%s\n", VERSION);
+	p += fas216_print_host(&info->info, p);
+	p += sprintf(p, "Term    : o%s\n",
+			info->term_ctl ? "n" : "ff");
+
+	p += fas216_print_stats(&info->info, p);
+	p += fas216_print_devices(&info->info, p);
+
+	*start = buffer + offset;
+	pos = p - buffer - offset;
+	if (pos > length)
+		pos = length;
+
+	return pos;
+}
+
+static ssize_t powertecscsi_show_term(struct device *dev, char *buf)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct powertec_info *info = (struct powertec_info *)host->hostdata;
+
+	return sprintf(buf, "%d\n", info->term_ctl ? 1 : 0);
+}
+
+static ssize_t
+powertecscsi_store_term(struct device *dev, const char *buf, size_t len)
+{
+	struct expansion_card *ec = ECARD_DEV(dev);
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+
+	if (len > 1)
+		powertecscsi_terminator_ctl(host, buf[0] != '0');
+
+	return len;
+}
+
+static DEVICE_ATTR(bus_term, S_IRUGO | S_IWUSR,
+		   powertecscsi_show_term, powertecscsi_store_term);
+
+static Scsi_Host_Template powertecscsi_template = {
+	.module				= THIS_MODULE,
+	.proc_info			= powertecscsi_proc_info,
+	.name				= "PowerTec SCSI",
+	.info				= powertecscsi_info,
+	.command			= fas216_command,
+	.queuecommand			= fas216_queue_command,
+	.eh_host_reset_handler		= fas216_eh_host_reset,
+	.eh_bus_reset_handler		= fas216_eh_bus_reset,
+	.eh_device_reset_handler	= fas216_eh_device_reset,
+	.eh_abort_handler		= fas216_eh_abort,
+
+	.can_queue			= 8,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 2,
+	.use_clustering			= ENABLE_CLUSTERING,
+	.proc_name			= "powertec",
+};
+
+static int __devinit
+powertecscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
+{
+	struct Scsi_Host *host;
+	struct powertec_info *info;
+	unsigned long resbase, reslen;
+	unsigned char *base;
+	int ret;
+
+	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
+
+	if (!request_mem_region(resbase, reslen, "powertecscsi")) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	base = ioremap(resbase, reslen);
+	if (!base) {
+		ret = -ENOMEM;
+		goto out_region;
+	}
+
+	host = scsi_register(&powertecscsi_template,
+			     sizeof (struct powertec_info));
+	if (!host) {
+		ret = -ENOMEM;
+		goto out_unmap;
+	}
+
+	host->base	  = (unsigned long)base;
+	host->irq	  = ec->irq;
+	host->dma_channel = ec->dma;
+
+	ec->irqaddr	= base + POWERTEC_INTR_STATUS;
+	ec->irqmask	= POWERTEC_INTR_BIT;
+	ec->irq_data	= base + POWERTEC_INTR_CONTROL;
+	ec->ops		= &powertecscsi_ops;
+
+	ecard_set_drvdata(ec, host);
+
+	info = (struct powertec_info *)host->hostdata;
+	info->term_port = base + POWERTEC_TERM_CONTROL;
+	powertecscsi_terminator_ctl(host, term[ec->slot_no]);
+
+	device_create_file(&ec->dev, &dev_attr_bus_term);
+
+	info->info.scsi.io_base		= base + POWERTEC_FAS216_OFFSET;
+	info->info.scsi.io_shift	= POWERTEC_FAS216_SHIFT;
+	info->info.scsi.irq		= host->irq;
+	info->info.ifcfg.clockrate	= 40; /* MHz */
+	info->info.ifcfg.select_timeout	= 255;
+	info->info.ifcfg.asyncperiod	= 200; /* ns */
+	info->info.ifcfg.sync_max_depth	= 7;
+	info->info.ifcfg.cntl3		= CNTL3_BS8 | CNTL3_FASTSCSI | CNTL3_FASTCLK;
+	info->info.ifcfg.disconnect_ok	= 1;
+	info->info.ifcfg.wide_max_size	= 0;
+	info->info.ifcfg.capabilities	= 0;
+	info->info.dma.setup		= powertecscsi_dma_setup;
+	info->info.dma.pseudo		= NULL;
+	info->info.dma.stop		= powertecscsi_dma_stop;
+
+	ret = fas216_init(host);
+	if (ret)
+		goto out_free;
+
+	ret = request_irq(host->irq, powertecscsi_intr,
+			  SA_INTERRUPT, "powertec", info);
+	if (ret) {
+		printk("scsi%d: IRQ%d not free: %d\n",
+		       host->host_no, host->irq, ret);
+		goto out_release;
+	}
+
+	if (host->dma_channel != NO_DMA) {
+		if (request_dma(host->dma_channel, "powertec")) {
+			printk("scsi%d: DMA%d not free, using PIO\n",
+			       host->host_no, host->dma_channel);
+			host->dma_channel = NO_DMA;
+		} else {
+			set_dma_speed(host->dma_channel, 180);
+			info->info.ifcfg.capabilities |= FASCAP_DMA;
+		}
+	}
+
+	ret = fas216_add(host, &ec->dev);
+	if (ret == 0)
+		goto out;
+
+	if (host->dma_channel != NO_DMA)
+		free_dma(host->dma_channel);
+	free_irq(host->irq, host);
+
+ out_release:
+	fas216_release(host);
+
+ out_free:
+	device_remove_file(&ec->dev, &dev_attr_bus_term);
+	scsi_unregister(host);
+
+ out_unmap:
+	iounmap(base);
+
+ out_region:
+	release_mem_region(resbase, reslen);
+
+ out:
+	return ret;
+}
+
+static void __devexit powertecscsi_remove(struct expansion_card *ec)
+{
+	struct Scsi_Host *host = ecard_get_drvdata(ec);
+	struct powertecscsi_info *info = (struct powertecscsi_info *)host->hostdata;
+	unsigned long resbase, reslen;
+
+	ecard_set_drvdata(ec, NULL);
+	fas216_remove(host);
+
+	device_remove_file(&ec->dev, &dev_attr_bus_term);
+
+	if (host->dma_channel != NO_DMA)
+		free_dma(host->dma_channel);
+	free_irq(host->irq, info);
+
+	iounmap((void *)host->base);
+
+	resbase = ecard_resource_start(ec, ECARD_RES_IOCFAST);
+	reslen = ecard_resource_len(ec, ECARD_RES_IOCFAST);
+
+	release_mem_region(resbase, reslen);
+
+	fas216_release(host);
+	scsi_unregister(host);
+}
+
+static const struct ecard_id powertecscsi_cids[] = {
+	{ MANU_ALSYSTEMS, PROD_ALSYS_SCSIATAPI },
+	{ 0xffff, 0xffff },
+};
+
+static struct ecard_driver powertecscsi_driver = {
+	.probe		= powertecscsi_probe,
+	.remove		= __devexit_p(powertecscsi_remove),
+	.id_table	= powertecscsi_cids,
+	.drv = {
+		.name		= "powertecscsi",
+	},
+};
+
+static int __init powertecscsi_init(void)
+{
+	return ecard_register_driver(&powertecscsi_driver);
+}
+
+static void __exit powertecscsi_exit(void)
+{
+	ecard_remove_driver(&powertecscsi_driver);
+}
+
+module_init(powertecscsi_init);
+module_exit(powertecscsi_exit);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("Powertec SCSI driver");
+MODULE_PARM(term, "1-8i");
+MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/arm/queue.c b/drivers/scsi/arm/queue.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/queue.c	Sat May 17 06:52:33 2003
@@ -0,0 +1,319 @@
+/*
+ *  linux/drivers/acorn/scsi/queue.c: queue handling primitives
+ *
+ *  Copyright (C) 1997-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.
+ *
+ *  Changelog:
+ *   15-Sep-1997 RMK	Created.
+ *   11-Oct-1997 RMK	Corrected problem with queue_remove_exclude
+ *			not updating internal linked list properly
+ *			(was causing commands to go missing).
+ *   30-Aug-2000 RMK	Use Linux list handling and spinlocks
+ */
+#include <linux/module.h>
+#include <linux/blk.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/init.h>
+
+#include "../scsi.h"
+
+#define DEBUG
+
+typedef struct queue_entry {
+	struct list_head   list;
+	Scsi_Cmnd	   *SCpnt;
+#ifdef DEBUG
+	unsigned long	   magic;
+#endif
+} QE_t;
+
+#ifdef DEBUG
+#define QUEUE_MAGIC_FREE	0xf7e1c9a3
+#define QUEUE_MAGIC_USED	0xf7e1cc33
+
+#define SET_MAGIC(q,m)	((q)->magic = (m))
+#define BAD_MAGIC(q,m)	((q)->magic != (m))
+#else
+#define SET_MAGIC(q,m)	do { } while (0)
+#define BAD_MAGIC(q,m)	(0)
+#endif
+
+#include "queue.h"
+
+#define NR_QE	32
+
+/*
+ * Function: void queue_initialise (Queue_t *queue)
+ * Purpose : initialise a queue
+ * Params  : queue - queue to initialise
+ */
+int queue_initialise (Queue_t *queue)
+{
+	unsigned int nqueues = NR_QE;
+	QE_t *q;
+
+	spin_lock_init(&queue->queue_lock);
+	INIT_LIST_HEAD(&queue->head);
+	INIT_LIST_HEAD(&queue->free);
+
+	/*
+	 * If life was easier, then SCpnt would have a
+	 * host-available list head, and we wouldn't
+	 * need to keep free lists or allocate this
+	 * memory.
+	 */
+	queue->alloc = q = kmalloc(sizeof(QE_t) * nqueues, GFP_KERNEL);
+	if (q) {
+		for (; nqueues; q++, nqueues--) {
+			SET_MAGIC(q, QUEUE_MAGIC_FREE);
+			q->SCpnt = NULL;
+			list_add(&q->list, &queue->free);
+		}
+	}
+
+	return queue->alloc != NULL;
+}
+
+/*
+ * Function: void queue_free (Queue_t *queue)
+ * Purpose : free a queue
+ * Params  : queue - queue to free
+ */
+void queue_free (Queue_t *queue)
+{
+	if (!list_empty(&queue->head))
+		printk(KERN_WARNING "freeing non-empty queue %p\n", queue);
+	if (queue->alloc)
+		kfree(queue->alloc);
+}
+     
+
+/*
+ * Function: int queue_add_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+ * Purpose : Add a new command onto a queue, adding REQUEST_SENSE to head.
+ * Params  : queue - destination queue
+ *	     SCpnt - command to add
+ *	     head  - add command to head of queue
+ * Returns : 0 on error, !0 on success
+ */
+int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+{
+	unsigned long flags;
+	struct list_head *l;
+	QE_t *q;
+	int ret = 0;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	if (list_empty(&queue->free))
+		goto empty;
+
+	l = queue->free.next;
+	list_del(l);
+
+	q = list_entry(l, QE_t, list);
+	if (BAD_MAGIC(q, QUEUE_MAGIC_FREE))
+		BUG();
+
+	SET_MAGIC(q, QUEUE_MAGIC_USED);
+	q->SCpnt = SCpnt;
+
+	if (head)
+		list_add(l, &queue->head);
+	else
+		list_add_tail(l, &queue->head);
+
+	ret = 1;
+empty:
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+	return ret;
+}
+
+static Scsi_Cmnd *__queue_remove(Queue_t *queue, struct list_head *ent)
+{
+	QE_t *q;
+
+	/*
+	 * Move the entry from the "used" list onto the "free" list
+	 */
+	list_del(ent);
+	q = list_entry(ent, QE_t, list);
+	if (BAD_MAGIC(q, QUEUE_MAGIC_USED))
+		BUG();
+
+	SET_MAGIC(q, QUEUE_MAGIC_FREE);
+	list_add(ent, &queue->free);
+
+	return q->SCpnt;
+}
+
+/*
+ * Function: Scsi_Cmnd *queue_remove_exclude (queue, exclude)
+ * Purpose : remove a SCSI command from a queue
+ * Params  : queue   - queue to remove command from
+ *	     exclude - bit array of target&lun which is busy
+ * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ */
+Scsi_Cmnd *queue_remove_exclude(Queue_t *queue, unsigned long *exclude)
+{
+	unsigned long flags;
+	struct list_head *l;
+	Scsi_Cmnd *SCpnt = NULL;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (!test_bit(q->SCpnt->device->id * 8 + q->SCpnt->device->lun, exclude)) {
+			SCpnt = __queue_remove(queue, l);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return SCpnt;
+}
+
+/*
+ * Function: Scsi_Cmnd *queue_remove (queue)
+ * Purpose : removes first SCSI command from a queue
+ * Params  : queue   - queue to remove command from
+ * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ */
+Scsi_Cmnd *queue_remove(Queue_t *queue)
+{
+	unsigned long flags;
+	Scsi_Cmnd *SCpnt = NULL;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	if (!list_empty(&queue->head))
+		SCpnt = __queue_remove(queue, queue->head.next);
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return SCpnt;
+}
+
+/*
+ * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Purpose : remove a SCSI command from the queue for a specified target/lun/tag
+ * Params  : queue  - queue to remove command from
+ *	     target - target that we want
+ *	     lun    - lun on device
+ *	     tag    - tag on device
+ * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
+ */
+Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag)
+{
+	unsigned long flags;
+	struct list_head *l;
+	Scsi_Cmnd *SCpnt = NULL;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun &&
+		    q->SCpnt->tag == tag) {
+			SCpnt = __queue_remove(queue, l);
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return SCpnt;
+}
+
+/*
+ * Function: queue_remove_all_target(queue, target)
+ * Purpose : remove all SCSI commands from the queue for a specified target
+ * Params  : queue  - queue to remove command from
+ *           target - target device id
+ * Returns : nothing
+ */
+void queue_remove_all_target(Queue_t *queue, int target)
+{
+	unsigned long flags;
+	struct list_head *l;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (q->SCpnt->device->id == target)
+			__queue_remove(queue, l);
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+}
+
+/*
+ * Function: int queue_probetgtlun (queue, target, lun)
+ * Purpose : check to see if we have a command in the queue for the specified
+ *	     target/lun.
+ * Params  : queue  - queue to look in
+ *	     target - target we want to probe
+ *	     lun    - lun on target
+ * Returns : 0 if not found, != 0 if found
+ */
+int queue_probetgtlun (Queue_t *queue, int target, int lun)
+{
+	unsigned long flags;
+	struct list_head *l;
+	int found = 0;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (q->SCpnt->device->id == target && q->SCpnt->device->lun == lun) {
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return found;
+}
+
+/*
+ * Function: int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
+ * Purpose : remove a specific command from the queues
+ * Params  : queue - queue to look in
+ *	     SCpnt - command to find
+ * Returns : 0 if not found
+ */
+int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt)
+{
+	unsigned long flags;
+	struct list_head *l;
+	int found = 0;
+
+	spin_lock_irqsave(&queue->queue_lock, flags);
+	list_for_each(l, &queue->head) {
+		QE_t *q = list_entry(l, QE_t, list);
+		if (q->SCpnt == SCpnt) {
+			__queue_remove(queue, l);
+			found = 1;
+			break;
+		}
+	}
+	spin_unlock_irqrestore(&queue->queue_lock, flags);
+
+	return found;
+}
+
+EXPORT_SYMBOL(queue_initialise);
+EXPORT_SYMBOL(queue_free);
+EXPORT_SYMBOL(__queue_add);
+EXPORT_SYMBOL(queue_remove);
+EXPORT_SYMBOL(queue_remove_exclude);
+EXPORT_SYMBOL(queue_remove_tgtluntag);
+EXPORT_SYMBOL(queue_remove_cmd);
+EXPORT_SYMBOL(queue_remove_all_target);
+EXPORT_SYMBOL(queue_probetgtlun);
+
+MODULE_AUTHOR("Russell King");
+MODULE_DESCRIPTION("SCSI command queueing");
+MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/arm/queue.h b/drivers/scsi/arm/queue.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/queue.h	Thu May 15 17:33:17 2003
@@ -0,0 +1,105 @@
+/*
+ *  linux/drivers/acorn/scsi/queue.h: queue handling
+ *
+ *  Copyright (C) 1997 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.
+ */
+#ifndef QUEUE_H
+#define QUEUE_H
+
+typedef struct {
+	struct list_head head;
+	struct list_head free;
+	spinlock_t queue_lock;
+	void *alloc;			/* start of allocated mem */
+} Queue_t;
+
+/*
+ * Function: void queue_initialise (Queue_t *queue)
+ * Purpose : initialise a queue
+ * Params  : queue - queue to initialise
+ */
+extern int queue_initialise (Queue_t *queue);
+
+/*
+ * Function: void queue_free (Queue_t *queue)
+ * Purpose : free a queue
+ * Params  : queue - queue to free
+ */
+extern void queue_free (Queue_t *queue);
+
+/*
+ * Function: Scsi_Cmnd *queue_remove (queue)
+ * Purpose : removes first SCSI command from a queue
+ * Params  : queue   - queue to remove command from
+ * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ */
+extern Scsi_Cmnd *queue_remove (Queue_t *queue);
+
+/*
+ * Function: Scsi_Cmnd *queue_remove_exclude_ref (queue, exclude)
+ * Purpose : remove a SCSI command from a queue
+ * Params  : queue   - queue to remove command from
+ *	     exclude - array of busy LUNs
+ * Returns : Scsi_Cmnd if successful (and a reference), or NULL if no command available
+ */
+extern Scsi_Cmnd *queue_remove_exclude (Queue_t *queue, unsigned long *exclude);
+
+#define queue_add_cmd_ordered(queue,SCpnt) \
+	__queue_add(queue,SCpnt,(SCpnt)->cmnd[0] == REQUEST_SENSE)
+#define queue_add_cmd_tail(queue,SCpnt) \
+	__queue_add(queue,SCpnt,0)
+/*
+ * Function: int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head)
+ * Purpose : Add a new command onto a queue
+ * Params  : queue - destination queue
+ *	     SCpnt - command to add
+ *	     head  - add command to head of queue
+ * Returns : 0 on error, !0 on success
+ */
+extern int __queue_add(Queue_t *queue, Scsi_Cmnd *SCpnt, int head);
+
+/*
+ * Function: Scsi_Cmnd *queue_remove_tgtluntag (queue, target, lun, tag)
+ * Purpose : remove a SCSI command from the queue for a specified target/lun/tag
+ * Params  : queue  - queue to remove command from
+ *	     target - target that we want
+ *	     lun    - lun on device
+ *	     tag    - tag on device
+ * Returns : Scsi_Cmnd if successful, or NULL if no command satisfies requirements
+ */
+extern Scsi_Cmnd *queue_remove_tgtluntag (Queue_t *queue, int target, int lun, int tag);
+
+/*
+ * Function: queue_remove_all_target(queue, target)
+ * Purpose : remove all SCSI commands from the queue for a specified target
+ * Params  : queue  - queue to remove command from
+ *           target - target device id
+ * Returns : nothing
+ */
+extern void queue_remove_all_target(Queue_t *queue, int target);
+
+/*
+ * Function: int queue_probetgtlun (queue, target, lun)
+ * Purpose : check to see if we have a command in the queue for the specified
+ *	     target/lun.
+ * Params  : queue  - queue to look in
+ *	     target - target we want to probe
+ *	     lun    - lun on target
+ * Returns : 0 if not found, != 0 if found
+ */
+extern int queue_probetgtlun (Queue_t *queue, int target, int lun);
+
+/*
+ * Function: int queue_remove_cmd (Queue_t *queue, Scsi_Cmnd *SCpnt)
+ * Purpose : remove a specific command from the queues
+ * Params  : queue - queue to look in
+ *	     SCpnt - command to find
+ * Returns : 0 if not found
+ */
+int queue_remove_cmd(Queue_t *queue, Scsi_Cmnd *SCpnt);
+
+#endif /* QUEUE_H */
diff -Nru a/drivers/scsi/arm/scsi.h b/drivers/scsi/arm/scsi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/arm/scsi.h	Thu May 15 17:33:18 2003
@@ -0,0 +1,115 @@
+/*
+ *  linux/drivers/acorn/scsi/scsi.h
+ *
+ *  Copyright (C) 2002 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.
+ *
+ *  Commonly used scsi driver functions.
+ */
+
+#define BELT_AND_BRACES
+
+/*
+ * The scatter-gather list handling.  This contains all
+ * the yucky stuff that needs to be fixed properly.
+ */
+static inline int copy_SCp_to_sg(struct scatterlist *sg, Scsi_Pointer *SCp, int max)
+{
+	int bufs = SCp->buffers_residual;
+
+	BUG_ON(bufs + 1 > max);
+
+	sg->page   = virt_to_page(SCp->ptr);
+	sg->offset = ((unsigned int)SCp->ptr) & ~PAGE_MASK;
+	sg->length = SCp->this_residual;
+
+	if (bufs)
+		memcpy(sg + 1, SCp->buffer + 1,
+		       sizeof(struct scatterlist) * bufs);
+	return bufs + 1;
+}
+
+static inline int next_SCp(Scsi_Pointer *SCp)
+{
+	int ret = SCp->buffers_residual;
+	if (ret) {
+		SCp->buffer++;
+		SCp->buffers_residual--;
+		SCp->ptr = (char *)
+			 (page_address(SCp->buffer->page) +
+			  SCp->buffer->offset);
+		SCp->this_residual = SCp->buffer->length;
+	} else {
+		SCp->ptr = NULL;
+		SCp->this_residual = 0;
+	}
+	return ret;
+}
+
+static inline unsigned char get_next_SCp_byte(Scsi_Pointer *SCp)
+{
+	char c = *SCp->ptr;
+
+	SCp->ptr += 1;
+	SCp->this_residual -= 1;
+
+	return c;
+}
+
+static inline void put_next_SCp_byte(Scsi_Pointer *SCp, unsigned char c)
+{
+	*SCp->ptr = c;
+	SCp->ptr += 1;
+	SCp->this_residual -= 1;
+}
+
+static inline void init_SCp(Scsi_Cmnd *SCpnt)
+{
+	memset(&SCpnt->SCp, 0, sizeof(struct scsi_pointer));
+
+	if (SCpnt->use_sg) {
+		unsigned long len = 0;
+		int buf;
+
+		SCpnt->SCp.buffer = (struct scatterlist *) SCpnt->buffer;
+		SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
+		SCpnt->SCp.ptr = (char *)
+			 (page_address(SCpnt->SCp.buffer->page) +
+			  SCpnt->SCp.buffer->offset);
+		SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length;
+
+#ifdef BELT_AND_BRACES
+		/*
+		 * Calculate correct buffer length.  Some commands
+		 * come in with the wrong request_bufflen.
+		 */
+		for (buf = 0; buf <= SCpnt->SCp.buffers_residual; buf++)
+			len += SCpnt->SCp.buffer[buf].length;
+
+		if (SCpnt->request_bufflen != len)
+			printk(KERN_WARNING "scsi%d.%c: bad request buffer "
+			       "length %d, should be %ld\n", SCpnt->device->host->host_no,
+			       '0' + SCpnt->device->id, SCpnt->request_bufflen, len);
+		SCpnt->request_bufflen = len;
+#endif
+	} else {
+		SCpnt->SCp.ptr = (unsigned char *)SCpnt->request_buffer;
+		SCpnt->SCp.this_residual = SCpnt->request_bufflen;
+	}
+
+	/*
+	 * If the upper SCSI layers pass a buffer, but zero length,
+	 * we aren't interested in the buffer pointer.
+	 */
+	if (SCpnt->SCp.this_residual == 0 && SCpnt->SCp.ptr) {
+#if 0 //def BELT_AND_BRACES
+		printk(KERN_WARNING "scsi%d.%c: zero length buffer passed for "
+		       "command ", SCpnt->host->host_no, '0' + SCpnt->target);
+		print_command(SCpnt->cmnd);
+#endif
+		SCpnt->SCp.ptr = NULL;
+	}
+}
diff -Nru a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
--- a/drivers/scsi/atp870u.c	Sat Apr 26 07:28:18 2003
+++ b/drivers/scsi/atp870u.c	Sun May  4 02:56:43 2003
@@ -2748,5 +2748,19 @@
 
 MODULE_LICENSE("GPL");
 
-static Scsi_Host_Template driver_template = ATP870U;
+static Scsi_Host_Template driver_template = {
+	.proc_info		= atp870u_proc_info,
+	.detect			= atp870u_detect,
+	.release		= atp870u_release,
+	.info			= atp870u_info,
+	.command		= atp870u_command,
+	.queuecommand		= atp870u_queuecommand,
+	.eh_abort_handler	= atp870u_abort,
+	.bios_param		= atp870u_biosparam,
+	.can_queue		= qcnt,
+	.this_id		= 7,
+	.sg_tablesize		= ATP870U_SCATTER,
+	.cmd_per_lun		= ATP870U_CMDLUN,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/atp870u.h b/drivers/scsi/atp870u.h
--- a/drivers/scsi/atp870u.h	Tue Dec 10 12:28:32 2002
+++ b/drivers/scsi/atp870u.h	Sun May  4 02:56:43 2003
@@ -37,22 +37,4 @@
 
 extern int atp870u_proc_info(char *, char **, off_t, int, int, int);
 
-#define ATP870U {						\
-	.proc_info = atp870u_proc_info,				\
-	.detect = atp870u_detect, 				\
-	.release = atp870u_release,				\
-	.info = atp870u_info,					\
-	.command = atp870u_command,				\
-	.queuecommand = atp870u_queuecommand,			\
-	.eh_abort_handler = atp870u_abort, 			\
-	.bios_param = atp870u_biosparam,				\
-	.can_queue = qcnt,	 /* max simultaneous cmds      */\
-	.this_id = 7,	       /* scsi id of host adapter    */\
-	.sg_tablesize = ATP870U_SCATTER,	/* max scatter-gather cmds    */\
-	.cmd_per_lun = ATP870U_CMDLUN,	/* cmds per lun (linked cmds) */\
-	.present = 0,		/* number of 7xxx's present   */\
-	.unchecked_isa_dma = 0,	/* no memory DMA restrictions */\
-	.use_clustering = ENABLE_CLUSTERING,			\
-}
-
 #endif
diff -Nru a/drivers/scsi/cpqfcTS.h b/drivers/scsi/cpqfcTS.h
--- a/drivers/scsi/cpqfcTS.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/cpqfcTS.h	Sun May  4 02:56:43 2003
@@ -16,27 +16,4 @@
 		sector_t, int[]);
 extern int cpqfcTS_ioctl( Scsi_Device *ScsiDev, int Cmnd, void *arg);
 
-// note: since Tachyon TS supports an extended scatter/gather
-// linked list of infinite length (with linked Ext S/G pages,
-// limited only by available physical memory) we use SG_ALL.
-
-#define CPQFCTS {                                \
- .detect                 = cpqfcTS_detect,         \
- .release                = cpqfcTS_release,        \
- .info                   = cpqfcTS_info,           \
- .proc_info              = cpqfcTS_proc_info,      \
- .ioctl                  = cpqfcTS_ioctl,          \
- .queuecommand           = cpqfcTS_queuecommand,   \
- .eh_device_reset_handler   = cpqfcTS_eh_device_reset,   \
- .eh_abort_handler       = cpqfcTS_eh_abort,       \
- .bios_param             = cpqfcTS_biosparam,      \
- .can_queue              = CPQFCTS_REQ_QUEUE_LEN,  \
- .this_id                = -1,                     \
- .sg_tablesize           = SG_ALL,                 \
- .cmd_per_lun            = CPQFCTS_CMD_PER_LUN,    \
- .present                = 0,                      \
- .unchecked_isa_dma      = 0,                      \
- .use_clustering         = ENABLE_CLUSTERING,      \
-}
-
 #endif /* CPQFCTS_H */ 
diff -Nru a/drivers/scsi/cpqfcTSinit.c b/drivers/scsi/cpqfcTSinit.c
--- a/drivers/scsi/cpqfcTSinit.c	Sat Apr 26 07:28:19 2003
+++ b/drivers/scsi/cpqfcTSinit.c	Sun May  4 02:56:43 2003
@@ -677,11 +677,6 @@
         scsi_release_request(ScsiPassThruReq); // "de-allocate"
         ScsiPassThruReq = NULL;
 
-        // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-        //  (*SDpnt->scsi_request_fn)();
-
-        wake_up(&SDpnt->scpnt_wait);
-
 	// need to pass data back to user (space)?
 	if( (vendor_cmd->rw_flag == VENDOR_READ_OPCODE) &&
 	     vendor_cmd->len )
@@ -1656,10 +1651,6 @@
   scsi_put_command(SCpnt);
   SCpnt = NULL;
 
-  // if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
-  // 	(*SDpnt->scsi_request_fn)();
-
-  wake_up(&SDpnt->scpnt_wait);
   // printk("   LEAVING cpqfcTS_TargetDeviceReset() - return SUCCESS \n");
   return SUCCESS;
 }
@@ -2060,7 +2051,21 @@
 }
 
 
-static Scsi_Host_Template driver_template = CPQFCTS;
-
+static Scsi_Host_Template driver_template = {
+	.detect                 = cpqfcTS_detect,
+	.release                = cpqfcTS_release,
+	.info                   = cpqfcTS_info,
+	.proc_info              = cpqfcTS_proc_info,
+	.ioctl                  = cpqfcTS_ioctl,
+	.queuecommand           = cpqfcTS_queuecommand,
+	.eh_device_reset_handler   = cpqfcTS_eh_device_reset,
+	.eh_abort_handler       = cpqfcTS_eh_abort, 
+	.bios_param             = cpqfcTS_biosparam, 
+	.can_queue              = CPQFCTS_REQ_QUEUE_LEN,
+	.this_id                = -1, 
+	.sg_tablesize           = SG_ALL, 
+	.cmd_per_lun            = CPQFCTS_CMD_PER_LUN,
+	.use_clustering         = ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
 
diff -Nru a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h
--- a/drivers/scsi/dc390.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/dc390.h	Sun May  4 02:56:43 2003
@@ -50,45 +50,4 @@
 
 extern int DC390_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,30)
-#define DC390_T    {					\
-   .proc_name      = "tmscsim",                           \
-   .proc_info      = DC390_proc_info,			\
-   .name           = DC390_BANNER " V" DC390_VERSION,	\
-   .detect         = DC390_detect,			\
-   .release        = DC390_release,			\
-   .queuecommand   = DC390_queue_command,			\
-   .abort          = DC390_abort,				\
-   .reset          = DC390_reset,				\
-   .bios_param     = DC390_bios_param,			\
-   .can_queue      = 42,					\
-   .this_id        = 7,					\
-   .sg_tablesize   = SG_ALL,				\
-   .cmd_per_lun    = 16,					\
-   .unchecked_isa_dma = 0,				\
-   .use_clustering = DISABLE_CLUSTERING			\
-   }
-#else
-extern struct proc_dir_entry DC390_proc_scsi_tmscsim;
-#define DC390_T    {					\
-   .proc_dir       = &DC390_proc_scsi_tmscsim,		\
-   .proc_info      = DC390_proc_info,			\
-   .name           = DC390_BANNER " V" DC390_VERSION,	\
-   .detect         = DC390_detect,			\
-   .release        = DC390_release,			\
-   .queuecommand   = DC390_queue_command,			\
-   .abort          = DC390_abort,				\
-   .reset          = DC390_reset,				\
-   .bios_param     = DC390_bios_param,			\
-   .can_queue      = 42,					\
-   .this_id        = 7,					\
-   .sg_tablesize   = SG_ALL,				\
-   .cmd_per_lun    = 16,					\
-   NEW_EH						\
-   .unchecked_isa_dma = 0,				\
-   .use_clustering = DISABLE_CLUSTERING			\
-   }
-#endif
-#endif /* defined(HOSTS_C) || defined(MODULE) */
-
 #endif /* DC390_H */
diff -Nru a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
--- a/drivers/scsi/dc395x.c	Sat Apr 26 14:17:07 2003
+++ b/drivers/scsi/dc395x.c	Tue May  6 13:16:34 2003
@@ -51,6 +51,7 @@
 #include <linux/delay.h>
 #include <linux/ctype.h>
 #include <linux/blk.h>
+#include <asm/io.h>
 #include "scsi.h"
 #include "hosts.h"
 #include "dc395x.h"
diff -Nru a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
--- a/drivers/scsi/dmx3191d.c	Thu Apr 24 05:16:59 2003
+++ b/drivers/scsi/dmx3191d.c	Sun May  4 02:56:43 2003
@@ -121,6 +121,21 @@
 
 MODULE_LICENSE("GPL");
 
-static Scsi_Host_Template driver_template = DMX3191D;
+static Scsi_Host_Template driver_template = {
+	.proc_info		= dmx3191d_proc_info,
+	.name			= "Domex DMX3191D",
+	.detect			= dmx3191d_detect,
+	.release		= dmx3191d_release_resources,
+	.info			= dmx3191d_info,
+	.queuecommand		= dmx3191d_queue_command,
+	.eh_abort_handler	= dmx3191d_abort,
+	.eh_bus_reset_handler	= dmx3191d_bus_reset,
+	.eh_device_reset_handler = dmx3191d_device_reset,
+	.eh_host_reset_handler	= dmx3191d_host_reset,
+	.can_queue		= 32,
+        .this_id		= 7,
+        .sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 2,
+        .use_clustering		= DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
-
diff -Nru a/drivers/scsi/dmx3191d.h b/drivers/scsi/dmx3191d.h
--- a/drivers/scsi/dmx3191d.h	Tue Dec 10 12:28:34 2002
+++ b/drivers/scsi/dmx3191d.h	Sun May  4 02:56:43 2003
@@ -30,27 +30,6 @@
 static int dmx3191d_host_reset(Scsi_Cmnd *);
 static int dmx3191d_device_reset(Scsi_Cmnd *);
 
-
-#define DMX3191D {				\
-	.proc_info	= dmx3191d_proc_info,		\
-	.name		= "Domex DMX3191D",		\
-	.detect		= dmx3191d_detect,		\
-	.release	= dmx3191d_release_resources,	\
-	.info		= dmx3191d_info,			\
-	.queuecommand	= dmx3191d_queue_command,		\
-	.eh_abort_handler	= dmx3191d_abort,		\
-	.eh_bus_reset_handler	= dmx3191d_bus_reset, 	\
-	.eh_device_reset_handler = dmx3191d_device_reset, 	\
-	.eh_host_reset_handler	= dmx3191d_host_reset, 	\
-	.bios_param	= NULL,				\
-	.can_queue	= 32,				\
-        .this_id	= 7,				\
-        .sg_tablesize	= SG_ALL,				\
-	.cmd_per_lun	= 2,				\
-        .use_clustering	= DISABLE_CLUSTERING		\
-}
-
-
 #define NCR5380_read(reg)			inb(port + reg)
 #define NCR5380_write(reg, value)		outb(value, port + reg)
 
diff -Nru a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
--- a/drivers/scsi/dpt_i2o.c	Wed Feb 26 19:03:02 2003
+++ b/drivers/scsi/dpt_i2o.c	Sun May  4 02:56:43 2003
@@ -2495,8 +2495,6 @@
 				pDev->pScsi_dev->online = FALSE;
 				if (pDev->pScsi_dev->access_count) {
 					// A drive that was mounted is no longer there... bad!
-					SCSI_LOG_ERROR_RECOVERY(1, printk ("%s:Rescan: Previously "
-								 "mounted drive not found!\n",pHba->name));
 					printk(KERN_WARNING"%s:Mounted drive taken offline\n",pHba->name);
 				}
 			}
@@ -3306,6 +3304,24 @@
 
 #endif
 
-static Scsi_Host_Template driver_template = DPT_I2O;
+static Scsi_Host_Template driver_template = {
+	.name			= "dpt_i2o",
+	.proc_name		= "dpt_i2o",
+	.proc_info		= adpt_proc_info,
+	.detect			= adpt_detect,	
+	.release		= adpt_release,
+	.info			= adpt_info,
+	.queuecommand		= adpt_queue,
+	.eh_abort_handler	= adpt_abort,
+	.eh_device_reset_handler = adpt_device_reset,
+	.eh_bus_reset_handler	= adpt_bus_reset,
+	.eh_host_reset_handler	= adpt_reset,
+	.bios_param		= adpt_bios_param,
+	.slave_configure	= adpt_slave_configure,
+	.can_queue		= MAX_TO_IOP_MESSAGES,
+	.this_id		= 7,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
 MODULE_LICENSE("GPL");
diff -Nru a/drivers/scsi/dpti.h b/drivers/scsi/dpti.h
--- a/drivers/scsi/dpti.h	Tue Dec 10 12:28:32 2002
+++ b/drivers/scsi/dpti.h	Sun May  4 02:56:43 2003
@@ -60,49 +60,6 @@
 
 #define DPT_DRIVER_NAME	"Adaptec I2O RAID"
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,00)
-#define DPT_I2O { \
-	.proc_info = adpt_proc_info,					\
-	.detect = adpt_detect,						\
-	.release = adpt_release,						\
-	.info = adpt_info,						\
-	.queuecommand = adpt_queue,					\
-	.eh_abort_handler = adpt_abort,					\
-	.eh_device_reset_handler = adpt_device_reset,			\
-	.eh_bus_reset_handler = adpt_bus_reset,				\
-	.eh_host_reset_handler = adpt_reset,				\
-	.bios_param = adpt_bios_param,					\
-	.can_queue = MAX_TO_IOP_MESSAGES ,/* max simultaneous cmds      */\
-	.this_id = 7,			/* scsi id of host adapter    */\
-	.sg_tablesize = 0,		/* max scatter-gather cmds    */\
-	.cmd_per_lun = 256,		/* cmds per lun (linked cmds) */\
-	.use_clustering = ENABLE_CLUSTERING,				\
-	.use_new_eh_code = 1						\
-}
-
-#else				/* KERNEL_VERSION > 2.2.16 */
-
-#define DPT_I2O { \
-	.proc_info = adpt_proc_info,					\
-	.detect = adpt_detect,						\
-	.release = adpt_release,						\
-	.info = adpt_info,						\
-	.queuecommand = adpt_queue,					\
-	.eh_abort_handler = adpt_abort,					\
-	.eh_device_reset_handler = adpt_device_reset,			\
-	.eh_bus_reset_handler = adpt_bus_reset,				\
-	.eh_host_reset_handler = adpt_reset,				\
-	.bios_param = adpt_bios_param,					\
-	.slave_configure = adpt_slave_configure,				\
-	.can_queue = MAX_TO_IOP_MESSAGES,	/* max simultaneous cmds      */\
-	.this_id = 7,			/* scsi id of host adapter    */\
-	.sg_tablesize = 0,		/* max scatter-gather cmds    */\
-	.cmd_per_lun = 1,			/* cmds per lun (linked cmds) */\
-	.use_clustering = ENABLE_CLUSTERING,				\
-	.proc_name = "dpt_i2o"	/* this is the name of our proc node*/	\
-}
-#endif
-
 #ifndef HOSTS_C
 
 #include "dpt/sys_info.h"
diff -Nru a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
--- a/drivers/scsi/dtc.c	Thu Apr 24 05:16:59 2003
+++ b/drivers/scsi/dtc.c	Sun May  4 02:56:43 2003
@@ -447,6 +447,19 @@
 
 #include "NCR5380.c"
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = DTC3x80;
+static Scsi_Host_Template driver_template = {
+	.name				= "DTC 3180/3280 ",
+	.detect				= dtc_detect,
+	.queuecommand			= dtc_queue_command,
+	.eh_abort_handler		= dtc_abort,
+	.eh_bus_reset_handler		= dtc_bus_reset,
+	.eh_device_reset_handler	= dtc_device_reset,
+	.eh_host_reset_handler          = dtc_host_reset,
+	.bios_param     		= dtc_biosparam,
+	.can_queue      		= CAN_QUEUE,
+	.this_id        		= 7,
+	.sg_tablesize   		= SG_ALL,
+	.cmd_per_lun    		= CMD_PER_LUN,
+	.use_clustering 		= DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
--- a/drivers/scsi/dtc.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/dtc.h	Sun May  4 02:56:43 2003
@@ -47,27 +47,6 @@
 #define CAN_QUEUE 32 
 #endif
 
-/* 
- * I hadn't thought of this with the earlier drivers - but to prevent
- * macro definition conflicts, we shouldn't define all of the internal
- * macros when this is being used solely for the host stub.
- */
-
-#define DTC3x80 {						\
-	.name				= "DTC 3180/3280 ",	\
-	.detect				= dtc_detect,		\
-	.queuecommand			= dtc_queue_command,	\
-	.eh_abort_handler		= dtc_abort,		\
-	.eh_bus_reset_handler		= dtc_bus_reset,		\
-	.eh_device_reset_handler	= dtc_device_reset,	\
-	.eh_host_reset_handler          = dtc_host_reset,		\
-	.bios_param     = dtc_biosparam,				\
-	.can_queue      = CAN_QUEUE,				\
-	.this_id        = 7,					\
-	.sg_tablesize   = SG_ALL,					\
-	.cmd_per_lun    = CMD_PER_LUN ,				\
-	.use_clustering = DISABLE_CLUSTERING}
-
 #define NCR5380_implementation_fields \
     unsigned int base
 
diff -Nru a/drivers/scsi/eata.c b/drivers/scsi/eata.c
--- a/drivers/scsi/eata.c	Sat Apr 26 07:28:19 2003
+++ b/drivers/scsi/eata.c	Sun May  4 02:56:43 2003
@@ -2375,8 +2375,19 @@
    return FALSE;
 }
 
-static Scsi_Host_Template driver_template = EATA;
-
+static Scsi_Host_Template driver_template = {
+	.name              	= "EATA/DMA 2.0x rev. " EATA_VERSION " ",
+	.detect                  = eata2x_detect,
+	.release                 = eata2x_release,
+	.queuecommand            = eata2x_queuecommand,
+	.eh_abort_handler        = eata2x_eh_abort,
+	.eh_host_reset_handler   = eata2x_eh_host_reset,
+	.bios_param              = eata2x_bios_param,
+	.slave_configure	 = eata2x_slave_configure,
+	.this_id                 = 7,
+	.unchecked_isa_dma       = 1,
+	.use_clustering          = ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
 
 #ifndef MODULE
diff -Nru a/drivers/scsi/eata.h b/drivers/scsi/eata.h
--- a/drivers/scsi/eata.h	Tue Nov 12 04:39:06 2002
+++ b/drivers/scsi/eata.h	Sun May  4 02:56:43 2003
@@ -13,18 +13,3 @@
 
 #define EATA_VERSION "8.03.00"
 
-#define EATA {                                                               \
-                .name              = "EATA/DMA 2.0x rev. " EATA_VERSION " ",   \
-                .detect                  = eata2x_detect,                      \
-                .release                 = eata2x_release,                     \
-                .queuecommand            = eata2x_queuecommand,                \
-                .eh_abort_handler        = eata2x_eh_abort,                    \
-                .eh_device_reset_handler = NULL,                               \
-                .eh_bus_reset_handler    = NULL,                               \
-                .eh_host_reset_handler   = eata2x_eh_host_reset,               \
-                .bios_param              = eata2x_bios_param,                  \
-		.slave_configure	 = eata2x_slave_configure,	     \
-                .this_id                 = 7,                                  \
-                .unchecked_isa_dma       = 1,                                  \
-                .use_clustering          = ENABLE_CLUSTERING                   \
-             }
diff -Nru a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
--- a/drivers/scsi/eata_pio.c	Sat Apr 26 07:28:20 2003
+++ b/drivers/scsi/eata_pio.c	Thu May  8 11:24:14 2003
@@ -106,7 +106,6 @@
 			      int length, int hostno, int rw)
 {
     struct Scsi_Host *shost;
-    struct scsi_device *sdev;
     static u8 buff[512];
     int size, len = 0;
     off_t begin = 0, pos = 0;
diff -Nru a/drivers/scsi/esp.c b/drivers/scsi/esp.c
--- a/drivers/scsi/esp.c	Sun Apr 20 23:54:46 2003
+++ b/drivers/scsi/esp.c	Sun May 18 03:04:59 2003
@@ -1215,11 +1215,33 @@
 
 #endif /* !CONFIG_SUN4 */
 
+/*
+ */
+static int esp_release(struct Scsi_Host *host)
+{
+	struct esp *esp = (struct esp *) host->hostdata;
+
+	ESP_INTSOFF(esp->dregs);
+#if 0
+	esp_reset_dma(esp);
+	esp_reset_esp(esp);
+#endif
+
+	free_irq(esp->ehost->irq, esp);
+	sbus_free_consistent(esp->sdev, 16,
+			     (void *) esp->esp_command, esp->esp_command_dvma);
+	sbus_iounmap(esp->eregs, ESP_REG_SIZE);
+	esp->dma->allocated = 0;
+	esp_chain_del(esp);
+
+        return 0;
+}
+
 /* The info function will return whatever useful
  * information the developer sees fit.  If not provided, then
  * the name field will be used instead.
  */
-const char *esp_info(struct Scsi_Host *host)
+static const char *esp_info(struct Scsi_Host *host)
 {
 	struct esp *esp;
 
@@ -4370,6 +4392,7 @@
 	.detect			= esp_detect,
 	.slave_alloc		= esp_slave_alloc,
 	.slave_destroy		= esp_slave_destroy,
+	.release		= esp_release,
 	.info			= esp_info,
 	.command		= esp_command,
 	.queuecommand		= esp_queue,
@@ -4380,10 +4403,7 @@
 	.sg_tablesize		= SG_ALL,
 	.cmd_per_lun		= 1,
 	.use_clustering		= ENABLE_CLUSTERING,
-/* Sparc32's iommu code cannot handle highmem pages yet. */
-#ifdef CONFIG_SPARC64
 	.highmem_io		= 1,
-#endif
 };
 
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/fcal.c b/drivers/scsi/fcal.c
--- a/drivers/scsi/fcal.c	Tue Feb  4 03:55:10 2003
+++ b/drivers/scsi/fcal.c	Sun May  4 02:56:43 2003
@@ -302,7 +302,22 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = FCAL;
-
+static Scsi_Host_Template driver_template = {
+	.name			= "Fibre Channel Arbitrated Loop",
+	.detect			= fcal_detect,
+	.release		= fcal_release,	
+	.proc_info		= fcal_proc_info,
+	.queuecommand		= fcp_scsi_queuecommand,
+	.slave_configure	= fcal_slave_configure,
+	.can_queue		= FCAL_CAN_QUEUE,
+	.this_id		= -1,
+	.sg_tablesize		= 1,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.eh_abort_handler	= fcp_scsi_abort,
+	.eh_device_reset_handler = fcp_scsi_dev_reset,
+	.eh_bus_reset_handler	= fcp_scsi_bus_reset,
+	.eh_host_reset_handler	= fcp_scsi_host_reset,
+};
 #include "scsi_module.c"
 
diff -Nru a/drivers/scsi/fcal.h b/drivers/scsi/fcal.h
--- a/drivers/scsi/fcal.h	Tue Dec 10 12:28:32 2002
+++ b/drivers/scsi/fcal.h	Sun May  4 02:56:43 2003
@@ -25,22 +25,4 @@
 int fcal_proc_info (char *, char **, off_t, int, int, int);
 int fcal_slave_configure(Scsi_Device *);
 
-#define FCAL {							\
-	.name			= "Fibre Channel Arbitrated Loop",\
-	.detect			= fcal_detect,			\
-	.release		= fcal_release,			\
-	.proc_info		= fcal_proc_info,			\
-	.queuecommand		= fcp_scsi_queuecommand,		\
-	.slave_configure	= fcal_slave_configure,		\
-	.can_queue		= FCAL_CAN_QUEUE,			\
-	.this_id		= -1,				\
-	.sg_tablesize		= 1,				\
-	.cmd_per_lun		= 1,				\
-	.use_clustering		= ENABLE_CLUSTERING,		\
-	.eh_abort_handler	= fcp_scsi_abort,			\
-	.eh_device_reset_handler = fcp_scsi_dev_reset,		\
-	.eh_bus_reset_handler	= fcp_scsi_bus_reset,		\
-	.eh_host_reset_handler	= fcp_scsi_host_reset,		\
-}	
-
 #endif /* !(_FCAL_H) */
diff -Nru a/drivers/scsi/fd_mcs.c b/drivers/scsi/fd_mcs.c
--- a/drivers/scsi/fd_mcs.c	Sat Apr 26 07:28:20 2003
+++ b/drivers/scsi/fd_mcs.c	Thu May  8 11:24:14 2003
@@ -740,7 +740,7 @@
 #if DEBUG_RACE
 		in_interrupt_flag = 0;
 #endif
-		return;
+		return IRQ_HANDLED;
 	} else if (current_SC->SCp.phase & in_selection) {
 		status = inb(SCSI_Status_port);
 		if (!(status & 0x01)) {
@@ -1436,7 +1436,23 @@
 	return 0;
 }
 
-/* Eventually this will go into an include file, but this will be later */
-	static Scsi_Host_Template driver_template = FD_MCS;
-
+static Scsi_Host_Template driver_template = {
+	.proc_name			= "fd_mcs",
+	.proc_info			= fd_mcs_proc_info,
+	.detect				= fd_mcs_detect,
+	.release			= fd_mcs_release,
+	.info				= fd_mcs_info,
+	.command			= fd_mcs_command,
+	.queuecommand   		= fd_mcs_queue, 
+	.eh_abort_handler		= fd_mcs_abort,
+	.eh_bus_reset_handler		= fd_mcs_bus_reset,
+	.eh_host_reset_handler		= fd_mcs_host_reset,
+	.eh_device_reset_handler	= fd_mcs_device_reset,
+	.bios_param     		= fd_mcs_biosparam,
+	.can_queue      		= 1,
+	.this_id        		= 7,
+	.sg_tablesize   		= 64,
+	.cmd_per_lun    		= 1,
+	.use_clustering 		= DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/fd_mcs.h b/drivers/scsi/fd_mcs.h
--- a/drivers/scsi/fd_mcs.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/fd_mcs.h	Sun May  4 02:56:43 2003
@@ -35,24 +35,4 @@
 static int fd_mcs_proc_info(char *, char **, off_t, int, int, int);
 static const char *fd_mcs_info(struct Scsi_Host *);
 
-#define FD_MCS {\
-                    .proc_name			= "fd_mcs",		\
-                    .proc_info			= fd_mcs_proc_info,	\
-		    .detect			= fd_mcs_detect,		\
-		    .release			= fd_mcs_release,		\
-		    .info			= fd_mcs_info,		\
-		    .command			= fd_mcs_command,		\
-		    .queuecommand   		= fd_mcs_queue,           \
-		    .eh_abort_handler		= fd_mcs_abort,           \
-		    .eh_bus_reset_handler	= fd_mcs_bus_reset,       \
-		    .eh_host_reset_handler	= fd_mcs_host_reset,      \
-		    .eh_device_reset_handler	= fd_mcs_device_reset,    \
-		    .bios_param     		= fd_mcs_biosparam,       \
-		    .can_queue      		= 1, 			\
-		    .this_id        		= 7, 			\
-		    .sg_tablesize   		= 64, 			\
-		    .cmd_per_lun    		= 1, 			\
-		    .use_clustering 		= DISABLE_CLUSTERING	\
-		}
-
 #endif				/* _FD_MCS_H */
diff -Nru a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
--- a/drivers/scsi/g_NCR5380.c	Sat Apr 26 07:28:20 2003
+++ b/drivers/scsi/g_NCR5380.c	Sun May  4 02:56:43 2003
@@ -885,11 +885,24 @@
 #undef PRINTP
 #undef ANDP
 
-/*
- *	Eventually this will go into an include file, but this will be later 
- */
-static Scsi_Host_Template driver_template = GENERIC_NCR5380;
-
+static Scsi_Host_Template driver_template = {
+	.proc_info      	= generic_NCR5380_proc_info,
+	.name           	= "Generic NCR5380/NCR53C400 Scsi Driver",
+	.detect         	= generic_NCR5380_detect,
+	.release        	= generic_NCR5380_release_resources,
+	.info           	= generic_NCR5380_info,
+	.queuecommand   	= generic_NCR5380_queue_command,
+	.eh_abort_handler	= generic_NCR5380_abort,
+	.eh_bus_reset_handler	= generic_NCR5380_bus_reset,
+	.eh_device_reset_handler = generic_NCR5380_device_reset,
+	.eh_host_reset_handler	= generic_NCR5380_host_reset,
+	.bios_param     	= NCR5380_BIOSPARAM,
+	.can_queue      	= CAN_QUEUE,
+        .this_id        	= 7,
+        .sg_tablesize   	= SG_ALL,
+	.cmd_per_lun    	= CMD_PER_LUN,
+        .use_clustering		= DISABLE_CLUSTERING,
+};
 #include <linux/module.h>
 #include "scsi_module.c"
 
diff -Nru a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
--- a/drivers/scsi/g_NCR5380.h	Tue Dec 10 12:28:32 2002
+++ b/drivers/scsi/g_NCR5380.h	Sun May  4 02:56:43 2003
@@ -65,24 +65,6 @@
 #define CAN_QUEUE 16
 #endif
 
-#define GENERIC_NCR5380 {						\
-	.proc_info      = generic_NCR5380_proc_info,			\
-	.name           = "Generic NCR5380/NCR53C400 Scsi Driver",	\
-	.detect         = generic_NCR5380_detect,				\
-	.release        = generic_NCR5380_release_resources,		\
-	.info           = (void *)generic_NCR5380_info,			\
-	.queuecommand   = generic_NCR5380_queue_command,			\
-	.eh_abort_handler = generic_NCR5380_abort,				\
-	.eh_bus_reset_handler = generic_NCR5380_bus_reset,			\
-	.eh_device_reset_handler = generic_NCR5380_device_reset,		\
-	.eh_host_reset_handler = generic_NCR5380_host_reset,			\
-	.bios_param     = NCR5380_BIOSPARAM,				\
-	.can_queue      = CAN_QUEUE,					\
-        .this_id        = 7,						\
-        .sg_tablesize   = SG_ALL,						\
-	.cmd_per_lun    = CMD_PER_LUN ,					\
-        .use_clustering = DISABLE_CLUSTERING}
-
 #ifndef HOSTS_C
 
 #define __STRVAL(x) #x
diff -Nru a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
--- a/drivers/scsi/gdth.c	Sat Apr 26 07:28:21 2003
+++ b/drivers/scsi/gdth.c	Sun May  4 02:56:43 2003
@@ -5790,7 +5790,34 @@
 
 #else
 
-static Scsi_Host_Template driver_template = GDTH;
+static Scsi_Host_Template driver_template = {
+#if LINUX_VERSION_CODE >= 0x02015F
+	.proc_name		= "gdth", 
+#else
+	.proc_dir		= &proc_scsi_gdth,
+#endif
+	.proc_info		= gdth_proc_info,
+	.name			= "GDT SCSI Disk Array Controller",
+	.detect			= gdth_detect, 
+	.release		= gdth_release,
+	.info			= gdth_info, 
+	.queuecommand		= gdth_queuecommand,
+	.eh_abort_handler	= gdth_eh_abort, 
+	.eh_device_reset_handler = gdth_eh_device_reset,
+	.eh_bus_reset_handler	= gdth_eh_bus_reset,
+	.eh_host_reset_handler	= gdth_eh_host_reset,
+	.bios_param		= gdth_bios_param,
+	.can_queue		= GDTH_MAXCMDS,
+	.this_id		= -1,
+	.sg_tablesize		= GDTH_MAXSG,
+	.cmd_per_lun		= GDTH_MAXC_P_L,
+	.unchecked_isa_dma	= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+#if LINUX_VERSION_CODE < 0x020501
+	.use_new_eh_code	= 1,
+#endif
+};
+
 #include "scsi_module.c"
 #ifndef MODULE
 __setup("gdth=", option_setup);
diff -Nru a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
--- a/drivers/scsi/gdth.h	Thu Mar  6 15:10:14 2003
+++ b/drivers/scsi/gdth.h	Sun May  4 02:56:43 2003
@@ -983,29 +983,6 @@
 int gdth_eh_device_reset(Scsi_Cmnd *scp);
 int gdth_eh_bus_reset(Scsi_Cmnd *scp);
 int gdth_eh_host_reset(Scsi_Cmnd *scp);
-#define GDTH { .proc_name =      "gdth",                          \
-               .proc_info =      gdth_proc_info,                  \
-               .name =           "GDT SCSI Disk Array Controller",\
-               .detect =         gdth_detect,                     \
-               .release =        gdth_release,                    \
-               .info =           gdth_info,                       \
-               .command =        NULL,                            \
-               .queuecommand =   gdth_queuecommand,               \
-               .eh_abort_handler = gdth_eh_abort,                 \
-               .eh_device_reset_handler = gdth_eh_device_reset,   \
-               .eh_bus_reset_handler = gdth_eh_bus_reset,         \
-               .eh_host_reset_handler = gdth_eh_host_reset,       \
-               .abort =          NULL,                            \
-               .reset =          NULL,                            \
-               .bios_param =     gdth_bios_param,                 \
-               .can_queue =      GDTH_MAXCMDS,                    \
-               .this_id =        -1,                              \
-               .sg_tablesize =   GDTH_MAXSG,                      \
-               .cmd_per_lun =    GDTH_MAXC_P_L,                   \
-               .present =        0,                               \
-               .unchecked_isa_dma = 1,                            \
-               .use_clustering = ENABLE_CLUSTERING}
-
 #elif LINUX_VERSION_CODE >= 0x020322
 int gdth_bios_param(Disk *,kdev_t,int *);
 int gdth_proc_info(char *,char **,off_t,int,int,int);
@@ -1013,30 +990,6 @@
 int gdth_eh_device_reset(Scsi_Cmnd *scp);
 int gdth_eh_bus_reset(Scsi_Cmnd *scp);
 int gdth_eh_host_reset(Scsi_Cmnd *scp);
-#define GDTH { proc_name:       "gdth",                          \
-               proc_info:       gdth_proc_info,                  \
-               name:            "GDT SCSI Disk Array Controller",\
-               detect:          gdth_detect,                     \
-               release:         gdth_release,                    \
-               info:            gdth_info,                       \
-               command:         NULL,                            \
-               queuecommand:    gdth_queuecommand,               \
-               eh_abort_handler: gdth_eh_abort,                  \
-               eh_device_reset_handler: gdth_eh_device_reset,    \
-               eh_bus_reset_handler: gdth_eh_bus_reset,          \
-               eh_host_reset_handler: gdth_eh_host_reset,        \
-               abort:           gdth_abort,                      \
-               reset:           gdth_reset,                      \
-               bios_param:      gdth_bios_param,                 \
-               can_queue:       GDTH_MAXCMDS,                    \
-               this_id:         -1,                              \
-               sg_tablesize:    GDTH_MAXSG,                      \
-               cmd_per_lun:     GDTH_MAXC_P_L,                   \
-               present:         0,                               \
-               unchecked_isa_dma: 1,                             \
-               use_clustering:  ENABLE_CLUSTERING,               \
-               use_new_eh_code: 1       /* use new error code */ }    
-
 #elif LINUX_VERSION_CODE >= 0x02015F
 int gdth_bios_param(Disk *,kdev_t,int *);
 extern struct proc_dir_entry proc_scsi_gdth;
@@ -1045,76 +998,12 @@
 int gdth_eh_device_reset(Scsi_Cmnd *scp);
 int gdth_eh_bus_reset(Scsi_Cmnd *scp);
 int gdth_eh_host_reset(Scsi_Cmnd *scp);
-#define GDTH { proc_dir:        &proc_scsi_gdth,                 \
-               proc_info:       gdth_proc_info,                  \
-               name:            "GDT SCSI Disk Array Controller",\
-               detect:          gdth_detect,                     \
-               release:         gdth_release,                    \
-               info:            gdth_info,                       \
-               command:         NULL,                            \
-               queuecommand:    gdth_queuecommand,               \
-               eh_abort_handler: gdth_eh_abort,                  \
-               eh_device_reset_handler: gdth_eh_device_reset,    \
-               eh_bus_reset_handler: gdth_eh_bus_reset,          \
-               eh_host_reset_handler: gdth_eh_host_reset,        \
-               abort:           gdth_abort,                      \
-               reset:           gdth_reset,                      \
-               bios_param:      gdth_bios_param,                 \
-               can_queue:       GDTH_MAXCMDS,                    \
-               this_id:         -1,                              \
-               sg_tablesize:    GDTH_MAXSG,                      \
-               cmd_per_lun:     GDTH_MAXC_P_L,                   \
-               present:         0,                               \
-               unchecked_isa_dma: 1,                             \
-               use_clustering:  ENABLE_CLUSTERING,               \
-               use_new_eh_code: 1       /* use new error code */ }    
-
 #elif LINUX_VERSION_CODE >= 0x010300
 int gdth_bios_param(Disk *,kdev_t,int *);
 extern struct proc_dir_entry proc_scsi_gdth;
 int gdth_proc_info(char *,char **,off_t,int,int,int);
-#define GDTH { NULL, NULL,                              \
-                   &proc_scsi_gdth,                     \
-                   gdth_proc_info,                      \
-                   "GDT SCSI Disk Array Controller",    \
-                   gdth_detect,                         \
-                   gdth_release,                        \
-                   gdth_info,                           \
-                   NULL,                                \
-                   gdth_queuecommand,                   \
-                   gdth_abort,                          \
-                   gdth_reset,                          \
-                   NULL,                                \
-                   gdth_bios_param,                     \
-                   GDTH_MAXCMDS,                        \
-                   -1,                                  \
-                   GDTH_MAXSG,                          \
-                   GDTH_MAXC_P_L,                       \
-                   0,                                   \
-                   1,                                   \
-                   ENABLE_CLUSTERING}
-
 #else
 int gdth_bios_param(Disk *,int,int *);
-#define GDTH { NULL, NULL,                              \
-                   "GDT SCSI Disk Array Controller",    \
-                   gdth_detect,                         \
-                   gdth_release,                        \
-                   gdth_info,                           \
-                   NULL,                                \
-                   gdth_queuecommand,                   \
-                   gdth_abort,                          \
-                   gdth_reset,                          \
-                   NULL,                                \
-                   gdth_bios_param,                     \
-                   GDTH_MAXCMDS,                        \
-                   -1,                                  \
-                   GDTH_MAXSG,                          \
-                   GDTH_MAXC_P_L,                       \
-                   0,                                   \
-                   1,                                   \
-                   ENABLE_CLUSTERING}
 #endif
-
 #endif
 
diff -Nru a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
--- a/drivers/scsi/hosts.c	Tue Apr 29 00:11:53 2003
+++ b/drivers/scsi/hosts.c	Mon May 12 15:50:42 2003
@@ -32,20 +32,20 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/list.h>
 #include <linux/completion.h>
-
-#define __KERNEL_SYSCALLS__
-
 #include <linux/unistd.h>
 #include <asm/dma.h>
 
 #include "scsi.h"
 #include "hosts.h"
 
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
+
 static LIST_HEAD(scsi_host_list);
 static spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED;
 
@@ -193,62 +193,6 @@
 	return 0;
 }
 
-static int scsi_remove_legacy_host(struct Scsi_Host *shost)
-{
-	int error;
-
-	error = scsi_remove_host(shost);
-	if (!error)
-		(*shost->hostt->release)(shost);
-	return 0;
-}
-
-static int scsi_check_device_busy(struct scsi_device *sdev)
-{
-	struct Scsi_Host *shost = sdev->host;
-	struct scsi_cmnd *scmd;
-	unsigned long flags;
-
-	/*
-	 * Loop over all of the commands associated with the
-	 * device.  If any of them are busy, then set the state
-	 * back to inactive and bail.
-	 */
-	spin_lock_irqsave(&sdev->list_lock, flags);
-	list_for_each_entry(scmd, &sdev->cmd_list, list) {
-		if (scmd->request && scmd->request->rq_status != RQ_INACTIVE)
-			goto active;
-
-		/*
-		 * No, this device is really free.  Mark it as such, and
-		 * continue on.
-		 */
-		scmd->state = SCSI_STATE_DISCONNECTING;
-		if (scmd->request)
-			scmd->request->rq_status = RQ_SCSI_DISCONNECTING;
-	}
-	spin_unlock_irqrestore(&sdev->list_lock, flags);
-
-	return 0;
-
-active:
-	printk(KERN_ERR "SCSI device not inactive - rq_status=%d, target=%d, "
-			"pid=%ld, state=%d, owner=%d.\n",
-			scmd->request->rq_status, scmd->device->id,
-			scmd->pid, scmd->state, scmd->owner);
-
-	list_for_each_entry(sdev, &shost->my_devices, siblings) {
-		list_for_each_entry(scmd, &sdev->cmd_list, list) {
-			if (scmd->request->rq_status == RQ_SCSI_DISCONNECTING)
-				scmd->request->rq_status = RQ_INACTIVE;
-		}
-	}
-
-	spin_unlock_irqrestore(&sdev->list_lock, flags);
-	printk(KERN_ERR "Device busy???\n");
-	return 1;
-}
-
 /**
  * scsi_remove_host - check a scsi host for release and release
  * @shost:	a pointer to a scsi host to release
@@ -268,11 +212,9 @@
 	list_for_each_entry(sdev, &shost->my_devices, siblings)
 		sdev->online = FALSE;
 
-	list_for_each_entry(sdev, &shost->my_devices, siblings)
-		if (scsi_check_device_busy(sdev))
-			return 1;
-
+	scsi_proc_host_rm(shost);
 	scsi_forget_host(shost);
+	scsi_sysfs_remove_host(shost);
 	return 0;
 }
 
@@ -293,9 +235,11 @@
 	printk(KERN_INFO "scsi%d : %s\n", shost->host_no,
 			sht->info ? sht->info(shost) : sht->name);
 
-	if (dev) {
-		shost->host_gendev = dev;
-	}
+	error = scsi_sysfs_add_host(shost, dev);
+	if (error)
+		return error;
+
+	scsi_proc_host_add(shost);
 
 	scsi_scan_host(shost);
 			
@@ -314,6 +258,15 @@
  **/
 void scsi_unregister(struct Scsi_Host *shost)
 {
+	scsi_host_put(shost);
+}
+
+/**
+ * scsi_free_sdev - free a scsi hosts resources
+ * @shost:	scsi host to free 
+ **/
+void scsi_free_shost(struct Scsi_Host *shost)
+{
 	/* Remove shost from scsi_host_list */
 	spin_lock(&scsi_host_list_lock);
 	list_del(&shost->sh_list);
@@ -332,7 +285,6 @@
 	}
 
 	shost->hostt->present--;
-	scsi_proc_host_rm(shost);
 	scsi_destroy_command_freelist(shost);
 	kfree(shost);
 }
@@ -423,8 +375,14 @@
 	shost->use_clustering = shost_tp->use_clustering;
 	if (!blk_nohighio)
 		shost->highmem_io = shost_tp->highmem_io;
-
-	shost->max_sectors = shost_tp->max_sectors;
+	if (!shost_tp->max_sectors) {
+		/*
+		 * Driver imposes no hard sector transfer limit.
+		 * start at machine infinity initially.
+		 */
+		shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
+	} else
+		shost->max_sectors = shost_tp->max_sectors;
 	shost->use_blk_tcq = shost_tp->use_blk_tcq;
 
 	spin_lock(&scsi_host_list_lock);
@@ -447,7 +405,8 @@
 	rval = scsi_setup_command_freelist(shost);
 	if (rval)
 		goto fail;
-	scsi_proc_host_add(shost);
+
+	scsi_sysfs_init_host(shost);
 
 	shost->eh_notify = &sem;
 	kernel_thread((int (*)(void *)) scsi_error_handler, (void *) shost, 0);
@@ -525,7 +484,7 @@
  **/
 int scsi_unregister_host(Scsi_Host_Template *shost_tp)
 {
-	scsi_tp_for_each_host(shost_tp, scsi_remove_legacy_host);
+	scsi_tp_for_each_host(shost_tp, scsi_remove_host);
 	return 0;
 
 }
@@ -576,15 +535,26 @@
 }
 
 /**
+ * *scsi_host_get - inc a Scsi_Host ref count
+ * @shost:	Pointer to Scsi_Host to inc.
+ **/
+void scsi_host_get(struct Scsi_Host *shost)
+{
+
+	get_device(&shost->host_gendev);
+	class_device_get(&shost->class_dev);
+	return;
+}
+
+/**
  * *scsi_host_put - dec a Scsi_Host ref count
  * @shost:	Pointer to Scsi_Host to dec.
  **/
 void scsi_host_put(struct Scsi_Host *shost)
 {
 
-	/* XXX Get list lock */
-	/* XXX dec ref count */
-	/* XXX Release list lock */
+	class_device_put(&shost->class_dev);
+	put_device(&shost->host_gendev);
 	return;
 }
 
diff -Nru a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
--- a/drivers/scsi/hosts.h	Tue Apr 29 00:11:53 2003
+++ b/drivers/scsi/hosts.h	Thu May  8 11:24:14 2003
@@ -482,9 +482,10 @@
     unsigned int max_host_blocked;
 
     /* 
-     * Support for driverfs filesystem
+     * Support for sysfs
      */
-    struct device *host_gendev;
+    struct device host_gendev;
+    struct class_device class_dev;
 
     /*
      * We should ensure that this is aligned, both for better performance
@@ -495,8 +496,11 @@
         __attribute__ ((aligned (sizeof(unsigned long))));
 };
 
-#define	to_scsi_host(d)	d->driver_data	/* Major logical breakage, but we compile again... */
-	
+#define		dev_to_shost(d)		\
+	container_of(d, struct Scsi_Host, host_gendev)
+#define		class_to_shost(d)	\
+	container_of(d, struct Scsi_Host, class_dev)
+
 /*
  * These two functions are used to allocate and free a pseudo device
  * which will connect to the host adapter itself rather than any
@@ -510,6 +514,7 @@
 extern void scsi_unblock_requests(struct Scsi_Host *);
 extern void scsi_block_requests(struct Scsi_Host *);
 extern void scsi_report_bus_reset(struct Scsi_Host *, int);
+extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
 
 static inline void scsi_assign_lock(struct Scsi_Host *shost, spinlock_t *lock)
 {
@@ -519,21 +524,14 @@
 static inline void scsi_set_device(struct Scsi_Host *shost,
                                    struct device *dev)
 {
-        shost->host_gendev = dev;
+        shost->host_gendev.parent = dev;
 }
 
 static inline struct device *scsi_get_device(struct Scsi_Host *shost)
 {
-        return shost->host_gendev;
+        return shost->host_gendev.parent;
 }
 
-/*
- * Prototypes for functions/data in scsi_scan.c
- */
-extern void scsi_scan_host(struct Scsi_Host *);
-extern void scsi_forget_host(struct Scsi_Host *);
-
-
 struct Scsi_Device_Template
 {
     struct list_head list;
@@ -572,16 +570,8 @@
 extern int scsi_register_host(Scsi_Host_Template *);
 extern int scsi_unregister_host(Scsi_Host_Template *);
 
-extern struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *);
 extern struct Scsi_Host *scsi_host_hn_get(unsigned short);
 extern void scsi_host_put(struct Scsi_Host *);
-extern void scsi_host_init(void);
-
-/*
- * host_busy inc/dec/test functions
- */
-extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *);
-extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *);
 
 /**
  * scsi_find_device - find a device given the host
@@ -601,30 +591,4 @@
         return NULL;
 }
 
-/*
- * sysfs support
- */
-extern int scsi_upper_driver_register(struct Scsi_Device_Template *);
-extern void scsi_upper_driver_unregister(struct Scsi_Device_Template *);
-
-extern struct class shost_class;
-
 #endif
-/*
- * 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: 4
- * c-brace-imaginary-offset: 0
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * c-continued-statement-offset: 4
- * c-continued-brace-offset: 0
- * indent-tabs-mode: nil
- * tab-width: 8
- * End:
- */
diff -Nru a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
--- a/drivers/scsi/ibmmca.c	Sat Apr 26 07:28:22 2003
+++ b/drivers/scsi/ibmmca.c	Sun May  4 02:56:43 2003
@@ -2484,6 +2484,21 @@
 
 __setup("ibmmcascsi=", option_setup);
 
-static Scsi_Host_Template driver_template = IBMMCA;
-
+static Scsi_Host_Template driver_template = {
+          .proc_name      = "ibmmca",
+	  .proc_info	  = ibmmca_proc_info,
+          .name           = "IBM SCSI-Subsystem",
+          .detect         = ibmmca_detect,
+          .release        = ibmmca_release,
+          .command        = ibmmca_command,
+          .queuecommand   = ibmmca_queuecommand,
+	  .eh_abort_handler = ibmmca_abort,
+	  .eh_host_reset_handler = ibmmca_host_reset,
+          .bios_param     = ibmmca_biosparam,
+          .can_queue      = 16,
+          .this_id        = 7,
+          .sg_tablesize   = 16,
+          .cmd_per_lun    = 1,
+          .use_clustering = ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h
--- a/drivers/scsi/ibmmca.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/ibmmca.h	Sun May  4 02:56:43 2003
@@ -20,29 +20,4 @@
 static int ibmmca_host_reset (Scsi_Cmnd *);
 static int ibmmca_biosparam (struct scsi_device *, struct block_device *, sector_t, int *);
 
-/*
- * 2/8/98
- * Note to maintainer of IBMMCA.  Do not change this initializer back to
- * the old format.  Please ask eric@andante.jic.com if you have any questions
- * about this, but it will break things in the future.
- */
-#define IBMMCA {                                                      \
-          .proc_name      = "ibmmca",             /*proc_name*/         \
-	  .proc_info	  = ibmmca_proc_info,     /*proc info fn*/      \
-          .name           = "IBM SCSI-Subsystem", /*name*/              \
-          .detect         = ibmmca_detect,        /*detect fn*/         \
-          .release        = ibmmca_release,       /*release fn*/        \
-          .command        = ibmmca_command,       /*command fn*/        \
-          .queuecommand   = ibmmca_queuecommand,  /*queuecommand fn*/   \
-	  .eh_abort_handler = ibmmca_abort,         /*abort fn*/          \
-	  .eh_host_reset_handler = ibmmca_host_reset,         /*reset fn*/          \
-          .bios_param     = ibmmca_biosparam,     /*bios fn*/           \
-          .can_queue      = 16,                   /*can_queue*/         \
-          .this_id        = 7,                    /*set by detect*/     \
-          .sg_tablesize   = 16,                   /*sg_tablesize*/      \
-          .cmd_per_lun    = 1,                    /*cmd_per_lun*/       \
-          .unchecked_isa_dma = 0,                 /*32-Bit Busmaster */ \
-          .use_clustering = ENABLE_CLUSTERING     /*use_clustering*/    \
-          }
-
 #endif /* _IBMMCA_H */
diff -Nru a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
--- a/drivers/scsi/ide-scsi.c	Tue Jan 28 09:01:08 2003
+++ b/drivers/scsi/ide-scsi.c	Wed May 14 19:55:52 2003
@@ -78,6 +78,7 @@
 #define PC_DMA_IN_PROGRESS		0	/* 1 while DMA in progress */
 #define PC_WRITING			1	/* Data direction */
 #define PC_TRANSFORM			2	/* transform SCSI commands */
+#define PC_DMA_OK			4	/* Use DMA */
 
 /*
  *	SCSI command transformation layer
@@ -494,6 +495,10 @@
 	ide_set_handler(drive, &idescsi_pc_intr, get_timeout(pc), NULL);
 	/* Send the actual packet */
 	atapi_output_bytes(drive, scsi->pc->c, 12);
+	if (test_bit (PC_DMA_OK, &pc->flags)) {
+		set_bit (PC_DMA_IN_PROGRESS, &pc->flags);
+		(void) (HWIF(drive)->ide_dma_begin(drive));
+	}
 	return ide_started;
 }
 
@@ -527,10 +532,9 @@
 	HWIF(drive)->OUTB(bcount.b.high, IDE_BCOUNTH_REG);
 	HWIF(drive)->OUTB(bcount.b.low, IDE_BCOUNTL_REG);
 
-	if (feature.b.dma) {
-		set_bit(PC_DMA_IN_PROGRESS, &pc->flags);
-		(void) (HWIF(drive)->ide_dma_begin(drive));
-	}
+	if (feature.b.dma)
+		set_bit(PC_DMA_OK, &pc->flags);
+
 	if (test_bit(IDESCSI_DRQ_INTERRUPT, &scsi->flags)) {
 		if (HWGROUP(drive)->handler != NULL)
 			BUG();
diff -Nru a/drivers/scsi/imm.c b/drivers/scsi/imm.c
--- a/drivers/scsi/imm.c	Thu Mar  6 15:50:31 2003
+++ b/drivers/scsi/imm.c	Sun May  4 02:56:43 2003
@@ -107,7 +107,23 @@
  *                   Parallel port probing routines                        *
  ***************************************************************************/
 
-static Scsi_Host_Template driver_template = IMM;
+static Scsi_Host_Template driver_template = {
+	.proc_name			= "imm",
+	.proc_info			= imm_proc_info,
+	.name				= "Iomega VPI2 (imm) interface",
+	.detect				= imm_detect,
+	.release			= imm_release,
+	.command			= imm_command,
+	.queuecommand			= imm_queuecommand,
+	.eh_abort_handler               = imm_abort,
+	.eh_bus_reset_handler           = imm_reset,
+	.eh_host_reset_handler          = imm_reset, 
+	.bios_param		        = imm_biosparam,
+	.this_id			= 7,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= ENABLE_CLUSTERING,
+};
 #include  "scsi_module.c"
 
 int imm_detect(Scsi_Host_Template * host)
diff -Nru a/drivers/scsi/imm.h b/drivers/scsi/imm.h
--- a/drivers/scsi/imm.h	Tue Dec 10 12:28:32 2002
+++ b/drivers/scsi/imm.h	Sun May  4 02:56:43 2003
@@ -163,21 +163,4 @@
 int imm_biosparam(struct scsi_device *, struct block_device *,
 		sector_t, int *);
 
-#define IMM {	.proc_name			= "imm",			\
-		.proc_info			= imm_proc_info,		\
-		.name				= "Iomega VPI2 (imm) interface",\
-		.detect				= imm_detect,		\
-		.release			= imm_release,		\
-		.command			= imm_command,		\
-		.queuecommand			= imm_queuecommand,	\
-                .eh_abort_handler               = imm_abort,              \
-                .eh_device_reset_handler        = NULL,                   \
-                .eh_bus_reset_handler           = imm_reset,              \
-                .eh_host_reset_handler          = imm_reset,              \
-		.bios_param		        = imm_biosparam,		\
-		.this_id			= 7,			\
-		.sg_tablesize			= SG_ALL,			\
-		.cmd_per_lun			= 1,			\
-		.use_clustering			= ENABLE_CLUSTERING	\
-}
 #endif				/* _IMM_H */
diff -Nru a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
--- a/drivers/scsi/in2000.c	Sat Apr 26 07:28:22 2003
+++ b/drivers/scsi/in2000.c	Sun May  4 02:56:43 2003
@@ -2312,5 +2312,22 @@
 MODULE_LICENSE("GPL");
 
 
-static Scsi_Host_Template driver_template = IN2000;
+static Scsi_Host_Template driver_template = {
+	.proc_name       		= "in2000",
+	.proc_info       		= in2000_proc_info,
+	.name            		= "Always IN2000",
+	.detect          		= in2000_detect, 
+	.release			= in2000_release,
+	.queuecommand    		= in2000_queuecommand,
+	.eh_abort_handler		= in2000_abort,
+	.eh_bus_reset_handler		= in2000_bus_reset,
+	.eh_device_reset_handler	= in2000_device_reset,
+	.eh_host_reset_handler	= in2000_host_reset, 
+	.bios_param      		= in2000_biosparam, 
+	.can_queue       		= IN2000_CAN_Q,
+	.this_id         		= IN2000_HOST_ID,
+	.sg_tablesize    		= IN2000_SG,
+	.cmd_per_lun     		= IN2000_CPL,
+	.use_clustering  		= DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
--- a/drivers/scsi/in2000.h	Tue Dec 10 12:28:32 2002
+++ b/drivers/scsi/in2000.h	Sun May  4 02:56:43 2003
@@ -414,22 +414,4 @@
 #define IN2000_CPL      2
 #define IN2000_HOST_ID  7
 
-#define IN2000 {  .proc_name       		= "in2000",	     /* name of /proc/scsi directory entry */ \
-                  .proc_info       		= in2000_proc_info,    /* pointer to proc info function */ \
-                  .name            		= "Always IN2000",     /* device name */ \
-                  .detect          		= in2000_detect,       /* returns number of in2000's found */ \
-                  .release			= in2000_release,	     /* release the in2000 controller */ \
-                  .queuecommand    		= in2000_queuecommand, /* queue scsi command, don't wait */ \
-                  .eh_abort_handler		= in2000_abort,        /* abort current command */ \
-                  .eh_bus_reset_handler		= in2000_bus_reset,    /* reset scsi bus */ \
-                  .eh_device_reset_handler	= in2000_device_reset, /* reset scsi device */ \
-                  .eh_host_reset_handler	= in2000_host_reset,   /* reset scsi hba */ \
-                  .bios_param      		= in2000_biosparam,    /* figures out BIOS parameters for lilo, etc */ \
-                  .can_queue       		= IN2000_CAN_Q,        /* max commands we can queue up */ \
-                  .this_id         		= IN2000_HOST_ID,      /* host-adapter scsi id */ \
-                  .sg_tablesize    		= IN2000_SG,           /* scatter-gather table size */ \
-                  .cmd_per_lun     		= IN2000_CPL,          /* commands per lun */ \
-                  .use_clustering  		= DISABLE_CLUSTERING,  /* ENABLE_CLUSTERING may speed things up */ \
-                }
-
 #endif /* IN2000_H */
diff -Nru a/drivers/scsi/ini9100u.c b/drivers/scsi/ini9100u.c
--- a/drivers/scsi/ini9100u.c	Sat Apr 26 07:28:22 2003
+++ b/drivers/scsi/ini9100u.c	Sun May  4 02:56:43 2003
@@ -141,7 +141,23 @@
 unsigned int i91u_debug = DEBUG_DEFAULT;
 #endif
 
-static Scsi_Host_Template driver_template = INI9100U;
+static Scsi_Host_Template driver_template = {
+	.proc_name	= "INI9100U",
+	.proc_info	= "INI9100U",
+	.name		= i91u_REVID,
+	.detect		= i91u_detect,
+	.release	= i91u_release,
+	.command	= i91u_command,
+	.queuecommand	= i91u_queue,
+	.abort		= i91u_abort,
+	.reset		= i91u_reset,
+	.bios_param	= i91u_biosparam,
+	.can_queue	= 1,
+	.this_id	= 1,
+	.sg_tablesize	= SG_ALL,
+	.cmd_per_lun 	= 1,
+	.use_clustering	= ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
 
 char *i91uCopyright = "Copyright (C) 1996-98";
diff -Nru a/drivers/scsi/ini9100u.h b/drivers/scsi/ini9100u.h
--- a/drivers/scsi/ini9100u.h	Tue Dec 10 12:28:34 2002
+++ b/drivers/scsi/ini9100u.h	Sun May  4 02:56:43 2003
@@ -87,34 +87,6 @@
 
 #define i91u_REVID "Initio INI-9X00U/UW SCSI device driver; Revision: 1.03g"
 
-#define INI9100U	{ \
-	.next		= NULL,						\
-	.module		= NULL,						\
-	.proc_name	= "INI9100U", \
-	.proc_info	= NULL,				\
-	.name		= i91u_REVID, \
-	.detect		= i91u_detect, \
-	.release	= i91u_release, \
-	.info		= NULL,					\
-	.command	= i91u_command, \
-	.queuecommand	= i91u_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		= i91u_abort, \
-	.reset		= i91u_reset, \
-	.bios_param	= i91u_biosparam, \
-	.can_queue	= 1, \
-	.this_id	= 1, \
-	.sg_tablesize	= SG_ALL, \
-	.cmd_per_lun 	= 1, \
-	.present	= 0, \
-	.unchecked_isa_dma = 0, \
-	.use_clustering	= ENABLE_CLUSTERING, \
-}
-
 #define VIRT_TO_BUS(i)  (unsigned int) virt_to_bus((void *)(i))
 #define ULONG   unsigned long
 #define USHORT  unsigned short
diff -Nru a/drivers/scsi/inia100.c b/drivers/scsi/inia100.c
--- a/drivers/scsi/inia100.c	Sat Apr 26 07:28:22 2003
+++ b/drivers/scsi/inia100.c	Sun May  4 02:56:43 2003
@@ -91,7 +91,21 @@
 #include "hosts.h"
 #include "inia100.h"
 
-static Scsi_Host_Template driver_template = INIA100;
+static Scsi_Host_Template driver_template = {
+	.proc_name	= "inia100",
+	.name		= inia100_REVID,
+	.detect		= inia100_detect,
+	.release	= inia100_release,
+	.queuecommand	= inia100_queue,
+	.eh_abort_handler = inia100_abort,
+	.eh_bus_reset_handler	= inia100_bus_reset,
+	.eh_device_reset_handler = inia100_device_reset,
+	.can_queue	= 1,
+	.this_id	= 1,
+	.sg_tablesize	= SG_ALL,
+	.cmd_per_lun 	= 1,
+	.use_clustering	= ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
 
 #define ORC_RDWORD(x,y)         (short)(inl((int)((ULONG)((ULONG)x+(UCHAR)y)) ))
diff -Nru a/drivers/scsi/inia100.h b/drivers/scsi/inia100.h
--- a/drivers/scsi/inia100.h	Sun Feb 16 16:18:17 2003
+++ b/drivers/scsi/inia100.h	Sun May  4 02:56:43 2003
@@ -76,24 +76,6 @@
 
 #define inia100_REVID "Initio INI-A100U2W SCSI device driver; Revision: 1.02d"
 
-#define INIA100	{ \
-	.proc_name	= "inia100", \
-	.name		= inia100_REVID, \
-	.detect		= inia100_detect, \
-	.release	= inia100_release, \
-	.queuecommand	= inia100_queue, \
-	.eh_abort_handler = inia100_abort, \
-	.eh_bus_reset_handler	= inia100_bus_reset, \
-	.eh_device_reset_handler = inia100_device_reset, \
-	.can_queue	= 1, \
-	.this_id	= 1, \
-	.sg_tablesize	= SG_ALL, \
-	.cmd_per_lun 	= 1, \
-	.present	= 0, \
-	.unchecked_isa_dma = 0, \
-	.use_clustering	= ENABLE_CLUSTERING, \
-}
-
 #define ULONG   unsigned long
 #define PVOID   void *
 #define USHORT  unsigned short
diff -Nru a/drivers/scsi/ips.c b/drivers/scsi/ips.c
--- a/drivers/scsi/ips.c	Sat Apr 26 07:28:23 2003
+++ b/drivers/scsi/ips.c	Tue May  6 10:19:58 2003
@@ -238,20 +238,43 @@
 static const char   ips_name[] = "ips";
 static struct Scsi_Host *ips_sh[IPS_MAX_ADAPTERS];   /* Array of host controller structures */
 static ips_ha_t    *ips_ha[IPS_MAX_ADAPTERS];        /* Array of HA structures */
-static unsigned int ips_next_controller = 0;
-static unsigned int ips_num_controllers = 0;
-static unsigned int ips_released_controllers = 0;
+static unsigned int ips_next_controller;
+static unsigned int ips_num_controllers;
+static unsigned int ips_released_controllers;
 static int          ips_hotplug;
 static int          ips_cmd_timeout = 60;
 static int          ips_reset_timeout = 60 * 5;
 static int          ips_force_memio = 1;             /* Always use Memory Mapped I/O    */
 static int          ips_force_i2o = 1;               /* Always use I2O command delivery */
 static int          ips_ioctlsize = IPS_IOCTL_SIZE;  /* Size of the ioctl buffer        */
-static int          ips_cd_boot = 0;                 /* Booting from Manager CD         */
+static int          ips_cd_boot;                     /* Booting from Manager CD         */
 static char        *ips_FlashData = NULL;            /* CD Boot - Flash Data Buffer      */
-static long         ips_FlashDataInUse = 0;          /* CD Boot - Flash Data In Use Flag */
+static long         ips_FlashDataInUse;              /* CD Boot - Flash Data In Use Flag */
 static uint32_t     MaxLiteCmds = 32;                /* Max Active Cmds for a Lite Adapter */  
-static Scsi_Host_Template ips_driver_template = IPS;
+static Scsi_Host_Template ips_driver_template = {
+	.detect			= ips_detect,
+	.release		= ips_release,
+	.info			= ips_info,
+	.queuecommand		= ips_queue,
+	.eh_abort_handler	= ips_eh_abort,
+	.eh_host_reset_handler	= ips_eh_reset,
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)
+	.slave_configure	= ips_slave_configure,
+#else
+	.select_queue_depths	= ips_select_queue_depth,
+#endif
+	.bios_param		= ips_biosparam,
+	.this_id		= -1,
+	.sg_tablesize		= IPS_MAX_SG,
+	.cmd_per_lun		= 3,
+	.use_clustering		= ENABLE_CLUSTERING,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) || (defined CONFIG_HIGHIO)
+	.highmem_io		= 1,
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+	.use_new_eh_code	= 1,
+#endif
+};
 
 IPS_DEFINE_COMPAT_TABLE( Compatable );               /* Version Compatability Table      */
 
@@ -426,8 +449,8 @@
 static void ips_enable_int_copperhead(ips_ha_t *);
 static void ips_enable_int_copperhead_memio(ips_ha_t *);
 static void ips_enable_int_morpheus(ips_ha_t *);
-static void ips_intr_copperhead(ips_ha_t *);
-static void ips_intr_morpheus(ips_ha_t *);
+static int ips_intr_copperhead(ips_ha_t *);
+static int ips_intr_morpheus(ips_ha_t *);
 static void ips_next(ips_ha_t *, int);
 static void ipsintr_blocking(ips_ha_t *, struct ips_scb *);
 static void ipsintr_done(ips_ha_t *, struct ips_scb *);
@@ -562,8 +585,6 @@
          printk( KERN_WARNING "ERROR: Can't Allocate Large Buffer for Flashing\n" );
       }
    }                                                                               
-   if (!pci_present())
-      return (0);
 
    SHT->proc_info = ips_proc_info;
    SHT->proc_name = "ips";
@@ -682,13 +703,13 @@
    scb->cmd.flush_cache.reserved3 = 0;
    scb->cmd.flush_cache.reserved4 = 0;
 
-   printk(KERN_NOTICE "(%s%d) Flushing Cache.\n", ips_name, ha->host_num);
+   IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
 
    /* send command */
    if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
-      printk(KERN_NOTICE "(%s%d) Incomplete Flush.\n", ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n");
 
-   printk(KERN_NOTICE "(%s%d) Flushing Complete.\n", ips_name, ha->host_num);
+   IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n");
 
    ips_sh[i] = NULL;
    ips_ha[i] = NULL;
@@ -755,13 +776,13 @@
       scb->cmd.flush_cache.reserved3 = 0;
       scb->cmd.flush_cache.reserved4 = 0;
 
-      printk(KERN_NOTICE "(%s%d) Flushing Cache.\n", ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Cache.\n");
 
       /* send command */
       if (ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_ON) == IPS_FAILURE)
-         printk(KERN_NOTICE "(%s%d) Incomplete Flush.\n", ips_name, ha->host_num);
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "Incomplete Flush.\n");
       else
-         printk(KERN_NOTICE "(%s%d) Flushing Complete.\n", ips_name, ha->host_num);
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flushing Complete.\n");
    }
 
    return (NOTIFY_OK);
@@ -911,7 +932,7 @@
       /* Attempt the flush command */
       ret = ips_send_wait(ha, scb, ips_cmd_timeout, IPS_INTR_IORL);
       if (ret == IPS_SUCCESS) {
-         printk(KERN_NOTICE "(%s%d) Reset Request - Flushed Cache\n", ips_name, ha->host_num);
+         IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Reset Request - Flushed Cache\n");
          return (SUCCESS);
          }
    }
@@ -925,16 +946,14 @@
     * command must have already been sent
     * reset the controller
     */
-   printk(KERN_NOTICE "(%s%d) Resetting controller.\n",
-          ips_name, ha->host_num);
+   IPS_PRINTK(KERN_NOTICE, ha->pcidev, "Resetting controller.\n");
    ret = (*ha->func.reset)(ha);
 
    if (!ret) {
       Scsi_Cmnd *scsi_cmd;
 
-      printk(KERN_NOTICE
-             "(%s%d) Controller reset failed - controller now offline.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+                 "Controller reset failed - controller now offline.\n");
 
       /* Now fail all of the active commands */
       DEBUG_VAR(1, "(%s%d) Failing active commands",
@@ -962,9 +981,8 @@
    if (!ips_clear_adapter(ha, IPS_INTR_IORL)) {
       Scsi_Cmnd *scsi_cmd;
 
-      printk(KERN_NOTICE
-             "(%s%d) Controller reset failed - controller now offline.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_NOTICE, ha->pcidev,
+                 "Controller reset failed - controller now offline.\n");
 
       /* Now fail all of the active commands */
       DEBUG_VAR(1, "(%s%d) Failing active commands",
@@ -1269,7 +1287,8 @@
    ips_ha_t         *ha;
    unsigned long     cpu_flags;
    struct Scsi_Host *host;
-
+   int       irqstatus;
+   
    METHOD_TRACE("do_ipsintr", 2);
 
    ha = (ips_ha_t *) dev_id;
@@ -1289,13 +1308,13 @@
       return IRQ_HANDLED;
    }
 
-   (*ha->func.intr)(ha);
+   irqstatus = (*ha->func.intr)(ha);
 
    IPS_UNLOCK_RESTORE(host->host_lock, cpu_flags);
 
    /* start the next command */
    ips_next(ha, IPS_INTR_ON);
-   return IRQ_HANDLED;
+   return IRQ_RETVAL(irqstatus);
 }
 
 /****************************************************************************/
@@ -1309,7 +1328,7 @@
 /*   ASSUMES interrupts are disabled                                        */
 /*                                                                          */
 /****************************************************************************/
-void
+int
 ips_intr_copperhead(ips_ha_t *ha) {
    ips_stat_t       *sp;
    ips_scb_t        *scb;
@@ -1319,10 +1338,10 @@
    METHOD_TRACE("ips_intr", 2);
 
    if (!ha)
-      return;
+      return 0;
 
    if (!ha->active)
-      return;
+      return 0;
 
    intrstatus = (*ha->func.isintr)(ha);
 
@@ -1331,7 +1350,7 @@
        * Unexpected/Shared interrupt
        */
 
-      return;
+      return 0;
    }
 
    while (TRUE) {
@@ -1358,6 +1377,7 @@
        */
       (*scb->callback) (ha, scb);
    } /* end while */
+   return 1;
 }
 
 /****************************************************************************/
@@ -1371,7 +1391,7 @@
 /*   ASSUMES interrupts are disabled                                        */
 /*                                                                          */
 /****************************************************************************/
-void
+int
 ips_intr_morpheus(ips_ha_t *ha) {
    ips_stat_t       *sp;
    ips_scb_t        *scb;
@@ -1381,10 +1401,10 @@
    METHOD_TRACE("ips_intr_morpheus", 2);
 
    if (!ha)
-      return;
+      return 0;
 
    if (!ha->active)
-      return;
+      return 0;
 
    intrstatus = (*ha->func.isintr)(ha);
 
@@ -1393,7 +1413,7 @@
        * Unexpected/Shared interrupt
        */
 
-      return;
+      return 0;
    }
 
    while (TRUE) {
@@ -1411,8 +1431,7 @@
          break;
 
       if (cstatus.fields.command_id > (IPS_MAX_CMDS - 1)) {
-         printk(KERN_WARNING "(%s%d) Spurious interrupt; no ccb.\n",
-                ips_name, ha->host_num);
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "Spurious interrupt; no ccb.\n");
 
          continue;
       }
@@ -1426,6 +1445,7 @@
        */
       (*scb->callback) (ha, scb);
    } /* end while */
+   return 1;
 }
 
 /****************************************************************************/
@@ -1728,7 +1748,7 @@
       if(pt->CoppCP.cmd.flashfw.count + ha->flash_datasize >
         (PAGE_SIZE << ha->flash_order)){
          ips_free_flash_copperhead(ha);
-         printk(KERN_WARNING "failed size sanity check\n");
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "failed size sanity check\n");
          return IPS_FAILURE;
       }
    }
@@ -2400,6 +2420,7 @@
          minor    = buffer[0x1fe + 0xC0];  /* Offset 0x1fe after the header (0xc0) */
          subminor = buffer[0x1fd + 0xC0];  /* Offset 0x1fd after the header (0xc0) */
       } else {
+         kfree(buffer);
          return;
       }
 
@@ -2450,15 +2471,13 @@
    ips_ffdc_reset(ha, IPS_INTR_IORL);
 
    if (!ips_read_config(ha, IPS_INTR_IORL)) {
-      printk(KERN_WARNING "(%s%d) unable to read config from controller.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "unable to read config from controller.\n");
 
       return (0);
    } /* end if */
 
    if (!ips_read_adapter_status(ha, IPS_INTR_IORL)) {
-      printk(KERN_WARNING "(%s%d) unable to read controller status.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "unable to read controller status.\n");
 
       return (0);
    }
@@ -2467,16 +2486,14 @@
    ips_identify_controller(ha);
 
    if (!ips_read_subsystem_parameters(ha, IPS_INTR_IORL)) {
-      printk(KERN_WARNING "(%s%d) unable to read subsystem parameters.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "unable to read subsystem parameters.\n");
 
       return (0);
    }
 
    /* write nvram user page 5 */
    if (!ips_write_driver_status(ha, IPS_INTR_IORL)) {
-      printk(KERN_WARNING "(%s%d) unable to write driver info to controller.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "unable to write driver info to controller.\n");
 
       return (0);
    }
@@ -3233,16 +3250,14 @@
    METHOD_TRACE("ipsintr_done", 2);
 
    if (!scb) {
-      printk(KERN_WARNING "(%s%d) Spurious interrupt; scb NULL.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "Spurious interrupt; scb NULL.\n");
 
       return ;
    }
 
    if (scb->scsi_cmd == NULL) {
       /* unexpected interrupt */
-      printk(KERN_WARNING "(%s%d) Spurious interrupt; scsi_cmd not set.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "Spurious interrupt; scsi_cmd not set.\n");
 
       return;
    }
@@ -4677,8 +4692,8 @@
    }
 
    if (PostByte[0] < IPS_GOOD_POST_STATUS) {
-      printk(KERN_WARNING "(%s%d) reset controller fails (post status %x %x).\n",
-             ips_name, ha->host_num, PostByte[0], PostByte[1]);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "reset controller fails (post status %x %x).\n",
+                 PostByte[0], PostByte[1]);
 
       return (0);
    }
@@ -4769,8 +4784,8 @@
    }
 
    if (PostByte[0] < IPS_GOOD_POST_STATUS) {
-      printk(KERN_WARNING "(%s%d) reset controller fails (post status %x %x).\n",
-             ips_name, ha->host_num, PostByte[0], PostByte[1]);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "reset controller fails (post status %x %x).\n",
+                 PostByte[0], PostByte[1]);
 
       return (0);
    }
@@ -4856,8 +4871,7 @@
 
    if (i >= 45) {
       /* error occurred */
-      printk(KERN_WARNING "(%s%d) timeout waiting for post.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "timeout waiting for post.\n");
 
       return (0);
    }
@@ -4865,7 +4879,7 @@
    Post = readl(ha->mem_ptr + IPS_REG_I960_MSG0);
 
    if (Post == 0x4F00) {                          /* If Flashing the Battery PIC         */
-       printk(KERN_WARNING "Flashing Battery PIC, Please wait ...\n" );
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "Flashing Battery PIC, Please wait ...\n" );
 
        /* Clear the interrupt bit */
        Isr = (uint32_t) IPS_BIT_I960_MSG0I;
@@ -4880,8 +4894,7 @@
        }
 
        if (i >= 120) {
-          printk(KERN_WARNING "(%s%d) timeout waiting for Battery PIC Flash\n",
-                 ips_name, ha->host_num);
+          IPS_PRINTK(KERN_WARNING, ha->pcidev, "timeout waiting for Battery PIC Flash\n");
           return (0);
        }
 
@@ -4892,8 +4905,7 @@
    writel(Isr, ha->mem_ptr + IPS_REG_I2O_HIR);
 
    if (Post < (IPS_GOOD_POST_STATUS << 8)) {
-      printk(KERN_WARNING "(%s%d) reset controller fails (post status %x).\n",
-             ips_name, ha->host_num, Post);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "reset controller fails (post status %x).\n", Post);
 
       return (0);
    }
@@ -4911,8 +4923,7 @@
 
    if (i >= 240) {
       /* error occurred */
-      printk(KERN_WARNING "(%s%d) timeout waiting for config.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "timeout waiting for config.\n");
 
       return (0);
    }
@@ -5239,10 +5250,8 @@
          if (!(val & IPS_BIT_START_STOP))
             break;
 
-         printk(KERN_WARNING "(%s%d) ips_issue val [0x%x].\n",
-                ips_name, ha->host_num, val);
-         printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n",
-                ips_name, ha->host_num);
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "ips_issue val [0x%x].\n", val);
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "ips_issue semaphore chk timeout.\n");
 
          return (IPS_FAILURE);
       } /* end if */
@@ -5295,10 +5304,8 @@
          if (!(val & IPS_BIT_START_STOP))
             break;
 
-         printk(KERN_WARNING "(%s%d) ips_issue val [0x%x].\n",
-                ips_name, ha->host_num, val);
-         printk(KERN_WARNING "(%s%d) ips_issue semaphore chk timeout.\n",
-                ips_name, ha->host_num);
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "ips_issue val [0x%x].\n", val);
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "ips_issue semaphore chk timeout.\n");
 
          return (IPS_FAILURE);
       } /* end if */
@@ -5538,8 +5545,7 @@
    METHOD_TRACE("ips_write_driver_status", 1);
 
    if (!ips_readwrite_page5(ha, FALSE, intr)) {
-      printk(KERN_WARNING "(%s%d) unable to read NVRAM page 5.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "unable to read NVRAM page 5.\n");
 
       return (0);
    }
@@ -5574,8 +5580,7 @@
 
    /* now update the page */
    if (!ips_readwrite_page5(ha, TRUE, intr)) {
-      printk(KERN_WARNING "(%s%d) unable to write NVRAM page 5.\n",
-             ips_name, ha->host_num);
+      IPS_PRINTK(KERN_WARNING, ha->pcidev, "unable to write NVRAM page 5.\n");
 
       return (0);
    }
@@ -6538,10 +6543,10 @@
          strncpy(&FirmwareString[0], ha->enq->CodeBlkVersion, 8);
          FirmwareString[8] = 0;
 
-         printk(KERN_WARNING "Warning ! ! ! ServeRAID Version Mismatch\n");
-         printk(KERN_WARNING "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
-                              BiosString, FirmwareString, IPS_VERSION_HIGH, IPS_VERSION_LOW );
-         printk(KERN_WARNING "These levels should match to avoid possible compatibility problems.\n" );
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "Warning ! ! ! ServeRAID Version Mismatch\n");
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "Bios = %s, Firmware = %s, Device Driver = %s%s\n",
+                    BiosString, FirmwareString, IPS_VERSION_HIGH, IPS_VERSION_LOW );
+         IPS_PRINTK(KERN_WARNING, ha->pcidev, "These levels should match to avoid possible compatibility problems.\n");
      }
  }
  else
@@ -6682,6 +6687,7 @@
 					}
 					break;
 				default:
+					break;
 				}
 			}
 		}
@@ -6725,19 +6731,18 @@
 static int
 ips_register_scsi( int index){
 	struct Scsi_Host *sh;
-	ips_ha_t *ha, *oldha;
+	ips_ha_t *ha, *oldha = ips_ha[index];
 	sh = scsi_register(&ips_driver_template, sizeof(ips_ha_t));
 	if(!sh) {
-		printk(KERN_WARNING "Unable to register controller with SCSI subsystem\n" );
+		IPS_PRINTK(KERN_WARNING, oldha->pcidev, "Unable to register controller with SCSI subsystem\n");
 		return -1;
 	}
-	oldha = ips_ha[index];
 	ha = IPS_HA(sh);
 	memcpy(ha, oldha, sizeof(ips_ha_t));
 	free_irq(oldha->irq, oldha);
 	/* Install the interrupt handler with the new ha */
 	if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
-		printk(KERN_WARNING "Unable to install interrupt handler\n" );
+		IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to install interrupt handler\n" );
 		scsi_unregister(sh);
 		return -1;
 	}
@@ -6745,7 +6750,7 @@
 	kfree(oldha);
 	ips_sh[index] = sh;
 	ips_ha[index] = ha;
-	scsi_set_device(sh, &ha->pcidev->dev);
+	IPS_SCSI_SET_DEVICE(sh, ha);
 
 	/* Store away needed values for later use */
 	sh->io_port = ha->io_addr;
@@ -6940,7 +6945,7 @@
        uint32_t offs;
 
        if (!request_mem_region(mem_addr, mem_len, "ips")) {
-          printk(KERN_WARNING "Couldn't allocate IO Memory space %x len %d.\n", mem_addr, mem_len);
+          IPS_PRINTK(KERN_WARNING, pci_dev, "Couldn't allocate IO Memory space %x len %d.\n", mem_addr, mem_len);
           return -1;
           }
 
@@ -6956,14 +6961,14 @@
     /* setup I/O mapped area (if applicable) */
     if (io_addr) {
        if (!request_region(io_addr, io_len, "ips")) {
-          printk(KERN_WARNING "Couldn't allocate IO space %x len %d.\n", io_addr, io_len);
+          IPS_PRINTK(KERN_WARNING, pci_dev, "Couldn't allocate IO space %x len %d.\n", io_addr, io_len);
           return -1;
        }
     }
 
     /* get the revision ID */
     if (pci_read_config_byte(pci_dev, PCI_REVISION_ID, &revision_id)) {
-       printk(KERN_WARNING "Can't get revision id.\n" );
+       IPS_PRINTK(KERN_WARNING, pci_dev, "Can't get revision id.\n");
        return -1;
     }
 
@@ -6972,7 +6977,7 @@
     /* found a controller */
     ha = kmalloc(sizeof(ips_ha_t), GFP_KERNEL);
     if (ha == NULL) {
-       printk(KERN_WARNING "Unable to allocate temporary ha struct\n" );
+       IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate temporary ha struct\n");
        return -1;
     }
 
@@ -7007,20 +7012,23 @@
          !pci_set_dma_mask(ha->pcidev, (u64)0xffffffffffffffff)) {
        (ha)->flags |= IPS_HA_ENH_SG;
     } else {
-       pci_set_dma_mask(ha->pcidev, (u64)0xffffffff);
+       if ( pci_set_dma_mask(ha->pcidev, (u64)0xffffffff) != 0 ) { 
+          printk(KERN_WARNING "Unable to set DMA Mask\n");
+          return ips_abort_init(ha, index);
+       }
     }
 
     ha->enq = kmalloc(sizeof(IPS_ENQ), IPS_INIT_GFP);
 
     if (!ha->enq) {
-       printk(KERN_WARNING "Unable to allocate host inquiry structure\n" );
+       IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host inquiry structure\n" );
        return ips_abort_init(ha, index);
     }
 
     ha->adapt = pci_alloc_consistent(pci_dev, sizeof(IPS_ADAPTER) +
                                      sizeof(IPS_IO_CMD), &dma_address);
     if (!ha->adapt) {
-       printk(KERN_WARNING "Unable to allocate host adapt & dummy structures\n");
+       IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host adapt & dummy structures\n");
        return ips_abort_init(ha, index);
     }
     ha->adapt->hw_status_start = dma_address;
@@ -7029,21 +7037,21 @@
     ha->conf = kmalloc(sizeof(IPS_CONF), IPS_INIT_GFP);
 
     if (!ha->conf) {
-       printk(KERN_WARNING "Unable to allocate host conf structure\n" );
+       IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host conf structure\n");
        return ips_abort_init(ha, index);
     }
 
     ha->nvram = kmalloc(sizeof(IPS_NVRAM_P5), IPS_INIT_GFP);
 
     if (!ha->nvram) {
-       printk(KERN_WARNING "Unable to allocate host NVRAM structure\n" );
+       IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host NVRAM structure\n");
        return ips_abort_init(ha, index);
     }
 
     ha->subsys = kmalloc(sizeof(IPS_SUBSYS), IPS_INIT_GFP);
 
     if (!ha->subsys) {
-       printk(KERN_WARNING "Unable to allocate host subsystem structure\n" );
+       IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate host subsystem structure\n");
        return ips_abort_init(ha, index);
     }
 
@@ -7055,7 +7063,7 @@
     ha->ioctl_datasize = count;
 
     if (!ha->ioctl_data) {
-       printk(KERN_WARNING "Unable to allocate IOCTL data\n" );
+       IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to allocate IOCTL data\n");
        ha->ioctl_data = NULL;
        ha->ioctl_order = 0;
        ha->ioctl_datasize = 0;
@@ -7083,7 +7091,7 @@
           /*
            * Initialization failed
            */
-          printk(KERN_WARNING "Unable to initialize controller\n" );
+          IPS_PRINTK(KERN_WARNING, pci_dev, "Unable to initialize controller\n");
           return ips_abort_init(ha, index);
        }
     }
@@ -7115,7 +7123,7 @@
 
     /* Install the interrupt handler */
      if (request_irq(ha->irq, do_ipsintr, SA_SHIRQ, ips_name, ha)) {
-       printk(KERN_WARNING "Unable to install interrupt handler\n" );
+       IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to install interrupt handler\n");
        return ips_abort_init(ha, index);
     }
 
@@ -7124,13 +7132,13 @@
      */
     ha->max_cmds = 1;
     if (!ips_allocatescbs(ha)) {
-       printk(KERN_WARNING "Unable to allocate a CCB\n" );
+       IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to allocate a CCB\n");
        free_irq(ha->irq, ha);
        return ips_abort_init(ha, index);
     }
 
     if (!ips_hainit(ha)) {
-       printk(KERN_WARNING "Unable to initialize controller\n" );
+       IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to initialize controller\n");
        free_irq(ha->irq, ha);
        return ips_abort_init(ha, index);
     }
@@ -7139,7 +7147,7 @@
 
     /* allocate CCBs */
     if (!ips_allocatescbs(ha)) {
-       printk(KERN_WARNING "Unable to allocate CCBs\n" );
+       IPS_PRINTK(KERN_WARNING, ha->pcidev, "Unable to allocate CCBs\n");
        free_irq(ha->irq, ha);
        return ips_abort_init(ha, index);
     }
diff -Nru a/drivers/scsi/ips.h b/drivers/scsi/ips.h
--- a/drivers/scsi/ips.h	Tue Feb 11 03:04:04 2003
+++ b/drivers/scsi/ips.h	Tue May  6 10:19:58 2003
@@ -66,9 +66,6 @@
     */
    #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,20) || defined CONFIG_HIGHIO
       #define IPS_HIGHIO
-      #define IPS_HIGHMEM_IO     .highmem_io = 1,
-   #else
-      #define IPS_HIGHMEM_IO
    #endif
 
    #define IPS_HA(x)                   ((ips_ha_t *) x->hostdata)
@@ -94,20 +91,31 @@
                                          sizeof(IPS_ENH_SG_LIST) : sizeof(IPS_STD_SG_LIST))
 
    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,4)
-      #define pci_set_dma_mask(dev,mask) (1)
+      #define pci_set_dma_mask(dev,mask) ( mask > 0xffffffff ? 1:0 )
       #define scsi_set_pci_device(sh,dev) (0)
    #endif
 
    #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+      typedef void irqreturn_t;
+      #define IRQ_NONE
+      #define IRQ_HANDLED
+      #define IRQ_RETVAL(x)
       #define IPS_REGISTER_HOSTS(SHT)      scsi_register_module(MODULE_SCSI_HA,SHT)
       #define IPS_UNREGISTER_HOSTS(SHT)    scsi_unregister_module(MODULE_SCSI_HA,SHT)
       #define IPS_ADD_HOST(shost,device)
       #define IPS_REMOVE_HOST(shost)
+      #define IPS_SCSI_SET_DEVICE(sh,ha)   scsi_set_pci_device(sh, (ha)->pcidev)
+      #define IPS_PRINTK(level, pcidev, format, arg...)                 \
+            printk(level "%s %s:" format , (pcidev)->driver->name ,     \
+            (pcidev)->slot_name , ## arg)
    #else
       #define IPS_REGISTER_HOSTS(SHT)      (!ips_detect(SHT))
       #define IPS_UNREGISTER_HOSTS(SHT)
       #define IPS_ADD_HOST(shost,device)   scsi_add_host(shost,device)
       #define IPS_REMOVE_HOST(shost)       scsi_remove_host(shost)
+      #define IPS_SCSI_SET_DEVICE(sh,ha)   scsi_set_device(sh, &(ha)->pcidev->dev)
+      #define IPS_PRINTK(level, pcidev, format, arg...)                 \
+            dev_printk(level , &((pcidev)->dev) , format , ## arg)
    #endif
 
    #ifndef MDELAY
@@ -445,47 +453,10 @@
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
    static void ips_select_queue_depth(struct Scsi_Host *, Scsi_Device *);
    static int ips_biosparam(Disk *disk, kdev_t dev, int geom[]);
-#define IPS {	\
-	.detect				= ips_detect,	\
-	.release			= ips_release,	\
-	.info				= ips_info,	\
-	.queuecommand			= ips_queue,	\
-	.eh_abort_handler		= ips_eh_abort,	\
-	.eh_host_reset_handler		= ips_eh_reset,	\
-	.bios_param			= ips_biosparam,\
-	.select_queue_depths		= ips_select_queue_depth, \
-	.can_queue			= 0,		\
-	.this_id			= -1,		\
-	.sg_tablesize			= IPS_MAX_SG,	\
-	.cmd_per_lun			= 16,		\
-	.present			= 0,		\
-	.unchecked_isa_dma		= 0,		\
-	.use_clustering			= ENABLE_CLUSTERING,\
-	.use_new_eh_code		= 1, \
-	IPS_HIGHMEM_IO \
-}
 #else
    static int ips_biosparam(struct scsi_device *sdev, struct block_device *bdev,
 		sector_t capacity, int geom[]);
    int ips_slave_configure(Scsi_Device *SDptr);
-#define IPS {	\
-	.detect			= ips_detect,		\
-	.release		= ips_release,		\
-	.info			= ips_info,		\
-	.queuecommand		= ips_queue,		\
-	.eh_abort_handler	= ips_eh_abort,		\
-	.eh_host_reset_handler	= ips_eh_reset,		\
-	.slave_configure	= ips_slave_configure,	\
-	.bios_param		= ips_biosparam,	\
-	.can_queue		= 0,			\
-	.this_id		= -1,			\
-	.sg_tablesize		= IPS_MAX_SG,		\
-	.cmd_per_lun		= 3,			\
-	.present		= 0,			\
-	.unchecked_isa_dma	= 0,			\
-	.use_clustering		= ENABLE_CLUSTERING,	\
-	.highmem_io		= 1 \
-}
 #endif
 
 /*
@@ -1092,7 +1063,7 @@
    int       (*programbios)(struct ips_ha *, char *, uint32_t, uint32_t);
    int       (*verifybios)(struct ips_ha *, char *, uint32_t, uint32_t);
    void      (*statinit)(struct ips_ha *);
-   void      (*intr)(struct ips_ha *);
+   int       (*intr)(struct ips_ha *);
    void      (*enableint)(struct ips_ha *);
    uint32_t (*statupd)(struct ips_ha *);
 } ips_hw_func_t;
diff -Nru a/drivers/scsi/lasi700.c b/drivers/scsi/lasi700.c
--- a/drivers/scsi/lasi700.c	Sun Apr 13 06:26:12 2003
+++ b/drivers/scsi/lasi700.c	Sun May  4 02:56:44 2003
@@ -208,6 +208,11 @@
 	return 1;
 }
 
-static Scsi_Host_Template driver_template = LASI700_SCSI;
-
+static Scsi_Host_Template driver_template = {
+	.name		= "LASI SCSI 53c700",
+	.proc_name	= "lasi700",
+	.detect		= lasi700_detect,
+	.release	= lasi700_release,
+	.this_id	= 7,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/lasi700.h b/drivers/scsi/lasi700.h
--- a/drivers/scsi/lasi700.h	Mon Dec 23 10:33:04 2002
+++ b/drivers/scsi/lasi700.h	Sun May  4 02:56:44 2003
@@ -29,15 +29,6 @@
 static int lasi700_driver_callback(struct parisc_device *dev);
 static int lasi700_release(struct Scsi_Host *host);
 
-
-#define LASI700_SCSI {				\
-	.name		= "LASI SCSI 53c700",	\
-	.proc_name	= "lasi700",		\
-	.detect		= lasi700_detect,		\
-	.release	= lasi700_release,	\
-	.this_id	= 7,			\
-}
-
 #define LASI_710_SVERSION	0x082
 #define LASI_700_SVERSION	0x071
 
diff -Nru a/drivers/scsi/mac53c94.c b/drivers/scsi/mac53c94.c
--- a/drivers/scsi/mac53c94.c	Sat Feb  8 21:38:15 2003
+++ b/drivers/scsi/mac53c94.c	Wed Apr 23 06:09:39 2003
@@ -59,7 +59,7 @@
 static void mac53c94_init(struct fsc_state *);
 static void mac53c94_start(struct fsc_state *);
 static void mac53c94_interrupt(int, void *, struct pt_regs *);
-static void do_mac53c94_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t do_mac53c94_interrupt(int, void *, struct pt_regs *);
 static void cmd_done(struct fsc_state *, int result);
 static void set_dma_cmds(struct fsc_state *, Scsi_Cmnd *);
 static int data_goes_out(Scsi_Cmnd *);
@@ -316,7 +316,7 @@
 		set_dma_cmds(state, cmd);
 }
 
-static void
+static irqreturn_t
 do_mac53c94_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	unsigned long flags;
@@ -325,6 +325,7 @@
 	spin_lock_irqsave(dev->host_lock, flags);
 	mac53c94_interrupt(irq, dev_id, ptregs);
 	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
 }
 
 static void
diff -Nru a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
--- a/drivers/scsi/megaraid.c	Sat Apr 26 13:49:01 2003
+++ b/drivers/scsi/megaraid.c	Sat May 17 14:09:51 2003
@@ -4664,7 +4664,7 @@
 
 	mbox = (mbox_t *)raw_mbox;
 
-	memset(mbox, 0, sizeof(mbox));
+	memset(mbox, 0, sizeof(*mbox));
 
 	memset((void *)adapter->mega_buffer, 0, MEGA_BUFFER_SIZE);
 
@@ -4697,7 +4697,7 @@
 
 	mbox = (mbox_t *)raw_mbox;
 
-	memset(mbox, 0, sizeof(mbox));
+	memset(mbox, 0, sizeof(*mbox));
 
 	/*
 	 * issue command to find out what channels are raid/scsi
@@ -4818,7 +4818,7 @@
 
 	mbox = (mbox_t *)raw_mbox;
 
-	memset(mbox, 0, sizeof(mbox));
+	memset(mbox, 0, sizeof(*mbox));
 
 	/*
 	 * issue command
@@ -4847,7 +4847,7 @@
 
 	mbox = (mbox_t *)raw_mbox;
 
-	memset(mbox, 0, sizeof (mbox));
+	memset(mbox, 0, sizeof(*mbox));
 	/*
 	 * issue command to find out if controller supports extended CDBs.
 	 */
@@ -5377,9 +5377,27 @@
 	kfree(pdev);
 }
 
-
-static Scsi_Host_Template driver_template = MEGARAID;
-
+static Scsi_Host_Template driver_template = {
+	.name =				"MegaRAID",
+	.proc_info =			megaraid_proc_info,
+	.detect =			megaraid_detect,
+	.release =			megaraid_release,
+	.info =				megaraid_info,
+	.command =			megaraid_command,
+	.queuecommand =			megaraid_queue,	
+	.bios_param =			megaraid_biosparam,
+	.max_sectors =			MAX_SECTORS_PER_IO,
+	.can_queue =			MAX_COMMANDS,
+	.this_id =			DEFAULT_INITIATOR_ID,
+	.sg_tablesize =			MAX_SGLIST,
+	.cmd_per_lun =			DEF_CMD_PER_LUN,
+	.use_clustering =		ENABLE_CLUSTERING,
+	.eh_abort_handler =		megaraid_abort,
+	.eh_device_reset_handler =	megaraid_reset,
+	.eh_bus_reset_handler =		megaraid_reset,
+	.eh_host_reset_handler =	megaraid_reset,
+	.highmem_io =			1,
+};
 #include "scsi_module.c"
 
 /* vi: set ts=8 sw=8 tw=78: */
diff -Nru a/drivers/scsi/megaraid.h b/drivers/scsi/megaraid.h
--- a/drivers/scsi/megaraid.h	Thu Apr 24 06:40:49 2003
+++ b/drivers/scsi/megaraid.h	Sun May  4 02:56:44 2003
@@ -121,33 +121,6 @@
 #define NVIRT_CHAN		4	/* # of virtual channels to represent
 					   up to 60 logical drives */
 
-#define MEGARAID						\
-{								\
-	.name =				"MegaRAID",		\
-	.proc_info =			megaraid_proc_info,	\
-	.detect =			megaraid_detect,	\
-	.release =			megaraid_release,	\
-	.info =				megaraid_info,		\
-	.command =			megaraid_command,	\
-	.queuecommand =			megaraid_queue,		\
-	.bios_param =			megaraid_biosparam,	\
-	.max_sectors =			MAX_SECTORS_PER_IO,	\
-	.can_queue =			MAX_COMMANDS,		\
-	.this_id =			DEFAULT_INITIATOR_ID,	\
-	.sg_tablesize =			MAX_SGLIST,		\
-	.cmd_per_lun =			DEF_CMD_PER_LUN,	\
-	.present =  			0,			\
-	.unchecked_isa_dma =		0,			\
-	.use_clustering =		ENABLE_CLUSTERING,	\
-	.eh_abort_handler =		megaraid_abort,		\
-	.eh_device_reset_handler =	megaraid_reset,		\
-	.eh_bus_reset_handler =		megaraid_reset,		\
-	.eh_host_reset_handler =	megaraid_reset,		\
-	.highmem_io =			1,			\
-}
-
-
-
 typedef struct {
 	/* 0x0 */ u8 cmd;
 	/* 0x1 */ u8 cmdid;
diff -Nru a/drivers/scsi/mesh.c b/drivers/scsi/mesh.c
--- a/drivers/scsi/mesh.c	Sat Feb  8 21:38:15 2003
+++ b/drivers/scsi/mesh.c	Wed Apr 23 06:09:26 2003
@@ -212,7 +212,7 @@
 static void handle_error(struct mesh_state *);
 static void handle_exception(struct mesh_state *);
 static void mesh_interrupt(int, void *, struct pt_regs *);
-static void do_mesh_interrupt(int, void *, struct pt_regs *);
+static irqreturn_t do_mesh_interrupt(int, void *, struct pt_regs *);
 static void handle_msgin(struct mesh_state *);
 static void mesh_done(struct mesh_state *, int);
 static void mesh_completed(struct mesh_state *, Scsi_Cmnd *);
@@ -1471,7 +1471,7 @@
 	out_8(&mr->sequence, SEQ_ENBRESEL);
 }
 
-static void
+static irqreturn_t
 do_mesh_interrupt(int irq, void *dev_id, struct pt_regs *ptregs)
 {
 	unsigned long flags;
@@ -1480,6 +1480,7 @@
 	spin_lock_irqsave(dev->host_lock, flags);
 	mesh_interrupt(irq, dev_id, ptregs);
 	spin_unlock_irqrestore(dev->host_lock, flags);
+	return IRQ_HANDLED;
 }
 
 static void handle_error(struct mesh_state *ms)
diff -Nru a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
--- a/drivers/scsi/ncr53c8xx.c	Sat Apr 26 07:28:25 2003
+++ b/drivers/scsi/ncr53c8xx.c	Tue May  6 12:54:34 2003
@@ -9430,18 +9430,6 @@
 */
 int __init ncr53c8xx_detect(Scsi_Host_Template *tpnt)
 {
-	/*
-	**    Initialize driver general stuff.
-	*/
-#ifdef SCSI_NCR_PROC_INFO_SUPPORT
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,27)
-     tpnt->proc_dir  = &proc_scsi_ncr53c8xx;
-#else
-     tpnt->proc_name = NAME53C8XX;
-#endif
-     tpnt->proc_info = ncr53c8xx_proc_info;
-#endif
-
 #if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
 if (ncr53c8xx)
 	ncr53c8xx_setup(ncr53c8xx);
@@ -9467,29 +9455,27 @@
 */
 MODULE_LICENSE("GPL");
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-static
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) || defined(MODULE)
+static Scsi_Host_Template driver_template =  {
 #ifdef ENABLE_SCSI_ZALON
-Scsi_Host_Template driver_template =  {
-	.proc_name =		"zalon720",
-	.detect =		zalon7xx_detect,
-	.release =		zalon7xx_release,
-	.info =			ncr53c8xx_info,
-	.queuecommand =		ncr53c8xx_queue_command,
-	.slave_configure =	ncr53c8xx_slave_configure,
-	.eh_bus_reset_handler =	ncr53c8xx_bus_reset,
-	.can_queue =		SCSI_NCR_CAN_QUEUE,
-	.this_id =		7,
-	.sg_tablesize =		SCSI_NCR_SG_TABLESIZE,
-	.cmd_per_lun =		SCSI_NCR_CMD_PER_LUN,
-	.use_clustering =	DISABLE_CLUSTERING,
-};
-
-
+	.proc_name		= "zalon720",
+	.detect			= zalon7xx_detect,
+	.release		= zalon7xx_release,
 #else
-Scsi_Host_Template driver_template = NCR53C8XX;
+	.proc_name		= NAME53C8XX,
+	.detect			= ncr53c8xx_detect,
+	.release		= ncr53c8xx_release,
 #endif
-#include "scsi_module.c"
+#ifdef SCSI_NCR_PROC_INFO_SUPPORT
+	.proc_info		= ncr53c8xx_proc_info,
 #endif
+	.info			= ncr53c8xx_info,
+	.queuecommand		= ncr53c8xx_queue_command,
+	.slave_configure	= ncr53c8xx_slave_configure,
+	.eh_bus_reset_handler	= ncr53c8xx_bus_reset,
+	.can_queue		= SCSI_NCR_CAN_QUEUE,
+	.this_id		= 7,
+	.sg_tablesize		= SCSI_NCR_SG_TABLESIZE,
+	.cmd_per_lun		= SCSI_NCR_CMD_PER_LUN,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff -Nru a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
--- a/drivers/scsi/ncr53c8xx.h	Tue Apr 22 13:52:48 2003
+++ b/drivers/scsi/ncr53c8xx.h	Sun May  4 02:56:44 2003
@@ -44,38 +44,4 @@
 
 #include "sym53c8xx_defs.h"
 
-/*
-**	Define Scsi_Host_Template parameters
-**
-**	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 *);
-int ncr53c8xx_detect(Scsi_Host_Template *tpnt);
-const char *ncr53c8xx_info(struct Scsi_Host *host);
-int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int);
-int ncr53c8xx_slave_configure(Scsi_Device *);
-int ncr53c8xx_release(struct Scsi_Host *);
-
-
-#define NCR53C8XX {     .name           = "ncr53c8xx",		\
-			.detect         = ncr53c8xx_detect,	\
-			.release        = ncr53c8xx_release,	\
-			.info           = ncr53c8xx_info, 	\
-			.queuecommand   = ncr53c8xx_queue_command,\
-			.slave_configure = ncr53c8xx_slave_configure,\
-			.eh_bus_reset_handler = ncr53c8xx_bus_reset,	\
-			.can_queue      = SCSI_NCR_CAN_QUEUE,	\
-			.this_id        = 7,			\
-			.sg_tablesize   = SCSI_NCR_SG_TABLESIZE,	\
-			.cmd_per_lun    = SCSI_NCR_CMD_PER_LUN,	\
-			.use_clustering = DISABLE_CLUSTERING} 
-
-#endif /* defined(HOSTS_C) || defined(MODULE) */ 
-
 #endif /* NCR53C8XX_H */
diff -Nru a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
--- a/drivers/scsi/nsp32.c	Sat Apr 26 07:28:25 2003
+++ b/drivers/scsi/nsp32.c	Thu May  8 11:24:14 2003
@@ -2420,7 +2420,6 @@
 static void nsp32_msgout_occur(nsp32_hw_data *data)
 {
 	unsigned int base = data->BaseAddress;
-	unsigned short command;
 	long new_sgtp;
 	int i;
 	
diff -Nru a/drivers/scsi/osst.c b/drivers/scsi/osst.c
--- a/drivers/scsi/osst.c	Fri Apr 18 08:58:31 2003
+++ b/drivers/scsi/osst.c	Mon May 12 20:52:55 2003
@@ -5397,15 +5397,10 @@
 	if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
 		return 1;
 
-	if (scsi_slave_attach(SDp)) {
-		printk(KERN_ERR "osst :E: Failed to attach scsi slave.\n");
-		return 1;
-	}
-
 	drive = alloc_disk(1);
 	if (!drive) {
 		printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
-		goto out_slave_detach;
+		return 1;
 	}
 
 	/* if this is the first attach, build the infrastructure */
@@ -5527,11 +5522,10 @@
 	write_unlock(&os_scsi_tapes_lock);
 
 	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-		char name[8], devfs_name[64];
+		char name[8];
 
 		/*  Rewind entry  */
 		sprintf(name, "ot%s", osst_formats[mode]);
-		sprintf(devfs_name, "%s/ot%s", SDp->devfs_name, osst_formats[mode]);
 
 		sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
 				SDp->sdev_driverfs_dev.bus_id, name);
@@ -5545,13 +5539,13 @@
 		device_create_file(&tpnt->driverfs_dev_r[mode], 
 				&dev_attr_type);
 		device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
-		devfs_register(NULL, devfs_name, 0,
-					OSST_MAJOR, dev_num + (mode << 5),
-					S_IFCHR | S_IRUGO | S_IWUGO,
-					&osst_fops, NULL);
+
+		devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5)),
+				S_IFCHR | S_IRUGO | S_IWUGO,
+				"%s/ot%s", SDp->devfs_name, osst_formats[mode]);
+
 		/*  No-rewind entry  */
 		sprintf (name, "ot%sn", osst_formats[mode]);
-		sprintf(devfs_name, "%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
 
 		sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", 
 				SDp->sdev_driverfs_dev.bus_id, name);
@@ -5566,10 +5560,10 @@
 				&dev_attr_type);
 		device_create_file(&tpnt->driverfs_dev_n[mode], 
 				&dev_attr_kdev);
-		devfs_register(NULL, devfs_name, 0,
-					OSST_MAJOR, dev_num + (mode << 5) + 128,
-					S_IFCHR | S_IRUGO | S_IWUGO,
-					&osst_fops, NULL);
+
+		devfs_mk_cdev(MKDEV(OSST_MAJOR, dev_num + (mode << 5) + 128),
+				S_IFCHR | S_IRUGO | S_IWUGO,
+				"%s/ot%sn", SDp->devfs_name, osst_formats[mode]);
 	}
 	drive->number = devfs_register_tape(SDp->devfs_name);
 
@@ -5581,8 +5575,6 @@
 
 out_put_disk:
         put_disk(drive);
-out_slave_detach:
-        scsi_slave_detach(SDp);
         return 1;
 };
 
@@ -5605,7 +5597,6 @@
 		devfs_unregister_tape(tpnt->drive->number);
 		put_disk(tpnt->drive);
 		os_scsi_tapes[i] = NULL;
-		scsi_slave_detach(SDp);
 		osst_nr_dev--;
 		write_unlock(&os_scsi_tapes_lock);
 		for (mode = 0; mode < ST_NBR_MODES; ++mode) {
diff -Nru a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
--- a/drivers/scsi/pas16.c	Thu Apr 24 05:16:59 2003
+++ b/drivers/scsi/pas16.c	Sun May  4 02:56:44 2003
@@ -600,9 +600,21 @@
 
 #include "NCR5380.c"
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = MV_PAS16;
-
+static Scsi_Host_Template driver_template = {
+	.name           = "Pro Audio Spectrum-16 SCSI",
+	.detect         = pas16_detect,
+	.queuecommand   = pas16_queue_command,
+	.eh_abort_handler = pas16_abort,
+	.eh_bus_reset_handler = pas16_bus_reset,
+	.eh_device_reset_handler = pas16_device_reset,
+	.eh_host_reset_handler = pas16_host_reset,
+	.bios_param     = pas16_biosparam, 
+	.can_queue      = CAN_QUEUE,
+	.this_id        = 7,
+	.sg_tablesize   = SG_ALL,
+	.cmd_per_lun    = CMD_PER_LUN,
+	.use_clustering = DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
 
 #ifdef MODULE
diff -Nru a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
--- a/drivers/scsi/pas16.h	Tue Dec 10 12:28:34 2002
+++ b/drivers/scsi/pas16.h	Sun May  4 02:56:44 2003
@@ -137,27 +137,6 @@
 #define CAN_QUEUE 32 
 #endif
 
-/* 
- * I hadn't thought of this with the earlier drivers - but to prevent
- * macro definition conflicts, we shouldn't define all of the internal
- * macros when this is being used solely for the host stub.
- */
-
-#define MV_PAS16 {					\
-	.name           = "Pro Audio Spectrum-16 SCSI", 	\
-	.detect         = pas16_detect, 			\
-	.queuecommand   = pas16_queue_command,		\
-	.eh_abort_handler = pas16_abort,			\
-	.eh_bus_reset_handler = pas16_bus_reset,		\
-	.eh_device_reset_handler = pas16_device_reset,	\
-	.eh_host_reset_handler = pas16_host_reset,	\
-	.bios_param     = pas16_biosparam, 		\
-	.can_queue      = CAN_QUEUE,			\
-	.this_id        = 7,				\
-	.sg_tablesize   = SG_ALL,				\
-	.cmd_per_lun    = CMD_PER_LUN ,			\
-	.use_clustering = DISABLE_CLUSTERING}
-
 #ifndef HOSTS_C
 
 #define NCR5380_implementation_fields \
diff -Nru a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
--- a/drivers/scsi/pci2000.c	Sat Apr 26 07:28:25 2003
+++ b/drivers/scsi/pci2000.c	Sun May  4 02:56:44 2003
@@ -857,7 +857,21 @@
 
 
 MODULE_LICENSE("Dual BSD/GPL");
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = PCI2000;
 
+static Scsi_Host_Template driver_template = {
+	.proc_name	= "pci2000",
+	.name		= "PCI-2000 SCSI Intelligent Disk Controller",
+	.detect		= Pci2000_Detect,
+	.release	= Pci2000_Release,
+	.command	= Pci2000_Command,
+	.queuecommand	= Pci2000_QueueCommand,
+	.abort		= Pci2000_Abort,
+	.reset		= Pci2000_Reset,
+	.bios_param	= Pci2000_BiosParam,
+	.can_queue	= 16,
+	.this_id	= -1,
+	.sg_tablesize	= 16,
+	.cmd_per_lun	= 1,
+	.use_clustering	= DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
--- a/drivers/scsi/pci2000.h	Fri Jan  3 09:19:16 2003
+++ b/drivers/scsi/pci2000.h	Sun May  4 02:56:44 2003
@@ -201,24 +201,4 @@
 	#define NULL 0
 #endif
 
-/* screen is 80 columns wide, damnit! */
-#define PCI2000 {				                        \
-	.proc_name	= "pci2000",					\
-	.name		= "PCI-2000 SCSI Intelligent Disk Controller",	\
-	.detect		= Pci2000_Detect,				\
-	.release	= Pci2000_Release,				\
-	.command	= Pci2000_Command,				\
-	.queuecommand	= Pci2000_QueueCommand,				\
-	.abort		= Pci2000_Abort,				\
-	.reset		= Pci2000_Reset,				\
-	.bios_param	= Pci2000_BiosParam,				\
-	.can_queue	= 16,						\
-	.this_id	= -1,						\
-	.sg_tablesize	= 16,						\
-	.cmd_per_lun	= 1,						\
-	.present	= 0,						\
-	.unchecked_isa_dma = 0,						\
-	.use_clustering	= DISABLE_CLUSTERING,				\
-}
-
 #endif
diff -Nru a/drivers/scsi/pci2220i.c b/drivers/scsi/pci2220i.c
--- a/drivers/scsi/pci2220i.c	Sat Apr 26 07:28:26 2003
+++ b/drivers/scsi/pci2220i.c	Sun May  4 02:56:44 2003
@@ -2925,7 +2925,20 @@
 
 MODULE_LICENSE("Dual BSD/GPL");
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = PCI2220I;
-
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "pci2220i",
+	.name			= "PCI-2220I/PCI-2240I",
+	.detect			= Pci2220i_Detect,
+	.release		= Pci2220i_Release,
+	.command		= Pci2220i_Command,
+	.queuecommand		= Pci2220i_QueueCommand,
+	.abort			= Pci2220i_Abort,
+	.reset			= Pci2220i_Reset,
+	.bios_param		= Pci2220i_BiosParam,
+	.can_queue		= 1,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h
--- a/drivers/scsi/pci2220i.h	Tue Dec 10 12:28:34 2002
+++ b/drivers/scsi/pci2220i.h	Sun May  4 02:56:44 2003
@@ -40,23 +40,4 @@
 #ifndef NULL
 	#define NULL 0
 #endif
-
-#define PCI2220I {					\
-	.proc_name		= "pci2220i",		\
-	.name			= "PCI-2220I/PCI-2240I",	\
-	.detect			= Pci2220i_Detect,	\
-	.release		= Pci2220i_Release,	\
-	.command		= Pci2220i_Command,	\
-	.queuecommand		= Pci2220i_QueueCommand,	\
-	.abort			= Pci2220i_Abort,		\
-	.reset			= Pci2220i_Reset,		\
-	.bios_param		= Pci2220i_BiosParam,	\
-	.can_queue		= 1,			\
-	.this_id		= -1,			\
-	.sg_tablesize		= SG_ALL,			\
-	.cmd_per_lun		= 1,			\
-	.present		= 0,			\
-	.unchecked_isa_dma	= 0,			\
-	.use_clustering		= DISABLE_CLUSTERING,	\
-}
 #endif
diff -Nru a/drivers/scsi/pcmcia/aha152x_stub.c b/drivers/scsi/pcmcia/aha152x_stub.c
--- a/drivers/scsi/pcmcia/aha152x_stub.c	Sat Apr 26 09:16:26 2003
+++ b/drivers/scsi/pcmcia/aha152x_stub.c	Thu May  1 09:44:51 2003
@@ -98,9 +98,8 @@
 
 typedef struct scsi_info_t {
     dev_link_t		link;
+    dev_node_t		node;
     struct Scsi_Host	*host;
-    int			ndev;
-    dev_node_t		node[8];
 } scsi_info_t;
 
 static void aha152x_release_cs(u_long arg);
@@ -217,8 +216,6 @@
     cisparse_t parse;
     int i, last_ret, last_fn;
     u_char tuple_data[64];
-    struct scsi_device *dev;
-    dev_node_t *node, **tail;
     struct Scsi_Host *host;
     
     DEBUG(0, "aha152x_config(0x%p)\n", link);
@@ -275,9 +272,6 @@
     if (ext_trans)
         s.ext_trans = ext_trans;
 
-    tail = &link->dev;
-    info->ndev = 0;
-
     host = aha152x_probe_one(&s);
     if (host == NULL) {
 	printk(KERN_INFO "aha152x_cs: no SCSI devices found\n");
@@ -286,39 +280,10 @@
 
     scsi_add_host(host, NULL);
 
-    list_for_each_entry(dev, &host->my_devices, siblings) {
-	    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 = &info->node[info->ndev];
-	    node->minor = 0;
-	    switch (dev->type) {
-	    case TYPE_TAPE:
-		node->major = SCSI_TAPE_MAJOR;
-		sprintf(node->dev_name, "st#%04lx", id);
-		break;
-	    case TYPE_DISK:
-	    case TYPE_MOD:
-		node->major = SCSI_DISK0_MAJOR;
-		sprintf(node->dev_name, "sd#%04lx", id);
-		break;
-	    case TYPE_ROM:
-	    case TYPE_WORM:
-		node->major = SCSI_CDROM_MAJOR;
-		sprintf(node->dev_name, "sr#%04lx", id);
-		break;
-	    default:
-		node->major = SCSI_GENERIC_MAJOR;
-		sprintf(node->dev_name, "sg#%04lx", id);
-		break;
-	    }
-	    *tail = node; tail = &node->next;
-	    info->ndev++;
-	    info->host = dev->host;
-    }
+    sprintf(info->node.dev_name, "scsi%d", host->host_no);
+    link->dev = &info->node;
+    info->host = host;
 
-    *tail = NULL;
     link->state &= ~DEV_CONFIG_PENDING;
     return;
     
diff -Nru a/drivers/scsi/pcmcia/fdomain_stub.c b/drivers/scsi/pcmcia/fdomain_stub.c
--- a/drivers/scsi/pcmcia/fdomain_stub.c	Sat Apr 26 09:16:26 2003
+++ b/drivers/scsi/pcmcia/fdomain_stub.c	Thu May  1 09:44:52 2003
@@ -81,9 +81,8 @@
 
 typedef struct scsi_info_t {
     dev_link_t		link;
+    dev_node_t		node;
     struct Scsi_Host	*host;
-    int			ndev;
-    dev_node_t		node[8];
 } scsi_info_t;
 
 extern Scsi_Host_Template fdomain_driver_template;
@@ -206,8 +205,6 @@
     cisparse_t parse;
     int i, last_ret, last_fn, ints[3];
     u_char tuple_data[64];
-    Scsi_Device *dev;
-    dev_node_t *node, **tail;
     char str[16];
     struct Scsi_Host *host;
 
@@ -259,42 +256,8 @@
  
     scsi_add_host(host, NULL);
 
-    tail = &link->dev;
-    info->ndev = 0;
-   
-    list_for_each_entry (dev, &host->my_devices, siblings) {
-	    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 = &info->node[info->ndev];
-	    node->minor = 0;
-	    switch (dev->type) {
-	    case TYPE_TAPE:
-		node->major = SCSI_TAPE_MAJOR;
-		sprintf(node->dev_name, "st#%04lx", id);
-		break;
-	    case TYPE_DISK:
-	    case TYPE_MOD:
-		node->major = SCSI_DISK0_MAJOR;
-		sprintf(node->dev_name, "sd#%04lx", id);
-		break;
-	    case TYPE_ROM:
-	    case TYPE_WORM:
-		node->major = SCSI_CDROM_MAJOR;
-		sprintf(node->dev_name, "sr#%04lx", id);
-		break;
-	    default:
-		node->major = SCSI_GENERIC_MAJOR;
-		sprintf(node->dev_name, "sg#%04lx", id);
-		break;
-	    }
-	    *tail = node; tail = &node->next;
-	    info->ndev++;
-
-    }
-
-    *tail = NULL;
+    sprintf(info->node.dev_name, "scsi%d", host->host_no);
+    link->dev = &info->node;
     info->host = host;
     
     link->state &= ~DEV_CONFIG_PENDING;
diff -Nru a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
--- a/drivers/scsi/pcmcia/nsp_cs.c	Sat Apr 26 09:16:26 2003
+++ b/drivers/scsi/pcmcia/nsp_cs.c	Thu May  1 09:44:53 2003
@@ -88,9 +88,8 @@
 
 typedef struct scsi_info_t {
 	dev_link_t             link;
+	dev_node_t	       node;
 	struct Scsi_Host      *host;
-	int	               ndev;
-	dev_node_t             node[8];
 	int                    stop;
 } scsi_info_t;
 
@@ -1621,8 +1620,6 @@
 	memreq_t          map;
 	cistpl_cftable_entry_t dflt = { 0 };
 
-	Scsi_Device	 *dev;
-	dev_node_t	**tail, *node;
 	struct Scsi_Host *host;
 	nsp_hw_data      *data = &nsp_data;
 
@@ -1762,58 +1759,13 @@
 		goto cs_failed;
 	}
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,2))
 	host = __nsp_detect(&nsp_driver_template);
-#else
-	scsi_register_module(MODULE_SCSI_HA, &nsp_driver_template);
-	for (host = scsi_hostlist; host != NULL; host = host->next) {
-		if (host->hostt == &nsp_driver_template)
-			break;
-#endif
-
 	if (!host)
 		goto cs_failed;
 
-	DEBUG(0, "GET_SCSI_INFO\n");
-	tail = &link->dev;
-	info->ndev = 0;
-
-	list_for_each_entry (dev, &host->my_devices, siblings) {
-		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 = &info->node[info->ndev];
-		node->minor = 0;
-		switch (dev->type) {
-		case TYPE_TAPE:
-			node->major = SCSI_TAPE_MAJOR;
-			sprintf(node->dev_name, "st#%04lx", id);
-			break;
-		case TYPE_DISK:
-		case TYPE_MOD:
-			node->major = SCSI_DISK0_MAJOR;
-			sprintf(node->dev_name, "sd#%04lx", id);
-			break;
-		case TYPE_ROM:
-		case TYPE_WORM:
-			node->major = SCSI_CDROM_MAJOR;
-			sprintf(node->dev_name, "sr#%04lx", id);
-			break;
-		default:
-			node->major = SCSI_GENERIC_MAJOR;
-			sprintf(node->dev_name, "sg#%04lx", id);
-			break;
-		}
-		*tail = node; tail = &node->next;
-		info->ndev++;
-		info->host = dev->host;
-	}
-
-	*tail = NULL;
-	if (info->ndev == 0) {
-		printk(KERN_INFO "nsp_cs: no SCSI devices found\n");
-	}
+	sprintf(info->node.dev_name, "scsi%d", host->host_no);
+	link->dev = &info->node;
+	info->host = host;
 
 	/* Finally, report what we've done */
 	printk(KERN_INFO "nsp_cs: index 0x%02x: Vcc %d.%d",
@@ -1837,10 +1789,7 @@
 		       req.Base+req.Size-1);
 	printk("\n");
 
-#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
 	scsi_add_host(host, NULL);
-#endif
-
 	link->state &= ~DEV_CONFIG_PENDING;
 	return;
 
diff -Nru a/drivers/scsi/pcmcia/qlogic_stub.c b/drivers/scsi/pcmcia/qlogic_stub.c
--- a/drivers/scsi/pcmcia/qlogic_stub.c	Sat Apr 26 09:16:27 2003
+++ b/drivers/scsi/pcmcia/qlogic_stub.c	Thu May  1 09:44:53 2003
@@ -85,10 +85,9 @@
 
 typedef struct scsi_info_t {
 	dev_link_t link;
+	dev_node_t node;
 	struct Scsi_Host *host;
 	unsigned short manf_id;
-	int ndev;
-	dev_node_t node[8];
 } scsi_info_t;
 
 static void qlogic_release(u_long arg);
@@ -205,8 +204,6 @@
 	cisparse_t parse;
 	int i, last_ret, last_fn;
 	unsigned short tuple_data[32];
-	Scsi_Device *dev;
-	dev_node_t **tail, *node;
 	struct Scsi_Host *host;
 
 	DEBUG(0, "qlogic_config(0x%p)\n", link);
@@ -263,50 +260,17 @@
 	else
 		qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ);
 
-	tail = &link->dev;
-	info->ndev = 0;
-
 	host = __qlogicfas_detect(&qlogicfas_driver_template);
 	if (!host) {
 		printk(KERN_INFO "qlogic_cs: no SCSI devices found\n");
 		goto out;
 	}
 
-	scsi_add_host(host, NULL);
-
-	list_for_each_entry(dev, &host->my_devices, siblings) {
-		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 = &info->node[info->ndev];
-		node->minor = 0;
-		switch (dev->type) {
-		case TYPE_TAPE:
-			node->major = SCSI_TAPE_MAJOR;
-			sprintf(node->dev_name, "st#%04lx", id);
-			break;
-		case TYPE_DISK:
-		case TYPE_MOD:
-			node->major = SCSI_DISK0_MAJOR;
-			sprintf(node->dev_name, "sd#%04lx", id);
-			break;
-		case TYPE_ROM:
-		case TYPE_WORM:
-			node->major = SCSI_CDROM_MAJOR;
-			sprintf(node->dev_name, "sr#%04lx", id);
-			break;
-		default:
-			node->major = SCSI_GENERIC_MAJOR;
-			sprintf(node->dev_name, "sg#%04lx", id);
-			break;
-		}
-		*tail = node;
-		tail = &node->next;
-		info->ndev++;
-	}
-
-	*tail = NULL;
+	sprintf(info->node.dev_name, "scsi%d", host->host_no);
+	link->dev = &info->node;
 	info->host = host;
+
+	scsi_add_host(host, NULL);
 
 out:
 	link->state &= ~DEV_CONFIG_PENDING;
diff -Nru a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
--- a/drivers/scsi/pluto.c	Thu Feb 20 11:26:15 2003
+++ b/drivers/scsi/pluto.c	Sun May  4 02:56:44 2003
@@ -246,11 +246,6 @@
 				host->max_channel = inq->channels;
 				host->irq = fc->irq;
 
-#ifdef __sparc_v9__
-				host->unchecked_isa_dma = 1;
-#endif
-
-
 				fc->channels = inq->channels + 1;
 				fc->targets = inq->targets;
 				fc->ages = ages;
@@ -345,7 +340,23 @@
 	return 0;
 }
 
-static Scsi_Host_Template driver_template = PLUTO;
+static Scsi_Host_Template driver_template = {
+	.name			= "Sparc Storage Array 100/200",
+	.detect			= pluto_detect,
+	.release		= pluto_release,
+	.info			= pluto_info,
+	.queuecommand		= fcp_scsi_queuecommand,
+	.slave_configure	= pluto_slave_configure,
+	.can_queue		= PLUTO_CAN_QUEUE,
+	.this_id		= -1,
+	.sg_tablesize		= 1,
+	.cmd_per_lun		= 1,
+	.use_clustering		= ENABLE_CLUSTERING,
+	.eh_abort_handler	= fcp_scsi_abort,
+	.eh_device_reset_handler = fcp_scsi_dev_reset,
+	.eh_bus_reset_handler	= fcp_scsi_bus_reset,
+	.eh_host_reset_handler	= fcp_scsi_host_reset,
+};
 
 #include "scsi_module.c"
 
diff -Nru a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h
--- a/drivers/scsi/pluto.h	Tue Dec 10 12:28:34 2002
+++ b/drivers/scsi/pluto.h	Sun May  4 02:56:44 2003
@@ -43,23 +43,5 @@
 const char * pluto_info(struct Scsi_Host *);
 int pluto_slave_configure(Scsi_Device *);
 
-#define PLUTO {							\
-	.name			= "Sparc Storage Array 100/200",	\
-	.detect			= pluto_detect,			\
-	.release		= pluto_release,			\
-	.info			= pluto_info,			\
-	.queuecommand		= fcp_scsi_queuecommand,		\
-	.slave_configure	= pluto_slave_configure,		\
-	.can_queue		= PLUTO_CAN_QUEUE,		\
-	.this_id		= -1,				\
-	.sg_tablesize		= 1,				\
-	.cmd_per_lun		= 1,				\
-	.use_clustering		= ENABLE_CLUSTERING,		\
-	.eh_abort_handler	= fcp_scsi_abort,			\
-	.eh_device_reset_handler = fcp_scsi_dev_reset,		\
-	.eh_bus_reset_handler	= fcp_scsi_bus_reset,		\
-	.eh_host_reset_handler	= fcp_scsi_host_reset,		\
-}	
-
 #endif /* !(_PLUTO_H) */
 
diff -Nru a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
--- a/drivers/scsi/ppa.c	Tue Apr 15 04:54:34 2003
+++ b/drivers/scsi/ppa.c	Sun May  4 02:56:44 2003
@@ -97,7 +97,23 @@
  *                   Parallel port probing routines                        *
  ***************************************************************************/
 
-static Scsi_Host_Template driver_template = PPA;
+static Scsi_Host_Template driver_template = {
+	.proc_name			= "ppa",
+	.proc_info			= ppa_proc_info,
+	.name				= "Iomega VPI0 (ppa) interface",
+	.detect				= ppa_detect,
+	.release			= ppa_release,
+	.command			= ppa_command,
+	.queuecommand			= ppa_queuecommand,
+	.eh_abort_handler		= ppa_abort,
+	.eh_bus_reset_handler		= ppa_reset,
+	.eh_host_reset_handler		= ppa_reset,
+	.bios_param			= ppa_biosparam,
+	.this_id			= -1,
+	.sg_tablesize			= SG_ALL,
+	.cmd_per_lun			= 1,
+	.use_clustering			= ENABLE_CLUSTERING,
+};
 #include  "scsi_module.c"
 
 /*
diff -Nru a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
--- a/drivers/scsi/ppa.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/ppa.h	Sun May  4 02:56:44 2003
@@ -171,21 +171,4 @@
 int ppa_biosparam(struct scsi_device *, struct block_device *,
 		sector_t, int *);
 
-#define PPA {	.proc_name			= "ppa",		\
-		.proc_info			= ppa_proc_info,		\
-		.name				= "Iomega VPI0 (ppa) interface",\
-		.detect				= ppa_detect,		\
-		.release			= ppa_release,		\
-		.command			= ppa_command,		\
-		.queuecommand			= ppa_queuecommand,	\
-		.eh_abort_handler		= ppa_abort,		\
-		.eh_device_reset_handler	= NULL,			\
-		.eh_bus_reset_handler		= ppa_reset,		\
-		.eh_host_reset_handler		= ppa_reset,		\
-		.bios_param			= ppa_biosparam,		\
-		.this_id			= -1,			\
-		.sg_tablesize			= SG_ALL,			\
-		.cmd_per_lun			= 1,			\
-		.use_clustering			= ENABLE_CLUSTERING	\
-}
 #endif				/* _PPA_H */
diff -Nru a/drivers/scsi/psi240i.c b/drivers/scsi/psi240i.c
--- a/drivers/scsi/psi240i.c	Sat Apr 26 07:41:50 2003
+++ b/drivers/scsi/psi240i.c	Sun May  4 02:56:45 2003
@@ -718,8 +718,19 @@
 
 MODULE_LICENSE("GPL");
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = PSI240I;
-
+static Scsi_Host_Template driver_template = {
+	.proc_name		= "psi240i", 
+	.name			= "PSI-240I EIDE Disk Controller",
+	.detect			= Psi240i_Detect,
+	.command		= Psi240i_Command,
+	.queuecommand		= Psi240i_QueueCommand,
+	.abort	  		= Psi240i_Abort,
+	.reset	  		= Psi240i_Reset,
+	.bios_param	  	= Psi240i_BiosParam,
+	.can_queue	  	= 1,
+	.this_id	  	= -1,
+	.sg_tablesize	  	= SG_NONE,
+	.cmd_per_lun	  	= 1, 
+	.use_clustering		= DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
-
diff -Nru a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
--- a/drivers/scsi/psi240i.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/psi240i.h	Sun May  4 02:56:45 2003
@@ -320,19 +320,4 @@
 #ifndef NULL
 	#define NULL 0
 #endif
-
-#define PSI240I { .proc_name      = "psi240i", \
-		  .name           = "PSI-240I EIDE Disk Controller",\
-		  .detect         = Psi240i_Detect,			\
-		  .command	  = Psi240i_Command,			\
-		  .queuecommand	  = Psi240i_QueueCommand,		\
-		  .abort	  = Psi240i_Abort,			\
-		  .reset	  = Psi240i_Reset,			\
-		  .bios_param	  = Psi240i_BiosParam,                 	\
-		  .can_queue	  = 1, 					\
-		  .this_id	  = -1, 					\
-		  .sg_tablesize	  = SG_NONE,		 		\
-		  .cmd_per_lun	  = 1, 					\
-		  .use_clustering = DISABLE_CLUSTERING }
-
 #endif
diff -Nru a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
--- a/drivers/scsi/qla1280.c	Sun Apr 20 14:14:29 2003
+++ b/drivers/scsi/qla1280.c	Sun May  4 02:56:45 2003
@@ -5939,15 +5939,24 @@
 	return ret;
 }
 
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
-#ifdef MODULE
-Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE;
+static Scsi_Host_Template driver_template = {
+	.proc_info		= qla1280_proc_info,
+	.name			= "Qlogic ISP 1280/12160",
+	.detect			= qla1280_detect,
+	.release		= qla1280_release,
+	.info			= qla1280_info,
+	.queuecommand		= qla1280_queuecommand,
+	.abort			= qla1280_abort,
+	.reset			= qla1280_reset,
+	.slave_configure	= qla1280_slave_configure,
+	.bios_param		= qla1280_biosparam,
+	.can_queue		= 255,
+	.this_id		= -1,
+	.sg_tablesize		= SG_ALL,
+	.cmd_per_lun		= 3,
+	.use_clustering		= ENABLE_CLUSTERING,			\
+};
 #include "scsi_module.c"
-#endif
-#else				/* new kernel scsi initialization scheme */
-static Scsi_Host_Template driver_template = QLA1280_LINUX_TEMPLATE;
-#include "scsi_module.c"
-#endif
 
 /************************************************************************
  * qla1280_check_for_dead_scsi_bus                                      *
diff -Nru a/drivers/scsi/qla1280.h b/drivers/scsi/qla1280.h
--- a/drivers/scsi/qla1280.h	Sun Apr 20 14:14:29 2003
+++ b/drivers/scsi/qla1280.h	Sun May  4 02:56:45 2003
@@ -1319,31 +1319,4 @@
 irqreturn_t qla1280_intr_handler(int, void *, struct pt_regs *);
 void qla1280_setup(char *s, int *dummy);
 
-/*
- * Scsi_Host_template (see hosts.h)
- * Device driver Interfaces to mid-level SCSI driver.
- */
-
-#define QLA1280_LINUX_TEMPLATE {				\
-	.proc_info = qla1280_proc_info,				\
-	.name = "Qlogic ISP 1280/12160",				\
-	.detect = qla1280_detect,					\
-	.release = qla1280_release,				\
-	.info = qla1280_info,					\
-	.queuecommand = qla1280_queuecommand,			\
-/*	use_new_eh_code: 0, */					\
-	.abort = qla1280_abort,					\
-	.reset = qla1280_reset,					\
-	.slave_configure = qla1280_slave_configure,		\
-	.bios_param = qla1280_biosparam,				\
-	.can_queue = 255,		/* max simultaneous cmds      */\
-	.this_id = -1,		/* scsi id of host adapter    */\
-	.sg_tablesize = SG_ALL,	/* max scatter-gather cmds    */\
-	.cmd_per_lun = 3,		/* cmds per lun (linked cmds) */\
-	.present = 0,		/* number of 1280's present   */\
-	.unchecked_isa_dma = 0,	/* no memory DMA restrictions */\
-	.use_clustering = ENABLE_CLUSTERING,			\
-	.emulated = 0						\
-}
-
 #endif				/* _IO_HBA_QLA1280_H */
diff -Nru a/drivers/scsi/qlogicfc.c b/drivers/scsi/qlogicfc.c
--- a/drivers/scsi/qlogicfc.c	Sun Apr 20 23:55:02 2003
+++ b/drivers/scsi/qlogicfc.c	Sun May  4 02:56:45 2003
@@ -2228,6 +2228,18 @@
 
 MODULE_LICENSE("GPL");
 
-static Scsi_Host_Template driver_template = QLOGICFC;
-
+static Scsi_Host_Template driver_template = {
+        .detect                 = isp2x00_detect,
+        .release                = isp2x00_release,
+        .info                   = isp2x00_info,
+        .queuecommand           = isp2x00_queuecommand,
+        .eh_abort_handler       = isp2x00_abort,
+        .bios_param             = isp2x00_biosparam,
+        .can_queue              = QLOGICFC_REQ_QUEUE_LEN,
+        .this_id                = -1,
+        .sg_tablesize           = QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN),
+	.cmd_per_lun		= QLOGICFC_CMD_PER_LUN,
+        .use_clustering         = ENABLE_CLUSTERING,
+	.highmem_io		= 1,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/qlogicfc.h b/drivers/scsi/qlogicfc.h
--- a/drivers/scsi/qlogicfc.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/qlogicfc.h	Sun May  4 02:56:45 2003
@@ -82,24 +82,4 @@
 #define NULL (0)
 #endif
 
-#define QLOGICFC {							   \
-        .detect                 = isp2x00_detect,                            \
-        .release                = isp2x00_release,                           \
-        .info                   = isp2x00_info,                              \
-        .queuecommand           = isp2x00_queuecommand,                      \
-        .eh_abort_handler       = isp2x00_abort,                             \
-        .bios_param             = isp2x00_biosparam,                         \
-        .can_queue              = QLOGICFC_REQ_QUEUE_LEN,                    \
-        .this_id                = -1,                                        \
-        .sg_tablesize           = QLOGICFC_MAX_SG(QLOGICFC_REQ_QUEUE_LEN),   \
-	.cmd_per_lun		= QLOGICFC_CMD_PER_LUN, 			   \
-        .present                = 0,                                         \
-        .unchecked_isa_dma      = 0,                                         \
-        .use_clustering         = ENABLE_CLUSTERING, 			   \
-	.highmem_io		= 1					   \
-}
-
 #endif /* _QLOGICFC_H */
-
-
-
diff -Nru a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c
--- a/drivers/scsi/qlogicisp.c	Sun Apr 20 23:55:22 2003
+++ b/drivers/scsi/qlogicisp.c	Sun May  4 02:56:45 2003
@@ -1985,6 +1985,16 @@
 
 MODULE_LICENSE("GPL");
 
-static Scsi_Host_Template driver_template = QLOGICISP;
-
+static Scsi_Host_Template driver_template = {
+	.detect			= isp1020_detect,
+	.release		= isp1020_release,
+	.info			= isp1020_info,	
+	.queuecommand		= isp1020_queuecommand,
+	.bios_param		= isp1020_biosparam,
+	.can_queue		= QLOGICISP_REQ_QUEUE_LEN,
+	.this_id		= -1,
+	.sg_tablesize		= QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN),
+	.cmd_per_lun		= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/qlogicisp.h b/drivers/scsi/qlogicisp.h
--- a/drivers/scsi/qlogicisp.h	Tue Dec 10 12:28:32 2002
+++ b/drivers/scsi/qlogicisp.h	Sun May  4 02:56:45 2003
@@ -70,20 +70,4 @@
 #ifndef NULL
 #define NULL (0)
 #endif
-
-#define QLOGICISP {							   \
-	.detect			= isp1020_detect,				   \
-	.release		= isp1020_release,			   \
-	.info			= isp1020_info,				   \
-	.queuecommand		= isp1020_queuecommand,			   \
-	.bios_param		= isp1020_biosparam,			   \
-	.can_queue		= QLOGICISP_REQ_QUEUE_LEN,		   \
-	.this_id		= -1,					   \
-	.sg_tablesize		= QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
-	.cmd_per_lun		= 1,					   \
-	.present		= 0,					   \
-	.unchecked_isa_dma	= 0,					   \
-	.use_clustering		= DISABLE_CLUSTERING			   \
-}
-
 #endif /* _QLOGICISP_H */
diff -Nru a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
--- a/drivers/scsi/scsi.c	Sat Apr 26 18:20:40 2003
+++ b/drivers/scsi/scsi.c	Thu May  8 11:31:08 2003
@@ -56,6 +56,9 @@
 #include "scsi.h"
 #include "hosts.h"
 
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
 
 /*
  * Definitions and constants.
@@ -111,16 +114,6 @@
 	"Enclosure        ",
 };
 
-static const char * const spaces = "                "; /* 16 of them */
-
-static unsigned scsi_default_dev_flags;
-LIST_HEAD(scsi_dev_info_list);
-
-/* 
- * Function prototypes.
- */
-extern void scsi_times_out(struct scsi_cmnd *cmd);
-
 MODULE_PARM(scsi_logging_level, "i");
 MODULE_PARM_DESC(scsi_logging_level, "SCSI logging level; should be zero or nonzero");
 
@@ -178,6 +171,16 @@
 	return sreq;
 }
 
+void __scsi_release_request(struct scsi_request *sreq)
+{
+	if (likely(sreq->sr_command != NULL)) {
+		struct scsi_cmnd *cmd = sreq->sr_command;
+
+		sreq->sr_command = NULL;
+		scsi_next_command(cmd);
+	}
+}
+
 /*
  * Function:    scsi_release_request
  *
@@ -189,14 +192,7 @@
  */
 void scsi_release_request(struct scsi_request *sreq)
 {
-	if (likely(sreq->sr_command != NULL)) {
-    		struct request_queue *q = sreq->sr_device->request_queue;
-
-		scsi_put_command(sreq->sr_command);
-		sreq->sr_command = NULL;
-		scsi_queue_next_request(q, NULL);
-	}
-
+	__scsi_release_request(sreq);
 	kfree(sreq);
 }
 
@@ -534,7 +530,6 @@
 
 	cmd->request = sreq->sr_request;
 	memcpy(cmd->data_cmnd, sreq->sr_cmnd, sizeof(cmd->data_cmnd));
-	cmd->reset_chain = NULL;
 	cmd->serial_number = 0;
 	cmd->serial_number_at_timeout = 0;
 	cmd->bufflen = sreq->sr_bufflen;
@@ -936,250 +931,6 @@
 	return depth;
 }
 
-
-/*
- * scsi_strcpy_devinfo: called from scsi_dev_info_list_add to copy into
- * devinfo vendor and model strings.
- */
-static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
-				char *from, int compatible)
-{
-	size_t from_length;
-
-	from_length = strlen(from);
-	strncpy(to, from, min(to_length, from_length));
-	if (from_length < to_length) {
-		if (compatible) {
-			/*
-			 * NUL terminate the string if it is short.
-			 */
-			to[from_length] = '\0';
-		} else {
-			/* 
-			 * space pad the string if it is short. 
-			 */
-			strncpy(&to[from_length], spaces,
-				to_length - from_length);
-		}
-	}
-	if (from_length > to_length)
-		 printk(KERN_WARNING "%s: %s string '%s' is too long\n",
-			__FUNCTION__, name, from);
-}
-
-/**
- * scsi_dev_info_list_add: add one dev_info list entry.
- * @vendor:	vendor string
- * @model:	model (product) string
- * @strflags:	integer string
- * @flag:	if strflags NULL, use this flag value
- *
- * Description:
- * 	Create and add one dev_info entry for @vendor, @model, @strflags or
- * 	@flag. If @compatible, add to the tail of the list, do not space
- * 	pad, and set devinfo->compatible. The scsi_static_device_list entries
- * 	are added with @compatible 1 and @clfags NULL.
- *
- * Returns: 0 OK, -error on failure.
- **/
-static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
-			    char *strflags, int flags)
-{
-	struct scsi_dev_info_list *devinfo;
-
-	devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL);
-	if (!devinfo) {
-		printk(KERN_ERR "%s: no memory\n", __FUNCTION__);
-		return -ENOMEM;
-	}
-
-	scsi_strcpy_devinfo("vendor", devinfo->vendor, sizeof(devinfo->vendor),
-			    vendor, compatible);
-	scsi_strcpy_devinfo("model", devinfo->model, sizeof(devinfo->model),
-			    model, compatible);
-
-	if (strflags)
-		devinfo->flags = simple_strtoul(strflags, NULL, 0);
-	else
-		devinfo->flags = flags;
-
-	devinfo->compatible = compatible;
-
-	if (compatible)
-		list_add_tail(&devinfo->dev_info_list, &scsi_dev_info_list);
-	else
-		list_add(&devinfo->dev_info_list, &scsi_dev_info_list);
-
-	return 0;
-}
-
-/**
- * scsi_dev_info_list_add_str: parse dev_list and add to the
- * scsi_dev_info_list.
- * @dev_list:	string of device flags to add
- *
- * Description:
- * 	Parse dev_list, and add entries to the scsi_dev_info_list.
- * 	dev_list is of the form "vendor:product:flag,vendor:product:flag".
- * 	dev_list is modified via strsep. Can be called for command line
- * 	addition, for proc or mabye a sysfs interface.
- *
- * Returns: 0 if OK, -error on failure.
- **/
-int scsi_dev_info_list_add_str (char *dev_list)
-{
-	char *vendor, *model, *strflags, *next;
-	char *next_check;
-	int res = 0;
-
-	next = dev_list;
-	if (next && next[0] == '"') {
-		/*
-		 * Ignore both the leading and trailing quote.
-		 */
-		next++;
-		next_check = ",\"";
-	} else {
-		next_check = ",";
-	}
-
-	/*
-	 * For the leading and trailing '"' case, the for loop comes
-	 * through the last time with vendor[0] == '\0'.
-	 */
-	for (vendor = strsep(&next, ":"); vendor && (vendor[0] != '\0')
-	     && (res == 0); vendor = strsep(&next, ":")) {
-		strflags = NULL;
-		model = strsep(&next, ":");
-		if (model)
-			strflags = strsep(&next, next_check);
-		if (!model || !strflags) {
-			printk(KERN_ERR "%s: bad dev info string '%s' '%s'"
-			       " '%s'\n", __FUNCTION__, vendor, model,
-			       strflags);
-			res = -EINVAL;
-		} else
-			res = scsi_dev_info_list_add(0 /* compatible */, vendor,
-						     model, strflags, 0);
-	}
-	return res;
-}
-
-/**
- * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove
- * 	the scsi_dev_info_list.
- **/
-static void scsi_dev_info_list_delete (void)
-{
-	struct list_head *lh, *lh_next;
-	struct scsi_dev_info_list *devinfo;
-
-	list_for_each_safe(lh, lh_next, &scsi_dev_info_list) {
-		devinfo = list_entry(lh, struct scsi_dev_info_list,
-				     dev_info_list);
-		kfree(devinfo);
-	}
-}
-
-/**
- * scsi_dev_list_init: set up the dynamic device list.
- * @dev_list:	string of device flags to add
- *
- * Description:
- * 	Add command line @dev_list entries, then add
- * 	scsi_static_device_list entries to the scsi device info list.
- **/
-static int scsi_dev_info_list_init (char *dev_list)
-{
-	int error, i;
-
-	error = scsi_dev_info_list_add_str(dev_list);
-	if (error)
-		return error;
-
-	for (i = 0; scsi_static_device_list[i].vendor != NULL; i++) {
-		error = scsi_dev_info_list_add(1 /* compatibile */,
-				scsi_static_device_list[i].vendor,
-				scsi_static_device_list[i].model,
-				NULL,
-				scsi_static_device_list[i].flags);
-		if (error)
-			break;
-	}
-
-	if (error)
-		scsi_dev_info_list_delete();
-	return error;
-}
-
-/**
- * get_device_flags - get device specific flags from the dynamic device
- * list. Called during scan time.
- * @vendor:	vendor name
- * @model:	model name
- *
- * Description:
- *     Search the scsi_dev_info_list for an entry matching @vendor and
- *     @model, if found, return the matching flags value, else return
- *     scsi_default_dev_flags.
- **/
-int scsi_get_device_flags(unsigned char *vendor, unsigned char *model)
-{
-	struct scsi_dev_info_list *devinfo;
-
-	list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
-		if (devinfo->compatible) {
-			/*
-			 * Behave like the older version of get_device_flags.
-			 */
-			size_t max;
-			/*
-			 * XXX why skip leading spaces? If an odd INQUIRY
-			 * value, that should have been part of the
-			 * scsi_static_device_list[] entry, such as "  FOO"
-			 * rather than "FOO". Since this code is already
-			 * here, and we don't know what device it is
-			 * trying to work with, leave it as-is.
-			 */
-			max = 8;	/* max length of vendor */
-			while ((max > 0) && *vendor == ' ') {
-				max--;
-				vendor++;
-			}
-			/*
-			 * XXX removing the following strlen() would be
-			 * good, using it means that for a an entry not in
-			 * the list, we scan every byte of every vendor
-			 * listed in scsi_static_device_list[], and never match
-			 * a single one (and still have to compare at
-			 * least the first byte of each vendor).
-			 */
-			if (memcmp(devinfo->vendor, vendor,
-				    min(max, strlen(devinfo->vendor))))
-				continue;
-			/*
-			 * Skip spaces again.
-			 */
-			max = 16;	/* max length of model */
-			while ((max > 0) && *model == ' ') {
-				max--;
-				model++;
-			}
-			if (memcmp(devinfo->model, model,
-				   min(max, strlen(devinfo->model))))
-				continue;
-			return devinfo->flags;
-		} else {
-			if (!memcmp(devinfo->vendor, vendor,
-				     sizeof(devinfo->vendor)) &&
-			     !memcmp(devinfo->model, model,
-				      sizeof(devinfo->model)))
-				return devinfo->flags;
-		}
-	}
-	return scsi_default_dev_flags;
-}
-
 int scsi_attach_device(struct scsi_device *sdev)
 {
 	struct Scsi_Device_Template *sdt;
@@ -1280,39 +1031,6 @@
 }
 
 /*
- * Function:	scsi_slave_attach()
- *
- * Purpose:	Called from the upper level driver attach to handle common
- * 		attach code.
- *
- * Arguments:	sdev - scsi_device to attach
- *
- * Returns:	1 on error, 0 on succes
- *
- * Lock Status:	Protected via scsi_devicelist_mutex.
- */
-int scsi_slave_attach(struct scsi_device *sdev)
-{
-	sdev->attached++;
-	return 0;
-}
-
-/*
- * Function:	scsi_slave_detach()
- *
- * Purpose:	Called from the upper level driver attach to handle common
- * 		detach code.
- *
- * Arguments:	sdev - struct scsi_device to detach
- *
- * Lock Status:	Protected via scsi_devicelist_mutex.
- */
-void scsi_slave_detach(struct scsi_device *sdev)
-{
-	sdev->attached--;
-}
-
-/*
  * This entry point is called from the upper level module's module_init()
  * routine.  That implies that when this function is called, the
  * scsi_mod module is locked down because of upper module layering and
@@ -1377,43 +1095,9 @@
 	return 0;
 }
 
-static char *scsi_dev_flags;
-MODULE_PARM(scsi_dev_flags, "s");
-MODULE_PARM_DESC(scsi_dev_flags,
-	 "Given scsi_dev_flags=vendor:model:flags, add a black/white list"
-	 " entry for vendor and model with an integer value of flags"
-	 " to the scsi device info list");
-MODULE_PARM(scsi_default_dev_flags, "i");
-MODULE_PARM_DESC(scsi_default_dev_flags,
-		 "scsi default device flag integer value");
 MODULE_DESCRIPTION("SCSI core");
 MODULE_LICENSE("GPL");
 
-#ifndef MODULE
-static int __init setup_scsi_dev_flags(char *str)
-{
-	scsi_dev_flags = str;
-	return 1;
-}
-__setup("scsi_dev_flags=", setup_scsi_dev_flags);
-
-static int __init setup_scsi_default_dev_flags(char *str)
-{
-	unsigned int tmp;
-	if (get_option(&str, &tmp) == 1) {
-		scsi_default_dev_flags = tmp;
-		printk(KERN_WARNING "%s %d\n", __FUNCTION__,
-		       scsi_default_dev_flags);
-		return 1;
-	} else {
-		printk(KERN_WARNING "%s: usage scsi_default_dev_flags=intr\n",
-		       __FUNCTION__);
-		return 0;
-	}
-}
-__setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags);
-#endif
-
 static int __init init_scsi(void)
 {
 	int error, i;
@@ -1424,7 +1108,7 @@
 	error = scsi_init_procfs();
 	if (error)
 		goto cleanup_queue;
-	error = scsi_dev_info_list_init(scsi_dev_flags);
+	error = scsi_init_devinfo();
 	if (error)
 		goto cleanup_procfs;
 	error = scsi_sysfs_register();
@@ -1441,7 +1125,7 @@
 	return 0;
 
 cleanup_devlist:
-	scsi_dev_info_list_delete();
+	scsi_exit_devinfo();
 cleanup_procfs:
 	scsi_exit_procfs();
 cleanup_queue:
@@ -1454,7 +1138,7 @@
 static void __exit exit_scsi(void)
 {
 	scsi_sysfs_unregister();
-	scsi_dev_info_list_delete();
+	scsi_exit_devinfo();
 	devfs_remove("scsi");
 	scsi_exit_procfs();
 	scsi_exit_queue();
diff -Nru a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
--- a/drivers/scsi/scsi.h	Wed Apr 23 01:06:29 2003
+++ b/drivers/scsi/scsi.h	Wed May  7 07:15:38 2003
@@ -18,7 +18,6 @@
 #include <linux/config.h>	    /* for CONFIG_SCSI_LOGGING */
 #include <scsi/scsi.h>
 
-
 /*
  * These are the values that the SCpnt->sc_data_direction and 
  * SRpnt->sr_data_direction can take.  These need to be set
@@ -126,144 +125,11 @@
 #define SCSI_STATE_BHQUEUE         0x100a
 #define SCSI_STATE_MLQUEUE         0x100b
 
-/*
- * These are the values that the owner field can take.
- * They are used as an indication of who the command belongs to.
- */
-#define SCSI_OWNER_HIGHLEVEL      0x100
-#define SCSI_OWNER_MIDLEVEL       0x101
-#define SCSI_OWNER_LOWLEVEL       0x102
-#define SCSI_OWNER_ERROR_HANDLER  0x103
-#define SCSI_OWNER_BH_HANDLER     0x104
-#define SCSI_OWNER_NOBODY         0x105
-
 #define IDENTIFY_BASE       0x80
 #define IDENTIFY(can_disconnect, lun)   (IDENTIFY_BASE |\
 		     ((can_disconnect) ?  0x40 : 0) |\
 		     ((lun) & 0x07))
 
-
-/*
- * This defines the scsi logging feature.  It is a means by which the
- * user can select how much information they get about various goings on,
- * and it can be really useful for fault tracing.  The logging word is divided
- * into 8 nibbles, each of which describes a loglevel.  The division of things
- * is somewhat arbitrary, and the division of the word could be changed if it
- * were really needed for any reason.  The numbers below are the only place where these
- * are specified.  For a first go-around, 3 bits is more than enough, since this
- * gives 8 levels of logging (really 7, since 0 is always off).  Cutting to 2 bits
- * might be wise at some point.
- */
-
-#define SCSI_LOG_ERROR_SHIFT              0
-#define SCSI_LOG_TIMEOUT_SHIFT            3
-#define SCSI_LOG_SCAN_SHIFT               6
-#define SCSI_LOG_MLQUEUE_SHIFT            9
-#define SCSI_LOG_MLCOMPLETE_SHIFT         12
-#define SCSI_LOG_LLQUEUE_SHIFT            15
-#define SCSI_LOG_LLCOMPLETE_SHIFT         18
-#define SCSI_LOG_HLQUEUE_SHIFT            21
-#define SCSI_LOG_HLCOMPLETE_SHIFT         24
-#define SCSI_LOG_IOCTL_SHIFT              27
-
-#define SCSI_LOG_ERROR_BITS               3
-#define SCSI_LOG_TIMEOUT_BITS             3
-#define SCSI_LOG_SCAN_BITS                3
-#define SCSI_LOG_MLQUEUE_BITS             3
-#define SCSI_LOG_MLCOMPLETE_BITS          3
-#define SCSI_LOG_LLQUEUE_BITS             3
-#define SCSI_LOG_LLCOMPLETE_BITS          3
-#define SCSI_LOG_HLQUEUE_BITS             3
-#define SCSI_LOG_HLCOMPLETE_BITS          3
-#define SCSI_LOG_IOCTL_BITS               3
-
-#ifdef CONFIG_SCSI_LOGGING
-
-#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)     \
-{                                                       \
-        unsigned int mask;                              \
-                                                        \
-        mask = (1 << (BITS)) - 1;                       \
-        if( ((scsi_logging_level >> (SHIFT)) & mask) > (LEVEL) ) \
-        {                                               \
-                (CMD);                                  \
-        }						\
-}
-
-#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)            \
-{                                                       \
-        unsigned int mask;                              \
-                                                        \
-        mask = ((1 << (BITS)) - 1) << SHIFT;            \
-        scsi_logging_level = ((scsi_logging_level & ~mask) \
-                              | ((LEVEL << SHIFT) & mask));     \
-}
-
-
-
-#else
-
-/*
- * With no logging enabled, stub these out so they don't do anything.
- */
-#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)
-
-#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)
-#endif
-
-/*
- * These are the macros that are actually used throughout the code to
- * log events.  If logging isn't enabled, they are no-ops and will be
- * completely absent from the user's code.
- *
- * The 'set' versions of the macros are really intended to only be called
- * from the /proc filesystem, and in production kernels this will be about
- * all that is ever used.  It could be useful in a debugging environment to
- * bump the logging level when certain strange events are detected, however.
- */
-#define SCSI_LOG_ERROR_RECOVERY(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD);
-#define SCSI_LOG_TIMEOUT(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL,CMD);
-#define SCSI_LOG_SCAN_BUS(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL,CMD);
-#define SCSI_LOG_MLQUEUE(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL,CMD);
-#define SCSI_LOG_MLCOMPLETE(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL,CMD);
-#define SCSI_LOG_LLQUEUE(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL,CMD);
-#define SCSI_LOG_LLCOMPLETE(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL,CMD);
-#define SCSI_LOG_HLQUEUE(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL,CMD);
-#define SCSI_LOG_HLCOMPLETE(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL,CMD);
-#define SCSI_LOG_IOCTL(LEVEL,CMD)  \
-        SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD);
-
-
-#define SCSI_SET_ERROR_RECOVERY_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL);
-#define SCSI_SET_TIMEOUT_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL);
-#define SCSI_SET_SCAN_BUS_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL);
-#define SCSI_SET_MLQUEUE_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL);
-#define SCSI_SET_MLCOMPLETE_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL);
-#define SCSI_SET_LLQUEUE_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL);
-#define SCSI_SET_LLCOMPLETE_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL);
-#define SCSI_SET_HLQUEUE_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL);
-#define SCSI_SET_HLCOMPLETE_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL);
-#define SCSI_SET_IOCTL_LOGGING(LEVEL)  \
-        SCSI_SET_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL);
-
 /* host byte codes */
 #define DID_OK          0x00	/* NO error                                */
 #define DID_NO_CONNECT  0x01	/* Couldn't connect before timeout period  */
@@ -356,6 +222,7 @@
  * Forward-declaration of structs for prototypes.
  */
 struct Scsi_Host;
+struct scsi_target;
 struct scatterlist;
 
 /*
@@ -365,24 +232,12 @@
 typedef struct scsi_cmnd Scsi_Cmnd;
 typedef struct scsi_request Scsi_Request;
 
-#define SCSI_CMND_MAGIC 0xE25C23A5
-#define SCSI_REQ_MAGIC  0x75F6D354
-
-/*
- * Here is where we prototype most of the mid-layer.
- */
-
-extern unsigned int scsi_logging_level;		/* What do we log? */
-
 /*
  * These are the error handling functions defined in scsi_error.c
  */
-extern void scsi_times_out(Scsi_Cmnd * SCpnt);
 extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout,
 			   void (*complete) (Scsi_Cmnd *));
 extern int scsi_delete_timer(Scsi_Cmnd * SCset);
-extern void scsi_error_handler(void *host);
-extern int scsi_decide_disposition(Scsi_Cmnd * SCpnt);
 extern int scsi_block_when_processing_errors(Scsi_Device *);
 extern void scsi_sleep(int);
 
@@ -396,39 +251,19 @@
 /*
  * Prototypes for functions in scsi_lib.c
  */
-extern int scsi_maybe_unblock_host(Scsi_Device * SDpnt);
-extern void scsi_setup_cmd_retry(Scsi_Cmnd *SCpnt);
 extern void scsi_io_completion(Scsi_Cmnd * SCpnt, int good_sectors,
 			       int block_sectors);
-extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
-extern void scsi_queue_next_request(request_queue_t *q, struct scsi_cmnd *cmd);
-extern request_queue_t *scsi_alloc_queue(struct scsi_device *sdev);
-extern void scsi_free_queue(request_queue_t *q);
-extern int scsi_init_queue(void);
-extern void scsi_exit_queue(void);
 
 /*
  * Prototypes for functions in scsi.c
  */
-extern int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt);
-extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
-extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
 extern struct scsi_cmnd *scsi_get_command(struct scsi_device *dev, int flags);
 extern void scsi_put_command(struct scsi_cmnd *cmd);
 extern void scsi_adjust_queue_depth(Scsi_Device *, int, int);
 extern int scsi_track_queue_full(Scsi_Device *, int);
-extern int scsi_slave_attach(struct scsi_device *);
-extern void scsi_slave_detach(struct scsi_device *);
 extern int scsi_device_get(struct scsi_device *);
 extern void scsi_device_put(struct scsi_device *);
 extern void scsi_set_device_offline(struct scsi_device *);
-extern void scsi_done(Scsi_Cmnd * SCpnt);
-extern void scsi_finish_command(Scsi_Cmnd *);
-extern int scsi_retry_command(Scsi_Cmnd *);
-extern int scsi_attach_device(struct scsi_device *);
-extern void scsi_detach_device(struct scsi_device *);
-extern void scsi_rescan_device(struct scsi_device *);
-extern int scsi_get_device_flags(unsigned char *vendor, unsigned char *model);
 
 /*
  * Newer request-based interfaces.
@@ -438,30 +273,10 @@
 extern void scsi_wait_req(Scsi_Request *, const void *cmnd,
 			  void *buffer, unsigned bufflen,
 			  int timeout, int retries);
-
 extern void scsi_do_req(Scsi_Request *, const void *cmnd,
 			void *buffer, unsigned bufflen,
 			void (*done) (struct scsi_cmnd *),
 			int timeout, int retries);
-extern int scsi_insert_special_req(Scsi_Request * SRpnt, int);
-extern void scsi_init_cmd_from_req(Scsi_Cmnd *, Scsi_Request *);
-
-/*
- * Prototypes for functions in scsi_proc.c
- */
-#ifdef CONFIG_PROC_FS
-extern int scsi_init_procfs(void);
-extern void scsi_exit_procfs(void);
-
-extern void scsi_proc_host_add(struct Scsi_Host *);
-extern void scsi_proc_host_rm(struct Scsi_Host *);
-#else
-static inline int scsi_init_procfs(void) { return 0; }
-static inline void scsi_exit_procfs(void) { ; }
-
-static inline void scsi_proc_host_add(struct Scsi_Host *);
-static inline void scsi_proc_host_rm(struct Scsi_Host *);
-#endif /* CONFIG_PROC_FS */
 
 /*
  * Prototypes for functions in scsi_scan.c
@@ -486,40 +301,6 @@
 extern const char *scsi_sense_key_string(unsigned char);
 extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
 
-/*
- * dev_info: for the black/white list in the old scsi_static_device_list
- */
-struct dev_info {
-	char *vendor;
-	char *model;
-	char *revision;	/* revision known to be bad, unused */
-	unsigned flags;
-};
-
-extern struct dev_info scsi_static_device_list[];
-
-/*
- * scsi_dev_info_list: structure to hold black/white listed devices.
- */
-struct scsi_dev_info_list {
-	struct list_head dev_info_list;
-	char vendor[8];
-	char model[16];
-	unsigned flags;
-	unsigned compatible; /* for use with scsi_static_device_list entries */
-};
-extern struct list_head scsi_dev_info_list;
-extern int scsi_dev_info_list_add_str(char *);
-
-/*
- * scsi_target: representation of a scsi target, for now, this is only
- * used for single_lun devices. If no one has active IO to the target,
- * starget_sdev_user is NULL, else it points to the active sdev.
- */
-struct scsi_target {
-	struct scsi_device *starget_sdev_user;
-	unsigned int starget_refcnt;
-};
 
 /*
  *  The scsi_device struct contains what we know about each given scsi
@@ -540,8 +321,6 @@
 	 */
 	struct list_head    siblings;   /* list of all devices on this host */
 	struct list_head    same_target_siblings; /* just the devices sharing same target id */
-	wait_queue_head_t   scpnt_wait;	/* Used to wait if
-					   device is busy */
 	struct Scsi_Host *host;
 	request_queue_t *request_queue;
 	volatile unsigned short device_busy;	/* commands actually active on low-level */
@@ -563,8 +342,6 @@
 					 * vendor-specific cmd's */
 	unsigned sector_size;	/* size in bytes */
 
-	int attached;		/* # of high level drivers attached to 
-				 * this */
 	int access_count;	/* Count of open channels/mounts */
 
 	void *hostdata;		/* available to low-level driver */
@@ -619,9 +396,6 @@
   	/* default value if the device doesn't override */
 	#define SCSI_DEFAULT_DEVICE_BLOCKED	3
 
-
-	// Flag to allow revalidate to succeed in sd_open
-	int allow_revalidate;
 	struct device sdev_driverfs_dev;
 };
 #define	to_scsi_device(d)	\
@@ -698,7 +472,6 @@
 	unsigned short state;
 	unsigned short owner;
 	Scsi_Request *sc_request;
-	struct scsi_cmnd *reset_chain;
 
 	struct list_head list;  /* scsi_cmnd participates in queue lists */
 
@@ -783,14 +556,6 @@
 
 	unsigned flags;
 
-	/*
-	 * Used to indicate that a command which has timed out also
-	 * completed normally.  Typically the completion function will
-	 * do nothing but set this flag in this instance because the
-	 * timeout handler is already running.
-	 */
-	unsigned done_late:1;
-
 	/* Low-level done function - can be used by low-level driver to point
 	 *        to completion function.  Not used by mid/upper level code. */
 	void (*scsi_done) (struct scsi_cmnd *);
@@ -817,11 +582,6 @@
 };
 
 /*
- *  Flag bit for the internal_timeout array
- */
-#define NORMAL_TIMEOUT 0
-
-/*
  * Definitions and prototypes used for scsi mid-level queue.
  */
 #define SCSI_MLQUEUE_HOST_BUSY   0x1055
@@ -829,8 +589,7 @@
 #define SCSI_MLQUEUE_EH_RETRY    0x1057
 
 /*
- * old style reset request from external source
- * (private to sg.c and scsi_error.c, supplied by scsi_obsolete.c)
+ * Reset request from external source
  */
 #define SCSI_TRY_RESET_DEVICE	1
 #define SCSI_TRY_RESET_BUS	2
@@ -922,34 +681,6 @@
         return (Scsi_Cmnd *)req->special;
 }
 
-#define scsi_eh_eflags_chk(scp, flags) (scp->eh_eflags & flags)
-
-#define scsi_eh_eflags_set(scp, flags) do { \
-	scp->eh_eflags |= flags; \
-	} while(0)
-
-#define scsi_eh_eflags_clr(scp, flags) do { \
-	scp->eh_eflags &= ~flags; \
-	} while(0)
-
-#define scsi_eh_eflags_clr_all(scp) (scp->eh_eflags = 0)
-
-/*
- * Scsi Error Handler Flags
- */
-#define SCSI_EH_CANCEL_CMD	0x0001	/* Cancel this cmd */
-#define SCSI_EH_REC_TIMEOUT	0x0002	/* EH retry timed out */
-
-#define SCSI_SENSE_VALID(scmd) ((scmd->sense_buffer[0] & 0x70) == 0x70)
-
-extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
-
 int scsi_set_medium_removal(Scsi_Device *dev, char state);
-
-extern int scsi_device_register(struct scsi_device *);
-extern void scsi_device_unregister(struct scsi_device *);
-
-extern int scsi_sysfs_register(void);
-extern void scsi_sysfs_unregister(void);
 
 #endif /* _SCSI_H */
diff -Nru a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
--- a/drivers/scsi/scsi_debug.c	Tue Apr 29 00:11:53 2003
+++ b/drivers/scsi/scsi_debug.c	Thu May  8 15:46:47 2003
@@ -52,9 +52,10 @@
 #include <linux/version.h>
 #endif
 
+#include "scsi_logging.h"
 #include "scsi_debug.h"
 
-static const char * scsi_debug_version_str = "Version: 1.69 (20030329)";
+static const char * scsi_debug_version_str = "Version: 1.70 (20030507)";
 
 /* Additional Sense Code (ASC) used */
 #define NO_ADDED_SENSE 0x0
@@ -144,10 +145,13 @@
 struct sdebug_host_info {
 	struct list_head host_list;
 	struct Scsi_Host *shost;
-	struct device *dev;
+	struct device dev;
 	struct list_head dev_info_list;
 };
 
+#define to_sdebug_host(d)	\
+	container_of(d, struct sdebug_host_info, dev)
+
 static LIST_HEAD(sdebug_host_list);
 static spinlock_t sdebug_host_list_lock = SPIN_LOCK_UNLOCKED;
 
@@ -162,6 +166,30 @@
 };
 static struct sdebug_queued_cmd queued_arr[SCSI_DEBUG_CANQUEUE];
 
+static Scsi_Host_Template sdebug_driver_template = {
+	.proc_info =		scsi_debug_proc_info,
+	.name =			"SCSI DEBUG",
+	.info =			scsi_debug_info,
+	.slave_alloc =		scsi_debug_slave_alloc,
+	.slave_configure =	scsi_debug_slave_configure,
+	.slave_destroy =	scsi_debug_slave_destroy,
+	.ioctl =		scsi_debug_ioctl,
+	.queuecommand =		scsi_debug_queuecommand,
+	.eh_abort_handler =	scsi_debug_abort,
+	.eh_bus_reset_handler = scsi_debug_bus_reset,
+	.eh_device_reset_handler = scsi_debug_device_reset,
+	.eh_host_reset_handler = scsi_debug_host_reset,
+	.bios_param =		scsi_debug_biosparam,
+	.can_queue =		SCSI_DEBUG_CANQUEUE,
+	.this_id =		7,
+	.sg_tablesize =		64,
+	.cmd_per_lun =		3,
+	.max_sectors =		4096,
+	.unchecked_isa_dma = 	0,
+	.use_clustering = 	ENABLE_CLUSTERING,
+	.module =		THIS_MODULE,
+};
+
 static unsigned char * fake_storep;	/* ramdisk storage */
 
 static unsigned char spare_buff[SDEBUG_SENSE_LEN];
@@ -178,9 +206,11 @@
 
 static int sdebug_driver_probe(struct device *);
 static int sdebug_driver_remove(struct device *);
+static struct bus_type pseudo_lld_bus;
 
 static struct device_driver sdebug_driverfs_driver = {
 	.name 		= sdebug_proc_name,
+	.bus		= &pseudo_lld_bus,
 	.probe          = sdebug_driver_probe,
 	.remove         = sdebug_driver_remove,
 };
@@ -221,24 +251,6 @@
 static void sdebug_remove_adapter(void);
 static struct device pseudo_primary;
 static struct bus_type pseudo_lld_bus;
-static int scsi_debug_register_driver(struct device_driver *);
-static int scsi_debug_unregister_driver(struct device_driver *);
-
-static struct sdebug_host_info * 
-		sdebug_shost_to_host_info(struct Scsi_Host *shost)
-{
-	struct sdebug_host_info * sdbg_host, * found = NULL;
-
-	spin_lock(&sdebug_host_list_lock);
-	list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
-		if (sdbg_host->shost == shost) {
-			found = sdbg_host;
-			break;
-		}
-	}
-	spin_unlock(&sdebug_host_list_lock);
-	return found;
-}
 
 static unsigned char * scatg2virt(const struct scatterlist * sclp)
 {
@@ -283,10 +295,12 @@
 		bufflen = SDEBUG_SENSE_LEN;
 	}
 
+
         if(target == sdebug_driver_template.this_id) {
-                printk(KERN_WARNING 
-		       "scsi_debug: initiator's id used as target!\n");
-		return schedule_resp(SCpnt, NULL, done, 0, 0);
+		printk(KERN_INFO "scsi_debug: initiator's id used as "
+		       "target!\n");
+		return schedule_resp(SCpnt, NULL, done,
+				     DID_NO_CONNECT << 16, 0);
         }
 
 	if (SCpnt->device->lun >= scsi_debug_max_luns)
@@ -643,6 +657,15 @@
 	return sizeof(ctrl_m_pg);
 }
 
+static int resp_iec_m_pg(unsigned char * p, int pcontrol, int target)
+{	/* Informational Exceptions control mode page for mode_sense */
+	unsigned char iec_m_pg[] = {0x1c, 0xa, 0x08, 0, 0, 0, 0, 0,
+				    0, 0, 0x0, 0x0};
+	memcpy(p, iec_m_pg, sizeof(iec_m_pg));
+	if (1 == pcontrol)
+		memset(p + 2, 0, sizeof(iec_m_pg) - 2);
+	return sizeof(iec_m_pg);
+}
 
 #define SDEBUG_MAX_MSENSE_SZ 256
 
@@ -709,12 +732,17 @@
 		len = resp_ctrl_m_pg(ap, pcontrol, target);
 		offset += len;
 		break;
+	case 0x1c:	/* Informational Exceptions Mode page, all devices */
+		len = resp_iec_m_pg(ap, pcontrol, target);
+		offset += len;
+		break;
 	case 0x3f:	/* Read all Mode pages */
 		len = resp_err_recov_pg(ap, pcontrol, target);
 		len += resp_disconnect_pg(ap + len, pcontrol, target);
 		len += resp_format_pg(ap + len, pcontrol, target);
 		len += resp_caching_pg(ap + len, pcontrol, target);
 		len += resp_ctrl_m_pg(ap + len, pcontrol, target);
+		len += resp_iec_m_pg(ap + len, pcontrol, target);
 		offset += len;
 		break;
 	default:
@@ -865,7 +893,7 @@
 static void timer_intr_handler(unsigned long indx)
 {
 	struct sdebug_queued_cmd * sqcp;
-	unsigned int iflags;
+	unsigned long iflags;
 
 	if (indx >= SCSI_DEBUG_CANQUEUE) {
 		printk(KERN_ERR "scsi_debug:timer_intr_handler: indx too "
@@ -938,9 +966,9 @@
 
 	if (devip)
 		return devip;
-	sdbg_host = sdebug_shost_to_host_info(sdev->host);
+	sdbg_host = *(struct sdebug_host_info **) sdev->host->hostdata;
         if(! sdbg_host) {
-                printk(KERN_ERR "Unable to locate host info\n");
+                printk(KERN_ERR "Host info NULL\n");
 		return NULL;
         }
 	list_for_each_entry(devip, &sdbg_host->dev_info_list, dev_list) {
@@ -1040,7 +1068,7 @@
 		printk(KERN_INFO "scsi_debug: bus_reset\n");
 	++num_bus_resets;
 	if (SCpnt && ((sdp = SCpnt->device)) && ((hp = sdp->host))) {
-		sdbg_host = sdebug_shost_to_host_info(hp);
+		sdbg_host = *(struct sdebug_host_info **) hp->hostdata;
 		if (sdbg_host) {
 			list_for_each_entry(dev_info,
                                             &sdbg_host->dev_info_list,
@@ -1496,7 +1524,7 @@
 
 	device_register(&pseudo_primary);
 	bus_register(&pseudo_lld_bus);
-	scsi_debug_register_driver(&sdebug_driverfs_driver);
+	driver_register(&sdebug_driverfs_driver);
 	do_create_driverfs_files();
 
 	sdebug_driver_template.proc_name = (char *)sdebug_proc_name;
@@ -1521,10 +1549,13 @@
 
 static void __exit scsi_debug_exit(void)
 {
-	/* free up adapters here ?? */
+	int k = scsi_debug_add_host;
+
 	stop_all_queued();
+	for (; k; k--)
+		sdebug_remove_adapter();
 	do_remove_driverfs_files();
-	scsi_debug_unregister_driver(&sdebug_driverfs_driver);
+	driver_unregister(&sdebug_driverfs_driver);
 	bus_unregister(&pseudo_lld_bus);
 	device_unregister(&pseudo_primary);
 
@@ -1550,51 +1581,76 @@
         .match = pseudo_lld_bus_match,
 };
 
-static int scsi_debug_register_driver(struct device_driver *dev_driver)
-{
-	dev_driver->bus = &pseudo_lld_bus;
-	driver_register(dev_driver);
-
-	return 0;
-}
-
-static int scsi_debug_unregister_driver(struct device_driver *dev_driver)
-{
-	driver_unregister(dev_driver);
-	return 0;
-}
-
 static void sdebug_release_adapter(struct device * dev)
 {
-        kfree(dev);
+        struct sdebug_host_info *sdbg_host;
+
+	sdbg_host = to_sdebug_host(dev);
+        kfree(sdbg_host);
 }
 
 static int sdebug_add_adapter()
 {
-        struct device * dev;
-        int error;
+	int k, devs_per_host;
+        int error = 0;
+        struct sdebug_host_info *sdbg_host;
+        struct sdebug_dev_info *sdbg_devinfo;
+        struct list_head *lh, *lh_sf;
+
+        sdbg_host = kmalloc(sizeof(*sdbg_host),GFP_KERNEL);
 
-        dev = kmalloc(sizeof(*dev),GFP_KERNEL);
-        if (NULL == dev) {
+        if (NULL == sdbg_host) {
                 printk(KERN_ERR "%s: out of memory at line %d\n",
                        __FUNCTION__, __LINE__);
                 return -ENOMEM;
         }
-        memset(dev, 0, sizeof(*dev));
 
-        dev->bus = &pseudo_lld_bus;
-        dev->parent = &pseudo_primary;
-        dev->release = &sdebug_release_adapter;
-        sprintf(dev->name, "scsi debug adapter");
-        sprintf(dev->bus_id, "adapter%d", scsi_debug_add_host);
+        memset(sdbg_host, 0, sizeof(*sdbg_host));
+        INIT_LIST_HEAD(&sdbg_host->dev_info_list);
+
+	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
+        for (k = 0; k < devs_per_host; k++) {
+                sdbg_devinfo = kmalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
+                if (NULL == sdbg_devinfo) {
+                        printk(KERN_ERR "%s: out of memory at line %d\n",
+                               __FUNCTION__, __LINE__);
+                        error = -ENOMEM;
+			goto clean1;
+                }
+                memset(sdbg_devinfo, 0, sizeof(*sdbg_devinfo));
+                sdbg_devinfo->sdbg_host = sdbg_host;
+                list_add_tail(&sdbg_devinfo->dev_list,
+                              &sdbg_host->dev_info_list);
+        }
+
+        spin_lock(&sdebug_host_list_lock);
+        list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
+        spin_unlock(&sdebug_host_list_lock);
+
+        sdbg_host->dev.bus = &pseudo_lld_bus;
+        sdbg_host->dev.parent = &pseudo_primary;
+        sdbg_host->dev.release = &sdebug_release_adapter;
+        sprintf(sdbg_host->dev.name, "scsi debug adapter");
+        sprintf(sdbg_host->dev.bus_id, "adapter%d", scsi_debug_add_host);
 
-        error = device_register(dev);
+        error = device_register(&sdbg_host->dev);
 
         if (error)
-                kfree(dev);
-        else
-                ++scsi_debug_add_host;
+		goto clean2;
 
+	++scsi_debug_add_host;
+        return error;
+
+clean2:
+	list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
+		sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
+					  dev_list);
+		list_del(&sdbg_devinfo->dev_list);
+		kfree(sdbg_devinfo);
+	}
+
+clean1:
+	kfree(sdbg_host);
         return error;
 }
 
@@ -1603,86 +1659,50 @@
         struct sdebug_host_info * sdbg_host = NULL;
 
         spin_lock(&sdebug_host_list_lock);
-        if (!list_empty(&sdebug_host_list))
+        if (!list_empty(&sdebug_host_list)) {
                 sdbg_host = list_entry(sdebug_host_list.prev,
                                        struct sdebug_host_info, host_list);
+		list_del(&sdbg_host->host_list);
+	}
         spin_unlock(&sdebug_host_list_lock);
 
-        device_unregister(sdbg_host->dev);
+	if (!sdbg_host)
+		return;
+
+        device_unregister(&sdbg_host->dev);
         --scsi_debug_add_host;
 }
 
 static int sdebug_driver_probe(struct device * dev)
 {
-	int k, devs_per_host;
         int error = 0;
         struct sdebug_host_info *sdbg_host;
-        struct sdebug_dev_info *sdbg_devinfo;
-        struct list_head *lh, *lh_sf;
         struct Scsi_Host *hpnt;
 
-        sdbg_host = kmalloc(sizeof(*sdbg_host),GFP_KERNEL);
-        if (NULL == sdbg_host) {
-                printk(KERN_ERR "%s: out of memory at line %d\n",
-                       __FUNCTION__, __LINE__);
-                return -ENOMEM;
-        }
-        memset(sdbg_host, 0, sizeof(*sdbg_host));
-
-        INIT_LIST_HEAD(&sdbg_host->dev_info_list);
-
-	devs_per_host = scsi_debug_num_tgts * scsi_debug_max_luns;
-        for (k = 0; k < devs_per_host; k++) {
-                sdbg_devinfo = kmalloc(sizeof(*sdbg_devinfo),GFP_KERNEL);
-                if (NULL == sdbg_devinfo) {
-                        printk(KERN_ERR "%s: out of memory at line %d\n",
-                               __FUNCTION__, __LINE__);
-                        error = -ENOMEM;
-                }
-                memset(sdbg_devinfo, 0, sizeof(*sdbg_devinfo));
-                sdbg_devinfo->sdbg_host = sdbg_host;
-                list_add_tail(&sdbg_devinfo->dev_list,
-                              &sdbg_host->dev_info_list);
-        }
-
-        list_add_tail(&sdbg_host->host_list, &sdebug_host_list);
+	sdbg_host = to_sdebug_host(dev);
 
-        hpnt = scsi_register(&sdebug_driver_template, 0);
+        hpnt = scsi_register(&sdebug_driver_template, sizeof(sdbg_host));
         if (NULL == hpnt) {
                 printk(KERN_ERR "%s: scsi_register failed\n", __FUNCTION__);
                 error = -ENODEV;
-                goto clean1;
+		return error;
         }
 
         sdbg_host->shost = hpnt;
-        sdbg_host->dev = dev;
+	*((struct sdebug_host_info **)hpnt->hostdata) = sdbg_host;
 	if ((hpnt->this_id >= 0) && (scsi_debug_num_tgts > hpnt->this_id))
 		hpnt->max_id = scsi_debug_num_tgts + 1;
 	else
 		hpnt->max_id = scsi_debug_num_tgts;
 	hpnt->max_lun = scsi_debug_max_luns;
 
-        error = scsi_add_host(hpnt, sdbg_host->dev);
+        error = scsi_add_host(hpnt, &sdbg_host->dev);
         if (error) {
                 printk(KERN_ERR "%s: scsi_add_host failed\n", __FUNCTION__);
                 error = -ENODEV;
-                goto clean2;
-        }
-
-
-        return 0;
-
-clean2:
-        scsi_unregister(hpnt);
-clean1:
-        list_for_each_safe(lh, lh_sf, &sdbg_host->dev_info_list) {
-                sdbg_devinfo = list_entry(lh, struct sdebug_dev_info,
-                                          dev_list);
-                list_del(&sdbg_devinfo->dev_list);
-                kfree(sdbg_devinfo);
+		scsi_unregister(hpnt);
         }
 
-        kfree(sdbg_host);
 
         return error;
 }
@@ -1690,25 +1710,16 @@
 static int sdebug_driver_remove(struct device * dev)
 {
         struct list_head *lh, *lh_sf;
+        struct sdebug_host_info *sdbg_host;
         struct sdebug_dev_info *sdbg_devinfo;
-        struct sdebug_host_info *sdbg_host, *found = NULL;
 
-        spin_lock(&sdebug_host_list_lock);
-        list_for_each_entry(sdbg_host, &sdebug_host_list, host_list) {
-                if (sdbg_host->dev == dev) {
-                        list_del(&sdbg_host->host_list);
-                        found = sdbg_host;
-                        break;
-                }
-        }
-        spin_unlock(&sdebug_host_list_lock);
-
-        if (!found) {
-                printk(KERN_ERR "%s: sdebug_host_info not found\n",
-                       __FUNCTION__);
-                return -ENODEV;
-        }
+	sdbg_host = to_sdebug_host(dev);
 
+	if (!sdbg_host) {
+		printk(KERN_ERR "%s: Unable to locate host info\n",
+		       __FUNCTION__);
+		return -ENODEV;
+	}
 
         if (scsi_remove_host(sdbg_host->shost)) {
                 printk(KERN_ERR "%s: scsi_remove_host failed\n", __FUNCTION__);
@@ -1723,8 +1734,6 @@
                 list_del(&sdbg_devinfo->dev_list);
                 kfree(sdbg_devinfo);
         }
-
-        kfree(sdbg_host);
 
         return 0;
 }
diff -Nru a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
--- a/drivers/scsi/scsi_debug.h	Sun Mar 16 07:05:12 2003
+++ b/drivers/scsi/scsi_debug.h	Thu May  8 15:46:47 2003
@@ -24,28 +24,4 @@
 
 #define SCSI_DEBUG_MAX_CMD_LEN 16
 
-static Scsi_Host_Template sdebug_driver_template = {
-	.proc_info =		scsi_debug_proc_info,
-	.name =			"SCSI DEBUG",
-	.info =			scsi_debug_info,
-	.slave_alloc =		scsi_debug_slave_alloc,
-	.slave_configure =	scsi_debug_slave_configure,
-	.slave_destroy =	scsi_debug_slave_destroy,
-	.ioctl =		scsi_debug_ioctl,
-	.queuecommand =		scsi_debug_queuecommand,
-	.eh_abort_handler =	scsi_debug_abort,
-	.eh_bus_reset_handler = scsi_debug_bus_reset,
-	.eh_device_reset_handler = scsi_debug_device_reset,
-	.eh_host_reset_handler = scsi_debug_host_reset,
-	.bios_param =		scsi_debug_biosparam,
-	.can_queue =		SCSI_DEBUG_CANQUEUE,
-	.this_id =		7,
-	.sg_tablesize =		64,
-	.cmd_per_lun =		3,
-	.max_sectors =		4096,
-	.unchecked_isa_dma = 	0,
-	.use_clustering = 	ENABLE_CLUSTERING,
-	.module =		THIS_MODULE,
-};
-
 #endif
diff -Nru a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/scsi_devinfo.c	Thu May  8 15:35:53 2003
@@ -0,0 +1,542 @@
+
+#include <linux/blkdev.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+#include "scsi.h"
+#include "scsi_priv.h"
+#include "scsi_devinfo.h"
+
+/*
+ * scsi_dev_info_list: structure to hold black/white listed devices.
+ */
+struct scsi_dev_info_list {
+	struct list_head dev_info_list;
+	char vendor[8];
+	char model[16];
+	unsigned flags;
+	unsigned compatible; /* for use with scsi_static_device_list entries */
+};
+
+
+static const char spaces[] = "                "; /* 16 of them */
+static char *scsi_dev_flags;
+static unsigned scsi_default_dev_flags;
+static LIST_HEAD(scsi_dev_info_list);
+
+/*
+ * scsi_static_device_list: deprecated list of devices that require
+ * settings that differ from the default, includes black-listed (broken)
+ * devices. The entries here are added to the tail of scsi_dev_info_list
+ * via scsi_dev_info_list_init.
+ *
+ * Do not add to this list, use the command line or proc interface to add
+ * to the scsi_dev_info_list. This table will eventually go away.
+ */
+static struct {
+	char *vendor;
+	char *model;
+	char *revision;	/* revision known to be bad, unused */
+	unsigned flags;
+} scsi_static_device_list[] __initdata = {
+	/*
+	 * The following devices are known not to tolerate a lun != 0 scan
+	 * for one reason or another. Some will respond to all luns,
+	 * others will lock up.
+	 */
+	{"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},	/* locks up */
+	{"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},	/* locks up */
+	{"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},	/* locks up */
+	{"DENON", "DRD-25X", "V", BLIST_NOLUN},			/* locks up */
+	{"HITACHI", "DK312C", "CM81", BLIST_NOLUN},	/* responds to all lun */
+	{"HITACHI", "DK314C", "CR21", BLIST_NOLUN},	/* responds to all lun */
+	{"IMS", "CDD521/10", "2.06", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},	/* locks up */
+	{"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},	/* locks up */
+	{"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},	/* responds to all lun */
+	{"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},/* locks up */
+	{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},	/* responds to all lun */
+	{"RODIME", "RO3000S", "2.33", BLIST_NOLUN},	/* locks up */
+	{"SUN", "SENA", NULL, BLIST_NOLUN},		/* responds to all luns */
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * aha152x controller, which causes SCSI code to reset bus.
+	 */
+	{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * aha152x controller, which causes SCSI code to reset bus.
+	 */
+	{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},
+	{"SEAGATE", "ST296", "921", BLIST_NOLUN},	/* responds to all lun */
+	{"SEAGATE", "ST1581", "6538", BLIST_NOLUN},	/* responds to all lun */
+	{"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},
+	{"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN},
+	{"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN},
+	{"SONY", "CD-ROM CDU-8012", NULL, BLIST_NOLUN},
+	{"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},	/* locks up */
+	{"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},	/* locks up */
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * seagate controller, which causes SCSI code to reset bus.
+	 */
+	{"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},
+	{"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN},	/* responds to all lun */
+	/*
+	 * The following causes a failed REQUEST SENSE on lun 1 for
+	 * seagate controller, which causes SCSI code to reset bus.
+	 */
+	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},
+	{"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},	/* locks up */
+	{"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},	/* locks up */
+	{"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN},	/* locks up */
+	{"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},	/* locks up */
+	{"SANKYO", "CP525", "6.64", BLIST_NOLUN},	/* causes failed REQ SENSE, extra reset */
+	{"HP", "C1750A", "3226", BLIST_NOLUN},		/* scanjet iic */
+	{"HP", "C1790A", "", BLIST_NOLUN},		/* scanjet iip */
+	{"HP", "C2500A", "", BLIST_NOLUN},		/* scanjet iicx */
+	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},	/* locks up */
+	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* locks up */
+	{"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN},	/* locks up */
+	{"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN},	/* locks up */
+	{"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN},	/* locks up */
+	{"RELISYS", "Scorpio", NULL, BLIST_NOLUN},	/* responds to all lun */
+	{"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},	/* responds to all lun */
+	{"NEC", "D3856", "0009", BLIST_NOLUN},
+
+	/*
+	 * Other types of devices that have special flags.
+	 */
+	{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
+	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
+	{"IOMEGA", "Io20S         *F", NULL, BLIST_KEY},
+	{"INSITE", "Floptical   F*8I", NULL, BLIST_KEY},
+	{"INSITE", "I325VM", NULL, BLIST_KEY},
+	{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"MICROP", "4110", NULL, BLIST_NOTQ},
+	{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
+	{"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
+	{"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
+	{"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN},
+	{"DEC", "HSG80", NULL, BLIST_FORCELUN},
+	{"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN},
+	{"COMPAQ", "CR3500", NULL, BLIST_FORCELUN},
+	{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
+	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
+	{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
+	{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
+	{"MegaRAID", "LD", NULL, BLIST_FORCELUN},
+	{"DGC", "RAID", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, storage on LUN 0 */
+	{"DGC", "DISK", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, no storage on LUN 0 */
+	{"DELL", "PV660F", NULL, BLIST_SPARSELUN},
+	{"DELL", "PV660F   PSEUDO", NULL, BLIST_SPARSELUN},
+	{"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN},	/* Dell PV 530F */
+	{"DELL", "PV530F", NULL, BLIST_SPARSELUN},
+	{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
+	{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP VA7400 */
+	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */
+	{"CMD", "CRA-7280", NULL, BLIST_SPARSELUN},	/* CMD RAID Controller */
+	{"CNSI", "G7324", NULL, BLIST_SPARSELUN},	/* Chaparral G7324 RAID */
+	{"CNSi", "G8324", NULL, BLIST_SPARSELUN},	/* Chaparral G8324 RAID */
+	{"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN},
+	{"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN},
+	{"SONY", "TSL", NULL, BLIST_FORCELUN},		/* DDS3 & DDS4 autoloaders */
+	{"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
+	{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
+	{"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN},
+	{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
+	{"COMPAQ", "MSA1000", NULL, BLIST_FORCELUN},
+	{"HP", "C1557A", NULL, BLIST_FORCELUN},
+	{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
+	{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN},
+	{"HITACHI", "DF400", "*", BLIST_SPARSELUN},
+	{"HITACHI", "DF500", "*", BLIST_SPARSELUN},
+	{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
+	{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"SUN", "T300", "*", BLIST_SPARSELUN},
+	{"SUN", "T4", "*", BLIST_SPARSELUN},
+	{"SGI", "RAID3", "*", BLIST_SPARSELUN},
+	{"SGI", "RAID5", "*", BLIST_SPARSELUN},
+	{"SGI", "TP9100", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"SGI", "TP9300", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
+	{ NULL, NULL, NULL, 0 },
+};
+
+/*
+ * scsi_strcpy_devinfo: called from scsi_dev_info_list_add to copy into
+ * devinfo vendor and model strings.
+ */
+static void scsi_strcpy_devinfo(char *name, char *to, size_t to_length,
+				char *from, int compatible)
+{
+	size_t from_length;
+
+	from_length = strlen(from);
+	strncpy(to, from, min(to_length, from_length));
+	if (from_length < to_length) {
+		if (compatible) {
+			/*
+			 * NUL terminate the string if it is short.
+			 */
+			to[from_length] = '\0';
+		} else {
+			/* 
+			 * space pad the string if it is short. 
+			 */
+			strncpy(&to[from_length], spaces,
+				to_length - from_length);
+		}
+	}
+	if (from_length > to_length)
+		 printk(KERN_WARNING "%s: %s string '%s' is too long\n",
+			__FUNCTION__, name, from);
+}
+
+/**
+ * scsi_dev_info_list_add: add one dev_info list entry.
+ * @vendor:	vendor string
+ * @model:	model (product) string
+ * @strflags:	integer string
+ * @flag:	if strflags NULL, use this flag value
+ *
+ * Description:
+ * 	Create and add one dev_info entry for @vendor, @model, @strflags or
+ * 	@flag. If @compatible, add to the tail of the list, do not space
+ * 	pad, and set devinfo->compatible. The scsi_static_device_list entries
+ * 	are added with @compatible 1 and @clfags NULL.
+ *
+ * Returns: 0 OK, -error on failure.
+ **/
+static int scsi_dev_info_list_add(int compatible, char *vendor, char *model,
+			    char *strflags, int flags)
+{
+	struct scsi_dev_info_list *devinfo;
+
+	devinfo = kmalloc(sizeof(*devinfo), GFP_KERNEL);
+	if (!devinfo) {
+		printk(KERN_ERR "%s: no memory\n", __FUNCTION__);
+		return -ENOMEM;
+	}
+
+	scsi_strcpy_devinfo("vendor", devinfo->vendor, sizeof(devinfo->vendor),
+			    vendor, compatible);
+	scsi_strcpy_devinfo("model", devinfo->model, sizeof(devinfo->model),
+			    model, compatible);
+
+	if (strflags)
+		devinfo->flags = simple_strtoul(strflags, NULL, 0);
+	else
+		devinfo->flags = flags;
+
+	devinfo->compatible = compatible;
+
+	if (compatible)
+		list_add_tail(&devinfo->dev_info_list, &scsi_dev_info_list);
+	else
+		list_add(&devinfo->dev_info_list, &scsi_dev_info_list);
+
+	return 0;
+}
+
+/**
+ * scsi_dev_info_list_add_str: parse dev_list and add to the
+ * scsi_dev_info_list.
+ * @dev_list:	string of device flags to add
+ *
+ * Description:
+ * 	Parse dev_list, and add entries to the scsi_dev_info_list.
+ * 	dev_list is of the form "vendor:product:flag,vendor:product:flag".
+ * 	dev_list is modified via strsep. Can be called for command line
+ * 	addition, for proc or mabye a sysfs interface.
+ *
+ * Returns: 0 if OK, -error on failure.
+ **/
+static int scsi_dev_info_list_add_str(char *dev_list)
+{
+	char *vendor, *model, *strflags, *next;
+	char *next_check;
+	int res = 0;
+
+	next = dev_list;
+	if (next && next[0] == '"') {
+		/*
+		 * Ignore both the leading and trailing quote.
+		 */
+		next++;
+		next_check = ",\"";
+	} else {
+		next_check = ",";
+	}
+
+	/*
+	 * For the leading and trailing '"' case, the for loop comes
+	 * through the last time with vendor[0] == '\0'.
+	 */
+	for (vendor = strsep(&next, ":"); vendor && (vendor[0] != '\0')
+	     && (res == 0); vendor = strsep(&next, ":")) {
+		strflags = NULL;
+		model = strsep(&next, ":");
+		if (model)
+			strflags = strsep(&next, next_check);
+		if (!model || !strflags) {
+			printk(KERN_ERR "%s: bad dev info string '%s' '%s'"
+			       " '%s'\n", __FUNCTION__, vendor, model,
+			       strflags);
+			res = -EINVAL;
+		} else
+			res = scsi_dev_info_list_add(0 /* compatible */, vendor,
+						     model, strflags, 0);
+	}
+	return res;
+}
+
+/**
+ * get_device_flags - get device specific flags from the dynamic device
+ * list. Called during scan time.
+ * @vendor:	vendor name
+ * @model:	model name
+ *
+ * Description:
+ *     Search the scsi_dev_info_list for an entry matching @vendor and
+ *     @model, if found, return the matching flags value, else return
+ *     scsi_default_dev_flags.
+ **/
+int scsi_get_device_flags(unsigned char *vendor, unsigned char *model)
+{
+	struct scsi_dev_info_list *devinfo;
+
+	list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
+		if (devinfo->compatible) {
+			/*
+			 * Behave like the older version of get_device_flags.
+			 */
+			size_t max;
+			/*
+			 * XXX why skip leading spaces? If an odd INQUIRY
+			 * value, that should have been part of the
+			 * scsi_static_device_list[] entry, such as "  FOO"
+			 * rather than "FOO". Since this code is already
+			 * here, and we don't know what device it is
+			 * trying to work with, leave it as-is.
+			 */
+			max = 8;	/* max length of vendor */
+			while ((max > 0) && *vendor == ' ') {
+				max--;
+				vendor++;
+			}
+			/*
+			 * XXX removing the following strlen() would be
+			 * good, using it means that for a an entry not in
+			 * the list, we scan every byte of every vendor
+			 * listed in scsi_static_device_list[], and never match
+			 * a single one (and still have to compare at
+			 * least the first byte of each vendor).
+			 */
+			if (memcmp(devinfo->vendor, vendor,
+				    min(max, strlen(devinfo->vendor))))
+				continue;
+			/*
+			 * Skip spaces again.
+			 */
+			max = 16;	/* max length of model */
+			while ((max > 0) && *model == ' ') {
+				max--;
+				model++;
+			}
+			if (memcmp(devinfo->model, model,
+				   min(max, strlen(devinfo->model))))
+				continue;
+			return devinfo->flags;
+		} else {
+			if (!memcmp(devinfo->vendor, vendor,
+				     sizeof(devinfo->vendor)) &&
+			     !memcmp(devinfo->model, model,
+				      sizeof(devinfo->model)))
+				return devinfo->flags;
+		}
+	}
+	return scsi_default_dev_flags;
+}
+
+/* 
+ * proc_scsi_dev_info_read: dump the scsi_dev_info_list via
+ * /proc/scsi/device_info
+ */
+static int proc_scsi_devinfo_read(char *buffer, char **start,
+				  off_t offset, int length)
+{
+	struct scsi_dev_info_list *devinfo;
+	int size, len = 0;
+	off_t begin = 0;
+	off_t pos = 0;
+
+	list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
+		size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",
+			devinfo->vendor, devinfo->model, devinfo->flags);
+		len += size;
+		pos = begin + len;
+		if (pos < offset) {
+			len = 0;
+			begin = pos;
+		}
+		if (pos > offset + length)
+			goto stop_output;
+	}
+
+stop_output:
+	*start = buffer + (offset - begin);	/* Start of wanted data */
+	len -= (offset - begin);	/* Start slop */
+	if (len > length)
+		len = length;	/* Ending slop */
+	return (len);
+}
+
+/* 
+ * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
+ * /proc.
+ *
+ * Use: echo "vendor:model:flag" > /proc/scsi/device_info
+ *
+ * To add a black/white list entry for vendor and model with an integer
+ * value of flag to the scsi device info list.
+ */
+static int proc_scsi_devinfo_write(struct file *file, const char *buf,
+				   unsigned long length, void *data)
+{
+	char *buffer;
+	int err = length;
+
+	if (!buf || length>PAGE_SIZE)
+		return -EINVAL;
+	if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
+		return -ENOMEM;
+	if (copy_from_user(buffer, buf, length)) {
+		err =-EFAULT;
+		goto out;
+	}
+
+	if (length < PAGE_SIZE)
+		buffer[length] = '\0';
+	else if (buffer[PAGE_SIZE-1]) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	scsi_dev_info_list_add_str(buffer);
+
+out:
+	free_page((unsigned long)buffer);
+	return err;
+}
+
+MODULE_PARM(scsi_dev_flags, "s");
+MODULE_PARM_DESC(scsi_dev_flags,
+	 "Given scsi_dev_flags=vendor:model:flags, add a black/white list"
+	 " entry for vendor and model with an integer value of flags"
+	 " to the scsi device info list");
+MODULE_PARM(scsi_default_dev_flags, "i");
+MODULE_PARM_DESC(scsi_default_dev_flags,
+		 "scsi default device flag integer value");
+
+static int __init setup_scsi_dev_flags(char *str)
+{
+	scsi_dev_flags = str;
+	return 1;
+}
+
+static int __init setup_scsi_default_dev_flags(char *str)
+{
+	unsigned int tmp;
+	if (get_option(&str, &tmp) == 1) {
+		scsi_default_dev_flags = tmp;
+		printk(KERN_WARNING "%s %d\n", __FUNCTION__,
+		       scsi_default_dev_flags);
+		return 1;
+	} else {
+		printk(KERN_WARNING "%s: usage scsi_default_dev_flags=intr\n",
+		       __FUNCTION__);
+		return 0;
+	}
+}
+
+/**
+ * scsi_dev_info_list_delete: called from scsi.c:exit_scsi to remove
+ * 	the scsi_dev_info_list.
+ **/
+void scsi_exit_devinfo(void)
+{
+	struct list_head *lh, *lh_next;
+	struct scsi_dev_info_list *devinfo;
+
+	remove_proc_entry("scsi/device_info", 0);
+
+	list_for_each_safe(lh, lh_next, &scsi_dev_info_list) {
+		devinfo = list_entry(lh, struct scsi_dev_info_list,
+				     dev_info_list);
+		kfree(devinfo);
+	}
+}
+
+/**
+ * scsi_dev_list_init: set up the dynamic device list.
+ * @dev_list:	string of device flags to add
+ *
+ * Description:
+ * 	Add command line @dev_list entries, then add
+ * 	scsi_static_device_list entries to the scsi device info list.
+ **/
+int scsi_init_devinfo(void)
+{
+	struct proc_dir_entry *p;
+	int error, i;
+
+	error = scsi_dev_info_list_add_str(scsi_dev_flags);
+	if (error)
+		return error;
+
+	for (i = 0; scsi_static_device_list[i].vendor; i++) {
+		error = scsi_dev_info_list_add(1 /* compatibile */,
+				scsi_static_device_list[i].vendor,
+				scsi_static_device_list[i].model,
+				NULL,
+				scsi_static_device_list[i].flags);
+		if (error)
+			goto out;
+	}
+
+	p = create_proc_entry("scsi/device_info", 0, NULL);
+	if (!p) {
+		error = -ENOMEM;
+		goto out;
+	}
+
+	p->owner = THIS_MODULE;
+	p->get_info = proc_scsi_devinfo_read;
+	p->write_proc = proc_scsi_devinfo_write;
+
+ out:
+	if (error)
+		scsi_exit_devinfo();
+	return error;
+}
+
+__setup("scsi_dev_flags=", setup_scsi_dev_flags);
+__setup("scsi_default_dev_flags=", setup_scsi_default_dev_flags);
diff -Nru a/drivers/scsi/scsi_devinfo.h b/drivers/scsi/scsi_devinfo.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/scsi_devinfo.h	Thu May  1 11:29:55 2003
@@ -0,0 +1,16 @@
+
+/*
+ * Flags for SCSI devices that need special treatment
+ */
+#define BLIST_NOLUN     	0x001	/* Only scan LUN 0 */
+#define BLIST_FORCELUN  	0x002	/* Known to have LUNs, force scanning */
+#define BLIST_BORKEN    	0x004	/* Flag for broken handshaking */
+#define BLIST_KEY       	0x008	/* unlock by special command */
+#define BLIST_SINGLELUN 	0x010	/* Do not use LUNs in parallel */
+#define BLIST_NOTQ		0x020	/* Buggy Tagged Command Queuing */
+#define BLIST_SPARSELUN 	0x040	/* Non consecutive LUN numbering */
+#define BLIST_MAX5LUN		0x080	/* Avoid LUNS >= 5 */
+#define BLIST_ISROM     	0x100	/* Treat as (removable) CD-ROM */
+#define BLIST_LARGELUN		0x200	/* LUNs past 7 on a SCSI-2 device */
+#define BLIST_INQUIRY_36	0x400	/* override additional length field */
+#define BLIST_INQUIRY_58	0x800	/* ... for broken inquiry responses */
diff -Nru a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
--- a/drivers/scsi/scsi_error.c	Mon Apr 21 07:17:33 2003
+++ b/drivers/scsi/scsi_error.c	Mon May 12 20:52:56 2003
@@ -28,6 +28,9 @@
 #include "scsi.h"
 #include "hosts.h"
 
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
 #ifdef DEBUG
 #define SENSE_TIMEOUT SCSI_TIMEOUT
 #else
@@ -188,7 +191,7 @@
 	return sdev->online;
 }
 
-#if CONFIG_SCSI_LOGGING
+#ifdef CONFIG_SCSI_LOGGING
 /**
  * scsi_eh_prt_fail_stats - Log info on failures.
  * @shost:	scsi host being recovered.
@@ -916,7 +919,6 @@
  **/
 static int scsi_try_bus_reset(struct scsi_cmnd *scmd)
 {
-	struct scsi_device *sdev;
 	unsigned long flags;
 	int rtn;
 
@@ -934,16 +936,9 @@
 
 	if (rtn == SUCCESS) {
 		scsi_sleep(BUS_RESET_SETTLE_TIME);
-		/*
-		 * Mark all affected devices to expect a unit attention.
-		 */
-		list_for_each_entry(sdev, &scmd->device->host->my_devices,
-				    siblings)
-			if (scmd->device->channel == sdev->channel) {
-				sdev->was_reset = 1;
-				sdev->expecting_cc_ua = 1;
-			}
+		scsi_report_bus_reset(scmd->device->host, scmd->device->channel);
 	}
+
 	return rtn;
 }
 
@@ -953,7 +948,6 @@
  **/
 static int scsi_try_host_reset(struct scsi_cmnd *scmd)
 {
-	struct scsi_device *sdev;
 	unsigned long flags;
 	int rtn;
 
@@ -971,16 +965,9 @@
 
 	if (rtn == SUCCESS) {
 		scsi_sleep(HOST_RESET_SETTLE_TIME);
-		/*
-		 * Mark all affected devices to expect a unit attention.
-		 */
-		list_for_each_entry(sdev, &scmd->device->host->my_devices,
-				    siblings)
-			if (scmd->device->channel == sdev->channel) {
-				sdev->was_reset = 1;
-				sdev->expecting_cc_ua = 1;
-			}
+		scsi_report_bus_reset(scmd->device->host, scmd->device->channel);
 	}
+
 	return rtn;
 }
 
@@ -1425,8 +1412,7 @@
 	 * now that error recovery is done, we will need to ensure that these
 	 * requests are started.
 	 */
-	list_for_each_entry(sdev, &shost->my_devices, siblings)
-		blk_run_queue(sdev->request_queue);
+	scsi_run_host_queues(shost);
 }
 
 /**
@@ -1638,6 +1624,74 @@
 	complete_and_exit(shost->eh_notify, 0);
 }
 
+/*
+ * Function:    scsi_report_bus_reset()
+ *
+ * Purpose:     Utility function used by low-level drivers to report that
+ *		they have observed a bus reset on the bus being handled.
+ *
+ * Arguments:   shost       - Host in question
+ *		channel     - channel on which reset was observed.
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes:       This only needs to be called if the reset is one which
+ *		originates from an unknown location.  Resets originated
+ *		by the mid-level itself don't need to call this, but there
+ *		should be no harm.
+ *
+ *		The main purpose of this is to make sure that a CHECK_CONDITION
+ *		is properly treated.
+ */
+void scsi_report_bus_reset(struct Scsi_Host *shost, int channel)
+{
+	struct scsi_device *sdev;
+
+	list_for_each_entry(sdev, &shost->my_devices, siblings) {
+		if (channel == sdev->channel) {
+			sdev->was_reset = 1;
+			sdev->expecting_cc_ua = 1;
+		}
+	}
+}
+
+/*
+ * Function:    scsi_report_device_reset()
+ *
+ * Purpose:     Utility function used by low-level drivers to report that
+ *		they have observed a device reset on the device being handled.
+ *
+ * Arguments:   shost       - Host in question
+ *		channel     - channel on which reset was observed
+ *		target	    - target on which reset was observed
+ *
+ * Returns:     Nothing
+ *
+ * Lock status: No locks are assumed held.
+ *
+ * Notes:       This only needs to be called if the reset is one which
+ *		originates from an unknown location.  Resets originated
+ *		by the mid-level itself don't need to call this, but there
+ *		should be no harm.
+ *
+ *		The main purpose of this is to make sure that a CHECK_CONDITION
+ *		is properly treated.
+ */
+void scsi_report_device_reset(struct Scsi_Host *shost, int channel, int target)
+{
+	struct scsi_device *sdev;
+
+	list_for_each_entry(sdev, &shost->my_devices, siblings) {
+		if (channel == sdev->channel &&
+		    target == sdev->id) {
+			sdev->was_reset = 1;
+			sdev->expecting_cc_ua = 1;
+		}
+	}
+}
+
 static void
 scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
 {
@@ -1662,7 +1716,6 @@
 	struct scsi_cmnd *scmd = scsi_get_command(dev, GFP_KERNEL);
 	struct request req;
 	int rtn;
-	struct request_queue *q;
 
 	scmd->request = &req;
 	memset(&scmd->eh_timeout, 0, sizeof(scmd->eh_timeout));
@@ -1674,13 +1727,10 @@
     
 	scmd->scsi_done		= scsi_reset_provider_done_command;
 	scmd->done			= NULL;
-	scmd->reset_chain		= NULL;
-        
 	scmd->buffer			= NULL;
 	scmd->bufflen			= 0;
 	scmd->request_buffer		= NULL;
 	scmd->request_bufflen		= 0;
-
 	scmd->internal_timeout		= NORMAL_TIMEOUT;
 	scmd->abort_reason		= DID_ABORT;
 
@@ -1717,8 +1767,6 @@
 	}
 
 	scsi_delete_timer(scmd);
-	q = scmd->device->request_queue;
-	scsi_put_command(scmd);
-	scsi_queue_next_request(q, NULL);
+	scsi_next_command(scmd);
 	return rtn;
 }
diff -Nru a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
--- a/drivers/scsi/scsi_ioctl.c	Wed Mar 26 01:47:18 2003
+++ b/drivers/scsi/scsi_ioctl.c	Sat Apr 26 13:04:25 2003
@@ -23,6 +23,8 @@
 #include "hosts.h"
 #include <scsi/scsi_ioctl.h>
 
+#include "scsi_logging.h"
+
 #define NORMAL_RETRIES			5
 #define IOCTL_NORMAL_TIMEOUT			(10 * HZ)
 #define FORMAT_UNIT_TIMEOUT		(2 * 60 * 60 * HZ)
diff -Nru a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
--- a/drivers/scsi/scsi_lib.c	Mon Apr 21 07:17:33 2003
+++ b/drivers/scsi/scsi_lib.c	Thu May  8 12:14:09 2003
@@ -19,6 +19,9 @@
 #include "scsi.h"
 #include "hosts.h"
 
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
 
 #define SG_MEMPOOL_NR		5
 #define SG_MEMPOOL_SIZE		32
@@ -178,19 +181,12 @@
 		 void (*done)(struct scsi_cmnd *),
 		 int timeout, int retries)
 {
-	struct request_queue *q;
-
 	/*
 	 * If the upper level driver is reusing these things, then
 	 * we should release the low-level block now.  Another one will
 	 * be allocated later when this request is getting queued.
 	 */
-	if (sreq->sr_command) {
-		q = sreq->sr_command->device->request_queue;
-		scsi_put_command(sreq->sr_command);
-		sreq->sr_command = NULL;
-		scsi_queue_next_request(q, NULL);
-	}
+	__scsi_release_request(sreq);
 
 	/*
 	 * Our own function scsi_done (which marks the host as not busy,
@@ -236,7 +232,6 @@
 void scsi_wait_req(struct scsi_request *sreq, const void *cmnd, void *buffer,
 		   unsigned bufflen, int timeout, int retries)
 {
-	struct request_queue *q;
 	DECLARE_COMPLETION(wait);
 	
 	sreq->sr_request->waiting = &wait;
@@ -247,12 +242,7 @@
 	wait_for_completion(&wait);
 	sreq->sr_request->waiting = NULL;
 
-	if (sreq->sr_command) {
-		q = sreq->sr_command->device->request_queue;
-		scsi_put_command(sreq->sr_command);
-		scsi_queue_next_request(q, NULL);
-		sreq->sr_command = NULL;
-	}
+	__scsi_release_request(sreq);
 }
 
 /*
@@ -271,7 +261,6 @@
 static int scsi_init_cmd_errh(struct scsi_cmnd *cmd)
 {
 	cmd->owner = SCSI_OWNER_MIDLEVEL;
-	cmd->reset_chain = NULL;
 	cmd->serial_number = 0;
 	cmd->serial_number_at_timeout = 0;
 	cmd->flags = 0;
@@ -296,7 +285,6 @@
 	memcpy(cmd->data_cmnd, cmd->cmnd, sizeof(cmd->cmnd));
 	cmd->buffer = cmd->request_buffer;
 	cmd->bufflen = cmd->request_bufflen;
-	cmd->reset_chain = NULL;
 	cmd->internal_timeout = NORMAL_TIMEOUT;
 	cmd->abort_reason = 0;
 
@@ -369,77 +357,26 @@
 }
 
 /*
- * Function:    scsi_queue_next_request()
+ * Function:	scsi_run_queue()
  *
- * Purpose:     Handle post-processing of completed commands.
+ * Purpose:	Select a proper request queue to serve next
  *
- * Arguments:   cmd	- command that may need to be requeued.
+ * Arguments:	q	- last request's queue
  *
  * Returns:     Nothing
  *
- * Notes:       After command completion, there may be blocks left
- *              over which weren't finished by the previous command
- *              this can be for a number of reasons - the main one is
- *              that a medium error occurred, and the sectors after
- *              the bad block need to be re-read.
- *
- *              If cmd is NULL, it means that the previous command
- *              was completely finished, and we should simply start
- *              a new command, if possible.
- *
- *		This is where a lot of special case code has begun to
- *		accumulate.  It doesn't really affect readability or
- *		anything, but it might be considered architecturally
- *		inelegant.  If more of these special cases start to
- *		accumulate, I am thinking along the lines of implementing
- *		an atexit() like technology that gets run when commands
- *		complete.  I am not convinced that it is worth the
- *		added overhead, however.  Right now as things stand,
- *		there are simple conditional checks, and most hosts
- *		would skip past.
- *
- *		Another possible solution would be to tailor different
- *		handler functions, sort of like what we did in scsi_merge.c.
- *		This is probably a better solution, but the number of different
- *		permutations grows as 2**N, and if too many more special cases
- *		get added, we start to get screwed.
+ * Notes:	The previous command was completely finished, start
+ *		a new one if possible.
  */
-void scsi_queue_next_request(request_queue_t *q, struct scsi_cmnd *cmd)
+static void scsi_run_queue(struct request_queue *q)
 {
-	struct scsi_device *sdev;
-	struct Scsi_Host *shost;
+	struct scsi_device *sdev = q->queuedata;
+	struct Scsi_Host *shost = sdev->host;
 	unsigned long flags;
 
-	if (cmd != NULL) {
-
-		/*
-		 * For some reason, we are not done with this request.
-		 * This happens for I/O errors in the middle of the request,
-		 * in which case we need to request the blocks that come after
-		 * the bad sector.
-		 */
-		spin_lock_irqsave(q->queue_lock, flags);
-		cmd->request->special = cmd;
-		if (blk_rq_tagged(cmd->request))
-			blk_queue_end_tag(q, cmd->request);
-
-		/*
-		 * set REQ_SPECIAL - we have a command
-		 * clear REQ_DONTPREP - we assume the sg table has been 
-		 *	nuked so we need to set it up again.
-		 */
-		cmd->request->flags |= REQ_SPECIAL;
-		cmd->request->flags &= ~REQ_DONTPREP;
-		__elv_add_request(q, cmd->request, 0, 0);
-		spin_unlock_irqrestore(q->queue_lock, flags);
-	}
-
-	sdev = q->queuedata;
-
 	if (sdev->single_lun)
 		scsi_single_lun_run(sdev);
 
-	shost = sdev->host;
 	spin_lock_irqsave(shost->host_lock, flags);
 	while (!list_empty(&shost->starved_list) &&
 	       !shost->host_blocked && !shost->host_self_blocked &&
@@ -477,6 +414,61 @@
 }
 
 /*
+ * Function:	scsi_requeue_command()
+ *
+ * Purpose:	Handle post-processing of completed commands.
+ *
+ * Arguments:	q	- queue to operate on
+ *		cmd	- command that may need to be requeued.
+ *
+ * Returns:	Nothing
+ *
+ * Notes:	After command completion, there may be blocks left
+ *		over which weren't finished by the previous command
+ *		this can be for a number of reasons - the main one is
+ *		I/O errors in the middle of the request, in which case
+ *		we need to request the blocks that come after the bad
+ *		sector.
+ */
+static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(q->queue_lock, flags);
+	cmd->request->special = cmd;
+	if (blk_rq_tagged(cmd->request))
+		blk_queue_end_tag(q, cmd->request);
+
+	/*
+	 * set REQ_SPECIAL - we have a command
+	 * clear REQ_DONTPREP - we assume the sg table has been 
+	 *	nuked so we need to set it up again.
+	 */
+	cmd->request->flags |= REQ_SPECIAL;
+	cmd->request->flags &= ~REQ_DONTPREP;
+	__elv_add_request(q, cmd->request, 0, 0);
+	spin_unlock_irqrestore(q->queue_lock, flags);
+
+	scsi_run_queue(q);
+}
+
+void scsi_next_command(struct scsi_cmnd *cmd)
+{
+	struct request_queue *q = cmd->device->request_queue;
+
+	scsi_put_command(cmd);
+	scsi_run_queue(q);
+}
+
+void scsi_run_host_queues(struct Scsi_Host *shost)
+{
+	struct scsi_device *sdev;
+
+	list_for_each_entry(sdev, &shost->my_devices, siblings)
+		scsi_run_queue(sdev->request_queue);
+}
+
+/*
  * Function:    scsi_end_request()
  *
  * Purpose:     Post-processing of completed commands called from interrupt
@@ -516,7 +508,7 @@
 			 * Bleah.  Leftovers again.  Stick the leftovers in
 			 * the front of the queue, and goose the queue again.
 			 */
-			scsi_queue_next_request(q, cmd);
+			scsi_requeue_command(q, cmd);
 		}
 		return cmd;
 	}
@@ -533,8 +525,7 @@
 	 * This will goose the queue request function at the end, so we don't
 	 * need to worry about launching another command.
 	 */
-	scsi_put_command(cmd);
-	scsi_queue_next_request(q, NULL);
+	scsi_next_command(cmd);
 	return NULL;
 }
 
@@ -660,6 +651,18 @@
  *              In other words, if there are no bounce buffers
  *              (the normal case for most drivers), we don't need
  *              the logic to deal with cleaning up afterwards.
+ *
+ *		We must do one of several things here:
+ *
+ *		a) Call scsi_end_request.  This will finish off the
+ *		   specified 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 queue.
+ *
+ *		b) We can just use scsi_requeue_command() here.  This would
+ *		   be used if we just wanted to retry, for example.
+ *
  */
 void scsi_io_completion(struct scsi_cmnd *cmd, int good_sectors,
 			int block_sectors)
@@ -671,19 +674,6 @@
 	int clear_errors = 1;
 
 	/*
-	 * We must do one of several things here:
-	 *
-	 *	Call scsi_end_request.  This will finish off the specified
-	 *	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 queue.
-	 *
-	 *	We can just use scsi_queue_next_request() here.  This
-	 *	would be used if we just wanted to retry, for example.
-	 *
-	 */
-	/*
 	 * Free up any indirection buffers we allocated for DMA purposes. 
 	 * For the case of a READ, we need to copy the data out of the
 	 * bounce buffer and into the real buffer.
@@ -782,7 +772,7 @@
 			 */
 			if (cmd->sense_buffer[12] == 0x04 &&
 			    cmd->sense_buffer[13] == 0x01) {
-				scsi_queue_next_request(q, cmd);
+				scsi_requeue_command(q, cmd);
 				return;
 			}
 			if ((cmd->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
@@ -801,7 +791,7 @@
 				 	* media change, so we just retry the
 				 	* request and see what happens.  
 				 	*/
-					scsi_queue_next_request(q, cmd);
+					scsi_requeue_command(q, cmd);
 					return;
 				}
 			}
@@ -821,7 +811,7 @@
 				 * This will cause a retry with a 6-byte
 				 * command.
 				 */
-				scsi_queue_next_request(q, cmd);
+				scsi_requeue_command(q, cmd);
 				result = 0;
 			} else {
 				cmd = scsi_end_request(cmd, 0, this_count, 1);
@@ -853,7 +843,7 @@
 		 * recovery reasons.  Just retry the request
 		 * and see what happens.  
 		 */
-		scsi_queue_next_request(q, cmd);
+		scsi_requeue_command(q, cmd);
 		return;
 	}
 	if (result) {
@@ -1140,66 +1130,61 @@
  *
  * Lock status: IO request lock assumed to be held when called.
  */
-static void scsi_request_fn(request_queue_t *q)
+static void scsi_request_fn(struct request_queue *q)
 {
 	struct scsi_device *sdev = q->queuedata;
 	struct Scsi_Host *shost = sdev->host;
 	struct scsi_cmnd *cmd;
 	struct request *req;
-	unsigned long flags;
 
 	/*
 	 * To start with, we keep looping until the queue is empty, or until
 	 * the host is no longer able to accept any more requests.
 	 */
-	for (;;) {
-		if (blk_queue_plugged(q))
-			goto completed;
-
+	while (!blk_queue_plugged(q)) {
 		/*
 		 * get next queueable request.  We do this early to make sure
 		 * that the request is fully prepared even if we cannot 
 		 * accept it.
 		 */
 		req = elv_next_request(q);
-
-		if (!req)
-			goto completed;
-
-		if (!scsi_dev_queue_ready(q, sdev))
-			goto completed;
+		if (!req || !scsi_dev_queue_ready(q, sdev))
+			break;
 
 		/*
 		 * Remove the request from the request list.
 		 */
-		if (!(blk_queue_tagged(q) && (blk_queue_start_tag(q, req) == 0)))
+		if (!(blk_queue_tagged(q) && !blk_queue_start_tag(q, req)))
 			blkdev_dequeue_request(req);
-
 		sdev->device_busy++;
-		spin_unlock_irq(q->queue_lock);
 
-		spin_lock_irqsave(shost->host_lock, flags);
-		if (!scsi_host_queue_ready(q, shost, sdev))
-			goto host_lock_held;
+		spin_unlock(q->queue_lock);
+		spin_lock(shost->host_lock);
 
+		if (!scsi_host_queue_ready(q, shost, sdev))
+			goto not_ready;
 		if (sdev->single_lun) {
 			if (sdev->sdev_target->starget_sdev_user &&
-			    (sdev->sdev_target->starget_sdev_user != sdev))
-				goto host_lock_held;
-			else
-				sdev->sdev_target->starget_sdev_user = sdev;
+			    sdev->sdev_target->starget_sdev_user != sdev)
+				goto not_ready;
+			sdev->sdev_target->starget_sdev_user = sdev;
 		}
-
 		shost->host_busy++;
-		spin_unlock_irqrestore(shost->host_lock, flags);
-
-		cmd = req->special;
 
 		/*
-		 * Should be impossible for a correctly prepared request
-		 * please mail the stack trace to linux-scsi@vger.kernel.org
+		 * XXX(hch): This is rather suboptimal, scsi_dispatch_cmd will
+		 *		take the lock again.
 		 */
-		BUG_ON(!cmd);
+		spin_unlock_irq(shost->host_lock);
+
+		cmd = req->special;
+		if (unlikely(cmd == NULL)) {
+			printk(KERN_CRIT "impossible request in %s.\n"
+					 "please mail a stack trace to "
+					 "linux-scsi@vger.kernel.org",
+					 __FUNCTION__);
+			BUG();
+		}
 
 		/*
 		 * Finally, initialize any error handling parameters, and set up
@@ -1211,18 +1196,14 @@
 		 * Dispatch the command to the low-level driver.
 		 */
 		scsi_dispatch_cmd(cmd);
-
-		/*
-		 * Now we need to grab the lock again.  We are about to mess
-		 * with the request queue and try to find another command.
-		 */
 		spin_lock_irq(q->queue_lock);
 	}
-completed:
+
 	return;
 
-host_lock_held:
-	spin_unlock_irqrestore(shost->host_lock, flags);
+ not_ready:
+	spin_unlock_irq(shost->host_lock);
+
 	/*
 	 * lock q, handle tag, requeue req, and decrement device_busy. We
 	 * must return with queue_lock held.
@@ -1257,28 +1238,15 @@
 	return BLK_BOUNCE_HIGH;
 }
 
-request_queue_t *scsi_alloc_queue(struct scsi_device *sdev)
+struct request_queue *scsi_alloc_queue(struct scsi_device *sdev)
 {
-	request_queue_t *q;
-	struct Scsi_Host *shost;
+	struct Scsi_Host *shost = sdev->host;
+	struct request_queue *q = kmalloc(sizeof(*q), GFP_ATOMIC);
 
-	q = kmalloc(sizeof(*q), GFP_ATOMIC);
 	if (!q)
 		return NULL;
 	memset(q, 0, sizeof(*q));
 
-	/*
-	 * XXX move host code to scsi_register
-	 */
-	shost = sdev->host;
-	if (!shost->max_sectors) {
-		/*
-		 * Driver imposes no hard sector transfer limit.
-		 * start at machine infinity initially.
-		 */
-		shost->max_sectors = SCSI_DEFAULT_MAX_SECTORS;
-	}
-
 	blk_init_queue(q, scsi_request_fn, &sdev->sdev_lock);
 	blk_queue_prep_rq(q, scsi_prep_fn);
 
@@ -1289,11 +1257,10 @@
 
 	if (!shost->use_clustering)
 		clear_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
-
 	return q;
 }
 
-void scsi_free_queue(request_queue_t *q)
+void scsi_free_queue(struct request_queue *q)
 {
 	blk_cleanup_queue(q);
 	kfree(q);
@@ -1342,48 +1309,8 @@
  */
 void scsi_unblock_requests(struct Scsi_Host *shost)
 {
-	struct scsi_device *sdev;
-
 	shost->host_self_blocked = 0;
-
-	/*
-	 * Now that we are unblocked, try to start the queues.
-	 */
-	list_for_each_entry(sdev, &shost->my_devices, siblings)
-		scsi_queue_next_request(sdev->request_queue, NULL);
-}
-
-/*
- * Function:    scsi_report_bus_reset()
- *
- * Purpose:     Utility function used by low-level drivers to report that
- *		they have observed a bus reset on the bus being handled.
- *
- * Arguments:   shost       - Host in question
- *		channel     - channel on which reset was observed.
- *
- * Returns:     Nothing
- *
- * Lock status: No locks are assumed held.
- *
- * Notes:       This only needs to be called if the reset is one which
- *		originates from an unknown location.  Resets originated
- *		by the mid-level itself don't need to call this, but there
- *		should be no harm.
- *
- *		The main purpose of this is to make sure that a CHECK_CONDITION
- *		is properly treated.
- */
-void scsi_report_bus_reset(struct Scsi_Host *shost, int channel)
-{
-	struct scsi_device *sdev;
-
-	list_for_each_entry(sdev, &shost->my_devices, siblings) {
-		if (channel == sdev->channel) {
-			sdev->was_reset = 1;
-			sdev->expecting_cc_ua = 1;
-		}
-	}
+	scsi_run_host_queues(shost);
 }
 
 int __init scsi_init_queue(void)
diff -Nru a/drivers/scsi/scsi_logging.h b/drivers/scsi/scsi_logging.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/scsi_logging.h	Tue Apr 29 08:29:44 2003
@@ -0,0 +1,117 @@
+#ifndef _SCSI_LOGGING_H
+#define _SCSI_LOGGING_H
+
+#include <linux/config.h>
+
+/*
+ * This defines the scsi logging feature.  It is a means by which the user
+ * can select how much information they get about various goings on, and it
+ * can be really useful for fault tracing.  The logging word is divided into
+ * 8 nibbles, each of which describes a loglevel.  The division of things is
+ * somewhat arbitrary, and the division of the word could be changed if it
+ * were really needed for any reason.  The numbers below are the only place
+ * where these are specified.  For a first go-around, 3 bits is more than
+ * enough, since this gives 8 levels of logging (really 7, since 0 is always
+ * off).  Cutting to 2 bits might be wise at some point.
+ */
+
+#define SCSI_LOG_ERROR_SHIFT              0
+#define SCSI_LOG_TIMEOUT_SHIFT            3
+#define SCSI_LOG_SCAN_SHIFT               6
+#define SCSI_LOG_MLQUEUE_SHIFT            9
+#define SCSI_LOG_MLCOMPLETE_SHIFT         12
+#define SCSI_LOG_LLQUEUE_SHIFT            15
+#define SCSI_LOG_LLCOMPLETE_SHIFT         18
+#define SCSI_LOG_HLQUEUE_SHIFT            21
+#define SCSI_LOG_HLCOMPLETE_SHIFT         24
+#define SCSI_LOG_IOCTL_SHIFT              27
+
+#define SCSI_LOG_ERROR_BITS               3
+#define SCSI_LOG_TIMEOUT_BITS             3
+#define SCSI_LOG_SCAN_BITS                3
+#define SCSI_LOG_MLQUEUE_BITS             3
+#define SCSI_LOG_MLCOMPLETE_BITS          3
+#define SCSI_LOG_LLQUEUE_BITS             3
+#define SCSI_LOG_LLCOMPLETE_BITS          3
+#define SCSI_LOG_HLQUEUE_BITS             3
+#define SCSI_LOG_HLCOMPLETE_BITS          3
+#define SCSI_LOG_IOCTL_BITS               3
+
+
+#ifdef CONFIG_SCSI_LOGGING
+extern unsigned int scsi_logging_level;
+#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)		\
+{								\
+        unsigned int mask = (1 << (BITS)) - 1;			\
+        if (((scsi_logging_level >> (SHIFT)) & mask) > (LEVEL))	\
+		(CMD);						\
+}
+
+#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)			\
+{								\
+        unsigned int mask = ((1 << (BITS)) - 1) << SHIFT;	\
+        scsi_logging_level = ((scsi_logging_level & ~mask)	\
+                              | ((LEVEL << SHIFT) & mask));	\
+}
+#else
+/*
+ * With no logging enabled, stub these out so they don't do anything.
+ */
+#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)
+#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)
+#endif /* CONFIG_SCSI_LOGGING */
+
+/*
+ * These are the macros that are actually used throughout the code to
+ * log events.  If logging isn't enabled, they are no-ops and will be
+ * completely absent from the user's code.
+ *
+ * The 'set' versions of the macros are really intended to only be called
+ * from the /proc filesystem, and in production kernels this will be about
+ * all that is ever used.  It could be useful in a debugging environment to
+ * bump the logging level when certain strange events are detected, however.
+ */
+#define SCSI_LOG_ERROR_RECOVERY(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD);
+#define SCSI_LOG_TIMEOUT(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL,CMD);
+#define SCSI_LOG_SCAN_BUS(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL,CMD);
+#define SCSI_LOG_MLQUEUE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_MLCOMPLETE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_LLQUEUE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_LLCOMPLETE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_HLQUEUE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_HLCOMPLETE(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_IOCTL(LEVEL,CMD)  \
+        SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD);
+
+
+#define SCSI_SET_ERROR_RECOVERY_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL);
+#define SCSI_SET_TIMEOUT_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL);
+#define SCSI_SET_SCAN_BUS_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL);
+#define SCSI_SET_MLQUEUE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL);
+#define SCSI_SET_MLCOMPLETE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL);
+#define SCSI_SET_LLQUEUE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL);
+#define SCSI_SET_LLCOMPLETE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL);
+#define SCSI_SET_HLQUEUE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL);
+#define SCSI_SET_HLCOMPLETE_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL);
+#define SCSI_SET_IOCTL_LOGGING(LEVEL)  \
+        SCSI_SET_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL);
+
+#endif /* _SCSI_LOGGING_H */
diff -Nru a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/scsi/scsi_priv.h	Sun May 11 15:12:54 2003
@@ -0,0 +1,132 @@
+#ifndef _SCSI_PRIV_H
+#define _SCSI_PRIV_H
+
+/*
+ * These are the values that the owner field can take.
+ * They are used as an indication of who the command belongs to.
+ */
+#define SCSI_OWNER_HIGHLEVEL      0x100
+#define SCSI_OWNER_MIDLEVEL       0x101
+#define SCSI_OWNER_LOWLEVEL       0x102
+#define SCSI_OWNER_ERROR_HANDLER  0x103
+#define SCSI_OWNER_BH_HANDLER     0x104
+#define SCSI_OWNER_NOBODY         0x105
+
+/*
+ * Magic values for certain scsi structs. Shouldn't ever be used.
+ */
+#define SCSI_CMND_MAGIC		0xE25C23A5
+#define SCSI_REQ_MAGIC		0x75F6D354
+
+/*
+ *  Flag bit for the internal_timeout array
+ */
+#define NORMAL_TIMEOUT		0
+
+/*
+ * Scsi Error Handler Flags
+ */
+#define scsi_eh_eflags_chk(scp, flags) \
+	((scp)->eh_eflags & (flags))
+#define scsi_eh_eflags_set(scp, flags) \
+	do { (scp)->eh_eflags |= (flags); } while(0)
+#define scsi_eh_eflags_clr(scp, flags) \
+	do { (scp)->eh_eflags &= ~(flags); } while(0)
+#define scsi_eh_eflags_clr_all(scp) \
+	(scp->eh_eflags = 0)
+
+#define SCSI_EH_CANCEL_CMD	0x0001	/* Cancel this cmd */
+#define SCSI_EH_REC_TIMEOUT	0x0002	/* EH retry timed out */
+
+#define SCSI_SENSE_VALID(scmd) \
+	(((scmd)->sense_buffer[0] & 0x70) == 0x70)
+
+struct Scsi_Device_Template;
+
+
+/*
+ * scsi_target: representation of a scsi target, for now, this is only
+ * used for single_lun devices. If no one has active IO to the target,
+ * starget_sdev_user is NULL, else it points to the active sdev.
+ */
+struct scsi_target {
+	struct scsi_device	*starget_sdev_user;
+	unsigned int		starget_refcnt;
+};
+
+
+/* hosts.c */
+extern void scsi_host_busy_inc(struct Scsi_Host *, Scsi_Device *);
+extern void scsi_host_busy_dec_and_test(struct Scsi_Host *, Scsi_Device *);
+extern struct Scsi_Host *scsi_host_get_next(struct Scsi_Host *);
+extern void scsi_host_init(void);
+
+/* scsi.c */
+extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
+extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
+extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
+extern void scsi_done(struct scsi_cmnd *cmd);
+extern void scsi_finish_command(struct scsi_cmnd *cmd);
+extern int scsi_retry_command(struct scsi_cmnd *cmd);
+extern int scsi_attach_device(struct scsi_device *sdev);
+extern void scsi_detach_device(struct scsi_device *sdev);
+extern void scsi_rescan_device(struct scsi_device *sdev);
+extern int scsi_insert_special_req(struct scsi_request *sreq, int);
+extern void scsi_init_cmd_from_req(struct scsi_cmnd *cmd,
+		struct scsi_request *sreq);
+extern void __scsi_release_request(struct scsi_request *sreq);
+
+/* scsi_devinfo.c */
+extern int scsi_get_device_flags(unsigned char *vendor, unsigned char *model);
+extern int scsi_init_devinfo(void);
+extern void scsi_exit_devinfo(void);
+
+/* scsi_error.c */
+extern void scsi_times_out(struct scsi_cmnd *cmd);
+extern void scsi_error_handler(void *host);
+extern int scsi_decide_disposition(struct scsi_cmnd *cmd);
+extern int scsi_eh_scmd_add(struct scsi_cmnd *, int);
+
+/* scsi_lib.c */
+extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
+extern void scsi_setup_cmd_retry(struct scsi_cmnd *cmd);
+extern int scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
+extern void scsi_next_command(struct scsi_cmnd *cmd);
+extern void scsi_run_host_queues(struct Scsi_Host *shost);
+extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
+extern void scsi_free_queue(struct request_queue *q);
+extern int scsi_init_queue(void);
+extern void scsi_exit_queue(void);
+
+/* scsi_proc.c */
+#ifdef CONFIG_PROC_FS
+extern void scsi_proc_host_add(struct Scsi_Host *);
+extern void scsi_proc_host_rm(struct Scsi_Host *);
+extern int scsi_init_procfs(void);
+extern void scsi_exit_procfs(void);
+#else
+# define scsi_proc_host_add(shost)	do { } while (0)
+# define scsi_proc_host_rm(shost)	do { } while (0)
+# define scsi_init_procfs()		(0)
+# define scsi_exit_procfs		do { } while (0)
+#endif /* CONFIG_PROC_FS */
+
+/* scsi_scan.c */
+extern void scsi_scan_host(struct Scsi_Host *shost);
+extern void scsi_forget_host(struct Scsi_Host *shost);
+extern void scsi_free_sdev(struct scsi_device *);
+extern void scsi_free_shost(struct Scsi_Host *);
+extern void scsi_host_get(struct Scsi_Host *);
+
+/* scsi_sysfs.c */
+extern int scsi_device_register(struct scsi_device *);
+extern void scsi_device_unregister(struct scsi_device *);
+extern int scsi_upper_driver_register(struct Scsi_Device_Template *);
+extern void scsi_upper_driver_unregister(struct Scsi_Device_Template *);
+extern void scsi_sysfs_init_host(struct Scsi_Host *);
+extern int scsi_sysfs_add_host(struct Scsi_Host *, struct device *);
+extern void scsi_sysfs_remove_host(struct Scsi_Host *);
+extern int scsi_sysfs_register(void);
+extern void scsi_sysfs_unregister(void);
+
+#endif /* _SCSI_PRIV_H */
diff -Nru a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
--- a/drivers/scsi/scsi_proc.c	Wed Apr 23 01:03:43 2003
+++ b/drivers/scsi/scsi_proc.c	Thu May  8 11:24:15 2003
@@ -29,6 +29,10 @@
 #include "scsi.h"
 #include "hosts.h"
 
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+
+
 /* 4K page size, but our output routines, use some slack for overruns */
 #define PROC_BLOCK_SIZE (3*1024)
 
@@ -196,77 +200,6 @@
 	return;
 }
 
-/* 
- * proc_scsi_dev_info_read: dump the scsi_dev_info_list via
- * /proc/scsi/device_info
- */
-static int proc_scsi_dev_info_read(char *buffer, char **start, off_t offset,
-				   int length)
-{
-	struct scsi_dev_info_list *devinfo;
-	int size, len = 0;
-	off_t begin = 0;
-	off_t pos = 0;
-
-	list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) {
-		size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n",
-			       devinfo->vendor, devinfo->model, devinfo->flags);
-		len += size;
-		pos = begin + len;
-		if (pos < offset) {
-			len = 0;
-			begin = pos;
-		}
-		if (pos > offset + length)
-			goto stop_output;
-	}
-
-stop_output:
-	*start = buffer + (offset - begin);	/* Start of wanted data */
-	len -= (offset - begin);	/* Start slop */
-	if (len > length)
-		len = length;	/* Ending slop */
-	return (len);
-}
-
-/* 
- * proc_scsi_dev_info_write: allow additions to the scsi_dev_info_list via
- * /proc.
- *
- * Use: echo "vendor:model:flag" > /proc/scsi/device_info
- *
- * To add a black/white list entry for vendor and model with an integer
- * value of flag to the scsi device info list.
- */
-static int proc_scsi_dev_info_write (struct file * file, const char * buf,
-                              unsigned long length, void *data)
-{
-	char *buffer;
-	int err = length;
-
-	if (!buf || length>PAGE_SIZE)
-		return -EINVAL;
-	if (!(buffer = (char *) __get_free_page(GFP_KERNEL)))
-		return -ENOMEM;
-	if (copy_from_user(buffer, buf, length)) {
-		err =-EFAULT;
-		goto out;
-	}
-
-	if (length < PAGE_SIZE)
-		buffer[length] = '\0';
-	else if (buffer[PAGE_SIZE-1]) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	scsi_dev_info_list_add_str(buffer);
-
-out:
-	free_page((unsigned long)buffer);
-	return err;
-}
-
 static int scsi_proc_info(char *buffer, char **start, off_t offset, int length)
 {
 	struct Scsi_Host *shost;
@@ -312,91 +245,6 @@
 	return (len);
 }
 
-#ifdef CONFIG_SCSI_LOGGING
-/*
- * Function:    scsi_dump_status
- *
- * Purpose:     Brain dump of scsi system, used for problem solving.
- *
- * Arguments:   level - used to indicate level of detail.
- *
- * Notes:       The level isn't used at all yet, but we need to find some
- *		way of sensibly logging varying degrees of information.
- *		A quick one-line display of each command, plus the status
- *		would be most useful.
- *
- *              This does depend upon CONFIG_SCSI_LOGGING - I do want some
- *		way of turning it all off if the user wants a lean and mean
- *		kernel.  It would probably also be useful to allow the user
- *		to specify one single host to be dumped.  A second argument
- *		to the function would be useful for that purpose.
- *
- *              FIXME - some formatting of the output into tables would be
- *		        very handy.
- */
-static void scsi_dump_status(int level)
-{
-	int i;
-	struct Scsi_Host *shpnt;
-	Scsi_Cmnd *SCpnt;
-	Scsi_Device *SDpnt;
-	printk(KERN_INFO "Dump of scsi host parameters:\n");
-	i = 0;
-	for (shpnt = scsi_host_get_next(NULL); shpnt;
-	     shpnt = scsi_host_get_next(shpnt)) {
-		printk(KERN_INFO " %d %d : %d %d\n",
-		       shpnt->host_failed,
-		       shpnt->host_busy,
-		       shpnt->host_blocked,
-		       shpnt->host_self_blocked);
-	}
-
-	printk(KERN_INFO "\n\n");
-	printk(KERN_INFO "Dump of scsi command parameters:\n");
-	for (shpnt = scsi_host_get_next(NULL); shpnt;
-	     shpnt = scsi_host_get_next(shpnt)) {
-		printk(KERN_INFO "h:c:t:l (dev sect nsect cnumsec sg) "
-			"(ret all flg) (to/cmd to ito) cmd snse result\n");
-		list_for_each_entry(SDpnt, &shpnt->my_devices, siblings) {
-			unsigned long flags;
-
-			spin_lock_irqsave(&SDpnt->list_lock, flags);
-			list_for_each_entry(SCpnt, &SDpnt->cmd_list, list) {
-				/*  (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x      */
-				printk(KERN_INFO "(%3d) %2d:%1d:%2d:%2d (%6s %4llu %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
-				       i++,
-
-				       SCpnt->device->host->host_no,
-				       SCpnt->device->channel,
-                                       SCpnt->device->id,
-                                       SCpnt->device->lun,
-
-                                       SCpnt->request->rq_disk ?
-                                       SCpnt->request->rq_disk->disk_name : "?",
-                                       (unsigned long long)SCpnt->request->sector,
-				       SCpnt->request->nr_sectors,
-				       (long)SCpnt->request->current_nr_sectors,
-				       SCpnt->request->rq_status,
-				       SCpnt->use_sg,
-
-				       SCpnt->retries,
-				       SCpnt->allowed,
-				       SCpnt->flags,
-
-				       SCpnt->timeout_per_command,
-				       SCpnt->timeout,
-				       SCpnt->internal_timeout,
-
-				       SCpnt->cmnd[0],
-				       SCpnt->sense_buffer[2],
-				       SCpnt->result);
-			}
-			spin_unlock_irqrestore(&SDpnt->list_lock, flags);
-		}
-	}
-}
-#endif	/* CONFIG_SCSI_LOGGING */ 
-
 static int scsi_add_single_device(uint host, uint channel, uint id, uint lun)
 {
 	struct Scsi_Host *shost;
@@ -440,7 +288,6 @@
 	return error;
 }
 
-
 static int proc_scsi_gen_write(struct file * file, const char * buf,
                               unsigned long length, void *data)
 {
@@ -471,22 +318,6 @@
 
 #ifdef CONFIG_SCSI_LOGGING
 	/*
-	 * Usage: echo "scsi dump #N" > /proc/scsi/scsi
-	 * to dump status of all scsi commands.  The number is used to
-	 * specify the level of detail in the dump.
-	 */
-	if (!strncmp("dump", buffer + 5, 4)) {
-		unsigned int level;
-
-		p = buffer + 10;
-
-		if (*p == '\0')
-			goto out;
-
-		level = simple_strtoul(p, NULL, 0);
-		scsi_dump_status(level);
-	}
-	/*
 	 * Usage: echo "scsi log token #N" > /proc/scsi/scsi
 	 * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
 	 * llcomplete,hlqueue,hlcomplete]
@@ -614,15 +445,8 @@
 		goto err2;
 	pde->write_proc = proc_scsi_gen_write;
 
-	pde = create_proc_info_entry("scsi/device_info", 0, 0,
-					  proc_scsi_dev_info_read);
-	if (!pde)
-		goto err3;
-	pde->write_proc = proc_scsi_dev_info_write;
 	return 0;
 
-err3:
-	remove_proc_entry("scsi/scsi", 0);
 err2:
 	remove_proc_entry("scsi", 0);
 err1:
@@ -631,7 +455,6 @@
 
 void scsi_exit_procfs(void)
 {
-	remove_proc_entry("scsi/device_info", 0);
 	remove_proc_entry("scsi/scsi", 0);
 	remove_proc_entry("scsi", 0);
 }
diff -Nru a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
--- a/drivers/scsi/scsi_scan.c	Thu Apr 24 09:55:44 2003
+++ b/drivers/scsi/scsi_scan.c	Thu May  8 11:24:15 2003
@@ -33,173 +33,9 @@
 #include "scsi.h"
 #include "hosts.h"
 
-#ifdef CONFIG_KMOD
-#include <linux/kmod.h>
-#endif
-
-/*
- * Flags for SCSI devices that need special treatment
- */
-#define BLIST_NOLUN     	0x001	/* Only scan LUN 0 */
-#define BLIST_FORCELUN  	0x002	/* Known to have LUNs, force scanning */
-#define BLIST_BORKEN    	0x004	/* Flag for broken handshaking */
-#define BLIST_KEY       	0x008	/* unlock by special command */
-#define BLIST_SINGLELUN 	0x010	/* Do not use LUNs in parallel */
-#define BLIST_NOTQ		0x020	/* Buggy Tagged Command Queuing */
-#define BLIST_SPARSELUN 	0x040	/* Non consecutive LUN numbering */
-#define BLIST_MAX5LUN		0x080	/* Avoid LUNS >= 5 */
-#define BLIST_ISROM     	0x100	/* Treat as (removable) CD-ROM */
-#define BLIST_LARGELUN		0x200	/* LUNs past 7 on a SCSI-2 device */
-#define BLIST_INQUIRY_36	0x400	/* override additional length field */
-#define BLIST_INQUIRY_58	0x800	/* ... for broken inquiry responses */
-
-/*
- * scsi_static_device_list: deprecated list of devices that require
- * settings that differ from the default, includes black-listed (broken)
- * devices. The entries here are added to the tail of scsi_dev_info_list
- * via scsi_dev_info_list_init.
- *
- * Do not add to this list, use the command line or proc interface to add
- * to the scsi_dev_info_list. This table will eventually go away.
- */
-struct dev_info scsi_static_device_list[] __initdata = {
-	/*
-	 * The following devices are known not to tolerate a lun != 0 scan
-	 * for one reason or another. Some will respond to all luns,
-	 * others will lock up.
-	 */
-	{"Aashima", "IMAGERY 2400SP", "1.03", BLIST_NOLUN},	/* locks up */
-	{"CHINON", "CD-ROM CDS-431", "H42", BLIST_NOLUN},	/* locks up */
-	{"CHINON", "CD-ROM CDS-535", "Q14", BLIST_NOLUN},	/* locks up */
-	{"DENON", "DRD-25X", "V", BLIST_NOLUN},			/* locks up */
-	{"HITACHI", "DK312C", "CM81", BLIST_NOLUN},	/* responds to all lun */
-	{"HITACHI", "DK314C", "CR21", BLIST_NOLUN},	/* responds to all lun */
-	{"IMS", "CDD521/10", "2.06", BLIST_NOLUN},	/* locks up */
-	{"MAXTOR", "XT-3280", "PR02", BLIST_NOLUN},	/* locks up */
-	{"MAXTOR", "XT-4380S", "B3C", BLIST_NOLUN},	/* locks up */
-	{"MAXTOR", "MXT-1240S", "I1.2", BLIST_NOLUN},	/* locks up */
-	{"MAXTOR", "XT-4170S", "B5A", BLIST_NOLUN},	/* locks up */
-	{"MAXTOR", "XT-8760S", "B7B", BLIST_NOLUN},	/* locks up */
-	{"MEDIAVIS", "RENO CD-ROMX2A", "2.03", BLIST_NOLUN},	/* responds to all lun */
-	{"NEC", "CD-ROM DRIVE:841", "1.0", BLIST_NOLUN},/* locks up */
-	{"PHILIPS", "PCA80SC", "V4-2", BLIST_NOLUN},	/* responds to all lun */
-	{"RODIME", "RO3000S", "2.33", BLIST_NOLUN},	/* locks up */
-	{"SUN", "SENA", NULL, BLIST_NOLUN},		/* responds to all luns */
-	/*
-	 * The following causes a failed REQUEST SENSE on lun 1 for
-	 * aha152x controller, which causes SCSI code to reset bus.
-	 */
-	{"SANYO", "CRD-250S", "1.20", BLIST_NOLUN},
-	/*
-	 * The following causes a failed REQUEST SENSE on lun 1 for
-	 * aha152x controller, which causes SCSI code to reset bus.
-	 */
-	{"SEAGATE", "ST157N", "\004|j", BLIST_NOLUN},
-	{"SEAGATE", "ST296", "921", BLIST_NOLUN},	/* responds to all lun */
-	{"SEAGATE", "ST1581", "6538", BLIST_NOLUN},	/* responds to all lun */
-	{"SONY", "CD-ROM CDU-541", "4.3d", BLIST_NOLUN},
-	{"SONY", "CD-ROM CDU-55S", "1.0i", BLIST_NOLUN},
-	{"SONY", "CD-ROM CDU-561", "1.7x", BLIST_NOLUN},
-	{"SONY", "CD-ROM CDU-8012", NULL, BLIST_NOLUN},
-	{"TANDBERG", "TDC 3600", "U07", BLIST_NOLUN},	/* locks up */
-	{"TEAC", "CD-R55S", "1.0H", BLIST_NOLUN},	/* locks up */
-	/*
-	 * The following causes a failed REQUEST SENSE on lun 1 for
-	 * seagate controller, which causes SCSI code to reset bus.
-	 */
-	{"TEAC", "CD-ROM", "1.06", BLIST_NOLUN},
-	{"TEAC", "MT-2ST/45S2-27", "RV M", BLIST_NOLUN},	/* responds to all lun */
-	/*
-	 * The following causes a failed REQUEST SENSE on lun 1 for
-	 * seagate controller, which causes SCSI code to reset bus.
-	 */
-	{"TEXEL", "CD-ROM", "1.06", BLIST_NOLUN},
-	{"QUANTUM", "LPS525S", "3110", BLIST_NOLUN},	/* locks up */
-	{"QUANTUM", "PD1225S", "3110", BLIST_NOLUN},	/* locks up */
-	{"QUANTUM", "FIREBALL ST4.3S", "0F0C", BLIST_NOLUN},	/* locks up */
-	{"MEDIAVIS", "CDR-H93MV", "1.31", BLIST_NOLUN},	/* locks up */
-	{"SANKYO", "CP525", "6.64", BLIST_NOLUN},	/* causes failed REQ SENSE, extra reset */
-	{"HP", "C1750A", "3226", BLIST_NOLUN},		/* scanjet iic */
-	{"HP", "C1790A", "", BLIST_NOLUN},		/* scanjet iip */
-	{"HP", "C2500A", "", BLIST_NOLUN},		/* scanjet iicx */
-	{"YAMAHA", "CDR100", "1.00", BLIST_NOLUN},	/* locks up */
-	{"YAMAHA", "CDR102", "1.00", BLIST_NOLUN},	/* locks up */
-	{"YAMAHA", "CRW8424S", "1.0", BLIST_NOLUN},	/* locks up */
-	{"YAMAHA", "CRW6416S", "1.0c", BLIST_NOLUN},	/* locks up */
-	{"MITSUMI", "CD-R CR-2201CS", "6119", BLIST_NOLUN},	/* locks up */
-	{"RELISYS", "Scorpio", NULL, BLIST_NOLUN},	/* responds to all lun */
-	{"MICROTEK", "ScanMaker II", "5.61", BLIST_NOLUN},	/* responds to all lun */
-	{"NEC", "D3856", "0009", BLIST_NOLUN},
-
-	/*
-	 * Other types of devices that have special flags.
-	 */
-	{"SONY", "CD-ROM CDU-8001", NULL, BLIST_BORKEN},
-	{"TEXEL", "CD-ROM", "1.06", BLIST_BORKEN},
-	{"IOMEGA", "Io20S         *F", NULL, BLIST_KEY},
-	{"INSITE", "Floptical   F*8I", NULL, BLIST_KEY},
-	{"INSITE", "I325VM", NULL, BLIST_KEY},
-	{"LASOUND", "CDX7405", "3.10", BLIST_MAX5LUN | BLIST_SINGLELUN},
-	{"MICROP", "4110", NULL, BLIST_NOTQ},
-	{"NRC", "MBR-7", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"NRC", "MBR-7.4", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN},
-	{"NAKAMICH", "MJ-4.8S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"NAKAMICH", "MJ-5.16S", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-600", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"EMULEX", "MD21/S2     ESDI", NULL, BLIST_SINGLELUN},
-	{"CANON", "IPUBJD", NULL, BLIST_SPARSELUN},
-	{"nCipher", "Fastness Crypto", NULL, BLIST_FORCELUN},
-	{"DEC", "HSG80", NULL, BLIST_FORCELUN},
-	{"COMPAQ", "LOGICAL VOLUME", NULL, BLIST_FORCELUN},
-	{"COMPAQ", "CR3500", NULL, BLIST_FORCELUN},
-	{"NEC", "PD-1 ODX654P", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"MATSHITA", "PD-1", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
-	{"iomega", "jaz 1GB", "J.86", BLIST_NOTQ | BLIST_NOLUN},
-	{"TOSHIBA", "CDROM", NULL, BLIST_ISROM},
-	{"TOSHIBA", "CD-ROM", NULL, BLIST_ISROM},
-	{"MegaRAID", "LD", NULL, BLIST_FORCELUN},
-	{"DGC", "RAID", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, storage on LUN 0 */
-	{"DGC", "DISK", NULL, BLIST_SPARSELUN},	/* Dell PV 650F, no storage on LUN 0 */
-	{"DELL", "PV660F", NULL, BLIST_SPARSELUN},
-	{"DELL", "PV660F   PSEUDO", NULL, BLIST_SPARSELUN},
-	{"DELL", "PSEUDO DEVICE .", NULL, BLIST_SPARSELUN},	/* Dell PV 530F */
-	{"DELL", "PV530F", NULL, BLIST_SPARSELUN},
-	{"EMC", "SYMMETRIX", NULL, BLIST_SPARSELUN | BLIST_LARGELUN | BLIST_FORCELUN},
-	{"HP", "A6189A", NULL, BLIST_SPARSELUN | BLIST_LARGELUN},	/* HP VA7400 */
-	{"HP", "OPEN-", "*", BLIST_SPARSELUN | BLIST_LARGELUN}, /* HP XP Arrays */
-	{"CMD", "CRA-7280", NULL, BLIST_SPARSELUN},	/* CMD RAID Controller */
-	{"CNSI", "G7324", NULL, BLIST_SPARSELUN},	/* Chaparral G7324 RAID */
-	{"CNSi", "G8324", NULL, BLIST_SPARSELUN},	/* Chaparral G8324 RAID */
-	{"Zzyzx", "RocketStor 500S", NULL, BLIST_SPARSELUN},
-	{"Zzyzx", "RocketStor 2000", NULL, BLIST_SPARSELUN},
-	{"SONY", "TSL", NULL, BLIST_FORCELUN},		/* DDS3 & DDS4 autoloaders */
-	{"DELL", "PERCRAID", NULL, BLIST_FORCELUN},
-	{"HP", "NetRAID-4M", NULL, BLIST_FORCELUN},
-	{"ADAPTEC", "AACRAID", NULL, BLIST_FORCELUN},
-	{"ADAPTEC", "Adaptec 5400S", NULL, BLIST_FORCELUN},
-	{"COMPAQ", "MSA1000", NULL, BLIST_FORCELUN},
-	{"HP", "C1557A", NULL, BLIST_FORCELUN},
-	{"IBM", "AuSaV1S2", NULL, BLIST_FORCELUN},
-	{"FSC", "CentricStor", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"DDN", "SAN DataDirector", "*", BLIST_SPARSELUN},
-	{"HITACHI", "DF400", "*", BLIST_SPARSELUN},
-	{"HITACHI", "DF500", "*", BLIST_SPARSELUN},
-	{"HITACHI", "DF600", "*", BLIST_SPARSELUN},
-	{"IBM", "ProFibre 4000R", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"SUN", "T300", "*", BLIST_SPARSELUN},
-	{"SUN", "T4", "*", BLIST_SPARSELUN},
-	{"SGI", "RAID3", "*", BLIST_SPARSELUN},
-	{"SGI", "RAID5", "*", BLIST_SPARSELUN},
-	{"SGI", "TP9100", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"SGI", "TP9300", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"SGI", "TP9400", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"SGI", "TP9500", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{"MYLEX", "DACARMRB", "*", BLIST_SPARSELUN | BLIST_LARGELUN},
-	{ NULL, NULL, NULL, 0 },
-};
+#include "scsi_priv.h"
+#include "scsi_logging.h"
+#include "scsi_devinfo.h"
 
 #define ALLOC_FAILURE_MSG	KERN_ERR "%s: Allocation failure during" \
 	" SCSI scanning, some SCSI devices might not be configured\n"
@@ -429,7 +265,6 @@
 
 	sdev->request_queue->queuedata = sdev;
 	scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
-	init_waitqueue_head(&sdev->scpnt_wait);
 
 	if (shost->hostt->slave_alloc) {
 		if (shost->hostt->slave_alloc(sdev))
@@ -481,7 +316,7 @@
  *     Undo the actions in scsi_alloc_sdev, including removing @sdev from
  *     the list, and freeing @sdev.
  **/
-static void scsi_free_sdev(struct scsi_device *sdev)
+void scsi_free_sdev(struct scsi_device *sdev)
 {
 	unsigned long flags;
 
@@ -1270,12 +1105,7 @@
 int scsi_remove_device(struct scsi_device *sdev)
 {
 	scsi_detach_device(sdev);
-	if (sdev->attached)
-		return -EINVAL;
-
 	scsi_device_unregister(sdev);
-
-	scsi_free_sdev(sdev);
 	return 0;
 }
 
diff -Nru a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
--- a/drivers/scsi/scsi_syms.c	Tue Apr 29 00:11:53 2003
+++ b/drivers/scsi/scsi_syms.c	Thu May  8 11:24:15 2003
@@ -21,6 +21,7 @@
 #include "scsi.h"
 #include <scsi/scsi_ioctl.h>
 #include "hosts.h"
+#include "scsi_logging.h"
 
 #include <scsi/scsicam.h>
 
@@ -64,6 +65,7 @@
 EXPORT_SYMBOL(scsi_put_command);
 
 EXPORT_SYMBOL(scsi_report_bus_reset);
+EXPORT_SYMBOL(scsi_report_device_reset);
 EXPORT_SYMBOL(scsi_block_requests);
 EXPORT_SYMBOL(scsi_unblock_requests);
 EXPORT_SYMBOL(scsi_adjust_queue_depth);
@@ -76,8 +78,6 @@
 
 EXPORT_SYMBOL(scsi_io_completion);
 
-EXPORT_SYMBOL(scsi_slave_attach);
-EXPORT_SYMBOL(scsi_slave_detach);
 EXPORT_SYMBOL(scsi_device_get);
 EXPORT_SYMBOL(scsi_device_put);
 EXPORT_SYMBOL(scsi_add_device);
@@ -104,12 +104,5 @@
 /*
  * Externalize timers so that HBAs can safely start/restart commands.
  */
-extern void scsi_add_timer(Scsi_Cmnd *, int, void ((*) (Scsi_Cmnd *)));
-extern int scsi_delete_timer(Scsi_Cmnd *);
 EXPORT_SYMBOL(scsi_add_timer);
 EXPORT_SYMBOL(scsi_delete_timer);
-
-/*
- * sysfs support
- */
-EXPORT_SYMBOL(shost_class);
diff -Nru a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
--- a/drivers/scsi/scsi_sysfs.c	Tue Apr 29 00:11:53 2003
+++ b/drivers/scsi/scsi_sysfs.c	Sun May 11 15:12:40 2003
@@ -14,6 +14,7 @@
 #include "scsi.h"
 #include "hosts.h"
 
+#include "scsi_priv.h"
 
 /*
  * shost_show_function: macro to create an attr function that can be used to
@@ -21,9 +22,9 @@
  */
 #define shost_show_function(field, format_string)			\
 static ssize_t								\
-show_##field (struct device *dev, char *buf)				\
+show_##field (struct class_device *class_dev, char *buf)		\
 {									\
-	struct Scsi_Host *shost = to_scsi_host(dev);			\
+	struct Scsi_Host *shost = class_to_shost(class_dev);		\
 	return snprintf (buf, 20, format_string, shost->field);	\
 }
 
@@ -32,8 +33,8 @@
  * read only field.
  */
 #define shost_rd_attr(field, format_string)				\
-	shost_show_function(field, format_string)				\
-static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
+	shost_show_function(field, format_string)			\
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)
 
 /*
  * Create the actual show/store functions and data structures.
@@ -44,39 +45,16 @@
 shost_rd_attr(sg_tablesize, "%hu\n");
 shost_rd_attr(unchecked_isa_dma, "%d\n");
 
-static struct device_attribute *const shost_attrs[] = {
-	&dev_attr_unique_id,
-	&dev_attr_host_busy,
-	&dev_attr_cmd_per_lun,
-	&dev_attr_sg_tablesize,
-	&dev_attr_unchecked_isa_dma,
+static struct class_device_attribute *const shost_attrs[] = {
+	&class_device_attr_unique_id,
+	&class_device_attr_host_busy,
+	&class_device_attr_cmd_per_lun,
+	&class_device_attr_sg_tablesize,
+	&class_device_attr_unchecked_isa_dma,
 };
 
-/**
- * scsi_host_class_name_show - copy out the SCSI host name
- * @dev:		device to check
- * @page:		copy data into this area
- * @count:		number of bytes to copy
- * @off:		start at this offset in page
- * Return:
- *     number of bytes written into page.
- **/
-static ssize_t scsi_host_class_name_show(struct device *dev, char *page)
-{
-	struct Scsi_Host *shost;
-
-	shost = to_scsi_host(dev);
-
-	if (!shost)
-		return 0;
-	
-	return snprintf(page, 20, "scsi%d\n", shost->host_no);
-}
-
-DEVICE_ATTR(class_name, S_IRUGO, scsi_host_class_name_show, NULL);
-
-struct class shost_class = {
-	.name		= "scsi-host",
+static struct class shost_class = {
+	.name		= "scsi_host",
 };
 
 /**
@@ -113,10 +91,16 @@
 
 int scsi_sysfs_register(void)
 {
-	bus_register(&scsi_bus_type);
-	class_register(&shost_class);
+	int error;
 
-	return 0;
+	error = bus_register(&scsi_bus_type);
+	if (error)
+		return error;
+	error = class_register(&shost_class);
+	if (error)
+		return error;
+
+	return error;
 }
 
 void scsi_sysfs_unregister(void)
@@ -272,6 +256,16 @@
 	&dev_attr_rescan,
 };
 
+static void scsi_device_release(struct device *dev)
+{
+	struct scsi_device *sdev;
+
+	sdev = to_scsi_device(dev);
+	if (!sdev)
+		return;
+	scsi_free_sdev(sdev);
+}
+
 /**
  * scsi_device_register - register a scsi device with the scsi bus
  * @sdev:	scsi_device to register
@@ -285,8 +279,9 @@
 
 	sprintf(sdev->sdev_driverfs_dev.bus_id,"%d:%d:%d:%d",
 		sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
-	sdev->sdev_driverfs_dev.parent = sdev->host->host_gendev;
+	sdev->sdev_driverfs_dev.parent = &sdev->host->host_gendev;
 	sdev->sdev_driverfs_dev.bus = &scsi_bus_type;
+	sdev->sdev_driverfs_dev.release = scsi_device_release;
 
 	error = device_register(&sdev->sdev_driverfs_dev);
 	if (error)
@@ -314,3 +309,77 @@
 		device_remove_file(&sdev->sdev_driverfs_dev, sdev_attrs[i]);
 	device_unregister(&sdev->sdev_driverfs_dev);
 }
+
+static void scsi_host_release(struct device *dev)
+{
+	struct Scsi_Host *shost;
+
+	shost = dev_to_shost(dev);
+	if (!shost)
+		return;
+
+	scsi_free_shost(shost);
+}
+
+void scsi_sysfs_init_host(struct Scsi_Host *shost)
+{
+	device_initialize(&shost->host_gendev);
+	snprintf(shost->host_gendev.bus_id, BUS_ID_SIZE, "host%d",
+		shost->host_no);
+	snprintf(shost->host_gendev.name, DEVICE_NAME_SIZE, "%s",
+		shost->hostt->proc_name);
+	shost->host_gendev.release = scsi_host_release;
+
+	class_device_initialize(&shost->class_dev);
+	shost->class_dev.dev = &shost->host_gendev;
+	shost->class_dev.class = &shost_class;
+	snprintf(shost->class_dev.class_id, BUS_ID_SIZE, "host%d",
+		  shost->host_no);
+}
+
+/**
+ * scsi_sysfs_add_host - add scsi host to subsystem
+ * @shost:     scsi host struct to add to subsystem
+ * @dev:       parent struct device pointer
+ **/
+int scsi_sysfs_add_host(struct Scsi_Host *shost, struct device *dev)
+{
+	int i, error;
+
+	if (!shost->host_gendev.parent)
+		shost->host_gendev.parent = (dev) ? dev : &legacy_bus;
+
+	error = device_add(&shost->host_gendev);
+	if (error)
+		return error;
+
+	error = class_device_add(&shost->class_dev);
+	if (error)
+		goto clean_device;
+
+	for (i = 0; !error && i < ARRAY_SIZE(shost_attrs); i++)
+		error = class_device_create_file(&shost->class_dev,
+					   shost_attrs[i]);
+	if (error)
+		goto clean_class;
+
+	return error;
+
+clean_class:
+	class_device_del(&shost->class_dev);
+clean_device:
+	device_del(&shost->host_gendev);
+
+	return error;
+}
+
+/**
+ * scsi_sysfs_remove_host - remove scsi host from subsystem
+ * @shost:     scsi host to remove from subsystem
+ **/
+void scsi_sysfs_remove_host(struct Scsi_Host *shost)
+{
+	class_device_del(&shost->class_dev);
+	device_del(&shost->host_gendev);
+}
+
diff -Nru a/drivers/scsi/sd.c b/drivers/scsi/sd.c
--- a/drivers/scsi/sd.c	Fri Apr 18 08:58:55 2003
+++ b/drivers/scsi/sd.c	Mon May 12 20:52:56 2003
@@ -52,6 +52,9 @@
 #include <scsi/scsi_ioctl.h>
 #include <scsi/scsicam.h>
 
+#include "scsi_logging.h"
+
+
 /*
  * Remaining dev_t-handling stuff
  */
@@ -696,7 +699,7 @@
 	int good_sectors = (result == 0 ? this_count : 0);
 	sector_t block_sectors = 1;
 	sector_t error_sector;
-#if CONFIG_SCSI_LOGGING
+#ifdef CONFIG_SCSI_LOGGING
 	SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", 
 				SCpnt->request->rq_disk->disk_name, result));
 	if (0 != result) {
@@ -808,7 +811,8 @@
 	       struct scsi_request *SRpnt, unsigned char *buffer) {
 	unsigned char cmd[10];
 	unsigned long spintime_value = 0;
-	int the_result, retries, spintime;
+	int retries, spintime;
+	unsigned int the_result;
 
 	spintime = 0;
 
@@ -817,7 +821,7 @@
 	do {
 		retries = 0;
 
-		while (retries < 3) {
+		do {
 			cmd[0] = TEST_UNIT_READY;
 			memset((void *) &cmd[1], 0, 9);
 
@@ -831,10 +835,9 @@
 
 			the_result = SRpnt->sr_result;
 			retries++;
-			if (the_result == 0
-			    || SRpnt->sr_sense_buffer[2] != UNIT_ATTENTION)
-				break;
-		}
+		} while (retries < 3 && !scsi_status_is_good(the_result)
+			 && ((driver_byte(the_result) & DRIVER_SENSE)
+			     && SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION));
 
 		/*
 		 * If the drive has indicated to us that it doesn't have
@@ -844,8 +847,15 @@
 		if (media_not_present(sdkp, SRpnt))
 			return;
 
-		if (the_result == 0)
-			break;		/* all is well now */
+		if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {
+			/* no sense, TUR either succeeded or failed
+			 * with a status error */
+			if(!spintime && !scsi_status_is_good(the_result))
+				printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", diskname, the_result);
+			break;
+		}
+					
+					
 
 		/*
 		 * If manual intervention is required, or this is an
@@ -853,13 +863,13 @@
 		 */
 		if (SRpnt->sr_sense_buffer[2] == NOT_READY &&
 		    SRpnt->sr_sense_buffer[12] == 4 /* not ready */ &&
-		    SRpnt->sr_sense_buffer[13] == 3)
+		    SRpnt->sr_sense_buffer[13] == 3) {
 			break;		/* manual intervention required */
 
 		/*
 		 * Issue command to spin up drive when not ready
 		 */
-		if (SRpnt->sr_sense_buffer[2] == NOT_READY) {
+		} else if (SRpnt->sr_sense_buffer[2] == NOT_READY) {
 			unsigned long time1;
 			if (!spintime) {
 				printk(KERN_NOTICE "%s: Spinning up disk...",
@@ -886,15 +896,24 @@
 				time1 = schedule_timeout(time1);
 			} while(time1);
 			printk(".");
+		} else {
+			/* we don't understand the sense code, so it's
+			 * probably pointless to loop */
+			if(!spintime) {
+				printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", diskname);
+				print_req_sense("", SRpnt);
+			}
+			break;
 		}
+				
 	} while (spintime &&
 		 time_after(spintime_value + 100 * HZ, jiffies));
 
 	if (spintime) {
-		if (the_result)
-			printk("not responding...\n");
-		else
+		if (scsi_status_is_good(the_result))
 			printk("ready\n");
+		else
+			printk("not responding...\n");
 	}
 }
 
@@ -1299,14 +1318,10 @@
 	SCSI_LOG_HLQUEUE(3, printk("sd_attach: scsi device: <%d,%d,%d,%d>\n", 
 			 sdp->host->host_no, sdp->channel, sdp->id, sdp->lun));
 
-	error = scsi_slave_attach(sdp);
-	if (error)
-		goto out;
-
 	error = -ENOMEM;
 	sdkp = kmalloc(sizeof(*sdkp), GFP_KERNEL);
 	if (!sdkp)
-		goto out_detach;
+		goto out;
 
 	gd = alloc_disk(16);
 	if (!gd)
@@ -1365,8 +1380,6 @@
 	put_disk(gd);
 out_free:
 	kfree(sdkp);
-out_detach:
-	scsi_slave_detach(sdp);
 out:
 	return error;
 }
@@ -1403,7 +1416,6 @@
 
 	sd_devlist_remove(sdkp);
 	del_gendisk(sdkp->disk);
-	scsi_slave_detach(sdp);
 
 	spin_lock(&sd_index_lock);
 	clear_bit(sdkp->index, sd_index_bits);
@@ -1502,7 +1514,8 @@
 			printk("FAILED\n  No memory for request\n");
 		return 0;
 	}
-		
+
+	SRpnt->sr_data_direction = SCSI_DATA_NONE;
 
 	for(retries = 3; retries > 0; --retries) {
 		unsigned char cmd[10] = { 0 };
diff -Nru a/drivers/scsi/seagate.c b/drivers/scsi/seagate.c
--- a/drivers/scsi/seagate.c	Sat Apr 26 07:28:27 2003
+++ b/drivers/scsi/seagate.c	Sun May  4 02:56:46 2003
@@ -1700,7 +1700,20 @@
 	return 0;
 }
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = SEAGATE_ST0X;
-
+static Scsi_Host_Template driver_template = {
+	.detect         	= seagate_st0x_detect,
+	.release        	= seagate_st0x_release,
+	.info           	= seagate_st0x_info,
+	.command        	= seagate_st0x_command,
+	.queuecommand   	= seagate_st0x_queue_command,
+	.eh_abort_handler	= seagate_st0x_abort,
+	.eh_bus_reset_handler	= seagate_st0x_bus_reset,
+	.eh_host_reset_handler	= seagate_st0x_host_reset,
+	.eh_device_reset_handler = seagate_st0x_device_reset,
+	.can_queue      	= 1,
+	.this_id        	= 7,
+	.sg_tablesize   	= SG_ALL,
+	.cmd_per_lun    	= 1,
+	.use_clustering		= DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
--- a/drivers/scsi/seagate.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/seagate.h	Sun May  4 02:56:46 2003
@@ -19,19 +19,4 @@
 static int seagate_st0x_device_reset(Scsi_Cmnd *);
 static int seagate_st0x_host_reset(Scsi_Cmnd *);
 
-#define SEAGATE_ST0X  {  .detect         = seagate_st0x_detect,			\
-			 .release        = seagate_st0x_release,			\
-			 .info           = seagate_st0x_info,			\
-			 .command        = seagate_st0x_command,			\
-			 .queuecommand   = seagate_st0x_queue_command,		\
-			 .eh_abort_handler	= seagate_st0x_abort,		\
-			 .eh_bus_reset_handler  = seagate_st0x_bus_reset,		\
-			 .eh_host_reset_handler = seagate_st0x_host_reset,	\
-			 .eh_device_reset_handler = seagate_st0x_device_reset,	\
-			 .can_queue      = 1,					\
-			 .this_id        = 7,					\
-			 .sg_tablesize   = SG_ALL,				\
-			 .cmd_per_lun    = 1,					\
-			 .use_clustering = DISABLE_CLUSTERING}
-
 #endif /* _SEAGATE_H */
diff -Nru a/drivers/scsi/sg.c b/drivers/scsi/sg.c
--- a/drivers/scsi/sg.c	Sat Apr 26 07:28:28 2003
+++ b/drivers/scsi/sg.c	Mon May 12 20:52:57 2003
@@ -67,6 +67,8 @@
 #include <scsi/scsi_ioctl.h>
 #include <scsi/sg.h>
 
+#include "scsi_logging.h"
+
 #ifdef CONFIG_PROC_FS
 #include <linux/proc_fs.h>
 static int sg_proc_init(void);
@@ -1350,17 +1352,12 @@
 	struct gendisk *disk;
 	Sg_device *sdp = NULL;
 	unsigned long iflags;
-	char devfs_name[64];
 	int k, error;
 
 	disk = alloc_disk(1);
 	if (!disk)
 		return -ENOMEM;
 
-	error = scsi_slave_attach(scsidp);
-	if (error)
-		goto out_put;
-		
 	write_lock_irqsave(&sg_dev_arr_lock, iflags);
 	if (sg_nr_dev >= sg_dev_max) {	/* try to resize */
 		Sg_device **tmp_da;
@@ -1373,7 +1370,7 @@
 			printk(KERN_ERR
 			       "sg_attach: device array cannot be resized\n");
 			error = -ENOMEM;
-			goto out_detach;
+			goto out;
 		}
 		write_lock_irqsave(&sg_dev_arr_lock, iflags);
 		memset(tmp_da, 0, tmp_dev_max * sizeof (Sg_device *));
@@ -1398,7 +1395,7 @@
 		if (NULL != sdp)
 			vfree((char *) sdp);
 		error = -ENODEV;
-		goto out_detach;
+		goto out;
 	}
 	if (k < sg_dev_max) {
 		if (NULL == sdp) {
@@ -1414,7 +1411,7 @@
 		write_unlock_irqrestore(&sg_dev_arr_lock, iflags);
 		printk(KERN_ERR "sg_attach: Sg_device cannot be allocated\n");
 		error = -ENOMEM;
-		goto out_detach;
+		goto out;
 	}
 
 	SCSI_LOG_TIMEOUT(3, printk("sg_attach: dev=%d \n", k));
@@ -1449,11 +1446,9 @@
 	device_create_file(&sdp->sg_driverfs_dev, &dev_attr_type);
 	device_create_file(&sdp->sg_driverfs_dev, &dev_attr_kdev);
 
-	sprintf(devfs_name, "%s/generic", scsidp->devfs_name);
-	devfs_register(NULL, devfs_name, 0,
-			SCSI_GENERIC_MAJOR, k,
+	devfs_mk_cdev(MKDEV(SCSI_GENERIC_MAJOR, k),
 			S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
-			&sg_fops, sdp);
+			"%s/generic", scsidp->devfs_name);
 
 	switch (scsidp->type) {
 	case TYPE_DISK:
@@ -1471,9 +1466,7 @@
 	}
 	return 0;
 
-out_detach:
-	scsi_slave_detach(scsidp);
-out_put:
+out:
 	put_disk(disk);
 	return error;
 }
@@ -1524,7 +1517,6 @@
 			SCSI_LOG_TIMEOUT(3, printk("sg_detach: dev=%d\n", k));
 			sg_dev_arr[k] = NULL;
 		}
-		scsi_slave_detach(scsidp);
 		sg_nr_dev--;
 		break;
 	}
diff -Nru a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
--- a/drivers/scsi/sgiwd93.c	Mon Feb 24 07:25:18 2003
+++ b/drivers/scsi/sgiwd93.c	Sun May  4 02:56:46 2003
@@ -227,9 +227,7 @@
 
 	if (request_irq(SGI_WD93_0_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host)) {
 		printk(KERN_WARNING "sgiwd93: Could not register IRQ %d (for host 0).\n", SGI_WD93_0_IRQ);
-#ifdef MODULE
 		wd33c93_release();
-#endif
 		free_page((unsigned long)buf);
 		scsi_unregister(sgiwd93_host);
 		return 0;
@@ -263,9 +261,7 @@
 	
 			if (request_irq(SGI_WD93_1_IRQ, sgiwd93_intr, 0, "SGI WD93", (void *) sgiwd93_host1)) {
 				printk(KERN_WARNING "sgiwd93: Could not allocate irq %d (for host1).\n", SGI_WD93_1_IRQ);
-#ifdef MODULE
 				wd33c93_release();
-#endif
 				free_page((unsigned long)buf);
 				scsi_unregister(sgiwd93_host1);
 				/* Fall through since host0 registered OK */
@@ -278,17 +274,8 @@
 	return 1; /* Found one. */
 }
 
-#define HOSTS_C
-
-#include "sgiwd93.h"
-
-static Scsi_Host_Template driver_template = SGIWD93_SCSI;
-
-#include "scsi_module.c"
-
 int sgiwd93_release(struct Scsi_Host *instance)
 {
-#ifdef MODULE
 	free_irq(SGI_WD93_0_IRQ, sgiwd93_intr);
 	free_page(KSEG0ADDR(hdata->dma_bounce_buffer));
 	wd33c93_release();
@@ -297,6 +284,21 @@
 		free_page(KSEG0ADDR(hdata1->dma_bounce_buffer));
 		wd33c93_release();
 	}
-#endif
 	return 1;
 }
+
+static Scsi_Host_Template driver_template = {
+	.proc_name	     = "SGIWD93",
+	.name                = "SGI WD93",
+	.detect              = sgiwd93_detect,
+	.release             = sgiwd93_release,
+	.queuecommand        = wd33c93_queuecommand,
+	.abort               = wd33c93_abort,
+	.reset               = wd33c93_reset,
+	.can_queue           = CAN_QUEUE,
+	.this_id             = 7,
+	.sg_tablesize        = SG_ALL,
+	.cmd_per_lun	     = CMD_PER_LUN,
+	.use_clustering      = DISABLE_CLUSTERING,
+};
+#include "scsi_module.c"
diff -Nru a/drivers/scsi/sgiwd93.h b/drivers/scsi/sgiwd93.h
--- a/drivers/scsi/sgiwd93.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/sgiwd93.h	Sun May  4 02:56:46 2003
@@ -25,17 +25,4 @@
 int wd33c93_abort(Scsi_Cmnd *);
 int wd33c93_reset(Scsi_Cmnd *, unsigned int);
 
-#define SGIWD93_SCSI {.proc_name	   = "SGIWD93", \
-		      .name                = "SGI WD93", \
-		      .detect              = sgiwd93_detect,    \
-		      .release             = sgiwd93_release,   \
-		      .queuecommand        = wd33c93_queuecommand, \
-		      .abort               = wd33c93_abort,   \
-		      .reset               = wd33c93_reset,   \
-		      .can_queue           = CAN_QUEUE,       \
-		      .this_id             = 7,               \
-		      .sg_tablesize        = SG_ALL,          \
-		      .cmd_per_lun	   = CMD_PER_LUN,     \
-		      .use_clustering      = DISABLE_CLUSTERING }
-
 #endif /* !(_SGIWD93_H) */
diff -Nru a/drivers/scsi/sim710.c b/drivers/scsi/sim710.c
--- a/drivers/scsi/sim710.c	Sat Feb 22 08:18:15 2003
+++ b/drivers/scsi/sim710.c	Tue May  6 12:56:04 2003
@@ -155,7 +155,7 @@
 static __devexit int
 sim710_device_remove(struct device *dev)
 {
-	struct Scsi_Host *host = to_scsi_host(dev);
+	struct Scsi_Host *host = dev_to_shost(dev);
 	struct NCR_700_Host_Parameters *hostdata =
 		(struct NCR_700_Host_Parameters *)host->hostdata[0];
 
diff -Nru a/drivers/scsi/sr.c b/drivers/scsi/sr.c
--- a/drivers/scsi/sr.c	Sat Apr 19 14:18:27 2003
+++ b/drivers/scsi/sr.c	Wed May  7 07:15:41 2003
@@ -50,6 +50,7 @@
 #include "hosts.h"
 #include <scsi/scsi_ioctl.h>	/* For the door lock/unlock commands */
 
+#include "scsi_logging.h"
 #include "sr.h"
 
 
@@ -514,10 +515,6 @@
 	if (sdev->type != TYPE_ROM && sdev->type != TYPE_WORM)
 		return 1;
 
-	error = scsi_slave_attach(sdev);
-	if (error)
-		return error;
-
 	error = -ENOMEM;
 	cd = kmalloc(sizeof(*cd), GFP_KERNEL);
 	if (!cd)
@@ -591,7 +588,6 @@
 fail_free:
 	kfree(cd);
 fail:
-	scsi_slave_detach(sdev);
 	return error;
 }
 
@@ -819,7 +815,6 @@
 		return;
 
 	sr_devlist_remove(cd);
-	scsi_slave_detach(SDp);
 	del_gendisk(cd->disk);
 
 	spin_lock(&sr_index_lock);
diff -Nru a/drivers/scsi/st.c b/drivers/scsi/st.c
--- a/drivers/scsi/st.c	Fri Apr 18 08:58:31 2003
+++ b/drivers/scsi/st.c	Mon May 12 20:52:58 2003
@@ -3725,16 +3725,13 @@
 		return 1;
 	}
 
-	if (scsi_slave_attach(SDp))
-		return 1;
-
 	i = SDp->host->sg_tablesize;
 	if (st_max_sg_segs < i)
 		i = st_max_sg_segs;
 	buffer = new_tape_buffer(TRUE, (SDp->host)->unchecked_isa_dma, i);
 	if (buffer == NULL) {
 		printk(KERN_ERR "st: Can't allocate new tape buffer. Device not attached.\n");
-		goto out_slave_detach;
+		goto out;
 	}
 
 	disk = alloc_disk(1);
@@ -3865,11 +3862,10 @@
 	write_unlock(&st_dev_arr_lock);
 
 	for (mode = 0; mode < ST_NBR_MODES; ++mode) {
-	    char name[8], devfs_name[64];
+	    char name[8];
 
 	    /*  Rewind entry  */
 	    sprintf(name, "mt%s", st_formats[mode]);
-	    sprintf(devfs_name, "%s/mt%s", SDp->devfs_name, st_formats[mode]);
 	    
 	    sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s", 
 		    SDp->sdev_driverfs_dev.bus_id, name);
@@ -3883,13 +3879,12 @@
 	    device_create_file(&tpnt->driverfs_dev_r[mode], 
 			       &dev_attr_type);
 	    device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
-	    devfs_register(NULL, devfs_name, 0,
-				SCSI_TAPE_MAJOR, dev_num + (mode << 5),
+	    devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5)),
 				S_IFCHR | S_IRUGO | S_IWUGO,
-				&st_fops, NULL);
+				"%s/mt%s", SDp->devfs_name, st_formats[mode]);
+
 	    /*  No-rewind entry  */
 	    sprintf (name, "mt%sn", st_formats[mode]);
-	    sprintf(devfs_name, "%s/mt%sn", SDp->devfs_name, st_formats[mode]);
 
 	    sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s", 
 		    SDp->sdev_driverfs_dev.bus_id, name);
@@ -3904,10 +3899,9 @@
 			       &dev_attr_type);
 	    device_create_file(&tpnt->driverfs_dev_n[mode], 
 			       &dev_attr_kdev);
-	    devfs_register(NULL, devfs_name, 0,
-				SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128,
+	    devfs_mk_cdev(MKDEV(SCSI_TAPE_MAJOR, dev_num + (mode << 5) + 128),
 				S_IFCHR | S_IRUGO | S_IWUGO,
-				&st_fops, NULL);
+				"%s/mt%sn", SDp->devfs_name, st_formats[mode]);
 	}
 	disk->number = devfs_register_tape(SDp->devfs_name);
 
@@ -3923,8 +3917,7 @@
 	put_disk(disk);
 out_buffer_free:
 	kfree(buffer);
-out_slave_detach:
-	scsi_slave_detach(SDp);
+out:
 	return 1;
 };
 
@@ -3962,7 +3955,6 @@
 				normalize_buffer(tpnt->buffer);
 				kfree(tpnt->buffer);
 			}
-			scsi_slave_detach(SDp);
 			put_disk(tpnt->disk);
 			kfree(tpnt);
 			return;
diff -Nru a/drivers/scsi/sym53c416.c b/drivers/scsi/sym53c416.c
--- a/drivers/scsi/sym53c416.c	Sat Apr 26 07:28:29 2003
+++ b/drivers/scsi/sym53c416.c	Sun May  4 02:56:46 2003
@@ -875,6 +875,24 @@
 
 #endif
 
-static Scsi_Host_Template driver_template = SYM53C416;
-
+static Scsi_Host_Template driver_template = {
+	.proc_name =		"sym53c416",
+	.name =			"Symbios Logic 53c416",
+	.detect =		sym53c416_detect,
+	.info =			sym53c416_info,	
+	.command =		sym53c416_command,
+	.queuecommand =		sym53c416_queuecommand,
+	.eh_abort_handler =	sym53c416_abort,
+	.eh_host_reset_handler =sym53c416_host_reset,
+	.eh_bus_reset_handler = sym53c416_bus_reset,
+	.eh_device_reset_handler =sym53c416_device_reset,
+	.release = 		sym53c416_release,
+	.bios_param =		sym53c416_bios_param,
+	.can_queue =		1,
+	.this_id =		SYM53C416_SCSI_ID,
+	.sg_tablesize =		32,
+	.cmd_per_lun =		1,
+	.unchecked_isa_dma =	1,
+	.use_clustering =	ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/sym53c416.h b/drivers/scsi/sym53c416.h
--- a/drivers/scsi/sym53c416.h	Thu Mar  6 15:56:54 2003
+++ b/drivers/scsi/sym53c416.h	Sun May  4 02:56:46 2003
@@ -34,25 +34,4 @@
 static int sym53c416_bios_param(struct scsi_device *, struct block_device *,
 		sector_t, int *);
 static void sym53c416_setup(char *str, int *ints);
-
-#define SYM53C416 {						\
-		.proc_name =		"sym53c416",		\
-		.name =			"Symbios Logic 53c416",	\
-		.detect =		sym53c416_detect,	\
-		.info =			sym53c416_info,		\
-		.command =		sym53c416_command,	\
-		.queuecommand =		sym53c416_queuecommand,	\
-		.eh_abort_handler =	sym53c416_abort,	\
-		.eh_host_reset_handler =sym53c416_host_reset,	\
-		.eh_bus_reset_handler = sym53c416_bus_reset,	\
-		.eh_device_reset_handler =sym53c416_device_reset,\
-		.release = 		sym53c416_release,	\
-		.bios_param =		sym53c416_bios_param,	\
-		.can_queue =		1,			\
-		.this_id =		SYM53C416_SCSI_ID,	\
-		.sg_tablesize =		32,			\
-		.cmd_per_lun =		1,			\
-		.unchecked_isa_dma =	1,			\
-		.use_clustering =	ENABLE_CLUSTERING	\
-		}
 #endif
diff -Nru a/drivers/scsi/sym53c8xx.c b/drivers/scsi/sym53c8xx.c
--- a/drivers/scsi/sym53c8xx.c	Fri Apr 25 20:59:11 2003
+++ b/drivers/scsi/sym53c8xx.c	Sun May  4 02:56:46 2003
@@ -14718,10 +14718,21 @@
 
 MODULE_LICENSE("GPL");
 
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-static
-#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) || defined(MODULE)
-Scsi_Host_Template driver_template = SYM53C8XX;
+static Scsi_Host_Template driver_template = {
+	.name           = "sym53c8xx",
+	.detect         = sym53c8xx_detect,
+	.release        = sym53c8xx_release,
+	.info           = sym53c8xx_info, 
+	.queuecommand   = sym53c8xx_queue_command,
+	.slave_configure = sym53c8xx_slave_configure,
+	.abort          = sym53c8xx_abort,
+	.reset          = sym53c8xx_reset,
+	.can_queue      = SCSI_NCR_CAN_QUEUE,
+	.this_id        = 7,
+	.sg_tablesize   = SCSI_NCR_SG_TABLESIZE,
+	.cmd_per_lun    = SCSI_NCR_CMD_PER_LUN,
+	.max_sectors	= MAX_HW_SEGMENTS*8,
+	.use_clustering = DISABLE_CLUSTERING,
+	.highmem_io	= 1
+};
 #include "scsi_module.c"
-#endif
diff -Nru a/drivers/scsi/sym53c8xx.h b/drivers/scsi/sym53c8xx.h
--- a/drivers/scsi/sym53c8xx.h	Mon Feb 17 12:02:12 2003
+++ b/drivers/scsi/sym53c8xx.h	Sun May  4 02:56:46 2003
@@ -77,37 +77,6 @@
 int sym53c8xx_slave_configure(Scsi_Device *);
 int sym53c8xx_release(struct Scsi_Host *);
 
-#if	LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75)
-
-#define SYM53C8XX {     .name           = "sym53c8xx",		\
-			.detect         = sym53c8xx_detect,	\
-			.release        = sym53c8xx_release,	\
-			.info           = sym53c8xx_info, 	\
-			.queuecommand   = sym53c8xx_queue_command,\
-			.slave_configure = sym53c8xx_slave_configure,\
-			.abort          = sym53c8xx_abort,	\
-			.reset          = sym53c8xx_reset,	\
-			.can_queue      = SCSI_NCR_CAN_QUEUE,	\
-			.this_id        = 7,			\
-			.sg_tablesize   = SCSI_NCR_SG_TABLESIZE,	\
-			.cmd_per_lun    = SCSI_NCR_CMD_PER_LUN,	\
-			.max_sectors	= MAX_HW_SEGMENTS*8,	\
-			.use_clustering = DISABLE_CLUSTERING,	\
-			.highmem_io	= 1} 
-
-#else
-
-#define SYM53C8XX {	NULL, NULL, NULL, NULL,				\
-			NULL,			sym53c8xx_detect,	\
-			sym53c8xx_release,	sym53c8xx_info,	NULL,	\
-			sym53c8xx_queue_command,sym53c8xx_abort,	\
-			sym53c8xx_reset, NULL,	scsicam_bios_param,	\
-			SCSI_NCR_CAN_QUEUE,	7,			\
-			SCSI_NCR_SG_TABLESIZE,	SCSI_NCR_CMD_PER_LUN,	\
-			0,	0,	DISABLE_CLUSTERING} 
- 
-#endif /* LINUX_VERSION_CODE */
-
 #endif /* defined(HOSTS_C) || defined(MODULE) */ 
 
 #endif /* SYM53C8XX_H */
diff -Nru a/drivers/scsi/sym53c8xx_2/sym53c8xx.h b/drivers/scsi/sym53c8xx_2/sym53c8xx.h
--- a/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Sat Mar  1 07:48:32 2003
+++ b/drivers/scsi/sym53c8xx_2/sym53c8xx.h	Sun May  4 02:56:46 2003
@@ -79,57 +79,10 @@
 #endif
 #endif
 
-int sym53c8xx_detect(Scsi_Host_Template *tpnt);
-const char *sym53c8xx_info(struct Scsi_Host *host);
-
-int sym53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-
-int sym53c8xx_eh_abort_handler(Scsi_Cmnd *);
-int sym53c8xx_eh_device_reset_handler(Scsi_Cmnd *);
-int sym53c8xx_eh_bus_reset_handler(Scsi_Cmnd *);
-int sym53c8xx_eh_host_reset_handler(Scsi_Cmnd *);
-
-int sym53c8xx_slave_configure(Scsi_Device *);
-
-#ifdef MODULE
-int sym53c8xx_release(struct Scsi_Host *);
-#else
-#define sym53c8xx_release NULL
-#endif
-
-
-/*
- *  Host template defintion
- */
-#if (LINUX_VERSION_CODE >= 0x020400) || defined(HOSTS_C) || defined(MODULE)
-
-#include <scsi/scsicam.h>
-
-#define SYM53C8XX {							\
-	.name			= "sym53c8xx",				\
-	.detect			= sym53c8xx_detect,			\
-	.release		= sym53c8xx_release,			\
-	.info			= sym53c8xx_info, 			\
-	.queuecommand		= sym53c8xx_queue_command,		\
-	.slave_configure	= sym53c8xx_slave_configure,		\
-	.eh_abort_handler	= sym53c8xx_eh_abort_handler,		\
-	.eh_device_reset_handler	= sym53c8xx_eh_device_reset_handler,\
-	.eh_bus_reset_handler	= sym53c8xx_eh_bus_reset_handler,	\
-	.eh_host_reset_handler	= sym53c8xx_eh_host_reset_handler,	\
-	.can_queue		= 0,					\
-	.this_id		= 7,					\
-	.sg_tablesize		= 0,					\
-	.cmd_per_lun		= 0,					\
-	.use_clustering		= DISABLE_CLUSTERING,			\
-	.highmem_io		= 1}
-
-#endif /* defined(HOSTS_C) || defined(MODULE) */ 
-
 /*
  *  Translate kernel configuration parameters
  *  into corresponding driver parameters.
  */
-#if !defined(HOSTS_C)
 
 /*
  *  Use normal IO if configured.
@@ -366,7 +319,5 @@
 #define DEBUG_FLAGS	sym_debug_flags
 #endif
 #define boot_verbose	sym_driver_setup.verbose
-
-#endif /* !defined(HOSTS_C) */ 
 
 #endif /* SYM53C8XX_H */
diff -Nru a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c	Mon Apr 21 10:36:31 2003
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c	Sun May  4 02:56:46 2003
@@ -2558,35 +2558,17 @@
 	bcopy(chip, &device->chip, sizeof(device->chip));
 	device->chip.revision_id = revision;
 
+	if (pci_enable_device(pdev))
+		return -1;
+
+	pci_set_master(pdev);
+
 	/*
 	 *  Read additionnal info from the configuration space.
 	 */
-	pci_read_config_word(pdev, PCI_COMMAND,		&command);
 	pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE,	&cache_line_size);
 
 	/*
-	 * Enable missing capabilities in the PCI COMMAND register.
-	 */
-#ifdef SYM_CONF_IOMAPPED
-#define	PCI_COMMAND_BITS_TO_ENABLE (PCI_COMMAND_IO | \
-	PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)
-#else
-#define	PCI_COMMAND_BITS_TO_ENABLE \
-	(PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_PARITY)
-#endif
-	if ((command & PCI_COMMAND_BITS_TO_ENABLE)
-		    != PCI_COMMAND_BITS_TO_ENABLE) {
-		printf_info("%s: setting%s%s%s%s...\n", sym_name(device),
-		(command & PCI_COMMAND_IO)     ? "" : " PCI_COMMAND_IO",
-		(command & PCI_COMMAND_MEMORY) ? "" : " PCI_COMMAND_MEMORY",
-		(command & PCI_COMMAND_MASTER) ? "" : " PCI_COMMAND_MASTER",
-		(command & PCI_COMMAND_PARITY) ? "" : " PCI_COMMAND_PARITY");
-		command |= PCI_COMMAND_BITS_TO_ENABLE;
-		pci_write_config_word(pdev, PCI_COMMAND, command);
-	}
-#undef	PCI_COMMAND_BITS_TO_ENABLE
-
-	/*
 	 *  If cache line size is not configured, suggest
 	 *  a value for well known CPUs.
 	 */
@@ -2625,6 +2607,7 @@
 		            sym_name(device), cache_line_size);
 	}
 
+	pci_read_config_word(pdev, PCI_COMMAND,	&command);
 	if ((pci_fix_up & 2) && cache_line_size &&
 	    (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
 		printf_info("%s: setting PCI_COMMAND_INVALIDATE.\n",
@@ -2725,15 +2708,6 @@
 	/*
 	 *    Initialize driver general stuff.
 	 */
-#ifdef SYM_LINUX_PROC_INFO_SUPPORT
-#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
-     tpnt->proc_dir  = &proc_scsi_sym53c8xx;
-#else
-     tpnt->proc_name = NAME53C8XX;
-#endif
-     tpnt->proc_info = sym53c8xx_proc_info;
-#endif
-
 #ifdef SYM_LINUX_BOOT_COMMAND_LINE_SUPPORT
 #ifdef MODULE
 if (sym53c8xx)
@@ -2916,7 +2890,6 @@
 
 
 
-#ifdef MODULE
 /*
  *  Linux release module stuff.
  *
@@ -2980,7 +2953,6 @@
 
      return 0;
 }
-#endif /* MODULE */
 
 /*
  * For bigots to keep silent. :)
@@ -2992,10 +2964,27 @@
 /*
  * Driver host template.
  */
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0)
-static
+static Scsi_Host_Template driver_template = {
+	.name			= "sym53c8xx",
+	.detect			= sym53c8xx_detect,
+	.release		= sym53c8xx_release,
+	.info			= sym53c8xx_info, 
+	.queuecommand		= sym53c8xx_queue_command,
+	.slave_configure	= sym53c8xx_slave_configure,
+	.eh_abort_handler	= sym53c8xx_eh_abort_handler,
+	.eh_device_reset_handler = sym53c8xx_eh_device_reset_handler,
+	.eh_bus_reset_handler	= sym53c8xx_eh_bus_reset_handler,
+	.eh_host_reset_handler	= sym53c8xx_eh_host_reset_handler,
+	.this_id		= 7,
+	.use_clustering		= DISABLE_CLUSTERING,
+	.highmem_io		= 1,
+#ifdef SYM_LINUX_PROC_INFO_SUPPORT
+	.proc_info		= sym53c8xx_proc_info,
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,3,27)
+	.proc_dir		= &proc_scsi_sym53c8xx,
+#else
+	.proc_name		= NAME53C8XX,
 #endif
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) || defined(MODULE)
-Scsi_Host_Template driver_template = SYM53C8XX;
-#include "../scsi_module.c"
 #endif
+};
+#include "../scsi_module.c"
diff -Nru a/drivers/scsi/t128.c b/drivers/scsi/t128.c
--- a/drivers/scsi/t128.c	Thu Apr 24 05:16:59 2003
+++ b/drivers/scsi/t128.c	Sun May  4 02:56:46 2003
@@ -400,7 +400,19 @@
 
 #include "NCR5380.c"
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = TRANTOR_T128;
-
+static Scsi_Host_Template driver_template = {
+	.name           = "Trantor T128/T128F/T228",
+	.detect         = t128_detect,
+	.queuecommand   = t128_queue_command,
+	.eh_abort_handler = t128_abort,
+	.eh_bus_reset_handler    = t128_bus_reset,
+	.eh_host_reset_handler   = t128_host_reset,
+	.eh_device_reset_handler = t128_device_reset,
+	.bios_param     = t128_biosparam,
+	.can_queue      = CAN_QUEUE,
+        .this_id        = 7,
+	.sg_tablesize   = SG_ALL,
+	.cmd_per_lun    = CMD_PER_LUN,
+	.use_clustering = DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/t128.h b/drivers/scsi/t128.h
--- a/drivers/scsi/t128.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/t128.h	Sun May  4 02:56:46 2003
@@ -114,27 +114,6 @@
 #define CAN_QUEUE 32 
 #endif
 
-/* 
- * I hadn't thought of this with the earlier drivers - but to prevent
- * macro definition conflicts, we shouldn't define all of the internal
- * macros when this is being used solely for the host stub.
- */
-
-#define TRANTOR_T128 {					\
-	.name           = "Trantor T128/T128F/T228",	\
-	.detect         = t128_detect,			\
-	.queuecommand   = t128_queue_command,		\
-	.eh_abort_handler = t128_abort,			\
-	.eh_bus_reset_handler    = t128_bus_reset,	\
-	.eh_host_reset_handler   = t128_host_reset,	\
-	.eh_device_reset_handler = t128_device_reset,	\
-	.bios_param     = t128_biosparam,			\
-	.can_queue      = CAN_QUEUE,			\
-        .this_id        = 7,				\
-	.sg_tablesize   = SG_ALL,				\
-	.cmd_per_lun    = CMD_PER_LUN,			\
-	.use_clustering = DISABLE_CLUSTERING}
-
 #ifndef HOSTS_C
 
 #define NCR5380_implementation_fields \
diff -Nru a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
--- a/drivers/scsi/tmscsim.c	Thu Apr 24 05:16:59 2003
+++ b/drivers/scsi/tmscsim.c	Sun May  4 02:56:46 2003
@@ -3059,7 +3059,20 @@
 }
 #endif /* def MODULE */
 
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,99)
 static Scsi_Host_Template driver_template = DC390_T;
+   .proc_name      = "tmscsim", 
+   .proc_info      = DC390_proc_info,
+   .name           = DC390_BANNER " V" DC390_VERSION,
+   .detect         = DC390_detect,
+   .release        = DC390_release,
+   .queuecommand   = DC390_queue_command,
+   .abort          = DC390_abort,
+   .reset          = DC390_reset,
+   .bios_param     = DC390_bios_param,
+   .can_queue      = 42,
+   .this_id        = 7,
+   .sg_tablesize   = SG_ALL,
+   .cmd_per_lun    = 16,
+   .use_clustering = DISABLE_CLUSTERING,
+};
 #include "scsi_module.c"
-#endif
diff -Nru a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
--- a/drivers/scsi/u14-34f.c	Sat Apr 26 07:28:29 2003
+++ b/drivers/scsi/u14-34f.c	Thu May  8 11:24:15 2003
@@ -1897,7 +1897,8 @@
    unsigned long spin_flags;
 
    /* Check if the interrupt must be processed by this handler */
-   if ((j = (unsigned int)((char *)shap - sha)) >= num_boards) return;
+   if ((j = (unsigned int)((char *)shap - sha)) >= num_boards)
+	   return IRQ_NONE;
 
    spin_lock_irqsave(sh[j]->host_lock, spin_flags);
    ihdlr(irq, j);
@@ -1929,8 +1930,19 @@
    return FALSE;
 }
 
-static Scsi_Host_Template driver_template = ULTRASTOR_14_34F;
-
+static Scsi_Host_Template driver_template = {
+	.name         = "UltraStor 14F/34F rev. " U14_34F_VERSION " ",
+	.detect                  = u14_34f_detect,
+	.release                 = u14_34f_release,
+	.queuecommand            = u14_34f_queuecommand,
+	.eh_abort_handler        = u14_34f_eh_abort,
+	.eh_host_reset_handler   = u14_34f_eh_host_reset,
+	.bios_param              = u14_34f_bios_param,
+	.slave_configure         = u14_34f_slave_configure,
+	.this_id                 = 7,
+	.unchecked_isa_dma       = 1, 
+	.use_clustering          = ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
 
 #ifndef MODULE
diff -Nru a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h
--- a/drivers/scsi/u14-34f.h	Tue Nov 12 04:39:14 2002
+++ b/drivers/scsi/u14-34f.h	Sun May  4 02:56:46 2003
@@ -12,19 +12,3 @@
 static int u14_34f_slave_configure(Scsi_Device *);
 
 #define U14_34F_VERSION "8.03.00"
-
-#define ULTRASTOR_14_34F {                                                   \
-                .name         = "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
-                .detect                  = u14_34f_detect,                     \
-                .release                 = u14_34f_release,                    \
-                .queuecommand            = u14_34f_queuecommand,               \
-                .eh_abort_handler        = u14_34f_eh_abort,                   \
-                .eh_device_reset_handler = NULL,                               \
-                .eh_bus_reset_handler    = NULL,                               \
-                .eh_host_reset_handler   = u14_34f_eh_host_reset,              \
-                .bios_param              = u14_34f_bios_param,                 \
-                .slave_configure         = u14_34f_slave_configure,            \
-                .this_id                 = 7,                                  \
-                .unchecked_isa_dma       = 1,                                  \
-                .use_clustering          = ENABLE_CLUSTERING                   \
-                }
diff -Nru a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
--- a/drivers/scsi/ultrastor.c	Sat Apr 26 07:28:29 2003
+++ b/drivers/scsi/ultrastor.c	Thu May  8 11:24:15 2003
@@ -252,7 +252,7 @@
 #if ULTRASTOR_MAX_CMDS == 1
   unsigned char mscp_busy;
 #else
-  unsigned short mscp_free;
+  unsigned long mscp_free;
 #endif
   volatile unsigned char aborted[ULTRASTOR_MAX_CMDS];
   struct mscp mscp[ULTRASTOR_MAX_CMDS];
@@ -1174,7 +1174,18 @@
 
 MODULE_LICENSE("GPL");
 
-/* Eventually this will go into an include file, but this will be later */
-static Scsi_Host_Template driver_template = ULTRASTOR_14F;
-
+static Scsi_Host_Template driver_template = {
+	.name              = "UltraStor 14F/24F/34F",
+	.detect            = ultrastor_detect,
+	.info              = ultrastor_info,
+	.queuecommand      = ultrastor_queuecommand,
+	.eh_abort_handler  = ultrastor_abort,
+	.eh_host_reset_handler  = ultrastor_host_reset,	
+	.bios_param        = ultrastor_biosparam,
+	.can_queue         = ULTRASTOR_MAX_CMDS,
+	.sg_tablesize      = ULTRASTOR_14F_MAX_SG,
+	.cmd_per_lun       = ULTRASTOR_MAX_CMDS_PER_LUN,
+	.unchecked_isa_dma = 1,
+	.use_clustering    = ENABLE_CLUSTERING,
+};
 #include "scsi_module.c"
diff -Nru a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
--- a/drivers/scsi/ultrastor.h	Tue Dec 10 12:28:33 2002
+++ b/drivers/scsi/ultrastor.h	Sun May  4 02:56:46 2003
@@ -30,21 +30,6 @@
 #define ULTRASTOR_24F_PORT 0xC80
 
 
-#define ULTRASTOR_14F {   .name              = "UltraStor 14F/24F/34F", 	\
-			  .detect            = ultrastor_detect, 		\
-			  .info              = ultrastor_info, 		\
-			  .queuecommand      = ultrastor_queuecommand,	\
-			  .eh_abort_handler  = ultrastor_abort, 		\
-			  .eh_host_reset_handler  = ultrastor_host_reset,	\
-			  .bios_param        = ultrastor_biosparam, 	\
-			  .can_queue         = ULTRASTOR_MAX_CMDS,	\
-			  .this_id           = 0, 			\
-			  .sg_tablesize      = ULTRASTOR_14F_MAX_SG, 	\
-			  .cmd_per_lun       = ULTRASTOR_MAX_CMDS_PER_LUN,\
-			  .unchecked_isa_dma = 1, 			\
-			  .use_clustering    = ENABLE_CLUSTERING }
-
-
 #ifdef ULTRASTOR_PRIVATE
 
 #define UD_ABORT	0x0001
diff -Nru a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
--- a/drivers/scsi/wd7000.c	Sat Apr 26 07:28:29 2003
+++ b/drivers/scsi/wd7000.c	Thu May  8 11:24:15 2003
@@ -1375,7 +1375,6 @@
 static int wd7000_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
 {
 	struct Scsi_Host *host = NULL;
-	Scsi_Device *scd;
 	Adapter *adapter;
 	unsigned long flags;
 	char *pos = buffer;
@@ -1449,27 +1448,6 @@
 
 	SPRINTF(count ? "\n" : "none\n");
 #endif
-
-	/*
-	 * Display driver information for each device attached to the board.
-	 */
-	SPRINTF("\nAttached devices: %s\n", !list_empty(&host->my_devices) ?
-		       	"" : "none");
-
-	list_for_each_entry (scd, &host->my_devices, siblings) {
-		SPRINTF("  [Channel: %02d, Id: %02d, Lun: %02d]  ", scd->channel, scd->id, scd->lun);
-		SPRINTF("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ? scsi_device_types[(short) scd->type] : "Unknown device");
-
-		for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++)
-			SPRINTF("%c", scd->vendor[i]);
-		SPRINTF(" ");
-
-		for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++)
-			SPRINTF("%c", scd->model[i]);
-		SPRINTF("\n");
-	}
-
-	SPRINTF("\n");
 
 	spin_unlock_irqrestore(host->host_lock, flags);
 
diff -Nru a/drivers/serial/21285.c b/drivers/serial/21285.c
--- a/drivers/serial/21285.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/serial/21285.c	Mon May 12 16:21:24 2003
@@ -85,7 +85,7 @@
 {
 }
 
-static void serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t serial21285_rx_chars(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct uart_port *port = dev_id;
 	struct tty_struct *tty = port->info->tty;
@@ -97,7 +97,7 @@
 			tty->flip.work.func((void *)tty);
 			if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
 				printk(KERN_WARNING "TTY_DONT_FLIP set\n");
-				return;
+				goto out;
 			}
 		}
 
@@ -143,9 +143,12 @@
 		status = *CSR_UARTFLG;
 	}
 	tty_flip_buffer_push(tty);
+
+ out:
+	return IRQ_HANDLED;
 }
 
-static void serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t serial21285_tx_chars(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct uart_port *port = dev_id;
 	struct circ_buf *xmit = &port->info->xmit;
@@ -155,11 +158,11 @@
 		*CSR_UARTDR = port->x_char;
 		port->icount.tx++;
 		port->x_char = 0;
-		return;
+		goto out;
 	}
 	if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
 		serial21285_stop_tx(port, 0);
-		return;
+		goto out;
 	}
 
 	do {
@@ -175,6 +178,9 @@
 
 	if (uart_circ_empty(xmit))
 		serial21285_stop_tx(port, 0);
+
+ out:
+	return IRQ_HANDLED;
 }
 
 static unsigned int serial21285_tx_empty(struct uart_port *port)
diff -Nru a/drivers/serial/amba.c b/drivers/serial/amba.c
--- a/drivers/serial/amba.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/serial/amba.c	Mon May 12 16:21:24 2003
@@ -278,7 +278,7 @@
 	wake_up_interruptible(&uap->port.info->delta_msr_wait);
 }
 
-static void ambauart_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t ambauart_int(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct uart_port *port = dev_id;
 	unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT;
@@ -302,6 +302,8 @@
 		status = UART_GET_INT_STATUS(port);
 	} while (status & (AMBA_UARTIIR_RTIS | AMBA_UARTIIR_RIS |
 			   AMBA_UARTIIR_TIS));
+
+	return IRQ_HANDLED;
 }
 
 static unsigned int ambauart_tx_empty(struct uart_port *port)
diff -Nru a/drivers/serial/core.c b/drivers/serial/core.c
--- a/drivers/serial/core.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/serial/core.c	Wed May  7 15:51:55 2003
@@ -2242,7 +2242,7 @@
 	 * Register the port whether it's detected or not.  This allows
 	 * setserial to be used to alter this ports parameters.
 	 */
-	tty_register_device(drv->tty_driver, port->line);
+	tty_register_device(drv->tty_driver, port->line, NULL);
 
  out:
 	up(&port_sem);
diff -Nru a/drivers/serial/sa1100.c b/drivers/serial/sa1100.c
--- a/drivers/serial/sa1100.c	Mon Apr 28 23:51:37 2003
+++ b/drivers/serial/sa1100.c	Mon May 12 16:21:25 2003
@@ -312,7 +312,7 @@
 		sa1100_stop_tx(&sport->port, 0);
 }
 
-static void sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t sa1100_int(int irq, void *dev_id, struct pt_regs *regs)
 {
 	struct sa1100_port *sport = dev_id;
 	unsigned int status, pass_counter = 0;
@@ -347,6 +347,8 @@
 			  ~UTSR0_TFS;
 	} while (status & (UTSR0_TFS | UTSR0_RFS | UTSR0_RID));
 	spin_unlock(&sport->port.lock);
+
+	return IRQ_HANDLED;
 }
 
 /*
@@ -830,7 +832,7 @@
 	.setup		= sa1100_console_setup,
 	.flags		= CON_PRINTBUFFER,
 	.index		= -1,
-	.data		= sa1100_reg,
+	.data		= &sa1100_reg,
 };
 
 static int __init sa1100_rs_console_init(void)
diff -Nru a/drivers/sgi/char/sgiserial.c b/drivers/sgi/char/sgiserial.c
--- a/drivers/sgi/char/sgiserial.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/sgi/char/sgiserial.c	Thu May  8 06:26:46 2003
@@ -1232,7 +1232,7 @@
 	tmp.close_delay = info->close_delay;
 	tmp.closing_wait = info->closing_wait;
 	tmp.custom_divisor = info->custom_divisor;
-	return copy_to_user(retinfo,&tmp,sizeof(*retinfo));
+	return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
 }
 
 static int set_serial_info(struct sgi_serial * info,
@@ -1867,6 +1867,7 @@
 	
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.owner = THIS_MODULE;
 	serial_driver.name = "ttyS";
 	serial_driver.major = TTY_MAJOR;
 	serial_driver.minor_start = 64;
diff -Nru a/drivers/sgi/char/shmiq.c b/drivers/sgi/char/shmiq.c
--- a/drivers/sgi/char/shmiq.c	Mon Dec  2 17:48:10 2002
+++ b/drivers/sgi/char/shmiq.c	Wed May  7 08:47:30 2003
@@ -470,9 +470,8 @@
 	printk ("SHMIQ setup\n");
 	register_chrdev(SHMIQ_MAJOR, "shmiq", &shmiq_fops);
 	for (i = 0; i < 3; i++) {
-		devfs_register (NULL, names[i], DEVFS_FL_DEFAULT,
-			SHMIQ_MAJOR, i, S_IFCHR | S_IRUSR | S_IWUSR,
-			&shmiq_fops, NULL);
+		devfs_mk_cdev(MKDEV(SHMIQ_MAJOR, i),
+				S_IFCHR | S_IRUSR | S_IWUSR, names[i]);
 	}
 }
 
diff -Nru a/drivers/tc/zs.c b/drivers/tc/zs.c
--- a/drivers/tc/zs.c	Thu Apr 24 03:30:40 2003
+++ b/drivers/tc/zs.c	Wed May  7 15:51:55 2003
@@ -1872,6 +1872,7 @@
 
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
+	serial_driver.owner = THIS_MODULE;
 #if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
 	serial_driver.name = "tts/";
 #else
@@ -1970,8 +1971,8 @@
 		printk("ttyS%02d at 0x%08x (irq = %d)", info->line, 
 		       info->port, info->irq);
 		printk(" is a Z85C30 SCC\n");
-		tty_register_device(&serial_driver, info->line);
-		tty_register_device(&callout_driver, info->line);
+		tty_register_device(&serial_driver, info->line, NULL);
+		tty_register_device(&callout_driver, info->line, NULL);
 
 	}
 
diff -Nru a/drivers/telephony/phonedev.c b/drivers/telephony/phonedev.c
--- a/drivers/telephony/phonedev.c	Sun Nov 17 23:09:30 2002
+++ b/drivers/telephony/phonedev.c	Sat May 17 12:39:13 2003
@@ -59,11 +59,8 @@
 	if (p)
 		new_fops = fops_get(p->f_op);
 	if (!new_fops) {
-		char modname[32];
-
 		up(&phone_lock);
-		sprintf(modname, "char-major-%d-%d", PHONE_MAJOR, minor);
-		request_module(modname);
+		request_module("char-major-%d-%d", PHONE_MAJOR, minor);
 		down(&phone_lock);
 		p = phone_device[minor];
 		if (p == NULL || (new_fops = fops_get(p->f_op)) == NULL)
diff -Nru a/drivers/usb/Kconfig b/drivers/usb/Kconfig
--- a/drivers/usb/Kconfig	Sun Feb  9 17:29:49 2003
+++ b/drivers/usb/Kconfig	Thu May  8 04:25:27 2003
@@ -91,5 +91,7 @@
 
 source "drivers/usb/misc/Kconfig"
 
+source "drivers/usb/gadget/Kconfig"
+
 endmenu
 
diff -Nru a/drivers/usb/Makefile b/drivers/usb/Makefile
--- a/drivers/usb/Makefile	Sat Apr 12 06:29:39 2003
+++ b/drivers/usb/Makefile	Sun May 11 11:12:52 2003
@@ -58,3 +58,4 @@
 obj-$(CONFIG_USB_TEST)		+= misc/
 obj-$(CONFIG_USB_TIGL)		+= misc/
 obj-$(CONFIG_USB_USS720)	+= misc/
+
diff -Nru a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
--- a/drivers/usb/class/Kconfig	Sun Feb  9 17:29:49 2003
+++ b/drivers/usb/class/Kconfig	Sun May 11 14:49:23 2003
@@ -90,6 +90,6 @@
 
 	  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 printer. If you want to compile it as a
+	  The module will be called usblp. If you want to compile it as a
 	  module, say M here and read <file:Documentation/modules.txt>.
 
diff -Nru a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
--- a/drivers/usb/class/bluetty.c	Mon Apr 21 20:58:42 2003
+++ b/drivers/usb/class/bluetty.c	Wed May  7 15:51:55 2003
@@ -1198,7 +1198,7 @@
 		     bluetooth, endpoint->bInterval);
 
 	/* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */
-	tty_register_device (&bluetooth_tty_driver, minor);
+	tty_register_device (&bluetooth_tty_driver, minor, &intf->dev);
 	info("Bluetooth converter now attached to ttyUB%d (or usb/ttub/%d for devfs)", minor, minor);
 
 	bluetooth_table[minor] = bluetooth;
diff -Nru a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
--- a/drivers/usb/class/cdc-acm.c	Thu Apr 24 16:01:58 2003
+++ b/drivers/usb/class/cdc-acm.c	Sat May 10 16:30:31 2003
@@ -252,7 +252,8 @@
 	unsigned char *data = urb->transfer_buffer;
 	int i = 0;
 
-	if (!ACM_READY(acm)) return;
+	if (!ACM_READY(acm))
+		return;
 
 	if (urb->status)
 		dbg("nonzero read bulk status received: %d", urb->status);
@@ -286,7 +287,8 @@
 {
 	struct acm *acm = (struct acm *)urb->context;
 
-	if (!ACM_READY(acm)) return;
+	if (!ACM_READY(acm))
+		return;
 
 	if (urb->status)
 		dbg("nonzero write bulk status received: %d", urb->status);
@@ -299,7 +301,8 @@
 	struct acm *acm = private;
 	struct tty_struct *tty = acm->tty;
 
-	if (!ACM_READY(acm)) return;
+	if (!ACM_READY(acm))
+		return;
 
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup)
 		(tty->ldisc.write_wakeup)(tty);
@@ -315,7 +318,8 @@
 {
 	struct acm *acm = acm_table[tty->index];
 
-	if (!acm || !acm->dev) return -EINVAL;
+	if (!acm || !acm->dev)
+		return -EINVAL;
 
 	tty->driver_data = acm;
 	acm->tty = tty;
@@ -350,7 +354,8 @@
 {
 	struct acm *acm = tty->driver_data;
 
-	if (!acm || !acm->used) return;
+	if (!acm || !acm->used)
+		return;
 
 	if (!--acm->used) {
 		if (acm->dev) {
@@ -373,9 +378,12 @@
 {
 	struct acm *acm = tty->driver_data;
 
-	if (!ACM_READY(acm)) return -EINVAL;
-	if (acm->writeurb->status == -EINPROGRESS) return 0;
-	if (!count) return 0;
+	if (!ACM_READY(acm))
+		return -EINVAL;
+	if (acm->writeurb->status == -EINPROGRESS)
+		return 0;
+	if (!count)
+		return 0;
 
 	count = (count > acm->writesize) ? acm->writesize : count;
 
@@ -397,28 +405,32 @@
 static int acm_tty_write_room(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
-	if (!ACM_READY(acm)) return -EINVAL;
+	if (!ACM_READY(acm))
+		return -EINVAL;
 	return acm->writeurb->status == -EINPROGRESS ? 0 : acm->writesize;
 }
 
 static int acm_tty_chars_in_buffer(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
-	if (!ACM_READY(acm)) return -EINVAL;
+	if (!ACM_READY(acm))
+		return -EINVAL;
 	return acm->writeurb->status == -EINPROGRESS ? acm->writeurb->transfer_buffer_length : 0;
 }
 
 static void acm_tty_throttle(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
-	if (!ACM_READY(acm)) return;
+	if (!ACM_READY(acm))
+		return;
 	acm->throttle = 1;
 }
 
 static void acm_tty_unthrottle(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
-	if (!ACM_READY(acm)) return;
+	if (!ACM_READY(acm))
+		return;
 	acm->throttle = 0;
 	if (acm->readurb->status != -EINPROGRESS)
 		acm_read_bulk(acm->readurb, NULL);
@@ -427,7 +439,8 @@
 static void acm_tty_break_ctl(struct tty_struct *tty, int state)
 {
 	struct acm *acm = tty->driver_data;
-	if (!ACM_READY(acm)) return;
+	if (!ACM_READY(acm))
+		return;
 	if (acm_send_break(acm, state ? 0xffff : 0))
 		dbg("send break failed");
 }
@@ -496,7 +509,8 @@
 	struct acm_line newline;
 	int newctrl = acm->ctrlout;
 
-	if (!ACM_READY(acm)) return;
+	if (!ACM_READY(acm))
+		return;
 
 	newline.speed = cpu_to_le32p(acm_tty_speed +
 		(termios->c_cflag & CBAUD & ~CBAUDEX) + (termios->c_cflag & CBAUDEX ? 15 : 0));
@@ -653,7 +667,7 @@
 		usb_driver_claim_interface(&acm_driver, acm->iface + 0, acm);
 		usb_driver_claim_interface(&acm_driver, acm->iface + 1, acm);
 
-		tty_register_device(&acm_tty_driver, minor);
+		tty_register_device(&acm_tty_driver, minor, &intf->dev);
 
 		acm_table[minor] = acm;
 		usb_set_intfdata (intf, acm);
diff -Nru a/drivers/usb/class/usb-midi.c b/drivers/usb/class/usb-midi.c
--- a/drivers/usb/class/usb-midi.c	Thu Apr 24 03:35:31 2003
+++ b/drivers/usb/class/usb-midi.c	Sat May 10 17:18:06 2003
@@ -1355,8 +1355,10 @@
 		next = p2 + p2[0];
 		length -= p2[0];
 
-		if (p2[0] < 2 ) break;
-		if (p2[1] != USB_DT_CS_INTERFACE) break;
+		if (p2[0] < 2 )
+			break;
+		if (p2[1] != USB_DT_CS_INTERFACE)
+			break;
 		if (p2[2] == MIDI_IN_JACK && p2[0] >= 6 ) {
 			jack = p2[4];
 #ifdef HAVE_JACK_STRINGS
@@ -1366,7 +1368,8 @@
 			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL" );
 		} else if ( p2[2] == MIDI_OUT_JACK && p2[0] >= 6) {
 			pins = p2[5];
-			if ( p2[0] < (6 + 2 * pins) ) continue;
+			if ( p2[0] < (6 + 2 * pins) )
+				continue;
 			jack = p2[4];
 #ifdef HAVE_JACK_STRINGS
 			jack2string[jack] = p2[5 + 2 * pins];
@@ -1375,9 +1378,11 @@
 			       jack, (p2[3] == EMBEDDED_JACK)?"EMBEDDED":"EXTERNAL", pins );
 		} else if ( p2[2] == ELEMENT_DESCRIPTOR  && p2[0]  >= 10) {
 			pins = p2[4];
-			if ( p2[0] < (9 + 2 * pins ) ) continue;
+			if ( p2[0] < (9 + 2 * pins ) )
+				continue;
 			nbytes = p2[8 + 2 * pins ];
-			if ( p2[0] < (10 + 2 * pins + nbytes) ) continue;
+			if ( p2[0] < (10 + 2 * pins + nbytes) )
+				continue;
 			longBits = 0L;
 			for ( offset = 0, shift = 0; offset < nbytes && offset < 8; offset ++, shift += 8) {
 				longBits |= ((long)(p2[9 + 2 * pins + offset])) << shift;
@@ -1408,7 +1413,8 @@
 			if ( p2 && next && ( p2 > next ) )
 				p2 = 0;
 
-			if ( p1[0] < 9 || !p2 || p2[0] < 4 ) continue;
+			if ( p1[0] < 9 || !p2 || p2[0] < 4 )
+				continue;
 
 			if ( (p1[2] & 0x80) == 0x80 ) {
 				if ( iep < 15 ) {
@@ -1417,7 +1423,8 @@
 						pins = 16;
 					u->in[iep].endpoint = p1[2];
 					u->in[iep].cableId = ( 1 << pins ) - 1;
-					if ( u->in[iep].cableId ) iep ++;
+					if ( u->in[iep].cableId )
+						iep ++;
 					if ( iep < 15 ) {
 						u->in[iep].endpoint = -1;
 						u->in[iep].cableId = -1;
@@ -1430,7 +1437,8 @@
 						pins = 16;
 					u->out[oep].endpoint = p1[2];
 					u->out[oep].cableId = ( 1 << pins ) - 1;
-					if ( u->out[oep].cableId ) oep ++;
+					if ( u->out[oep].cableId )
+						oep ++;
 					if ( oep < 15 ) {
 						u->out[oep].endpoint = -1;
 						u->out[oep].cableId = -1;
@@ -1446,7 +1454,8 @@
 			next = find_descriptor(buffer, bufSize, p1, USB_DT_ENDPOINT,
 					       ifnum, altSetting ); 
 	
-			if ( p1[0] < 7 ) continue;
+			if ( p1[0] < 7 )
+				continue;
 
 			if ( (p1[2] & 0x80) == 0x80 ) {
 				if ( iep < 15 ) {
@@ -1455,7 +1464,8 @@
 						pins = 16;
 					u->in[iep].endpoint = p1[2];
 					u->in[iep].cableId = ( 1 << pins ) - 1;
-					if ( u->in[iep].cableId ) iep ++;
+					if ( u->in[iep].cableId )
+						iep ++;
 					if ( iep < 15 ) {
 						u->in[iep].endpoint = -1;
 						u->in[iep].cableId = -1;
@@ -1468,7 +1478,8 @@
 						pins = 16;
 					u->out[oep].endpoint = p1[2];
 					u->out[oep].cableId = ( 1 << pins ) - 1;
-					if ( u->out[oep].cableId ) oep ++;
+					if ( u->out[oep].cableId )
+						oep ++;
 					if ( oep < 15 ) {
 						u->out[oep].endpoint = -1;
 						u->out[oep].cableId = -1;
@@ -1486,7 +1497,7 @@
 	return u;
 
 error_end:
-	if ( u ) kfree(u);
+	kfree(u);
 	return NULL;
 }
 
@@ -1501,7 +1512,8 @@
 	int ret=0;
 
 	for ( i=0 ; i<16 ; i++ ) {
-		if ( v & (1<<i) ) ret++;
+		if ( v & (1<<i) )
+			ret++;
 	}
 
 	return ret;
@@ -1578,7 +1590,8 @@
 	if ( alt < 0 ) {
 		alt = get_alt_setting( d, u->interface );
 	}
-	if ( alt < 0 ) { return -ENXIO; }
+	if ( alt < 0 )
+		return -ENXIO;
 
 	/* Configure interface */
 	if ( usb_set_interface( d, u->interface, alt ) < 0 ) {
@@ -1596,7 +1609,8 @@
 	       && u->in[inEndpoints].cableId >= 0 ) {
 		inDevs += on_bits((unsigned short)u->in[inEndpoints].cableId);
 		mins[inEndpoints] = alloc_midi_in_endpoint( d, u->in[inEndpoints].endpoint );
-		if ( mins[inEndpoints] == NULL ) { goto error_end; }
+		if ( mins[inEndpoints] == NULL )
+			goto error_end;
 		inEndpoints++;
 	}
 
@@ -1605,7 +1619,8 @@
 	       && u->out[outEndpoints].cableId >= 0 ) {
 		outDevs += on_bits((unsigned short)u->out[outEndpoints].cableId);
 		mouts[outEndpoints] = alloc_midi_out_endpoint( d, u->out[outEndpoints].endpoint );
-		if ( mouts[outEndpoints] == NULL ) { goto error_end; }
+		if ( mouts[outEndpoints] == NULL )
+			goto error_end;
 		outEndpoints++;
 	}
 
@@ -1707,7 +1722,8 @@
 		mout = mouts[outEndpoint];
 
 		mdevs[i] = allocMidiDev( s, min, mout, inCableId, outCableId );
-		if ( mdevs[i] == NULL ) { goto error_end; }
+		if ( mdevs[i] == NULL )
+			goto error_end;
 
 	}
 
@@ -1962,11 +1978,15 @@
 		return -EINVAL;
 	}
 
-	if ( ualt < 0 ) { ualt = -1; }
+	if ( ualt < 0 )
+		ualt = -1;
 
-	if ( umin   < 0 || umin   > 15 ) { umin   = 0x01 | USB_DIR_IN; }
-	if ( umout  < 0 || umout  > 15 ) { umout  = 0x01; }
-	if ( ucable < 0 || ucable > 15 ) { ucable = 0; }
+	if ( umin   < 0 || umin   > 15 )
+		umin   = 0x01 | USB_DIR_IN;
+	if ( umout  < 0 || umout  > 15 )
+		umout  = 0x01;
+	if ( ucable < 0 || ucable > 15 )
+		ucable = 0;
 
 	u.deviceName = 0; /* A flag for alloc_usb_midi_device to get device name
 			     from device. */
diff -Nru a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
--- a/drivers/usb/class/usblp.c	Sat Apr 19 02:08:38 2003
+++ b/drivers/usb/class/usblp.c	Sat May 10 16:30:31 2003
@@ -54,7 +54,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/lp.h>
-#include <linux/devfs_fs_kernel.h>
 #undef DEBUG
 #include <linux/usb.h>
 
@@ -109,11 +108,7 @@
 #define USBLP_REQ_RESET				0x02
 #define USBLP_REQ_HP_CHANNEL_CHANGE_REQUEST	0x00	/* HP Vendor-specific */
 
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define USBLP_MINORS		256
-#else
 #define USBLP_MINORS		16
-#endif
 #define USBLP_MINOR_BASE	0
 
 #define USBLP_WRITE_TIMEOUT	(5*HZ)			/* 5 seconds */
@@ -303,8 +298,10 @@
 	status = *usblp->statusbuf;
 	if (~status & LP_PERRORP) {
 		newerr = 3;
-		if (status & LP_POUTPA) newerr = 1;
-		if (~status & LP_PSELECD) newerr = 2;
+		if (status & LP_POUTPA)
+			newerr = 1;
+		if (~status & LP_PSELECD)
+			newerr = 2;
 	}
 
 	if (newerr != err)
@@ -324,13 +321,13 @@
 	struct usb_interface *intf;
 	int retval;
 
-	if (minor < 0 || minor >= USBLP_MINORS)
+	if (minor < 0)
 		return -ENODEV;
 
 	lock_kernel();
 
 	retval = -ENODEV;
-	intf = usb_find_interface(&usblp_driver, mk_kdev(USB_MAJOR,minor));
+	intf = usb_find_interface(&usblp_driver, minor);
 	if (!intf) {
 		goto out;
 	}
@@ -380,8 +377,6 @@
 
 static void usblp_cleanup (struct usblp *usblp)
 {
-	devfs_remove ("usb/lp%d", usblp->minor);
-	usb_deregister_dev (1, usblp->minor);
 	info("usblp%d: removed", usblp->minor);
 
 	usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
@@ -809,6 +804,13 @@
 	.release =	usblp_release,
 };
 
+static struct usb_class_driver usblp_class = {
+	.name =		"usb/lp%d",
+	.fops =		&usblp_fops,
+	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+	.minor_base =	USBLP_MINOR_BASE,
+};
+
 static int usblp_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
 {
@@ -816,7 +818,6 @@
 	struct usblp *usblp = 0;
 	int protocol;
 	int retval;
-	char name[10];
 
 	/* Malloc and start initializing usblp structure so we can use it
 	 * directly. */
@@ -830,11 +831,12 @@
 	init_waitqueue_head(&usblp->wait);
 	usblp->ifnum = intf->altsetting->desc.bInterfaceNumber;
 
-	retval = usb_register_dev(&usblp_fops, USBLP_MINOR_BASE, 1, &usblp->minor);
+	retval = usb_register_dev(intf, &usblp_class);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		goto abort;
 	}
+	usblp->minor = intf->minor;
 
 	usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!usblp->writeurb) {
@@ -904,13 +906,6 @@
 	usblp_check_status(usblp, 0);
 #endif
 
-	/* If we have devfs, create with perms=660. */
-	sprintf(name, "usb/lp%d", usblp->minor);
-	devfs_register(NULL, name, 0, USB_MAJOR,
-				      usblp->minor,
-				      S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
-				      S_IWGRP, &usblp_fops, NULL);
-
 	info("usblp%d: USB %sdirectional printer dev %d "
 		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
 		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
@@ -921,13 +916,10 @@
 
 	usb_set_intfdata (intf, usblp);
 
-	/* add device id so the device works when advertised */
-	intf->kdev = mk_kdev(USB_MAJOR,usblp->minor);
-
 	return 0;
 
 abort_minor:
-	usb_deregister_dev (1, usblp->minor);
+	usb_deregister_dev(intf, &usblp_class);
 abort:
 	if (usblp) {
 		if (usblp->writebuf)
@@ -936,8 +928,8 @@
 		if (usblp->readbuf)
 			usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
 				usblp->readbuf, usblp->writeurb->transfer_dma);
-		if (usblp->statusbuf) kfree(usblp->statusbuf);
-		if (usblp->device_id_string) kfree(usblp->device_id_string);
+		kfree(usblp->statusbuf);
+		kfree(usblp->device_id_string);
 		usb_free_urb(usblp->writeurb);
 		usb_free_urb(usblp->readurb);
 		kfree(usblp);
@@ -997,10 +989,12 @@
 				continue;
 
 			if (!(epd->bEndpointAddress & USB_ENDPOINT_DIR_MASK)) {
-				if (!epwrite) epwrite=epd;
+				if (!epwrite)
+					epwrite = epd;
 
 			} else {
-				if (!epread) epread=epd;
+				if (!epread)
+					epread = epd;
 			}
 		}
 
@@ -1030,9 +1024,12 @@
 		return proto_bias;
 
 	/* Ordering is important here. */
-	if (usblp->protocol[2].alt_setting != -1) return 2;
-	if (usblp->protocol[1].alt_setting != -1) return 1;
-	if (usblp->protocol[3].alt_setting != -1) return 3;
+	if (usblp->protocol[2].alt_setting != -1)
+		return 2;
+	if (usblp->protocol[1].alt_setting != -1)
+		return 1;
+	if (usblp->protocol[3].alt_setting != -1)
+		return 3;
 
 	/* If nothing is available, then don't bind to this device. */
 	return -1;
@@ -1046,7 +1043,8 @@
 		return -EINVAL;
 
 	alts = usblp->protocol[protocol].alt_setting;
-	if (alts < 0) return -EINVAL;
+	if (alts < 0)
+		return -EINVAL;
 	r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
 	if (r < 0) {
 		err("can't set desired altsetting %d on interface %d",
@@ -1108,8 +1106,7 @@
 {
 	struct usblp *usblp = usb_get_intfdata (intf);
 
-	/* remove device id to disable open() */
-	intf->kdev = NODEV;
+	usb_deregister_dev(intf, &usblp_class);
 
 	if (!usblp || !usblp->dev) {
 		err("bogus disconnect");
diff -Nru a/drivers/usb/core/file.c b/drivers/usb/core/file.c
--- a/drivers/usb/core/file.c	Fri Apr 18 11:15:45 2003
+++ b/drivers/usb/core/file.c	Thu May  8 01:09:52 2003
@@ -11,7 +11,7 @@
  	more docs, etc)
  * (C) Copyright Yggdrasil Computing, Inc. 2000
  *     (usb_device_id matching changes by Adam J. Richter)
- * (C) Copyright Greg Kroah-Hartman 2002
+ * (C) Copyright Greg Kroah-Hartman 2002-2003
  *
  */
 
@@ -66,6 +66,10 @@
 	.open =		usb_open,
 };
 
+static struct class usb_class = {
+	.name	= "usb",
+};
+
 int usb_major_init(void)
 {
 	if (register_chrdev(USB_MAJOR, "usb", &usb_fops)) {
@@ -74,41 +78,53 @@
 	}
 
 	devfs_mk_dir("usb");
+	class_register(&usb_class);
 	return 0;
 }
 
 void usb_major_cleanup(void)
 {
+	class_unregister(&usb_class);
 	devfs_remove("usb");
 	unregister_chrdev(USB_MAJOR, "usb");
 }
 
+static ssize_t show_dev(struct class_device *class_dev, char *buf)
+{
+	struct usb_interface *intf = class_dev_to_usb_interface(class_dev);
+	dev_t dev = MKDEV(USB_MAJOR, intf->minor);
+	return sprintf(buf, "%04x\n", dev);
+}
+static CLASS_DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
+
 /**
  * usb_register_dev - register a USB device, and ask for a minor number
- * @fops: the file operations for this USB device
- * @minor: the requested starting minor for this device.
- * @num_minors: number of minor numbers requested for this device
- * @start_minor: place to put the new starting minor number
+ * @intf: pointer to the usb_interface that is being registered
+ * @class_driver: pointer to the usb_class_driver for this device
  *
  * This should be called by all USB drivers that use the USB major number.
  * If CONFIG_USB_DYNAMIC_MINORS is enabled, the minor number will be
  * dynamically allocated out of the list of available ones.  If it is not
  * enabled, the minor number will be based on the next available free minor,
- * starting at the requested @minor.
+ * starting at the class_driver->minor_base.
+ *
+ * This function also creates the devfs file for the usb device, if devfs
+ * is enabled, and creates a usb class device in the sysfs tree.
  *
  * usb_deregister_dev() must be called when the driver is done with
  * the minor numbers given out by this function.
  *
  * Returns -EINVAL if something bad happens with trying to register a
- * device, and 0 on success, alone with a value that the driver should
- * use in start_minor.
+ * device, and 0 on success.
  */
-int usb_register_dev (struct file_operations *fops, int minor, int num_minors, int *start_minor)
+int usb_register_dev(struct usb_interface *intf,
+		     struct usb_class_driver *class_driver)
 {
-	int i;
-	int j;
-	int good_spot;
 	int retval = -EINVAL;
+	int minor_base = class_driver->minor_base;
+	int minor = 0;
+	char name[DEVICE_ID_SIZE];
+	char *temp;
 
 #ifdef CONFIG_USB_DYNAMIC_MINORS
 	/* 
@@ -116,65 +132,93 @@
 	 * at zero to pack the devices into the smallest available space with
 	 * no holes in the minor range.
 	 */
-	minor = 0;
+	minor_base = 0;
 #endif
+	intf->minor = -1;
 
-	dbg ("asking for %d minors, starting at %d", num_minors, minor);
+	dbg ("looking for a minor, starting at %d", minor_base);
 
-	if (fops == NULL)
+	if (class_driver->fops == NULL)
 		goto exit;
 
-	*start_minor = 0; 
 	spin_lock (&minor_lock);
-	for (i = minor; i < MAX_USB_MINORS; ++i) {
-		if (usb_minors[i])
+	for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
+		if (usb_minors[minor])
 			continue;
 
-		good_spot = 1;
-		for (j = 1; j <= num_minors-1; ++j)
-			if (usb_minors[i+j]) {
-				good_spot = 0;
-				break;
-			}
-		if (good_spot == 0)
-			continue;
-
-		*start_minor = i;
-		dbg("found a minor chunk free, starting at %d", i);
-		for (i = *start_minor; i < (*start_minor + num_minors); ++i)
-			usb_minors[i] = fops;
+		usb_minors[minor] = class_driver->fops;
 
 		retval = 0;
-		goto exit;
+		break;
 	}
-exit:
 	spin_unlock (&minor_lock);
+
+	if (retval)
+		goto exit;
+
+	intf->minor = minor;
+
+	/* handle the devfs registration */
+	snprintf(name, DEVICE_ID_SIZE, class_driver->name, minor - minor_base);
+	devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name);
+
+	/* create a usb class device for this usb interface */
+	memset(&intf->class_dev, 0x00, sizeof(struct class_device));
+	intf->class_dev.class = &usb_class;
+	intf->class_dev.dev = &intf->dev;
+
+	temp = strrchr(name, '/');
+	if (temp && (temp[1] != 0x00))
+		++temp;
+	else
+		temp = name;
+	snprintf(intf->class_dev.class_id, BUS_ID_SIZE, "%s", temp);
+	class_device_register(&intf->class_dev);
+	class_device_create_file (&intf->class_dev, &class_device_attr_dev);
+exit:
 	return retval;
 }
 EXPORT_SYMBOL(usb_register_dev);
 
 /**
  * usb_deregister_dev - deregister a USB device's dynamic minor.
- * @num_minors: number of minor numbers to put back.
- * @start_minor: the starting minor number
+ * @intf: pointer to the usb_interface that is being deregistered
+ * @class_driver: pointer to the usb_class_driver for this device
  *
  * Used in conjunction with usb_register_dev().  This function is called
  * when the USB driver is finished with the minor numbers gotten from a
  * call to usb_register_dev() (usually when the device is disconnected
  * from the system.)
+ *
+ * This function also cleans up the devfs file for the usb device, if devfs
+ * is enabled, and removes the usb class device from the sysfs tree.
  * 
  * This should be called by all drivers that use the USB major number.
  */
-void usb_deregister_dev (int num_minors, int start_minor)
+void usb_deregister_dev(struct usb_interface *intf,
+			struct usb_class_driver *class_driver)
 {
-	int i;
+	int minor_base = class_driver->minor_base;
+	char name[DEVICE_ID_SIZE];
 
-	dbg ("removing %d minors starting at %d", num_minors, start_minor);
+#ifdef CONFIG_USB_DYNAMIC_MINORS
+	minor_base = 0;
+#endif
+
+	if (intf->minor == -1)
+		return;
+
+	dbg ("removing %d minor", intf->minor);
 
 	spin_lock (&minor_lock);
-	for (i = start_minor; i < (start_minor + num_minors); ++i)
-		usb_minors[i] = NULL;
+	usb_minors[intf->minor] = NULL;
 	spin_unlock (&minor_lock);
+
+	snprintf(name, DEVICE_ID_SIZE, class_driver->name, intf->minor - minor_base);
+	devfs_remove (name);
+
+	class_device_unregister(&intf->class_dev);
+	intf->minor = -1;
 }
 EXPORT_SYMBOL(usb_deregister_dev);
 
diff -Nru a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
--- a/drivers/usb/core/hcd-pci.c	Mon Apr 21 07:45:46 2003
+++ b/drivers/usb/core/hcd-pci.c	Sat May 10 16:30:31 2003
@@ -209,7 +209,8 @@
 		return;
 	dev_info (hcd->controller, "remove, state %x\n", hcd->state);
 
-	if (in_interrupt ()) BUG ();
+	if (in_interrupt ())
+		BUG ();
 
 	hub = hcd->self.root_hub;
 	hcd->state = USB_STATE_QUIESCING;
diff -Nru a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
--- a/drivers/usb/core/hcd.c	Mon Apr 21 13:41:12 2003
+++ b/drivers/usb/core/hcd.c	Tue May 20 04:43:09 2003
@@ -324,6 +324,7 @@
 	const u8	*bufp = 0;
 	u8		*ubuf = urb->transfer_buffer;
 	int		len = 0;
+	unsigned long	flags;
 
 	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
 	wValue   = le16_to_cpu (cmd->wValue);
@@ -436,7 +437,9 @@
 	}
 
 	/* any errors get returned through the urb completion */
+	local_irq_save (flags);
 	usb_hcd_giveback_urb (hcd, urb, NULL);
+	local_irq_restore (flags);
 	return 0;
 }
 
@@ -454,20 +457,22 @@
 	int	len = 1 + (urb->dev->maxchild / 8);
 
 	/* rh_timer protected by hcd_data_lock */
-	if (timer_pending (&hcd->rh_timer)
+	if (hcd->rh_timer.data
 			|| urb->status != -EINPROGRESS
 			|| urb->transfer_buffer_length < len) {
-		dev_dbg (hcd->controller, "not queuing status urb, stat %d\n", urb->status);
+		dev_dbg (hcd->controller,
+				"not queuing rh status urb, stat %d\n",
+				urb->status);
 		return -EINVAL;
 	}
 
-	urb->hcpriv = hcd;	/* nonzero to indicate it's queued */
 	init_timer (&hcd->rh_timer);
 	hcd->rh_timer.function = rh_report_status;
 	hcd->rh_timer.data = (unsigned long) urb;
 	/* USB 2.0 spec says 256msec; this is close enough */
 	hcd->rh_timer.expires = jiffies + HZ/4;
 	add_timer (&hcd->rh_timer);
+	urb->hcpriv = hcd;	/* nonzero to indicate it's queued */
 	return 0;
 }
 
@@ -481,39 +486,37 @@
 	unsigned long	flags;
 
 	urb = (struct urb *) ptr;
-	spin_lock_irqsave (&urb->lock, flags);
-	if (!urb->dev) {
-		spin_unlock_irqrestore (&urb->lock, flags);
+	local_irq_save (flags);
+	spin_lock (&urb->lock);
+
+	/* do nothing if the hc is gone or the urb's been unlinked */
+	if (!urb->dev
+			|| urb->status != -EINPROGRESS
+			|| (hcd = urb->dev->bus->hcpriv) == 0
+			|| !HCD_IS_RUNNING (hcd->state)) {
+		spin_unlock (&urb->lock);
+		local_irq_restore (flags);
 		return;
 	}
 
-	hcd = urb->dev->bus->hcpriv;
-	if (urb->status == -EINPROGRESS) {
-		if (HCD_IS_RUNNING (hcd->state)) {
-			length = hcd->driver->hub_status_data (hcd,
-					urb->transfer_buffer);
-			spin_unlock_irqrestore (&urb->lock, flags);
-			if (length > 0) {
-				urb->actual_length = length;
-				urb->status = 0;
-				urb->hcpriv = 0;
-				urb->complete (urb, NULL);
-				return;
-			}
-		} else
-			spin_unlock_irqrestore (&urb->lock, flags);
+	length = hcd->driver->hub_status_data (hcd, urb->transfer_buffer);
 
-		/* retrigger timer until completion:  success or unlink */
-		spin_lock_irqsave (&hcd_data_lock, flags);
-		rh_status_urb (hcd, urb);
-		spin_unlock_irqrestore (&hcd_data_lock, flags);
-	} else {
-		/* this urb's been unlinked */
+	/* complete the status urb, or retrigger the timer */
+	spin_lock (&hcd_data_lock);
+	if (length > 0) {
+		hcd->rh_timer.data = 0;
+		urb->actual_length = length;
+		urb->status = 0;
 		urb->hcpriv = 0;
-		spin_unlock_irqrestore (&urb->lock, flags);
+	} else
+		mod_timer (&hcd->rh_timer, jiffies + HZ/4);
+	spin_unlock (&hcd_data_lock);
+	spin_unlock (&urb->lock);
 
+	/* local irqs are always blocked in completions */
+	if (length > 0)
 		usb_hcd_giveback_urb (hcd, urb, NULL);
-	}
+	local_irq_restore (flags);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -541,13 +544,14 @@
 {
 	unsigned long	flags;
 
-	spin_lock_irqsave (&hcd_data_lock, flags);
+	/* note:  always a synchronous unlink */
 	del_timer_sync (&hcd->rh_timer);
 	hcd->rh_timer.data = 0;
-	spin_unlock_irqrestore (&hcd_data_lock, flags);
 
-	/* we rely on RH callback code not unlinking its URB! */
+	local_irq_save (flags);
+	urb->hcpriv = 0;
 	usb_hcd_giveback_urb (hcd, urb, NULL);
+	local_irq_restore (flags);
 }
 
 /*-------------------------------------------------------------------------*/
diff -Nru a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
--- a/drivers/usb/core/hub.c	Sat Mar 29 09:51:15 2003
+++ b/drivers/usb/core/hub.c	Wed May  7 13:26:35 2003
@@ -42,7 +42,7 @@
 static LIST_HEAD(hub_list);		/* List of all hubs (for cleanup) */
 
 static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
-static int khubd_pid = 0;			/* PID of khubd */
+static pid_t khubd_pid = 0;			/* PID of khubd */
 static DECLARE_COMPLETION(khubd_exited);
 
 #ifdef	DEBUG
@@ -1126,7 +1126,7 @@
  */
 int usb_hub_init(void)
 {
-	int pid;
+	pid_t pid;
 
 	if (usb_register(&hub_driver) < 0) {
 		err("Unable to register USB hub driver");
diff -Nru a/drivers/usb/core/message.c b/drivers/usb/core/message.c
--- a/drivers/usb/core/message.c	Thu Apr  3 00:03:52 2003
+++ b/drivers/usb/core/message.c	Mon May 19 11:36:42 2003
@@ -795,6 +795,7 @@
 	struct usb_interface *iface;
 	struct usb_host_interface *iface_as;
 	int i, ret;
+	void (*disable)(struct usb_device *, int) = dev->bus->op->disable;
 
 	iface = usb_ifnum_to_if(dev, interface);
 	if (!iface) {
@@ -832,9 +833,11 @@
 		u8	ep = iface_as->endpoint [i].desc.bEndpointAddress;
 		int	out = !(ep & USB_DIR_IN);
 
+		/* clear out hcd state, then usbcore state */
+		if (disable)
+			disable (dev, ep);
 		ep &= USB_ENDPOINT_NUMBER_MASK;
 		(out ? dev->epmaxpacketout : dev->epmaxpacketin ) [ep] = 0;
-		// FIXME want hcd hook here, "no such endpoint"
 	}
 	iface->act_altsetting = alternate;
 
@@ -898,6 +901,7 @@
 {
 	int i, ret;
 	struct usb_host_config *cp = NULL;
+	void (*disable)(struct usb_device *, int) = dev->bus->op->disable;
 	
 	for (i=0; i<dev->descriptor.bNumConfigurations; i++) {
 		if (dev->config[i].desc.bConfigurationValue == configuration) {
@@ -911,11 +915,15 @@
 	}
 
 	/* if it's already configured, clear out old state first. */
-	if (dev->state != USB_STATE_ADDRESS) {
-		/* FIXME unbind drivers from all "old" interfaces.
-		 * handshake with hcd to reset cached hc endpoint state.
-		 */
+	if (dev->state != USB_STATE_ADDRESS && disable) {
+		for (i = 0; i < 15; i++) {
+			disable (dev, i);
+			disable (dev, USB_DIR_IN | i);
+		}
 	}
+	dev->toggle[0] = dev->toggle[1] = 0;
+	dev->halted[0] = dev->halted[1] = 0;
+	dev->state = USB_STATE_ADDRESS;
 
 	if ((ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			USB_REQ_SET_CONFIGURATION, 0, configuration, 0,
@@ -923,15 +931,9 @@
 		return ret;
 	if (configuration)
 		dev->state = USB_STATE_CONFIGURED;
-	else
-		dev->state = USB_STATE_ADDRESS;
 	dev->actconfig = cp;
 
 	/* reset more hc/hcd endpoint state */
-	dev->toggle[0] = 0;
-	dev->toggle[1] = 0;
-	dev->halted[0] = 0;
-	dev->halted[1] = 0;
 	usb_set_maxpacket(dev);
 
 	return 0;
diff -Nru a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
--- a/drivers/usb/core/usb.c	Mon Apr 21 09:54:44 2003
+++ b/drivers/usb/core/usb.c	Thu May  1 02:57:43 2003
@@ -457,12 +457,13 @@
 /**
  * usb_find_interface - find usb_interface pointer for driver and device
  * @drv: the driver whose current configuration is considered
- * @kdev: the desired device
+ * @minor: the minor number of the desired device
  *
  * This walks the driver device list and returns a pointer to the interface 
- * with the matching kdev_t.
+ * with the matching minor.  Note, this only works for devices that share the
+ * USB major number.
  */
-struct usb_interface *usb_find_interface(struct usb_driver *drv, kdev_t kdev)
+struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor)
 {
 	struct list_head *entry;
 	struct device *dev;
@@ -476,9 +477,10 @@
 			continue;
 
 		intf = to_usb_interface(dev);
-		if (kdev_same(intf->kdev,kdev)) {
+		if (intf->minor == -1)
+			continue;
+		if (intf->minor == minor)
 			return intf;
-		}
 	}
 
 	/* no device found that matches */
diff -Nru a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/Kconfig	Mon May 12 09:56:45 2003
@@ -0,0 +1,152 @@
+#
+# USB Gadget support on a system involves
+#    (a) a peripheral controller, and
+#    (b) the gadget driver using it.
+#
+# for 2.5 kbuild, drivers/usb/gadget/Kconfig
+# source this at the end of drivers/usb/Kconfig
+#
+menuconfig USB_GADGET
+	tristate "Support for USB Gadgets"
+	depends on EXPERIMENTAL
+	help
+	   USB is a master/slave protocol, organized with one master
+	   host (such as a PC) controlling up to 127 peripheral devices.
+	   The USB hardware is asymmetric, which makes it easier to set up:
+	   you can't connect two "to-the-host" connectors to each other.
+
+	   Linux can run in the host, or in the peripheral.  In both cases
+	   you need a low level bus controller driver, and some software
+	   talking to it.  Peripheral controllers are often discrete silicon,
+	   or are integrated with the CPU in a microcontroller.  The more
+	   familiar host side controllers have names like like "EHCI", "OHCI",
+	   or "UHCI", and are usually integrated into southbridges on PC
+	   motherboards.
+
+	   Enable this configuration option if you want to run Linux inside
+	   a USB peripheral device.  Configure one hardware driver for your
+	   peripheral/device side bus controller, and a "gadget driver" for
+	   your peripheral protocol.  (If you use modular gadget drivers,
+	   you may configure more than one.)
+
+	   If in doubt, say "N" and don't enable these drivers; most people
+	   don't have this kind of hardware (except maybe inside Linux PDAs).
+
+#
+# USB Peripheral Controller Support
+#
+choice
+	prompt "USB Peripheral Controller Support"
+	depends on USB_GADGET
+
+config USB_NET2280
+	tristate "NetChip 2280 USB Peripheral Controller"
+	depends on PCI && USB_GADGET
+	help
+	   NetChip 2280 is a PCI based USB peripheral controller which
+	   supports both full and high speed USB 2.0 data transfers.  
+	   
+	   It has six configurable endpoints, as well as endpoint zero
+	   (for control transfers) and several endpoints with dedicated
+	   functions.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "net2280" and force all
+	   gadget drivers to also be dynamically linked.
+
+endchoice
+
+#
+# USB Gadget Drivers
+#
+choice
+	prompt "USB Gadget Drivers"
+	depends on USB_GADGET
+	default USB_ETH
+
+# FIXME want a cleaner dependency/config approach for drivers.
+
+config USB_ZERO
+	tristate "Gadget Zero (DEVELOPMENT)"
+	depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA250 || USB_SA1100)
+	help
+	  Gadget Zero is a two-configuration device.  It either sinks and
+	  sources bulk data; or it loops back a configurable number of
+	  transfers.  It also implements control requests, for "chapter 9"
+	  conformance.  The driver needs only two bulk-capable endpoints, so
+	  it can work on top of most device-side usb controllers.  It's
+	  useful for testing, and is also a working example showing how
+	  USB "gadget drivers" can be written.
+
+	  Make this be the first driver you try using on top of any new
+	  USB peripheral controller driver.  Then you can use host-side
+	  test software, like the "usbtest" driver, to put your hardware
+	  and its driver through a basic set of functional tests.
+
+	  Gadget Zero also works with the host-side "usb-skeleton" driver,
+	  and with many kinds of host-side test software.  You may need
+	  to tweak product and vendor IDs before host software knows about
+	  this device, and arrange to select an appropriate configuration.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "g_zero".
+
+config USB_ZERO_NET2280
+	bool
+	# for now, treat the "dummy" hcd as if it were a net2280
+	depends on USB_ZERO && (USB_NET2280 || USB_DUMMY_HCD)
+	default y
+
+config USB_ZERO_PXA250
+	bool
+	depends on USB_ZERO && USB_PXA250
+	default y
+
+config USB_ZERO_SA1100
+	bool
+	depends on USB_ZERO && USB_SA1100
+	default y
+
+
+config USB_ETH
+	tristate "Ethernet Gadget"
+	depends on USB_GADGET && (USB_DUMMY_HCD || USB_NET2280 || USB_PXA250 || USB_SA1100)
+	help
+	  This driver implements the "Communication Device Class" (CDC)
+	  Ethernet Control Model.  That protocol is often avoided with pure
+	  Ethernet adapters, in favor of simpler vendor-specific hardware,
+	  but is widely supported by firmware for smart network devices.
+
+	  Within the USB device, this gadget driver exposes a network device
+	  "usbX", where X depends on what other networking devices you have.
+	  Treat it like a two-node Ethernet link:  host, and gadget.
+
+	  The Linux-USB host-side "usbnet" driver interoperates with this
+	  driver, so that deep I/O queues can be supported.  (On 2.4 kernels,
+	  use "CDCEther" instead.)  Deep queues are especially important with
+	  high speed devices.  It should also interoperate with standard CDC
+	  Ethernet class drivers on other host operating systems.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "g_ether".
+
+
+config USB_ETH_NET2280
+	bool
+	# for now, treat the "dummy" hcd as if it were a net2280
+	depends on USB_ETH && (USB_NET2280 || USB_DUMMY_HCD)
+	default y
+
+config USB_ETH_PXA250
+	bool
+	depends on USB_ETH && USB_PXA250
+	default y
+
+config USB_ETH_SA1100
+	bool
+	depends on USB_ETH && USB_SA1100
+	default y
+
+endchoice
+
+# endmenuconfig
diff -Nru a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/Makefile	Thu May  8 04:25:27 2003
@@ -0,0 +1,14 @@
+#
+# USB peripheral controller drivers
+#
+obj-$(CONFIG_USB_NET2280)	+= net2280.o
+
+#
+# USB gadget drivers
+#
+g_zero-objs			:= zero.o usbstring.o
+g_ether-objs			:= ether.o usbstring.o
+ 
+obj-$(CONFIG_USB_ZERO)		+= g_zero.o
+obj-$(CONFIG_USB_ETH)		+= g_ether.o
+
diff -Nru a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/ether.c	Sun May 11 11:12:52 2003
@@ -0,0 +1,1640 @@
+/*
+ * ether.c -- CDC 1.1 Ethernet gadget driver
+ *
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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 DEBUG 1
+// #define VERBOSE
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <linux/random.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * "Communications Device Class" (CDC) Ethernet class driver
+ *
+ * CDC Ethernet is the standard USB solution for sending Ethernet frames
+ * using USB.  Real hardware tends to use the same framing protocol but look
+ * different for control features.  And Microsoft pushes their own approach
+ * (RNDIS) instead of the standard.
+ */
+
+#define DRIVER_DESC		"CDC Ethernet Gadget"
+#define DRIVER_VERSION		"29 April 2003"
+
+static const char shortname [] = "ether";
+static const char driver_desc [] = DRIVER_DESC;
+static const char control_name [] = "Communications Control";
+static const char data_name [] = "CDC Ethernet Data";
+
+#define MIN_PACKET	sizeof(struct ethhdr)
+#define	MAX_PACKET	ETH_DATA_LEN	/* biggest packet we'll rx/tx */
+
+/* FIXME allow high speed jumbograms */
+
+/*-------------------------------------------------------------------------*/
+
+struct eth_dev {
+	spinlock_t		lock;
+	struct usb_gadget	*gadget;
+	struct usb_request	*req;		/* for control responses */
+
+	u8			config;
+	struct usb_ep		*in_ep, *out_ep, *status_ep;
+	const struct usb_endpoint_descriptor
+				*in, *out, *status;
+
+	struct semaphore	mutex;
+	struct net_device	net;
+	struct net_device_stats	stats;
+	atomic_t		tx_qlen;
+
+	struct work_struct	work;
+	unsigned long		todo;
+#define	WORK_RX_MEMORY		0
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* This driver keeps a variable number of requests queued, more at
+ * high speeds.  (Numbers are just educated guesses, untuned.)
+ * Shrink the queue if memory is tight, or make it bigger to
+ * handle bigger traffic bursts between IRQs.
+ */
+
+static unsigned qmult = 4;
+
+#define HS_FACTOR	15
+
+#define qlen(gadget) \
+	(qmult*((gadget->speed == USB_SPEED_HIGH) ? HS_FACTOR : 1))
+
+/* defer IRQs on highspeed TX */
+#define TX_DELAY	8
+
+
+module_param (qmult, uint, S_IRUGO|S_IWUSR);
+
+
+/*-------------------------------------------------------------------------*/
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define DRIVER_VENDOR_NUM	0x0525		/* NetChip */
+#define DRIVER_PRODUCT_NUM	0xa4a1		/* Linux-USB Ethernet Gadget */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * hardware-specific configuration, controlled by which device
+ * controller driver was configured.
+ *
+ * CHIP ... hardware identifier
+ * DRIVER_VERSION_NUM ... alerts the host side driver to differences
+ * EP0_MAXPACKET ... controls packetization of control requests
+ * EP_*_NAME ... which endpoints do we use for which purpose?
+ * EP_*_NUM ... numbers for them (often limited by hardware)
+ * HIGHSPEED ... define if ep0 and descriptors need high speed support
+ * MAX_USB_POWER ... define if we use other than 100 mA bus current
+ * SELFPOWER ... unless we can run on bus power, USB_CONFIG_ATT_SELFPOWER
+ * WAKEUP ... if hardware supports remote wakeup AND we will issue the
+ * 	usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
+ *
+ * hw_optimize(gadget) ... for any hardware tweaks we want to kick in
+ * 	before we enable our endpoints
+ *
+ * add other defines for other portability issues, like hardware that
+ * for some reason doesn't handle full speed bulk maxpacket of 64.
+ */
+
+/*
+ * NetChip 2280, PCI based.
+ *
+ * use DMA with fat fifos for all data traffic, PIO for the status channel
+ * where its 64 byte maxpacket ceiling is no issue.
+ *
+ * performance note:  only PIO needs per-usb-packet IRQs (ep0, ep-e, ep-f)
+ * otherwise IRQs are per-Ethernet-packet unless TX_DELAY and chaining help.
+ */
+#ifdef	CONFIG_USB_ETH_NET2280
+#define CHIP			"net2280"
+#define DRIVER_VERSION_NUM	0x0101
+#define EP0_MAXPACKET		64
+static const char EP_OUT_NAME [] = "ep-a";
+#define EP_OUT_NUM	2
+static const char EP_IN_NAME [] = "ep-b";
+#define EP_IN_NUM	2
+static const char EP_STATUS_NAME [] = "ep-f";
+#define EP_STATUS_NUM	3
+#define HIGHSPEED
+/* specific hardware configs could be bus-powered */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* supports remote wakeup, but this driver doesn't */
+
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
+static inline void hw_optimize (struct usb_gadget *gadget)
+{
+	/* we can have bigger ep-a/ep-b fifos (2KB each, 4 USB packets
+	 * for highspeed bulk) because we're not using ep-c/ep-d.
+	 */
+	net2280_set_fifo_mode (gadget, 1);
+}
+#endif
+
+/*
+ * PXA-250 UDC:  widely used in second gen Linux-capable PDAs.
+ *
+ * no limitations except from set_interface: docs say "no" to a third
+ * interface. and the interrupt-only endpoints don't toggle, so we'll
+ * just use a bulk-capable one instead.
+ */
+#ifdef	CONFIG_USB_ETH_PXA250
+#define CHIP			"pxa250"
+#define DRIVER_VERSION_NUM	0x0103
+#define EP0_MAXPACKET		16
+static const char EP_OUT_NAME [] = "ep12out-bulk";
+#define EP_OUT_NUM	12
+static const char EP_IN_NAME [] = "ep11in-bulk";
+#define EP_IN_NUM	11
+static const char EP_STATUS_NAME [] = "ep6in-bulk";
+#define EP_STATUS_NUM	6
+/* doesn't support bus-powered operation */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* supports remote wakeup, but this driver doesn't */
+
+/* no hw optimizations to apply */
+#define hw_optimize(g) do {} while (0);
+#endif
+
+/*
+ * SA-1100 UDC:  widely used in first gen Linux-capable PDAs.
+ *
+ * can't have a notification endpoint, since there are only the two
+ * bulk-capable ones.  the CDC spec allows that.
+ */
+#ifdef	CONFIG_USB_ETH_SA1100
+#define CHIP			"sa1100"
+#define DRIVER_VERSION_NUM	0x0105
+#define EP0_MAXPACKET		8
+static const char EP_OUT_NAME [] = "ep1out-bulk";
+#define EP_OUT_NUM	1
+static const char EP_IN_NAME [] = "ep2in-bulk";
+#define EP_IN_NUM	2
+// EP_STATUS_NUM is undefined
+/* doesn't support bus-powered operation */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* doesn't support remote wakeup? */
+
+/* no hw optimizations to apply */
+#define hw_optimize(g) do {} while (0);
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef EP0_MAXPACKET
+#	error Configure some USB peripheral controller driver!
+#endif
+
+/* power usage is config specific.
+ * hardware that supports remote wakeup defaults to disabling it.
+ */
+
+#ifndef	SELFPOWER
+/* default: say we rely on bus power */
+#define SELFPOWER	0
+/* else:
+ * - SELFPOWER value must be USB_CONFIG_ATT_SELFPOWER
+ * - MAX_USB_POWER may be nonzero.
+ */
+#endif
+
+#ifndef	MAX_USB_POWER
+/* any hub supports this steady state bus power consumption */
+#define MAX_USB_POWER	100	/* mA */
+#endif
+
+#ifndef	WAKEUP
+/* default: this driver won't do remote wakeup */
+#define WAKEUP		0
+/* else value must be USB_CONFIG_ATT_WAKEUP */
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(d,level,fmt,args...) \
+	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(dev,fmt,args...) \
+	xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DEBUG(dev,fmt,args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDEBUG	DEBUG
+#else
+#define VDEBUG(dev,fmt,args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#define ERROR(dev,fmt,args...) \
+	xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+	xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+	xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+/* USB DRIVER HOOKUP (to the hardware driver, below us), mostly
+ * ep0 implementation:  descriptors, config management, setup().
+ * also optional class-specific notification interrupt transfer.
+ */
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full) configuration
+ * descriptors are built on demand.  Notice how most of the cdc descriptors
+ * add no value to simple (typical) configurations.
+ */
+
+#define STRING_MANUFACTURER		1
+#define STRING_PRODUCT			2
+#define STRING_ETHADDR			3
+#define STRING_DATA			4
+#define STRING_CONTROL			5
+
+#define USB_BUFSIZ	256		/* holds our biggest descriptor */
+
+/*
+ * This device advertises one configuration.
+ */
+#define	CONFIG_CDC_ETHER	3
+
+static const struct usb_device_descriptor
+device_desc = {
+	.bLength =		sizeof device_desc,
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
+	.bDeviceClass =		USB_CLASS_COMM,
+	.bDeviceSubClass =	0,
+	.bDeviceProtocol =	0,
+	.bMaxPacketSize0 =	EP0_MAXPACKET,
+
+	.idVendor =		__constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
+	.idProduct =		__constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
+	.bcdDevice =		__constant_cpu_to_le16 (DRIVER_VERSION_NUM),
+	.iManufacturer =	STRING_MANUFACTURER,
+	.iProduct =		STRING_PRODUCT,
+	.bNumConfigurations =	1,
+};
+
+static const struct usb_config_descriptor
+eth_config = {
+	.bLength =		sizeof eth_config,
+	.bDescriptorType =	USB_DT_CONFIG,
+
+	/* compute wTotalLength on the fly */
+	.bNumInterfaces =	2,
+	.bConfigurationValue =	CONFIG_CDC_ETHER,
+	.iConfiguration =	STRING_PRODUCT,
+	.bmAttributes =		USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
+	.bMaxPower =		(MAX_USB_POWER + 1) / 2,
+};
+
+/* master comm interface optionally has a status notification endpoint */
+
+static const struct usb_interface_descriptor
+control_intf = {
+	.bLength =		sizeof control_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bInterfaceNumber =	0,
+#ifdef	EP_STATUS_NUM
+	.bNumEndpoints =	1,
+#else
+	.bNumEndpoints =	0,
+#endif
+	.bInterfaceClass =	USB_CLASS_COMM,
+	.bInterfaceSubClass =	6,	/* ethernet control model */
+	.bInterfaceProtocol =	0,
+	.iInterface =		STRING_CONTROL,
+};
+
+/* "Header Functional Descriptor" from CDC spec  5.2.3.1 */
+struct header_desc {
+	u8	bLength;
+	u8	bDescriptorType;
+	u8	bDescriptorSubType;
+
+	u16	bcdCDC;
+} __attribute__ ((packed));
+
+static const struct header_desc header_desc = {
+	.bLength =		sizeof header_desc,
+	.bDescriptorType =	0x24,
+	.bDescriptorSubType =	0,
+
+	.bcdCDC =		__constant_cpu_to_le16 (0x0110),
+};
+
+/* "Union Functional Descriptor" from CDC spec 5.2.3.X */
+struct union_desc {
+	u8	bLength;
+	u8	bDescriptorType;
+	u8	bDescriptorSubType;
+
+	u8	bMasterInterface0;
+	u8	bSlaveInterface0;
+	/* ... and there could be other slave interfaces */
+} __attribute__ ((packed));
+
+static const struct union_desc union_desc = {
+	.bLength =		sizeof union_desc,
+	.bDescriptorType =	0x24,
+	.bDescriptorSubType =	6,
+
+	.bMasterInterface0 =	0,	/* index of control interface */
+	.bSlaveInterface0 =	1,	/* index of DATA interface */
+};
+
+/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
+struct ether_desc {
+	u8	bLength;
+	u8	bDescriptorType;
+	u8	bDescriptorSubType;
+
+	u8	iMACAddress;
+	u32	bmEthernetStatistics;
+	u16	wMaxSegmentSize;
+	u16	wNumberMCFilters;
+	u8	bNumberPowerFilters;
+} __attribute__ ((packed));
+
+static const struct ether_desc ether_desc = {
+	.bLength =		sizeof ether_desc,
+	.bDescriptorType =	0x24,
+	.bDescriptorSubType =	0x0f,
+
+	/* this descriptor actually adds value, surprise! */
+	.iMACAddress =		STRING_ETHADDR,
+	.bmEthernetStatistics =	__constant_cpu_to_le32 (0), /* no statistics */
+	.wMaxSegmentSize =	__constant_cpu_to_le16 (MAX_PACKET + ETH_HLEN),
+	.wNumberMCFilters =	__constant_cpu_to_le16 (0),
+	.bNumberPowerFilters =	0,
+};
+
+#ifdef	EP_STATUS_NUM
+
+/* include the status endpoint if we can, even though it's optional.
+ *
+ * some drivers (like current Linux cdc-ether!) "need" it to exist even
+ * if they ignore the connect/disconnect notifications that real aether
+ * can provide.  more advanced cdc configurations might want to support
+ * encapsulated commands.
+ */
+ 
+#define LOG2_STATUS_INTERVAL_MSEC	6
+#define STATUS_BYTECOUNT		16	/* 8 byte header + data */
+static const struct usb_endpoint_descriptor
+fs_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_STATUS_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (STATUS_BYTECOUNT),
+	.bInterval =		1 << LOG2_STATUS_INTERVAL_MSEC,
+};
+#endif
+
+/* the default data interface has no endpoints ... */
+
+static const struct usb_interface_descriptor
+data_nop_intf = {
+	.bLength =		sizeof data_nop_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bInterfaceNumber =	1,
+	.bAlternateSetting =	0,
+	.bNumEndpoints =	0,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0,
+	.iInterface =		STRING_DATA,
+};
+
+/* ... but the "real" data interface has two full speed bulk endpoints */
+
+static const struct usb_interface_descriptor
+data_intf = {
+	.bLength =		sizeof data_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bInterfaceNumber =	1,
+	.bAlternateSetting =	1,
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_CDC_DATA,
+	.bInterfaceSubClass =	0,
+	.bInterfaceProtocol =	0,
+	.iInterface =		STRING_DATA,
+};
+
+static const struct usb_endpoint_descriptor
+fs_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_IN_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
+};
+
+static const struct usb_endpoint_descriptor
+fs_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_OUT_NUM,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
+};
+
+#ifdef	HIGHSPEED
+
+/*
+ * usb 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ */
+
+#ifdef	EP_STATUS_NUM
+static const struct usb_endpoint_descriptor
+hs_status_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_STATUS_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (STATUS_BYTECOUNT),
+	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 3,
+};
+#endif
+
+static const struct usb_endpoint_descriptor
+hs_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_IN_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (512),
+	.bInterval =		1,
+};
+
+static const struct usb_endpoint_descriptor
+hs_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_OUT_NUM,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (512),
+	.bInterval =		1,
+};
+
+static const struct usb_qualifier_descriptor
+dev_qualifier = {
+	.bLength =		sizeof dev_qualifier,
+	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
+
+	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
+	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,
+
+	/* assumes ep0 uses the same value for both speeds ... */
+	.bMaxPacketSize0 =	EP0_MAXPACKET,
+
+	.bNumConfigurations =	2,
+};
+
+/* maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
+
+#else
+
+/* if there's no high speed support, maxpacket doesn't change. */
+#define ep_desc(g,hs,fs) fs
+
+#endif	/* !HIGHSPEED */
+
+/* address that the host will use ... usually assigned at random */
+static char				ethaddr [2 * ETH_ALEN + 1];
+
+/* static strings, in iso 8859/1 */
+static struct usb_string		strings [] = {
+	{ STRING_MANUFACTURER,	UTS_SYSNAME " " UTS_RELEASE "/" CHIP, },
+	{ STRING_PRODUCT,	driver_desc, },
+	{ STRING_ETHADDR,	ethaddr, },
+	{ STRING_CONTROL,	control_name, },
+	{ STRING_DATA,		data_name, },
+	{  }		/* end of list */
+};
+
+static struct usb_gadget_strings	stringtab = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= strings,
+};
+
+/*
+ * one config, two interfaces:  control, data.
+ * complications: class descriptors, and an altsetting.
+ */
+static int
+config_buf (enum usb_device_speed speed, u8 *buf, u8 type, unsigned index)
+{
+	const unsigned	config_len = USB_DT_CONFIG_SIZE
+				+ 3 * USB_DT_INTERFACE_SIZE
+				+ sizeof header_desc
+				+ sizeof union_desc
+				+ sizeof ether_desc
+#ifdef	EP_STATUS_NUM
+				+ USB_DT_ENDPOINT_SIZE
+#endif
+				+ 2 * USB_DT_ENDPOINT_SIZE;
+#ifdef HIGHSPEED
+	int		hs;
+#endif
+	/* a single configuration must always be index 0 */
+	if (index > 0)
+		return -EINVAL;
+	if (config_len > USB_BUFSIZ)
+		return -EDOM;
+
+	/* config (or other speed config) */
+	memcpy (buf, &eth_config, USB_DT_CONFIG_SIZE);
+	buf [1] = type;
+	((struct usb_config_descriptor *) buf)->wTotalLength
+		= __constant_cpu_to_le16 (config_len);
+	buf += USB_DT_CONFIG_SIZE;
+#ifdef	HIGHSPEED
+	hs = (speed == USB_SPEED_HIGH);
+	if (type == USB_DT_OTHER_SPEED_CONFIG)
+		hs = !hs;
+#endif
+
+	/* control interface, class descriptors, optional status endpoint */
+	memcpy (buf, &control_intf, USB_DT_INTERFACE_SIZE);
+	buf += USB_DT_INTERFACE_SIZE;
+
+	memcpy (buf, &header_desc, sizeof header_desc);
+	buf += sizeof header_desc;
+	memcpy (buf, &union_desc, sizeof union_desc);
+	buf += sizeof union_desc;
+	memcpy (buf, &ether_desc, sizeof ether_desc);
+	buf += sizeof ether_desc;
+
+#ifdef	EP_STATUS_NUM
+#ifdef	HIGHSPEED
+	if (hs)
+		memcpy (buf, &hs_status_desc, USB_DT_ENDPOINT_SIZE);
+	else
+#endif	/* HIGHSPEED */
+		memcpy (buf, &fs_status_desc, USB_DT_ENDPOINT_SIZE);
+	buf += USB_DT_ENDPOINT_SIZE;
+#endif	/* EP_STATUS_NUM */
+
+	/* default data altsetting has no endpoints */
+	memcpy (buf, &data_nop_intf, USB_DT_INTERFACE_SIZE);
+	buf += USB_DT_INTERFACE_SIZE;
+
+	/* the "real" data interface has two endpoints */
+	memcpy (buf, &data_intf, USB_DT_INTERFACE_SIZE);
+	buf += USB_DT_INTERFACE_SIZE;
+#ifdef HIGHSPEED
+	if (hs) {
+		memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+		memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+	} else
+#endif
+	{
+		memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+		memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+	}
+
+	return config_len;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+set_ether_config (struct eth_dev *dev, int gfp_flags)
+{
+	int			result = 0;
+	struct usb_ep		*ep;
+	struct usb_gadget	*gadget = dev->gadget;
+
+	gadget_for_each_ep (ep, gadget) {
+		const struct usb_endpoint_descriptor	*d;
+
+		/* NOTE:  the host isn't allowed to use these two data
+		 * endpoints in the default altsetting for the interface.
+		 * so we don't activate them yet.
+		 */
+
+		/* one endpoint writes data back IN to the host */
+		if (strcmp (ep->name, EP_IN_NAME) == 0) {
+			d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
+			ep->driver_data = dev;
+			dev->in_ep = ep;
+			dev->in = d;
+			continue;
+
+		/* one endpoint just reads OUT packets */
+		} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
+			d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
+			ep->driver_data = dev;
+			dev->out_ep = ep;
+			dev->out = d;
+			continue;
+
+#ifdef	EP_STATUS_NUM
+		/* optional status/notification endpoint */
+		} else if (strcmp (ep->name, EP_STATUS_NAME) == 0) {
+			d = ep_desc (gadget, &hs_status_desc, &fs_status_desc);
+			result = usb_ep_enable (ep, d);
+			if (result == 0) {
+				ep->driver_data = dev;
+				dev->status_ep = ep;
+				dev->status = d;
+				continue;
+			}
+#endif
+
+		/* ignore any other endpoints */
+		} else
+			continue;
+
+		/* stop on error */
+		ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
+		break;
+	}
+
+	if (result == 0)
+		DEBUG (dev, "qlen %d\n", qlen (gadget));
+
+	/* caller is responsible for cleanup on error */
+	return result;
+}
+
+static void eth_reset_config (struct eth_dev *dev)
+{
+	if (dev->config == 0)
+		return;
+
+	DEBUG (dev, "%s\n", __FUNCTION__);
+
+	netif_stop_queue (&dev->net);
+	netif_carrier_off (&dev->net);
+
+	/* just disable endpoints, forcing completion of pending i/o.
+	 * all our completion handlers free their requests in this case.
+	 */
+	if (dev->in_ep) {
+		usb_ep_disable (dev->in_ep);
+		dev->in_ep = 0;
+	}
+	if (dev->out_ep) {
+		usb_ep_disable (dev->out_ep);
+		dev->out_ep = 0;
+	}
+#ifdef	EP_STATUS_NUM
+	if (dev->status_ep) {
+		usb_ep_disable (dev->status_ep);
+		dev->status_ep = 0;
+	}
+#endif
+	dev->config = 0;
+}
+
+/* change our operational config.  must agree with the code
+ * that returns config descriptors, and altsetting code.
+ */
+static int
+eth_set_config (struct eth_dev *dev, unsigned number, int gfp_flags)
+{
+	int			result = 0;
+	struct usb_gadget	*gadget = dev->gadget;
+
+	if (number == dev->config)
+		return 0;
+
+#ifdef CONFIG_USB_ETH_SA1100
+	if (dev->config && atomic_read (&dev->tx_qlen) != 0) {
+		/* tx fifo is full, but we can't clear it...*/
+		INFO (dev, "can't change configurations\n");
+		return -ESPIPE;
+	}
+#endif
+	eth_reset_config (dev);
+	hw_optimize (gadget);
+
+	switch (number) {
+	case CONFIG_CDC_ETHER:
+		result = set_ether_config (dev, gfp_flags);
+		break;
+	default:
+		result = -EINVAL;
+		/* FALL THROUGH */
+	case 0:
+		return result;
+	}
+
+	if (!result && (!dev->in_ep || !dev->out_ep))
+		result = -ENODEV;
+	if (result)
+		eth_reset_config (dev);
+	else {
+		char *speed;
+
+		switch (gadget->speed) {
+		case USB_SPEED_FULL:	speed = "full"; break;
+#ifdef HIGHSPEED
+		case USB_SPEED_HIGH:	speed = "high"; break;
+#endif
+		default: 		speed = "?"; break;
+		}
+
+		dev->config = number;
+		INFO (dev, "%s speed config #%d: %s\n", speed, number,
+				driver_desc);
+	}
+	return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	EP_STATUS_NUM
+
+/* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications */
+#define CDC_NOTIFY_NETWORK_CONNECTION	0x00	/* required; 6.3.1 */
+#define CDC_NOTIFY_SPEED_CHANGE		0x2a	/* required; 6.3.8 */
+
+struct cdc_notification {
+	u8	bmRequestType;
+	u8	bNotificationType;
+	u16	wValue;
+	u16	wIndex;
+	u16	wLength;
+
+	/* SPEED_CHANGE data looks like this */
+	u32	data [2];
+};
+
+static void eth_status_complete (struct usb_ep *ep, struct usb_request *req)
+{
+	struct cdc_notification	*event = req->buf;
+	int			value = req->status;
+	struct eth_dev		*dev = ep->driver_data;
+
+	/* issue the second notification if host reads the first */
+	if (event->bNotificationType == CDC_NOTIFY_NETWORK_CONNECTION
+			&& value == 0) {
+		event->bmRequestType = 0xA1;
+		event->bNotificationType = CDC_NOTIFY_SPEED_CHANGE;
+		event->wValue = __constant_cpu_to_le16 (0);
+		event->wIndex = __constant_cpu_to_le16 (1);
+		event->wLength = __constant_cpu_to_le16 (8);
+
+		/* SPEED_CHANGE data is up/down speeds in bits/sec */
+		event->data [0] = event->data [1] =
+			(dev->gadget->speed == USB_SPEED_HIGH)
+				? (13 * 512 * 8 * 1000 * 8)
+				: (19 *  64 * 1 * 1000 * 8);
+
+		req->length = 16;
+		value = usb_ep_queue (ep, req, GFP_ATOMIC);
+		DEBUG (dev, "send SPEED_CHANGE --> %d\n", value);
+		if (value == 0)
+			return;
+	} else
+		DEBUG (dev, "event %02x --> %d\n",
+			event->bNotificationType, value);
+
+	/* free when done */
+	usb_ep_free_buffer (ep, req->buf, req->dma, 16);
+	usb_ep_free_request (ep, req);
+}
+
+static void issue_start_status (struct eth_dev *dev)
+{
+	struct usb_request	*req;
+	struct cdc_notification	*event;
+	int			value;
+ 
+	DEBUG (dev, "%s, flush old status first\n", __FUNCTION__);
+
+	/* flush old status
+	 *
+	 * FIXME ugly idiom, maybe we'd be better with just
+	 * a "cancel the whole queue" primitive since any
+	 * unlink-one primitive has way too many error modes.
+	 */
+	usb_ep_disable (dev->status_ep);
+	usb_ep_enable (dev->status_ep, dev->status);
+
+	/* FIXME make these allocations static like dev->req */
+	req = usb_ep_alloc_request (dev->status_ep, GFP_ATOMIC);
+	if (req == 0) {
+		DEBUG (dev, "status ENOMEM\n");
+		return;
+	}
+	req->buf = usb_ep_alloc_buffer (dev->status_ep, 16,
+				&dev->req->dma, GFP_ATOMIC);
+	if (req->buf == 0) {
+		DEBUG (dev, "status buf ENOMEM\n");
+free_req:
+		usb_ep_free_request (dev->status_ep, req);
+		return;
+	}
+
+	/* 3.8.1 says to issue first NETWORK_CONNECTION, then
+	 * a SPEED_CHANGE.  could be useful in some configs.
+	 */
+	event = req->buf;
+	event->bmRequestType = 0xA1;
+	event->bNotificationType = CDC_NOTIFY_NETWORK_CONNECTION;
+	event->wValue = __constant_cpu_to_le16 (1);	/* connected */
+	event->wIndex = __constant_cpu_to_le16 (1);
+	event->wLength = 0;
+
+	req->length = 8;
+	req->complete = eth_status_complete;
+	value = usb_ep_queue (dev->status_ep, req, GFP_ATOMIC);
+	if (value < 0) {
+		DEBUG (dev, "status buf queue --> %d\n", value);
+		usb_ep_free_buffer (dev->status_ep,
+				req->buf, dev->req->dma, 16);
+		goto free_req;
+	}
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static void eth_setup_complete (struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->status || req->actual != req->length)
+		DEBUG ((struct eth_dev *) ep->driver_data,
+				"setup complete --> %d, %d/%d\n",
+				req->status, req->actual, req->length);
+}
+
+/* see section 3.8.2 table 10 of the CDC spec for more ethernet
+ * requests, mostly for filters (multicast, pm) and statistics
+ */
+#define CDC_SET_ETHERNET_PACKET_FILTER	0x43	/* required */
+
+static void eth_start (struct eth_dev *dev, int gfp_flags);
+
+/*
+ * The setup() callback implements all the ep0 functionality that's not
+ * handled lower down.  CDC has a number of less-common features:
+ *
+ *  - two interfaces:  control, and ethernet data
+ *  - data interface has two altsettings:  default, and active
+ *  - class-specific descriptors for the control interface
+ *  - a mandatory class-specific control request
+ */
+static int
+eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	struct eth_dev		*dev = get_gadget_data (gadget);
+	struct usb_request	*req = dev->req;
+	int			value = -EOPNOTSUPP;
+
+	/* descriptors just go into the pre-allocated ep0 buffer,
+	 * while config change events may enable network traffic.
+	 */
+	switch (ctrl->bRequest) {
+
+	case USB_REQ_GET_DESCRIPTOR:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			break;
+		switch (ctrl->wValue >> 8) {
+
+		case USB_DT_DEVICE:
+			value = min (ctrl->wLength, (u16) sizeof device_desc);
+			memcpy (req->buf, &device_desc, value);
+			break;
+#ifdef HIGHSPEED
+		case USB_DT_DEVICE_QUALIFIER:
+			value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
+			memcpy (req->buf, &dev_qualifier, value);
+			break;
+
+		case USB_DT_OTHER_SPEED_CONFIG:
+			// FALLTHROUGH
+#endif /* HIGHSPEED */
+		case USB_DT_CONFIG:
+			value = config_buf (gadget->speed, req->buf,
+					ctrl->wValue >> 8,
+					ctrl->wValue & 0xff);
+			if (value >= 0)
+				value = min (ctrl->wLength, (u16) value);
+			break;
+
+		case USB_DT_STRING:
+			value = usb_gadget_get_string (&stringtab,
+					ctrl->wValue & 0xff, req->buf);
+			if (value >= 0)
+				value = min (ctrl->wLength, (u16) value);
+			break;
+		}
+		break;
+
+	case USB_REQ_SET_CONFIGURATION:
+		if (ctrl->bRequestType != 0)
+			break;
+		spin_lock (&dev->lock);
+		value = eth_set_config (dev, ctrl->wValue, GFP_ATOMIC);
+		spin_unlock (&dev->lock);
+		break;
+	case USB_REQ_GET_CONFIGURATION:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			break;
+		*(u8 *)req->buf = dev->config;
+		value = min (ctrl->wLength, (u16) 1);
+		break;
+
+	case USB_REQ_SET_INTERFACE:
+		if (ctrl->bRequestType != USB_RECIP_INTERFACE
+				|| !dev->config
+				|| ctrl->wIndex > 1)
+			break;
+		spin_lock (&dev->lock);
+		switch (ctrl->wIndex) {
+		case 0:		/* control/master intf */
+			if (ctrl->wValue != 0)
+				break;
+#ifdef	EP_STATUS_NUM
+			if (dev->status_ep) {
+				usb_ep_disable (dev->status_ep);
+				usb_ep_enable (dev->status_ep, dev->status);
+			}
+#endif
+			value = 0;
+			break;
+		case 1:		/* data intf */
+			if (ctrl->wValue > 1)
+				break;
+			usb_ep_disable (dev->in_ep);
+			usb_ep_disable (dev->out_ep);
+
+			/* CDC requires the data transfers not be done from
+			 * the default interface setting ... also, setting
+			 * the non-default interface clears filters etc.
+			 */
+			if (ctrl->wValue == 1) {
+				usb_ep_enable (dev->in_ep, dev->in);
+				usb_ep_enable (dev->out_ep, dev->out);
+				netif_carrier_on (&dev->net);
+#ifdef	EP_STATUS_NUM
+				issue_start_status (dev);
+#endif
+				if (netif_running (&dev->net))
+					eth_start (dev, GFP_ATOMIC);
+			} else {
+				netif_stop_queue (&dev->net);
+				netif_carrier_off (&dev->net);
+			}
+			value = 0;
+			break;
+		}
+		spin_unlock (&dev->lock);
+		break;
+	case USB_REQ_GET_INTERFACE:
+		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
+				|| !dev->config
+				|| ctrl->wIndex > 1)
+			break;
+
+		/* if carrier is on, data interface is active. */
+		*(u8 *)req->buf =
+			((ctrl->wIndex == 1) && netif_carrier_ok (&dev->net))
+				? 1
+				: 0,
+		value = min (ctrl->wLength, (u16) 1);
+		break;
+
+	case CDC_SET_ETHERNET_PACKET_FILTER:
+		/* see 6.2.30: no data, wIndex = interface,
+		 * wValue = packet filter bitmap
+		 */
+		if (ctrl->bRequestType != (USB_TYPE_CLASS|USB_RECIP_INTERFACE)
+				|| ctrl->wLength != 0
+				|| ctrl->wIndex > 1)
+		DEBUG (dev, "NOP packet filter %04x\n", ctrl->wValue);
+		/* NOTE: table 62 has 5 filter bits to reduce traffic,
+		 * and we "must" support multicast and promiscuous.
+		 * this NOP implements a bad filter...
+		 */
+		value = 0;
+		break;
+
+	default:
+		VDEBUG (dev,
+			"unknown control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+	}
+
+	/* respond with data transfer before status phase? */
+	if (value > 0) {
+		req->length = value;
+		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0) {
+			DEBUG (dev, "ep_queue --> %d\n", value);
+			req->status = 0;
+			eth_setup_complete (gadget->ep0, req);
+		}
+	}
+
+	/* host either stalls (value < 0) or reports success */
+	return value;
+}
+
+static void
+eth_disconnect (struct usb_gadget *gadget)
+{
+	struct eth_dev		*dev = get_gadget_data (gadget);
+	unsigned long		flags;
+
+	spin_lock_irqsave (&dev->lock, flags);
+	netif_stop_queue (&dev->net);
+	netif_carrier_off (&dev->net);
+	eth_reset_config (dev);
+	spin_unlock_irqrestore (&dev->lock, flags);
+
+	/* next we may get setup() calls to enumerate new connections;
+	 * or an unbind() during shutdown (including removing module).
+	 */
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* NETWORK DRIVER HOOKUP (to the layer above this driver) */
+
+static int eth_change_mtu (struct net_device *net, int new_mtu)
+{
+	struct eth_dev	*dev = (struct eth_dev *) net->priv;
+
+	if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET)
+		return -ERANGE;
+	/* no zero-length packet read wanted after mtu-sized packets */
+	if (((new_mtu + sizeof (struct ethhdr)) % dev->in_ep->maxpacket) == 0)
+		return -EDOM;
+	net->mtu = new_mtu;
+	return 0;
+}
+
+static struct net_device_stats *eth_get_stats (struct net_device *net)
+{
+	return &((struct eth_dev *) net->priv)->stats;
+}
+
+static int eth_ethtool_ioctl (struct net_device *net, void *useraddr)
+{
+	struct eth_dev	*dev = (struct eth_dev *) net->priv;
+	u32		cmd;
+
+	if (get_user (cmd, (u32 *)useraddr))
+		return -EFAULT;
+	switch (cmd) {
+
+	case ETHTOOL_GDRVINFO: {	/* get driver info */
+		struct ethtool_drvinfo		info;
+
+		memset (&info, 0, sizeof info);
+		info.cmd = ETHTOOL_GDRVINFO;
+		strncpy (info.driver, shortname, sizeof info.driver);
+		strncpy (info.version, DRIVER_VERSION, sizeof info.version);
+		strncpy (info.fw_version, CHIP, sizeof info.fw_version);
+		strncpy (info.bus_info, dev->gadget->dev.bus_id,
+			sizeof info.bus_info);
+		if (copy_to_user (useraddr, &info, sizeof (info)))
+			return -EFAULT;
+		return 0;
+		}
+
+	case ETHTOOL_GLINK: {		/* get link status */
+		struct ethtool_value	edata = { ETHTOOL_GLINK };
+
+		edata.data = (dev->gadget->speed != USB_SPEED_UNKNOWN);
+		if (copy_to_user (useraddr, &edata, sizeof (edata)))
+			return -EFAULT;
+		return 0;
+		}
+
+	}
+	/* Note that the ethtool user space code requires EOPNOTSUPP */
+	return -EOPNOTSUPP;
+}
+
+static int eth_ioctl (struct net_device *net, struct ifreq *rq, int cmd)
+{
+	switch (cmd) {
+	case SIOCETHTOOL:
+		return eth_ethtool_ioctl (net, (void *)rq->ifr_data);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static void defer_kevent (struct eth_dev *dev, int flag)
+{
+	set_bit (flag, &dev->todo);
+	if (!schedule_work (&dev->work))
+		ERROR (dev, "kevent %d may have been dropped\n", flag);
+	else
+		DEBUG (dev, "kevent %d scheduled\n", flag);
+}
+
+static void rx_complete (struct usb_ep *ep, struct usb_request *req);
+
+static int
+rx_submit (struct eth_dev *dev, struct usb_request *req, int gfp_flags)
+{
+	struct sk_buff		*skb;
+	int			retval = 0;
+	size_t			size;
+
+	size = (sizeof (struct ethhdr) + dev->net.mtu);
+
+	if ((skb = alloc_skb (size, gfp_flags)) == 0) {
+		DEBUG (dev, "no rx skb\n");
+		defer_kevent (dev, WORK_RX_MEMORY);
+		usb_ep_free_request (dev->out_ep, req);
+		return -ENOMEM;
+	}
+
+	req->buf = skb->data;
+	req->length = size;
+	req->complete = rx_complete;
+	req->context = skb;
+
+	if (netif_running (&dev->net)) {
+		retval = usb_ep_queue (dev->out_ep, req, gfp_flags);
+		if (retval == -ENOMEM)
+			defer_kevent (dev, WORK_RX_MEMORY);
+		if (retval)
+			DEBUG (dev, "%s %d\n", __FUNCTION__, retval);
+	} else {
+		DEBUG (dev, "%s stopped\n", __FUNCTION__);
+		retval = -ENOLINK;
+	}
+	if (retval) {
+		DEBUG (dev, "rx submit --> %d\n", retval);
+		dev_kfree_skb_any (skb);
+		usb_ep_free_request (dev->out_ep, req);
+	}
+	return retval;
+}
+
+static void rx_complete (struct usb_ep *ep, struct usb_request *req)
+{
+	struct sk_buff	*skb = req->context;
+	struct eth_dev	*dev = ep->driver_data;
+	int		status = req->status;
+
+	switch (status) {
+
+	/* normal completion */
+	case 0:
+		skb_put (skb, req->actual);
+		if (MIN_PACKET > skb->len
+				|| skb->len > (MAX_PACKET + ETH_HLEN)) {
+			dev->stats.rx_errors++;
+			dev->stats.rx_length_errors++;
+			DEBUG (dev, "rx length %d\n", skb->len);
+			break;
+		}
+
+		skb->dev = &dev->net;
+		skb->protocol = eth_type_trans (skb, &dev->net);
+		dev->stats.rx_packets++;
+		dev->stats.rx_bytes += skb->len;
+
+		/* no buffer copies needed, unless hardware can't
+		 * use skb buffers.
+		 */
+		status = netif_rx (skb);
+		skb = 0;
+		break;
+
+	/* software-driven interface shutdown */
+	case -ECONNRESET:		// unlink
+	case -ESHUTDOWN:		// disconnect etc
+		VDEBUG (dev, "rx shutdown, code %d\n", status);
+		usb_ep_free_request (dev->out_ep, req);
+		req = 0;
+		break;
+
+	/* data overrun */
+	case -EOVERFLOW:
+		dev->stats.rx_over_errors++;
+		// FALLTHROUGH
+	    
+	default:
+		dev->stats.rx_errors++;
+		DEBUG (dev, "rx status %d\n", status);
+		break;
+	}
+
+	if (skb)
+		dev_kfree_skb_any (skb);
+
+	if (req)
+		rx_submit (dev, req, GFP_ATOMIC);
+}
+
+static void eth_work (void *_dev)
+{
+	struct eth_dev		*dev = _dev;
+
+	if (test_bit (WORK_RX_MEMORY, &dev->todo)) {
+		struct usb_request	*req = 0;
+
+		if (netif_running (&dev->net))
+			req = usb_ep_alloc_request (dev->in_ep, GFP_KERNEL);
+		else
+			clear_bit (WORK_RX_MEMORY, &dev->todo);
+		if (req != 0) {
+			clear_bit (WORK_RX_MEMORY, &dev->todo);
+			rx_submit (dev, req, GFP_KERNEL);
+		}
+	}
+
+	if (dev->todo)
+		DEBUG (dev, "work done, flags = 0x%lx\n", dev->todo);
+}
+
+static void tx_complete (struct usb_ep *ep, struct usb_request *req)
+{
+	struct sk_buff	*skb = req->context;
+	struct eth_dev	*dev = ep->driver_data;
+
+	if (req->status)
+		dev->stats.tx_errors++;
+	else
+		dev->stats.tx_bytes += skb->len;
+	dev->stats.tx_packets++;
+
+	usb_ep_free_request (ep, req);
+	dev_kfree_skb_any (skb);
+
+	atomic_inc (&dev->tx_qlen);
+	if (netif_carrier_ok (&dev->net))
+		netif_wake_queue (&dev->net);
+}
+
+static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
+{
+	struct eth_dev		*dev = (struct eth_dev *) net->priv;
+	int			length = skb->len;
+	int			retval;
+	struct usb_request	*req = 0;
+
+	if (!(req = usb_ep_alloc_request (dev->in_ep, GFP_ATOMIC))) {
+		DEBUG (dev, "no request\n");
+		goto drop;
+	}
+
+	/* no buffer copies needed, unless the network stack did it
+	 * or the hardware can't use skb buffers.
+	 */
+	req->buf = skb->data;
+	req->context = skb;
+	req->complete = tx_complete;
+
+#ifdef	CONFIG_USB_ETH_SA1100
+	/* don't demand zlp (req->zero) support from all hardware */
+	if ((length % dev->in_ep->maxpacket) == 0)
+		length++;
+#else
+	/* use zlp framing on tx for strict CDC-Ether conformance,
+	 * though any robust network rx path ignores extra padding.
+	 */
+	req->zero = 1;
+#endif
+	req->length = length;
+
+#ifdef	HIGHSPEED
+	/* throttle highspeed IRQ rate back slightly */
+	req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+		? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
+		: 0;
+#endif
+
+	retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+	switch (retval) {
+	default:
+		DEBUG (dev, "tx queue err %d\n", retval);
+		break;
+	case 0:
+		net->trans_start = jiffies;
+		if (atomic_dec_and_test (&dev->tx_qlen))
+			netif_stop_queue (net);
+	}
+
+	if (retval) {
+		DEBUG (dev, "drop, code %d\n", retval);
+drop:
+		dev->stats.tx_dropped++;
+		dev_kfree_skb_any (skb);
+		usb_ep_free_request (dev->in_ep, req);
+	}
+	return 0;
+}
+
+static void eth_start (struct eth_dev *dev, int gfp_flags)
+{
+	struct usb_request	*req;
+	int			retval = 0;
+	unsigned		i;
+	int			size = qlen (dev->gadget);
+
+	DEBUG (dev, "%s\n", __FUNCTION__);
+
+	/* fill the rx queue */
+	for (i = 0; retval == 0 && i < size; i++) {
+		req = usb_ep_alloc_request (dev->in_ep, gfp_flags);
+		if (req)
+			retval = rx_submit (dev, req, gfp_flags);
+		else if (i > 0)
+			defer_kevent (dev, WORK_RX_MEMORY);
+		else
+			retval = -ENOMEM;
+	}
+
+	/* and open the tx floodgates */ 
+	atomic_set (&dev->tx_qlen, size);
+	netif_wake_queue (&dev->net);
+}
+
+static int eth_open (struct net_device *net)
+{
+	struct eth_dev		*dev = (struct eth_dev *) net->priv;
+
+	DEBUG (dev, "%s\n", __FUNCTION__);
+	down (&dev->mutex);
+	if (netif_carrier_ok (&dev->net))
+		eth_start (dev, GFP_KERNEL);
+	up (&dev->mutex);
+	return 0;
+}
+
+static int eth_stop (struct net_device *net)
+{
+	struct eth_dev		*dev = (struct eth_dev *) net->priv;
+
+	DEBUG (dev, "%s\n", __FUNCTION__);
+	down (&dev->mutex);
+	netif_stop_queue (net);
+
+	DEBUG (dev, "stop stats: rx/tx %ld/%ld, errs %ld/%ld\n",
+		dev->stats.rx_packets, dev->stats.tx_packets, 
+		dev->stats.rx_errors, dev->stats.tx_errors
+		);
+
+	/* ensure there are no more active requests */
+	if (dev->gadget->speed != USB_SPEED_UNKNOWN) {
+		usb_ep_disable (dev->in_ep);
+		usb_ep_disable (dev->out_ep);
+		if (netif_carrier_ok (&dev->net)) {
+			DEBUG (dev, "host still using in/out endpoints\n");
+			usb_ep_enable (dev->in_ep, dev->in);
+			usb_ep_enable (dev->out_ep, dev->out);
+		}
+#ifdef	EP_STATUS_NUM
+		usb_ep_disable (dev->status_ep);
+		usb_ep_enable (dev->status_ep, dev->status);
+#endif
+	}
+
+	up (&dev->mutex);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+eth_unbind (struct usb_gadget *gadget)
+{
+	struct eth_dev		*dev = get_gadget_data (gadget);
+
+	DEBUG (dev, "unbind\n");
+	down (&dev->mutex);
+
+	/* we've already been disconnected ... no i/o is active */
+	if (dev->req) {
+		usb_ep_free_buffer (gadget->ep0,
+				dev->req->buf, dev->req->dma,
+				USB_BUFSIZ);
+		usb_ep_free_request (gadget->ep0, dev->req);
+	}
+
+	unregister_netdev (&dev->net);
+	up (&dev->mutex);
+
+	/* assuming we used keventd, it must quiesce too */
+	flush_scheduled_work ();
+
+	kfree (dev);
+	set_gadget_data (gadget, 0);
+}
+
+static int
+eth_bind (struct usb_gadget *gadget)
+{
+	struct eth_dev		*dev;
+	struct net_device	*net;
+	u8			node_id [ETH_ALEN];
+
+	/* just one upstream link at a time */
+	if (ethaddr [0] != 0)
+		return -ENODEV;
+
+	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+	memset (dev, 0, sizeof *dev);
+	spin_lock_init (&dev->lock);
+	init_MUTEX_LOCKED (&dev->mutex);
+	INIT_WORK (&dev->work, eth_work, dev);
+
+	/* network device setup */
+	net = &dev->net;
+	SET_MODULE_OWNER (net);
+	net->priv = dev;
+	strcpy (net->name, "usb%d");
+	ether_setup (net);
+
+	/* one random address for the gadget device ... both of these could
+	 * reasonably come from an id prom or a module parameter.
+	 */
+	get_random_bytes (net->dev_addr, ETH_ALEN);
+	net->dev_addr [0] &= 0xfe;	// clear multicast bit
+	net->dev_addr [0] |= 0x02;	// set local assignment bit (IEEE802)
+
+	/* ... another address for the host, on the other end of the
+	 * link, gets exported through CDC (see CDC spec table 41)
+	 */
+	get_random_bytes (node_id, sizeof node_id);
+	node_id [0] &= 0xfe;	// clear multicast bit
+	node_id [0] |= 0x02;    // set local assignment bit (IEEE802)
+	snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+		node_id [0], node_id [1], node_id [2],
+		node_id [3], node_id [4], node_id [5]);
+
+	net->change_mtu = eth_change_mtu;
+	net->get_stats = eth_get_stats;
+	net->hard_start_xmit = eth_start_xmit;
+	net->open = eth_open;
+	net->stop = eth_stop;
+	// watchdog_timeo, tx_timeout ...
+	// set_multicast_list
+	net->do_ioctl = eth_ioctl;
+
+	/* preallocate control response and buffer */
+	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+	if (!dev->req)
+		goto enomem;
+	dev->req->complete = eth_setup_complete;
+	dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
+				&dev->req->dma, GFP_KERNEL);
+	if (!dev->req->buf) {
+		usb_ep_free_request (gadget->ep0, dev->req);
+		goto enomem;
+	}
+
+	/* finish hookup to lower layer ... */
+	dev->gadget = gadget;
+	set_gadget_data (gadget, dev);
+	gadget->ep0->driver_data = dev;
+
+	/* two kinds of host-initiated state changes:
+	 *  - iff DATA transfer is active, carrier is "on"
+	 *  - tx queueing enabled if open *and* carrier is "on"
+	 */
+	INFO (dev, "%s, host enet %s, version: " DRIVER_VERSION "\n",
+			driver_desc, ethaddr);
+	register_netdev (&dev->net);
+	netif_stop_queue (&dev->net);
+	netif_carrier_off (&dev->net);
+
+	up (&dev->mutex);
+	return 0;
+
+enomem:
+	eth_unbind (gadget);
+	return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver eth_driver = {
+#ifdef HIGHSPEED
+	.speed		= USB_SPEED_HIGH,
+#else
+	.speed		= USB_SPEED_FULL,
+#endif
+	.function	= (char *) driver_desc,
+	.bind		= eth_bind,
+	.unbind		= eth_unbind,
+
+	.setup		= eth_setup,
+	.disconnect	= eth_disconnect,
+
+	.driver 	= {
+		.name		= (char *) shortname,
+		// .shutdown = ...
+		// .suspend = ...
+		// .resume = ...
+	},
+};
+
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_AUTHOR ("David Brownell");
+MODULE_LICENSE ("GPL");
+
+
+static int __init init (void)
+{
+	return usb_gadget_register_driver (&eth_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void)
+{
+	usb_gadget_unregister_driver (&eth_driver);
+}
+module_exit (cleanup);
+
diff -Nru a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/net2280.c	Sun May 18 17:48:51 2003
@@ -0,0 +1,2682 @@
+/*
+ * Driver for the NetChip 2280 USB device controller.
+ * Specs and errata are available from <http://www.netchip.com>.
+ *
+ * NetChip Technology Inc. supported the development of this driver.
+ *
+ *
+ * CODE STATUS HIGHLIGHTS
+ *
+ * Used with a gadget driver like "zero.c" this enumerates fine to Windows
+ * or Linux hosts; handles disconnect, reconnect, and reset, for full or
+ * high speed operation; and passes USB-IF "chapter 9" tests.
+ *
+ * Handles standard stress loads from the Linux "usbtest" driver, with
+ * either DMA (default) or PIO (use_dma=n) used for ep-{a,b,c,d}.  Testing
+ * with "ttcp" (and the "ether.c" driver) behaves nicely too.
+ *
+ * DMA is enabled by default.  Drivers using transfer queues might use
+ * DMA chaining to remove IRQ latencies between transfers.  (Except when
+ * short OUT transfers happen.)  Drivers can use the req->no_interrupt
+ * hint to completely eliminate some IRQs, if a later IRQ is guaranteed
+ * and DMA chaining is enabled.
+ */
+
+// #define NET2280_DMA_OUT_WORKAROUND
+// #define USE_DMA_CHAINING
+
+
+/*
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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 DEBUG	1
+// #define	VERBOSE		/* extra debug messages (success too) */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/moduleparam.h>
+#include <linux/device.h>
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+
+#define	DRIVER_DESC		"NetChip 2280 USB Peripheral Controller"
+#define	DRIVER_VERSION		"May Day 2003"
+
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+#define	EP_DONTUSE		13	/* nonzero */
+
+#define USE_RDK_LEDS		/* GPIO pins control three LEDs */
+#define USE_SYSFS_DEBUG_FILES
+
+
+static const char driver_name [] = "net2280";
+static const char driver_desc [] = DRIVER_DESC;
+
+static const char ep0name [] = "ep0";
+static const char *ep_name [] = {
+	ep0name,
+	"ep-a", "ep-b", "ep-c", "ep-d",
+	"ep-e", "ep-f",
+};
+
+static int use_dma = 1;
+
+/* "modprobe net2280 use_dma=n" etc */
+module_param (use_dma, bool, S_IRUGO|S_IWUSR);
+
+/* mode 0 == ep-{a,b,c,d} 1K fifo each
+ * mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
+ * mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
+ */
+static ushort fifo_mode = 0;
+
+/* "modprobe net2280 fifo_mode=1" etc */
+module_param (fifo_mode, ushort, 0644);
+
+#define	DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
+
+#if defined(USE_SYSFS_DEBUG_FILES) || defined (DEBUG)
+static char *type_string (u8 bmAttributes)
+{
+	switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_BULK:	return "bulk";
+	case USB_ENDPOINT_XFER_ISOC:	return "iso";
+	case USB_ENDPOINT_XFER_INT:	return "intr";
+	};
+	return "control";
+}
+#endif
+
+#include "net2280.h"
+
+#define valid_bit	__constant_cpu_to_le32 (1 << VALID_BIT)
+#define dma_done_ie	__constant_cpu_to_le32 (1 << DMA_DONE_INTERRUPT_ENABLE)
+
+/*-------------------------------------------------------------------------*/
+
+static int
+net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct net2280		*dev;
+	struct net2280_ep	*ep;
+	u32			max, tmp;
+	unsigned long		flags;
+
+	ep = container_of (_ep, struct net2280_ep, ep);
+	if (!_ep || !desc || ep->desc || _ep->name == ep0name
+			|| desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	/* erratum 0119 workaround ties up an endpoint number */
+	if ((desc->bEndpointAddress & 0x0f) == EP_DONTUSE)
+		return -EDOM;
+
+	/* sanity check ep-e/ep-f since their fifos are small */
+	max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff;
+	if (ep->num > 4 && max > 64)
+		return -ERANGE;
+
+	spin_lock_irqsave (&dev->lock, flags);
+	_ep->maxpacket = max & 0x7ff;
+	ep->desc = desc;
+
+	/* ep_reset() has already been called */
+	ep->stopped = 0;
+
+	/* set speed-dependent max packet; may kick in high bandwidth */
+	set_idx_reg (dev->regs, REG_EP_MAXPKT (dev, ep->num), max);
+
+	/* FIFO lines can't go to different packets.  PIO is ok, so
+	 * use it instead of troublesome (non-bulk) multi-packet DMA.
+	 */
+	if (ep->is_in && ep->dma && (max % 4) != 0) {
+		DEBUG (ep->dev, "%s, no IN dma for maxpacket %d\n",
+			ep->ep.name, ep->ep.maxpacket);
+		ep->dma = 0;
+	}
+
+	/* set type, direction, address; reset fifo counters */
+	writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat);
+	tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+	if (tmp == USB_ENDPOINT_XFER_INT) {
+		/* not just because of erratum 0105; avoid ever
+		 * kicking in the "toggle-irrelevant" mode.
+		 */
+		tmp = USB_ENDPOINT_XFER_BULK;
+	}
+	ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC) ? 1 : 0;
+	tmp <<= ENDPOINT_TYPE;
+	tmp |= desc->bEndpointAddress;
+	tmp |= (4 << ENDPOINT_BYTE_COUNT);	/* default full fifo lines */
+	tmp |= 1 << ENDPOINT_ENABLE;
+	wmb ();
+
+	/* for OUT transfers, block the rx fifo until a read is posted */
+	ep->is_in = (tmp & USB_DIR_IN) != 0;
+	if (!ep->is_in)
+		writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+
+	writel (tmp, &ep->regs->ep_cfg);
+
+#ifdef NET2280_DMA_OUT_WORKAROUND
+	if (!ep->is_in)
+		ep->dma = 0;
+#endif
+
+	/* enable irqs */
+	if (!ep->dma) {				/* pio, per-packet */
+		tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0);
+		writel (tmp, &dev->regs->pciirqenb0);
+
+		tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
+			| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
+			| readl (&ep->regs->ep_irqenb);
+		writel (tmp, &ep->regs->ep_irqenb);
+	} else {				/* dma, per-request */
+		tmp = (1 << (8 + ep->num));	/* completion */
+		tmp |= readl (&dev->regs->pciirqenb1);
+		writel (tmp, &dev->regs->pciirqenb1);
+
+		/* for short OUT transfers, dma completions can't
+		 * advance the queue; do it pio-style, by hand.
+		 * NOTE erratum 0112 workaround #2
+		 */
+		if ((desc->bEndpointAddress & USB_DIR_IN) == 0) {
+			tmp = (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE);
+			writel (tmp, &ep->regs->ep_irqenb);
+
+			tmp = (1 << ep->num) | readl (&dev->regs->pciirqenb0);
+			writel (tmp, &dev->regs->pciirqenb0);
+		}
+	}
+
+	tmp = desc->bEndpointAddress;
+	DEBUG (dev, "enabled %s (ep%d%s-%s) %s max %04x\n",
+		_ep->name, tmp & 0x0f, DIR_STRING (tmp),
+		type_string (desc->bmAttributes),
+		ep->dma ? "dma" : "pio", max);
+
+	/* pci writes may still be posted */
+	spin_unlock_irqrestore (&dev->lock, flags);
+	return 0;
+}
+
+static int handshake (u32 *ptr, u32 mask, u32 done, int usec)
+{
+	u32	result;
+
+	do {
+		result = readl (ptr);
+		if (result == ~(u32)0)		/* "device unplugged" */
+			return -ENODEV;
+		result &= mask;
+		if (result == done)
+			return 0;
+		udelay (1);
+		usec--;
+	} while (usec > 0);
+#ifdef DEBUG
+	if (done == 0) dump_stack (); 		/* ignore out_flush timeout */
+#endif
+	return -ETIMEDOUT;
+}
+
+static struct usb_ep_ops net2280_ep_ops;
+
+static void ep_reset (struct net2280_regs *regs, struct net2280_ep *ep)
+{
+	u32		tmp;
+
+	ep->desc = 0;
+	INIT_LIST_HEAD (&ep->queue);
+
+	ep->ep.maxpacket = ~0;
+	ep->ep.ops = &net2280_ep_ops;
+
+	/* disable the dma, irqs, endpoint... */
+	if (ep->dma) {
+		writel (0, &ep->dma->dmactl);
+		writel (  (1 << DMA_SCATTER_GATHER_DONE_INTERRUPT)
+			| (1 << DMA_TRANSACTION_DONE_INTERRUPT)
+			| (1 << DMA_ABORT)
+			, &ep->dma->dmastat);
+
+		tmp = readl (&regs->pciirqenb0);
+		tmp &= ~(1 << ep->num);
+		writel (tmp, &regs->pciirqenb0);
+	} else {
+		tmp = readl (&regs->pciirqenb1);
+		tmp &= ~(1 << (8 + ep->num));	/* completion */
+		writel (tmp, &regs->pciirqenb1);
+	}
+	writel (0, &ep->regs->ep_irqenb);
+
+	/* init to our chosen defaults, notably so that we NAK OUT
+	 * packets until the driver queues a read (+note erratum 0112)
+	 */
+	writel (  (1 << SET_NAK_OUT_PACKETS_MODE)
+		| (1 << SET_NAK_OUT_PACKETS)
+		| (1 << CLEAR_EP_HIDE_STATUS_PHASE)
+		| (1 << CLEAR_INTERRUPT_MODE)
+		| (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+		| (1 << CLEAR_ENDPOINT_TOGGLE)
+		| (1 << CLEAR_ENDPOINT_HALT)
+		, &ep->regs->ep_rsp);
+
+	/* scrub most status bits, and flush any fifo state */
+	writel (  (1 << TIMEOUT)
+		| (1 << USB_STALL_SENT)
+		| (1 << USB_IN_NAK_SENT)
+		| (1 << USB_IN_ACK_RCVD)
+		| (1 << USB_OUT_PING_NAK_SENT)
+		| (1 << USB_OUT_ACK_SENT)
+		| (1 << FIFO_OVERFLOW)
+		| (1 << FIFO_UNDERFLOW)
+		| (1 << FIFO_FLUSH)
+		| (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
+		| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
+		| (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+		| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
+		| (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+		| (1 << DATA_IN_TOKEN_INTERRUPT)
+		, &ep->regs->ep_stat);
+
+	/* fifo size is handled separately */
+}
+
+static void nuke (struct net2280_ep *);
+
+static int net2280_disable (struct usb_ep *_ep)
+{
+	struct net2280_ep	*ep;
+	unsigned long		flags;
+
+	ep = container_of (_ep, struct net2280_ep, ep);
+	if (!_ep || !ep->desc || _ep->name == ep0name)
+		return -EINVAL;
+
+	spin_lock_irqsave (&ep->dev->lock, flags);
+	nuke (ep);
+	ep_reset (ep->dev->regs, ep);
+
+	VDEBUG (ep->dev, "disabled %s %s\n",
+			ep->dma ? "dma" : "pio", _ep->name);
+
+	/* synch memory views with the device */
+	(void) readl (&ep->regs->ep_cfg);
+
+	if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
+		ep->dma = &ep->dev->dma [ep->num - 1];
+
+	spin_unlock_irqrestore (&ep->dev->lock, flags);
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+net2280_alloc_request (struct usb_ep *_ep, int gfp_flags)
+{
+	struct net2280_ep	*ep;
+	struct net2280_request	*req;
+
+	if (!_ep)
+		return 0;
+	ep = container_of (_ep, struct net2280_ep, ep);
+
+	req = kmalloc (sizeof *req, gfp_flags);
+	if (!req)
+		return 0;
+
+	memset (req, 0, sizeof *req);
+	req->req.dma = DMA_ADDR_INVALID;
+	INIT_LIST_HEAD (&req->queue);
+
+	/* this dma descriptor may be swapped with the previous dummy */
+	if (ep->dma) {
+		struct net2280_dma	*td;
+
+		td = pci_pool_alloc (ep->dev->requests, gfp_flags,
+				&req->td_dma);
+		if (!td) {
+			kfree (req);
+			return 0;
+		}
+		td->dmacount = 0;	/* not VALID */
+		td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID);
+		req->td = td;
+	}
+	return &req->req;
+}
+
+static void
+net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct net2280_ep	*ep;
+	struct net2280_request	*req;
+
+	ep = container_of (_ep, struct net2280_ep, ep);
+	if (!ep || !_req)
+		return;
+
+	req = container_of (_req, struct net2280_request, req);
+	WARN_ON (!list_empty (&req->queue));
+	if (req->td)
+		pci_pool_free (ep->dev->requests, req->td, req->td_dma);
+	kfree (req);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#undef USE_KMALLOC
+
+/* many common platforms have dma-coherent caches, which means that it's
+ * safe to use kmalloc() memory for all i/o buffers without using any
+ * cache flushing calls.  (unless you're trying to share cache lines
+ * between dma and non-dma activities, which is a slow idea in any case.)
+ *
+ * other platforms need more care, with 2.5 having a moderately general
+ * solution (which falls down for allocations smaller than one page)
+ * that improves significantly on the 2.4 PCI allocators by removing
+ * the restriction that memory never be freed in_interrupt().
+ */
+#if	defined(CONFIG_X86)
+#define USE_KMALLOC
+
+#elif	defined(CONFIG_PPC) && !defined(CONFIG_NOT_COHERENT_CACHE)
+#define USE_KMALLOC
+
+/* FIXME there are other cases, including an x86-64 one ...  */
+#endif
+
+/* allocating buffers this way eliminates dma mapping overhead, which
+ * on some platforms will mean eliminating a per-io buffer copy.  with
+ * some kinds of system caches, further tweaks may still be needed.
+ */
+static void *
+net2280_alloc_buffer (
+	struct usb_ep		*_ep,
+	unsigned		bytes,
+	dma_addr_t		*dma,
+	int			gfp_flags
+)
+{
+	void			*retval;
+	struct net2280_ep	*ep;
+
+	ep = container_of (_ep, struct net2280_ep, ep);
+	if (!ep || (!ep->desc && ep->num != 0))
+		return 0;
+
+	*dma = DMA_ADDR_INVALID;
+	if (ep->dma) {
+#if	defined(USE_KMALLOC)
+		retval = kmalloc (bytes, gfp_flags);
+		if (retval)
+			*dma = virt_to_phys (retval);
+
+#elif	LINUX_VERSION_CODE > KERNEL_VERSION(2,5,58)
+#warning Using dma_alloc_consistent even with sub-page allocations
+		/* the main problem with this call is that it wastes memory
+		 * on typical 1/N page allocations: it allocates 1-N pages.
+		 */
+		retval = dma_alloc_coherent (&ep->dev->pdev->dev,
+				bytes, dma, gfp_flags);
+#else
+#error No dma-coherent memory allocator is available
+		/* pci_alloc_consistent works, but pci_free_consistent()
+		 * isn't safe in_interrupt().  plus, in addition to the
+		 * 1/Nth page weakness, it doesn't understand gfp_flags.
+		 */
+#endif
+	} else
+		retval = kmalloc (bytes, gfp_flags);
+
+	return retval;
+}
+
+static void
+net2280_free_buffer (
+	struct usb_ep *_ep,
+	void *buf,
+	dma_addr_t dma,
+	unsigned bytes
+) {
+	/* free memory into the right allocator */
+#ifndef	USE_KMALLOC
+	if (dma != DMA_ADDR_INVALID)
+		dma_free_coherent (ep->dev->pdev, bytes, dma);
+	else
+#endif
+		kfree (buf);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* load a packet into the fifo we use for usb IN transfers.
+ * works for all endpoints.
+ *
+ * NOTE: pio with ep-a..ep-d could stuff multiple packets into the fifo
+ * at a time, but this code is simpler because it knows it only writes
+ * one packet.  ep-a..ep-d should use dma instead.
+ */
+static void
+write_fifo (struct net2280_ep *ep, struct usb_request *req)
+{
+	struct net2280_ep_regs	*regs = ep->regs;
+	u8			*buf;
+	u32			tmp;
+	unsigned		count, total;
+
+	/* INVARIANT:  fifo is currently empty. (testable) */
+
+	if (req) {
+		total = req->length - req->actual;
+		buf = req->buf + req->actual;
+	} else {
+		total = 0;
+		buf = 0;
+	}
+
+	/* write just one packet at a time */
+	count = min (ep->ep.maxpacket, total);
+	VDEBUG (ep->dev, "write %s fifo (IN) %d bytes%s req %p\n",
+			ep->ep.name, count,
+			(count != ep->ep.maxpacket) ? " (short)" : "",
+			req);
+	while (count >= 4) {
+		/* NOTE be careful if you try to align these. fifo lines
+		 * should normally be full (4 bytes) and successive partial
+		 * lines are ok only in certain cases.
+		 */
+		tmp = get_unaligned ((u32 *)buf);
+		cpu_to_le32s (&tmp);
+		writel (tmp, &regs->ep_data);
+		buf += 4;
+		count -= 4;
+	}
+
+	/* last fifo entry is "short" unless we wrote a full packet */
+	if (total < ep->ep.maxpacket) {
+		tmp = count ? get_unaligned ((u32 *)buf) : count;
+		cpu_to_le32s (&tmp);
+		set_fifo_bytecount (ep, count & 0x03);
+		writel (tmp, &regs->ep_data);
+	}
+
+	/* pci writes may still be posted */
+}
+
+/* work around erratum 0106: PCI and USB race over the OUT fifo.
+ * caller guarantees chiprev 0100, out endpoint is NAKing, and
+ * there's no real data in the fifo.
+ */
+static void out_flush (struct net2280_ep *ep)
+{
+	u32	*statp, tmp;
+
+	ASSERT_OUT_NAKING (ep);
+
+	statp = &ep->regs->ep_stat;
+	writel (  (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+		| (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+		, statp);
+	writel ((1 << FIFO_FLUSH), statp);
+	mb ();
+	tmp = readl (statp);
+	if (tmp & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) {
+		unsigned	usec;
+
+		if (ep->dev->gadget.speed == USB_SPEED_HIGH) {
+			if (ep->ep.maxpacket <= 512)
+				usec = 10;	/* 512 byte bulk */
+			else
+				usec = 21;	/* 1024 byte interrupt */
+		} else
+			usec = 50;		/* 64 byte bulk/interrupt */
+		handshake (statp, (1 << USB_OUT_PING_NAK_SENT),
+				(1 << USB_OUT_PING_NAK_SENT), usec);
+		/* NAK done; now CLEAR_NAK_OUT_PACKETS is safe */
+	}
+}
+
+/* unload packet(s) from the fifo we use for usb OUT transfers.
+ * returns true iff the request completed, because of short packet
+ * or the request buffer having filled with full packets.
+ *
+ * for ep-a..ep-d this will read multiple packets out when they
+ * have been accepted.
+ */
+static int
+read_fifo (struct net2280_ep *ep, struct net2280_request *req)
+{
+	struct net2280_ep_regs	*regs = ep->regs;
+	u8			*buf = req->req.buf + req->req.actual;
+	unsigned		count, tmp, is_short;
+	unsigned		cleanup = 0, prevent = 0;
+
+	/* erratum 0106 ... packets coming in during fifo reads might
+	 * be incompletely rejected.  not all cases have workarounds.
+	 */
+	if (ep->dev->chiprev == 0x0100) {
+		tmp = readl (&ep->regs->ep_stat);
+		if ((tmp & (1 << NAK_OUT_PACKETS)))
+			/* cleanup = 1 */;
+		else if ((tmp & (1 << FIFO_FULL))
+				/* don't break hs PING protocol ... */
+				|| ep->dev->gadget.speed == USB_SPEED_FULL) {
+			start_out_naking (ep);
+			prevent = 1;
+		}
+		/* else: hope we don't see the problem */
+	}
+
+	/* never overflow the rx buffer. the fifo reads packets until
+	 * it sees a short one; we might not be ready for them all.
+	 */
+	count = readl (&regs->ep_avail);
+	tmp = req->req.length - req->req.actual;
+	if (count > tmp) {
+		unsigned	over = tmp % ep->ep.maxpacket;
+
+		/* FIXME handle this consistently between PIO and DMA */
+		if (over) {
+			ERROR (ep->dev,
+				"%s out fifo %d bytes, over %d extra %d\n",
+				ep->ep.name, count, over, count - tmp);
+			req->req.status = -EOVERFLOW;
+			tmp -= over;
+		}
+		count = tmp;
+	}
+	req->req.actual += count;
+
+	is_short = (count == 0) || ((count % ep->ep.maxpacket) != 0);
+
+	VDEBUG (ep->dev, "read %s fifo (OUT) %d bytes%s%s%s req %p %d/%d\n",
+			ep->ep.name, count, is_short ? " (short)" : "",
+			cleanup ? " flush" : "", prevent ? " nak" : "",
+			req, req->req.actual, req->req.length);
+
+	while (count >= 4) {
+		tmp = readl (&regs->ep_data);
+		cpu_to_le32s (&tmp);
+		put_unaligned (tmp, (u32 *)buf);
+		buf += 4;
+		count -= 4;
+	}
+	if (count) {
+		tmp = readl (&regs->ep_data);
+		cpu_to_le32s (&tmp);
+		do {
+			*buf++ = (u8) tmp;
+			tmp >>= 8;
+		} while (--count);
+	}
+	if (cleanup)
+		out_flush (ep);
+	if (prevent) {
+		writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+		(void) readl (&ep->regs->ep_rsp);
+	}
+
+	return is_short || ((req->req.actual == req->req.length)
+				&& !req->req.zero);
+}
+
+/* fill out dma descriptor to match a given request */
+static inline void
+fill_dma_desc (struct net2280_ep *ep, struct net2280_request *req, int valid)
+{
+	struct net2280_dma	*td = req->td;
+	u32			dmacount = req->req.length;
+
+	/* don't let DMA continue after a short OUT packet,
+	 * so overruns can't affect the next transfer.
+	 */
+	if (ep->is_in)
+		dmacount |= (1 << DMA_DIRECTION);
+	else if ((dmacount % ep->ep.maxpacket) != 0)
+		dmacount |= (1 << END_OF_CHAIN);
+
+	req->valid = valid;
+	if (valid)
+		dmacount |= (1 << VALID_BIT);
+#ifdef USE_DMA_CHAINING
+	if (!req->req.no_interrupt)
+#endif
+		dmacount |= (1 << DMA_DONE_INTERRUPT_ENABLE);
+
+	/* td->dmadesc = previously set by caller */
+	td->dmaaddr = cpu_to_le32p (&req->req.dma);
+
+	/* 2280 may be polling VALID_BIT through ep->dma->dmadesc */
+	wmb ();
+	td->dmacount = cpu_to_le32p (&dmacount);
+}
+
+static const u32 dmactl_default =
+		  (1 << DMA_CLEAR_COUNT_ENABLE)
+		/* erratum 0116 workaround part 1 (use POLLING) */
+		| (POLL_100_USEC << DESCRIPTOR_POLLING_RATE)
+		| (1 << DMA_VALID_BIT_POLLING_ENABLE)
+		| (1 << DMA_VALID_BIT_ENABLE)
+		| (1 << DMA_SCATTER_GATHER_ENABLE)
+		/* erratum 0116 workaround part 2 (no AUTOSTART) */
+		| (1 << DMA_ENABLE);
+
+static inline void spin_stop_dma (struct net2280_dma_regs *dma)
+{
+	handshake (&dma->dmactl, (1 << DMA_ENABLE), 0, 50);
+}
+
+static inline void stop_dma (struct net2280_dma_regs *dma)
+{
+	writel (dmactl_default & ~(1 << DMA_ENABLE), &dma->dmactl);
+	spin_stop_dma (dma);
+}
+
+static void start_dma (struct net2280_ep *ep, struct net2280_request *req)
+{
+	u32			tmp;
+	int			clear_nak = 0;
+	struct net2280_dma_regs	*dma = ep->dma;
+
+	/* FIXME can't use DMA for ZLPs */
+
+	/* previous OUT packet might have been short */
+	if (!ep->is_in && ((tmp = readl (&ep->regs->ep_stat))
+		 		& (1 << NAK_OUT_PACKETS)) != 0) {
+		writel ((1 << SHORT_PACKET_TRANSFERRED_INTERRUPT),
+			&ep->regs->ep_stat);
+
+		tmp = readl (&ep->regs->ep_avail);
+		if (tmp == 0)
+			clear_nak = 1;
+		else {
+			/* transfer all/some fifo data */
+			writel (req->req.dma, &dma->dmaaddr);
+			tmp = min (tmp, req->req.length);
+
+			/* dma irq, faking scatterlist status */
+			req->td->dmacount = cpu_to_le32 (req->req.length - tmp);
+			writel ((1 << DMA_DONE_INTERRUPT_ENABLE)
+				| tmp, &dma->dmacount);
+
+			writel ((1 << DMA_ENABLE), &dma->dmactl);
+			writel ((1 << DMA_START), &dma->dmastat);
+			return;
+		}
+	}
+
+	/* on this path we know there's no dma queue (yet) */
+	WARN_ON (readl (&dma->dmactl) & (1 << DMA_ENABLE));
+	tmp = dmactl_default;
+
+	/* force packet boundaries between dma requests, but prevent the
+	 * controller from automagically writing a last "short" packet
+	 * (zero length) unless the driver explicitly said to do that.
+	 */
+	if (ep->is_in) {
+		if (likely ((req->req.length % ep->ep.maxpacket) != 0
+				|| req->req.zero)) {
+			tmp |= (1 << DMA_FIFO_VALIDATE);
+			ep->in_fifo_validate = 1;
+		} else
+			ep->in_fifo_validate = 0;
+	}
+
+	/* init req->td, pointing to the current dummy */
+	req->td->dmadesc = cpu_to_le32 (ep->td_dma);
+	fill_dma_desc (ep, req, 1);
+
+#ifdef USE_DMA_CHAINING
+	writel (  (1 << VALID_BIT)
+		| (ep->is_in << DMA_DIRECTION)
+		| 0, &dma->dmacount);
+#else
+	req->td->dmacount |= __constant_cpu_to_le32 (1 << END_OF_CHAIN);
+#endif
+
+	writel (req->td_dma, &dma->dmadesc);
+	writel (tmp, &dma->dmactl);
+
+	/* erratum 0116 workaround part 3:  pci arbiter away from net2280 */
+	(void) readl (&ep->dev->pci->pcimstctl);
+
+	writel ((1 << DMA_START), &dma->dmastat);
+
+	/* recover from previous short read; erratum 0112 workaround #1 */
+	if (clear_nak)
+		writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+}
+
+static inline void
+queue_dma (struct net2280_ep *ep, struct net2280_request *req, int valid)
+{
+	struct net2280_dma	*end;
+	dma_addr_t		tmp;
+
+	/* swap new dummy for old, link; fill and maybe activate */
+	end = ep->dummy;
+	ep->dummy = req->td;
+	req->td = end;
+
+	tmp = ep->td_dma;
+	ep->td_dma = req->td_dma;
+	req->td_dma = tmp;
+
+	end->dmadesc = cpu_to_le32 (ep->td_dma);
+
+	fill_dma_desc (ep, req, valid);
+}
+
+static void
+done (struct net2280_ep *ep, struct net2280_request *req, int status)
+{
+	struct net2280		*dev;
+	unsigned		stopped = ep->stopped;
+
+	list_del_init (&req->queue);
+
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	dev = ep->dev;
+	if (req->mapped) {
+		pci_unmap_single (dev->pdev, req->req.dma, req->req.length,
+			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	}
+
+	if (status && status != -ESHUTDOWN)
+		VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length);
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+	spin_unlock (&dev->lock);
+	req->req.complete (&ep->ep, &req->req);
+	spin_lock (&dev->lock);
+	ep->stopped = stopped;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+net2280_queue (struct usb_ep *_ep, struct usb_request *_req, int gfp_flags)
+{
+	struct net2280_request	*req;
+	struct net2280_ep	*ep;
+	struct net2280		*dev;
+	unsigned long		flags;
+
+	/* we always require a cpu-view buffer, so that we can
+	 * always use pio (as fallback or whatever).
+	 */
+	req = container_of (_req, struct net2280_request, req);
+	if (!_req || !_req->complete || !_req->buf
+			|| !list_empty (&req->queue))
+		return -EINVAL;
+	if (_req->length > (~0 & DMA_BYTE_COUNT_MASK))
+		return -EDOM;
+	ep = container_of (_ep, struct net2280_ep, ep);
+	if (!_ep || (!ep->desc && ep->num != 0))
+		return -EINVAL;
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	/* FIXME implement PIO fallback for ZLPs with DMA */
+	if (ep->dma && _req->length == 0)
+		return -EOPNOTSUPP;
+
+	/* set up dma mapping in case the caller didn't */
+	if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
+		_req->dma = pci_map_single (dev->pdev, _req->buf, _req->length,
+			ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
+		req->mapped = 1;
+	}
+
+#if 0
+	VDEBUG (dev, "%s queue req %p, len %d buf %p\n",
+			_ep->name, _req, _req->length, _req->buf);
+#endif
+
+	spin_lock_irqsave (&dev->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+	req->dma_done = 0;
+
+	/* kickstart this i/o queue? */
+	if (list_empty (&ep->queue) && !ep->stopped) {
+		/* use DMA if the endpoint supports it, else pio */
+		if (ep->dma)
+			start_dma (ep, req);
+		else {
+			/* maybe there's no control data, just status ack */
+			if (ep->num == 0 && _req->length == 0)
+				goto done;
+
+			/* PIO ... stuff the fifo, or unblock it.  */
+			if (ep->is_in)
+				write_fifo (ep, _req);
+			else if (list_empty (&ep->queue)) {
+				u32	s;
+
+				/* OUT FIFO might have packet(s) buffered */
+				s = readl (&ep->regs->ep_stat);
+				if ((s & (1 << FIFO_EMPTY)) == 0) {
+					/* note:  _req->short_not_ok is
+					 * ignored here since PIO _always_
+					 * stops queue advance here, and
+					 * _req->status doesn't change for
+					 * short reads (only _req->actual)
+					 */
+					if (read_fifo (ep, req)) {
+						done (ep, req, 0);
+						/* don't queue it */
+						req = 0;
+					} else
+						s = readl (&ep->regs->ep_stat);
+				}
+
+				/* don't NAK, let the fifo fill */
+				if (req && (s & (1 << NAK_OUT_PACKETS)))
+					writel ((1 << CLEAR_NAK_OUT_PACKETS),
+							&ep->regs->ep_rsp);
+			}
+		}
+
+	} else if (ep->dma) {
+		int	valid = 1;
+
+		if (ep->is_in) {
+			int	expect;
+
+			/* preventing magic zlps is per-engine state, not
+			 * per-transfer; irq logic must recover hiccups.
+			 */
+			expect = likely (req->req.zero
+				|| (req->req.length % ep->ep.maxpacket) != 0);
+			if (expect != ep->in_fifo_validate)
+				valid = 0;
+		}
+		queue_dma (ep, req, valid);
+
+	} /* else the irq handler advances the queue. */
+
+	if (req) {
+done:
+		list_add_tail (&req->queue, &ep->queue);
+	}
+	spin_unlock_irqrestore (&dev->lock, flags);
+
+	/* pci writes may still be posted */
+	return 0;
+}
+
+static inline void
+dma_done (
+	struct net2280_ep *ep,
+	struct net2280_request *req,
+	u32 dmacount,
+	int status
+)
+{
+	req->req.actual = req->req.length - (DMA_BYTE_COUNT_MASK & dmacount);
+	rmb ();
+	done (ep, req, status);
+}
+
+static void scan_dma_completions (struct net2280_ep *ep)
+{
+	/* only look at descriptors that were "naturally" retired,
+	 * so fifo and list head state won't matter
+	 */
+	while (!list_empty (&ep->queue)) {
+		struct net2280_request	*req;
+		u32			tmp;
+
+		req = list_entry (ep->queue.next,
+				struct net2280_request, queue);
+		if (!req->valid)
+			break;
+		rmb ();
+		tmp = le32_to_cpup (&req->td->dmacount);
+		if ((tmp & (1 << VALID_BIT)) != 0)
+			break;
+
+		/* SHORT_PACKET_TRANSFERRED_INTERRUPT handles "usb-short"
+		 * packets, including overruns, even when the transfer was
+		 * exactly the length requested (dmacount now zero).
+		 */
+		if (!ep->is_in && (req->req.length % ep->ep.maxpacket) != 0) {
+			req->dma_done = 1;
+			break;
+		}
+		dma_done (ep, req, tmp, 0);
+	}
+}
+
+static void restart_dma (struct net2280_ep *ep)
+{
+	struct net2280_request	*req;
+
+	if (ep->stopped)
+		return;
+	req = list_entry (ep->queue.next, struct net2280_request, queue);
+
+#ifdef USE_DMA_CHAINING
+	/* the 2280 will be processing the queue unless queue hiccups after
+	 * the previous transfer:
+	 *  IN:   wanted automagic zlp, head doesn't (or vice versa)
+	 *  OUT:  was "usb-short", we must restart.
+	 */
+	if (!req->valid) {
+		struct net2280_request	*entry, *prev = 0;
+		int			qmode, reqmode, done = 0;
+
+		DEBUG (ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
+		qmode = likely (req->req.zero
+			|| (req->req.length % ep->ep.maxpacket) != 0);
+		list_for_each_entry (entry, &ep->queue, queue) {
+			u32		dmacount;
+
+			if (entry != req)
+				continue;
+			dmacount = entry->td->dmacount;
+			if (!done) {
+				reqmode = likely (entry->req.zero
+					|| (entry->req.length
+						% ep->ep.maxpacket) != 0);
+				if (reqmode == qmode) {
+					entry->valid = 1;
+					dmacount |= valid_bit;
+					entry->td->dmacount = dmacount;
+					prev = entry;
+					continue;
+				} else {
+					prev->td->dmacount |= dma_done_ie;
+					done = 1;
+				}
+			}
+
+			/* walk the rest of the queue so unlinks behave */
+			entry->valid = 0;
+			dmacount &= ~valid_bit;
+			entry->td->dmacount = dmacount;
+			prev = entry;
+		}
+		start_dma (ep, req);
+	} else if (!ep->is_in
+			&& (readl (&ep->regs->ep_stat)
+				& (1 << NAK_OUT_PACKETS)) != 0)
+		start_dma (ep, req);
+#else
+	start_dma (ep, req);
+#endif
+}
+
+static inline void abort_dma (struct net2280_ep *ep)
+{
+	/* abort the current transfer */
+	writel ((1 << DMA_ABORT), &ep->dma->dmastat);
+
+	/* collect completed transfers (except the current one) */
+	scan_dma_completions (ep);
+}
+
+/* dequeue ALL requests */
+static void nuke (struct net2280_ep *ep)
+{
+	struct net2280_request	*req;
+
+	/* called with spinlock held */
+	ep->stopped = 1;
+	if (ep->dma)
+		abort_dma (ep);
+	while (!list_empty (&ep->queue)) {
+		req = list_entry (ep->queue.next,
+				struct net2280_request,
+				queue);
+		done (ep, req, -ESHUTDOWN);
+	}
+}
+
+/* dequeue JUST ONE request */
+static int net2280_dequeue (struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct net2280_ep	*ep;
+	struct net2280_request	*req;
+	unsigned long		flags;
+	u32			dmactl;
+	int			stopped;
+
+	ep = container_of (_ep, struct net2280_ep, ep);
+	req = container_of (_req, struct net2280_request, req);
+	if (!_ep || (!ep->desc && ep->num != 0) || !_req)
+		return -EINVAL;
+
+	spin_lock_irqsave (&ep->dev->lock, flags);
+	stopped = ep->stopped;
+
+	/* pause dma while we scan the queue */
+	dmactl = 0;
+	ep->stopped = 1;
+	if (ep->dma) {
+		dmactl = readl (&ep->dma->dmactl);
+		writel (dmactl & ~(1 << DMA_ENABLE), &ep->dma->dmactl);
+		/* force synch, clean any completed requests */
+		spin_stop_dma (ep->dma);
+		scan_dma_completions (ep);
+	}
+
+	/* queue head may be partially complete. */
+	if (ep->queue.next == &req->queue) {
+		if (ep->dma) {
+			DEBUG (ep->dev, "unlink (%s) dma\n", _ep->name);
+			_req->status = -ECONNRESET;
+			abort_dma (ep);
+			if (likely (ep->queue.next == &req->queue))
+				dma_done (ep, req,
+					le32_to_cpup (&req->td->dmacount),
+					-ECONNRESET);
+		} else {
+			DEBUG (ep->dev, "unlink (%s) pio\n", _ep->name);
+			done (ep, req, -ECONNRESET);
+		}
+		req = 0;
+
+#ifdef USE_DMA_CHAINING
+	/* patch up hardware chaining data */
+	} else if (ep->dma) {
+		if (req->queue.prev == ep->queue.next) {
+			writel (le32_to_cpu (req->td->dmadesc),
+				&ep->dma->dmadesc);
+			if (req->td->dmacount & dma_done_ie)
+				writel (readl (&ep->dma->dmacount)
+						| dma_done_ie,
+					&ep->dma->dmacount);
+		} else {
+			struct net2280_request	*prev;
+
+			prev = list_entry (req->queue.prev,
+				struct net2280_request, queue);
+			prev->td->dmadesc = req->td->dmadesc;
+			if (req->td->dmacount & dma_done_ie)
+				prev->td->dmacount |= dma_done_ie;
+		}
+#endif
+	}
+
+	if (req)
+		done (ep, req, -ECONNRESET);
+	ep->stopped = stopped;
+
+	if (ep->dma) {
+		/* turn off dma on inactive queues */
+		if (list_empty (&ep->queue))
+			stop_dma (ep->dma);
+		else if (!ep->stopped) {
+			/* resume current request, or start new one */
+			if (req)
+				writel (dmactl, &ep->dma->dmactl);
+			else
+				start_dma (ep, list_entry (ep->queue.next,
+					struct net2280_request, queue));
+		}
+	}
+
+	spin_unlock_irqrestore (&ep->dev->lock, flags);
+	return req ? 0 : -EOPNOTSUPP;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int
+net2280_set_halt (struct usb_ep *_ep, int value)
+{
+	struct net2280_ep	*ep;
+
+	ep = container_of (_ep, struct net2280_ep, ep);
+	if (!_ep || (!ep->desc && ep->num != 0))
+		return -EINVAL;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+	if ((ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC)
+		return -EINVAL;
+
+	VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
+
+	/* set/clear, then synch memory views with the device */
+	if (value)
+		set_halt (ep);
+	else
+		clear_halt (ep);
+	(void) readl (&ep->regs->ep_rsp);
+
+	return 0;
+}
+
+static int
+net2280_fifo_status (struct usb_ep *_ep)
+{
+	struct net2280_ep	*ep;
+	u32			avail;
+
+	ep = container_of (_ep, struct net2280_ep, ep);
+	if (!_ep || (!ep->desc && ep->num != 0))
+		return -ENODEV;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	avail = readl (&ep->regs->ep_avail) & ((1 << 12) - 1);
+	if (avail > ep->fifo_size)
+		return -EOVERFLOW;
+	if (ep->is_in)
+		avail = ep->fifo_size - avail;
+	return avail;
+}
+
+static void
+net2280_fifo_flush (struct usb_ep *_ep)
+{
+	struct net2280_ep	*ep;
+
+	ep = container_of (_ep, struct net2280_ep, ep);
+	if (!_ep || (!ep->desc && ep->num != 0))
+		return;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return;
+
+	writel ((1 << FIFO_FLUSH), &ep->regs->ep_stat);
+	(void) readl (&ep->regs->ep_rsp);
+}
+
+static struct usb_ep_ops net2280_ep_ops = {
+	.enable		= net2280_enable,
+	.disable	= net2280_disable,
+
+	.alloc_request	= net2280_alloc_request,
+	.free_request	= net2280_free_request,
+
+	.alloc_buffer	= net2280_alloc_buffer,
+	.free_buffer	= net2280_free_buffer,
+
+	.queue		= net2280_queue,
+	.dequeue	= net2280_dequeue,
+
+	.set_halt	= net2280_set_halt,
+	.fifo_status	= net2280_fifo_status,
+	.fifo_flush	= net2280_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int net2280_get_frame (struct usb_gadget *_gadget)
+{
+	struct net2280		*dev;
+	unsigned long		flags;
+	u16			retval;
+
+	if (!_gadget)
+		return -ENODEV;
+	dev = container_of (_gadget, struct net2280, gadget);
+	spin_lock_irqsave (&dev->lock, flags);
+	retval = get_idx_reg (dev->regs, REG_FRAME) & 0x03ff;
+	spin_unlock_irqrestore (&dev->lock, flags);
+	return retval;
+}
+
+static int net2280_wakeup (struct usb_gadget *_gadget)
+{
+	struct net2280		*dev;
+
+	if (!_gadget)
+		return 0;
+	dev = container_of (_gadget, struct net2280, gadget);
+	writel (1 << GENERATE_RESUME, &dev->usb->usbstat);
+
+	/* pci writes may still be posted */
+	return 0;
+}
+
+static const struct usb_gadget_ops net2280_ops = {
+	.get_frame	= net2280_get_frame,
+	.wakeup		= net2280_wakeup,
+
+	// .set_selfpowered = net2280_set_selfpowered,
+};
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	USE_SYSFS_DEBUG_FILES
+
+/* "function" sysfs attribute */
+static ssize_t
+show_function (struct device *_dev, char *buf)
+{
+	struct net2280	*dev = dev_get_drvdata (_dev);
+
+	if (!dev->driver
+			|| !dev->driver->function
+			|| strlen (dev->driver->function) > PAGE_SIZE)
+		return 0;
+	return snprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
+}
+static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
+
+static ssize_t
+show_registers (struct device *_dev, char *buf)
+{
+	struct net2280		*dev;
+	char			*next;
+	unsigned		size, t;
+	unsigned long		flags;
+	int			i;
+	u32			t1, t2;
+	char			*s;
+
+	dev = dev_get_drvdata (_dev);
+	next = buf;
+	size = PAGE_SIZE;
+	spin_lock_irqsave (&dev->lock, flags);
+
+	if (dev->driver)
+		s = dev->driver->driver.name;
+	else
+		s = "(none)";
+
+	/* Main Control Registers */
+	t = snprintf (next, size, "%s " DRIVER_VERSION "\n"
+			"devinit %03x fifoctl %08x gadget '%s'\n"
+			"pci irqenb0 %02x irqenb1 %08x "
+			"irqstat0 %04x irqstat1 %08x\n",
+			driver_name,
+			readl (&dev->regs->devinit),
+			readl (&dev->regs->fifoctl),
+			s,
+			readl (&dev->regs->pciirqenb0),
+			readl (&dev->regs->pciirqenb1),
+			readl (&dev->regs->irqstat0),
+			readl (&dev->regs->irqstat1));
+	size -= t;
+	next += t;
+
+	/* USB Control Registers */
+	t1 = readl (&dev->usb->usbctl);
+	t2 = readl (&dev->usb->usbstat);
+	if (t1 & (1 << VBUS_PIN)) {
+		if (t2 & (1 << HIGH_SPEED))
+			s = "high speed";
+		else if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+			s = "powered";
+		else
+			s = "full speed";
+		/* full speed bit (6) not working?? */
+	} else
+			s = "not attached";
+	t = snprintf (next, size,
+			"stdrsp %08x usbctl %08x usbstat %08x "
+				"addr 0x%02x (%s)\n",
+			readl (&dev->usb->stdrsp), t1, t2,
+			readl (&dev->usb->ouraddr), s);
+	size -= t;
+	next += t;
+
+	/* PCI Master Control Registers */
+
+	/* DMA Control Registers */
+
+	/* Configurable EP Control Registers */
+	for (i = 0; i < 7; i++) {
+		struct net2280_ep	*ep;
+
+		ep = &dev->ep [i];
+		if (i && !ep->desc)
+			continue;
+
+		t1 = readl (&ep->regs->ep_cfg);
+		t = snprintf (next, size,
+				"%s\tcfg %05x rsp %02x enb %02x ",
+				ep->ep.name, t1,
+				readl (&ep->regs->ep_rsp) & 0xff,
+				readl (&ep->regs->ep_irqenb));
+		size -= t;
+		next += t;
+
+		t = snprintf (next, size,
+				"stat %08x avail %04x "
+				"(ep%d%s-%s)%s\n",
+				readl (&ep->regs->ep_stat),
+				readl (&ep->regs->ep_avail),
+				t1 & 0x0f, DIR_STRING (t1),
+				type_string (t1 >> 8),
+				ep->stopped ? "*" : "");
+		size -= t;
+		next += t;
+
+		if (!ep->dma)
+			continue;
+
+		t = snprintf (next, size,
+				"  dma\tctl %08x stat %08x count %08x\n"
+				"\taddr %08x desc %08x\n",
+				readl (&ep->dma->dmactl),
+				readl (&ep->dma->dmastat),
+				readl (&ep->dma->dmacount),
+				readl (&ep->dma->dmaaddr),
+				readl (&ep->dma->dmadesc));
+		size -= t;
+		next += t;
+
+	}
+
+	/* Indexed Registers */
+		// none yet 
+
+	/* Statistics */
+	t = snprintf (next, size, "irqs:  ");
+	size -= t;
+	next += t;
+	for (i = 0; i < 7; i++) {
+		struct net2280_ep	*ep;
+
+		ep = &dev->ep [i];
+		if (i && !ep->irqs)
+			continue;
+		t = snprintf (next, size, " %s/%ld", ep->ep.name, ep->irqs);
+		size -= t;
+		next += t;
+
+	}
+	t = snprintf (next, size, "\n");
+	size -= t;
+	next += t;
+
+	spin_unlock_irqrestore (&dev->lock, flags);
+
+	return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (registers, S_IRUGO, show_registers, NULL);
+
+static ssize_t
+show_queues (struct device *_dev, char *buf)
+{
+	struct net2280		*dev;
+	char			*next;
+	unsigned		size;
+	unsigned long		flags;
+	int			i;
+
+	dev = dev_get_drvdata (_dev);
+	next = buf;
+	size = PAGE_SIZE;
+	spin_lock_irqsave (&dev->lock, flags);
+
+	for (i = 0; i < 7; i++) {
+		struct net2280_ep		*ep = &dev->ep [i];
+		struct net2280_request		*req;
+		int				t;
+
+		if (i != 0) {
+			const struct usb_endpoint_descriptor	*d;
+
+			d = ep->desc;
+			if (!d)
+				continue;
+			t = d->bEndpointAddress;
+			t = snprintf (next, size,
+				"%s (ep%d%s-%s) max %04x %s\n",
+				ep->ep.name, t & USB_ENDPOINT_NUMBER_MASK,
+				(t & USB_DIR_IN) ? "in" : "out",
+				({ char *val;
+				 switch (d->bmAttributes & 0x03) {
+				 case USB_ENDPOINT_XFER_BULK:
+				 	val = "bulk"; break;
+				 case USB_ENDPOINT_XFER_INT:
+				 	val = "intr"; break;
+				 default:
+				 	val = "iso"; break;
+				 }; val; }),
+				le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
+				ep->dma ? "dma" : "pio"
+				);
+		} else /* ep0 should only have one transfer queued */
+			t = snprintf (next, size, "ep0 max 64 pio %s\n",
+					ep->is_in ? "in" : "out");
+		if (t <= 0 || t > size)
+			goto done;
+		size -= t;
+		next += t;
+
+		if (list_empty (&ep->queue)) {
+			t = snprintf (next, size, "\t(nothing queued)\n");
+			if (t <= 0 || t > size)
+				goto done;
+			size -= t;
+			next += t;
+			continue;
+		}
+		list_for_each_entry (req, &ep->queue, queue) {
+			if (ep->dma && req->td_dma == readl (&ep->dma->dmadesc))
+				t = snprintf (next, size,
+					"\treq %p len %d/%d "
+					"buf %p (dmacount %08x)\n",
+					&req->req, req->req.actual,
+					req->req.length, req->req.buf,
+					readl (&ep->dma->dmacount));
+			else
+				t = snprintf (next, size,
+					"\treq %p len %d/%d buf %p\n",
+					&req->req, req->req.actual,
+					req->req.length, req->req.buf);
+			if (t <= 0 || t > size)
+				goto done;
+			size -= t;
+			next += t;
+		}
+	}
+
+done:
+	spin_unlock_irqrestore (&dev->lock, flags);
+	return PAGE_SIZE - size;
+}
+static DEVICE_ATTR (queues, S_IRUGO, show_queues, NULL);
+
+
+#else
+
+#define device_create_file(a,b)	do {} while (0)
+#define device_remove_file	device_create_file
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* another driver-specific mode might be a request type doing dma
+ * to/from another device fifo instead of to/from memory.
+ */
+
+static void set_fifo_mode (struct net2280 *dev, int mode)
+{
+	/* keeping high bits preserves BAR2 */
+	writel ((0xffff << PCI_BASE2_RANGE) | mode, &dev->regs->fifoctl);
+
+	/* always ep-{a,b,e,f} ... maybe not ep-c or ep-d */
+	INIT_LIST_HEAD (&dev->gadget.ep_list);
+	list_add_tail (&dev->ep [1].ep.ep_list, &dev->gadget.ep_list);
+	list_add_tail (&dev->ep [2].ep.ep_list, &dev->gadget.ep_list);
+	switch (mode) {
+	case 0:
+		list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list);
+		list_add_tail (&dev->ep [4].ep.ep_list, &dev->gadget.ep_list);
+		dev->ep [1].fifo_size = dev->ep [2].fifo_size = 1024;
+		break;
+	case 1:
+		dev->ep [1].fifo_size = dev->ep [2].fifo_size = 2048;
+		break;
+	case 2:
+		list_add_tail (&dev->ep [3].ep.ep_list, &dev->gadget.ep_list);
+		dev->ep [1].fifo_size = 2048;
+		dev->ep [2].fifo_size = 1024;
+		break;
+	}
+	/* fifo sizes for ep0, ep-c, ep-d, ep-e, and ep-f never change */
+	list_add_tail (&dev->ep [5].ep.ep_list, &dev->gadget.ep_list);
+	list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
+}
+
+/**
+ * net2280_set_fifo_mode - change allocation of fifo buffers
+ * @gadget: access to the net2280 device that will be updated
+ * @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
+ * 	1 for two 2kB buffers (ep-a and ep-b only);
+ * 	2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
+ *
+ * returns zero on success, else negative errno.  when this succeeds,
+ * the contents of gadget->ep_list may have changed.
+ *
+ * you may only call this function when endpoints a-d are all disabled.
+ * use it whenever extra hardware buffering can help performance, such
+ * as before enabling "high bandwidth" interrupt endpoints that use
+ * maxpacket bigger than 512 (when double buffering would otherwise
+ * be unavailable).
+ */
+int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
+{
+	int			i;
+	struct net2280		*dev;
+	int			status = 0;
+	unsigned long		flags;
+
+	if (!gadget)
+		return -ENODEV;
+	dev = container_of (gadget, struct net2280, gadget);
+
+	spin_lock_irqsave (&dev->lock, flags);
+
+	for (i = 1; i <= 4; i++)
+		if (dev->ep [i].desc) {
+			status = -EINVAL;
+			break;
+		}
+	if (mode < 0 || mode > 2)
+		status = -EINVAL;
+	if (status == 0)
+		set_fifo_mode (dev, mode);
+	spin_unlock_irqrestore (&dev->lock, flags);
+
+	if (status == 0) {
+		if (mode == 1)
+			DEBUG (dev, "fifo:  ep-a 2K, ep-b 2K\n");
+		else if (mode == 2)
+			DEBUG (dev, "fifo:  ep-a 2K, ep-b 1K, ep-c 1K\n");
+		/* else all are 1K */
+	}
+	return status;
+}
+EXPORT_SYMBOL (net2280_set_fifo_mode);
+
+/*-------------------------------------------------------------------------*/
+
+/* keeping it simple:
+ * - one bus driver, initted first;
+ * - one function driver, initted second
+ *
+ * most of the work to support multiple net2280 controllers would
+ * be to associate this gadget driver (yes?) with all of them, or
+ * perhaps to bind specific drivers to specific devices.
+ */
+
+static struct net2280	*the_controller;
+
+static void usb_reset (struct net2280 *dev)
+{
+	u32	tmp;
+
+	/* force immediate bus disconnect, and synch through pci */
+	writel (0, &dev->usb->usbctl);
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+	(void) readl (&dev->usb->usbctl);
+
+	net2280_led_init (dev);
+
+	/* disable automatic responses, and irqs */
+	writel (0, &dev->usb->stdrsp);
+	writel (0, &dev->regs->pciirqenb0);
+	writel (0, &dev->regs->pciirqenb1);
+
+	/* clear old dma and irq state */
+	for (tmp = 0; tmp < 4; tmp++) {
+		writel ((1 << DMA_ABORT), &dev->dma [tmp].dmastat);
+		stop_dma (&dev->dma [tmp]);
+	}
+	writel (~0, &dev->regs->irqstat0),
+	writel (~(1 << SUSPEND_REQUEST_INTERRUPT), &dev->regs->irqstat1),
+
+	/* reset, and enable pci */
+	tmp = readl (&dev->regs->devinit)
+		| (1 << PCI_ENABLE)
+		| (1 << FIFO_SOFT_RESET)
+		| (1 << USB_SOFT_RESET)
+		| (1 << M8051_RESET);
+	writel (tmp, &dev->regs->devinit);
+
+	/* standard fifo and endpoint allocations */
+	set_fifo_mode (dev, (fifo_mode <= 2) ? fifo_mode : 0);
+}
+
+static void usb_reinit (struct net2280 *dev)
+{
+	u32	tmp;
+	int	init_dma;
+
+	/* use_dma changes are ignored till next device re-init */
+	init_dma = use_dma;
+
+	/* basic endpoint init */
+	for (tmp = 0; tmp < 7; tmp++) {
+		struct net2280_ep	*ep = &dev->ep [tmp];
+
+		ep->ep.name = ep_name [tmp];
+		ep->dev = dev;
+		ep->num = tmp;
+
+		if (tmp > 0 && tmp <= 4) {
+			ep->fifo_size = 1024;
+			if (init_dma)
+				ep->dma = &dev->dma [tmp - 1];
+		} else
+			ep->fifo_size = 64;
+		ep->regs = &dev->epregs [tmp];
+		ep_reset (dev->regs, ep);
+	}
+	dev->ep [0].ep.maxpacket = 64;
+	dev->ep [5].ep.maxpacket = 64;
+	dev->ep [6].ep.maxpacket = 64;
+
+	dev->gadget.ep0 = &dev->ep [0].ep;
+	dev->ep [0].stopped = 0;
+	INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+
+	/* we want to prevent lowlevel/insecure access from the USB host,
+	 * but erratum 0119 means this enable bit is ignored
+	 */
+	for (tmp = 0; tmp < 5; tmp++)
+		writel (EP_DONTUSE, &dev->dep [tmp].dep_cfg);
+}
+
+static void ep0_start (struct net2280 *dev)
+{
+	writel (  (1 << SET_EP_HIDE_STATUS_PHASE)
+		| (1 << CLEAR_NAK_OUT_PACKETS)
+		| (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+		, &dev->epregs [0].ep_rsp);
+
+	/*
+	 * hardware optionally handles a bunch of standard requests
+	 * that the API hides from drivers anyway.  have it do so.
+	 * endpoint status/features are handled in software, to
+	 * help pass tests for some dubious behavior.
+	 */
+	writel (  (1 << SET_TEST_MODE)
+		| (1 << SET_ADDRESS)
+		| (1 << DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP)
+		| (1 << GET_DEVICE_STATUS)
+		| (1 << GET_INTERFACE_STATUS)
+		, &dev->usb->stdrsp);
+	writel (  (1 << USB_ROOT_PORT_WAKEUP_ENABLE)
+		| (1 << SELF_POWERED_USB_DEVICE)
+		| (1 << REMOTE_WAKEUP_SUPPORT)
+		| (1 << USB_DETECT_ENABLE)
+		| (1 << DEVICE_REMOTE_WAKEUP_ENABLE)
+		, &dev->usb->usbctl);
+
+	/* enable irqs so we can see ep0 and general operation  */
+	writel (  (1 << SETUP_PACKET_INTERRUPT_ENABLE)
+		| (1 << ENDPOINT_0_INTERRUPT_ENABLE)
+		, &dev->regs->pciirqenb0);
+	writel (  (1 << PCI_INTERRUPT_ENABLE)
+		| (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE)
+		| (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE)
+		| (1 << PCI_RETRY_ABORT_INTERRUPT_ENABLE)
+		| (1 << VBUS_INTERRUPT_ENABLE)
+		| (1 << ROOT_PORT_RESET_INTERRUPT_ENABLE)
+		, &dev->regs->pciirqenb1);
+
+	/* don't leave any writes posted */
+	(void) readl (&dev->usb->usbctl);
+}
+
+/* when a driver is successfully registered, it will receive
+ * control requests including set_configuration(), which enables
+ * non-control requests.  then usb traffic follows until a
+ * disconnect is reported.  then a host may connect again, or
+ * the driver might get unbound.
+ */
+int usb_gadget_register_driver (struct usb_gadget_driver *driver)
+{
+	struct net2280		*dev = the_controller;
+	int			retval;
+	unsigned		i;
+
+	/* insist on high speed support from the driver, since
+	 * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE)
+	 * "must not be used in normal operation"
+	 */
+	if (!driver
+			|| driver->speed != USB_SPEED_HIGH
+			|| !driver->bind
+			|| !driver->unbind
+			|| !driver->setup)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	for (i = 0; i < 7; i++)
+		dev->ep [i].irqs = 0;
+
+	/* hook up the driver ... */
+	dev->driver = driver;
+	dev->gadget.dev.driver = &driver->driver;
+	retval = driver->bind (&dev->gadget);
+	if (retval) {
+		DEBUG (dev, "bind to driver %s --> %d\n",
+				driver->driver.name, retval);
+		dev->driver = 0;
+		dev->gadget.dev.driver = 0;
+		return retval;
+	}
+
+	// FIXME
+	// driver_register (&driver->driver);
+	// device_register (&dev->gadget.dev);
+
+	device_create_file (&dev->pdev->dev, &dev_attr_function);
+	device_create_file (&dev->pdev->dev, &dev_attr_queues);
+
+	/* ... then enable host detection and ep0; and we're ready
+	 * for set_configuration as well as eventual disconnect.
+	 */
+	net2280_led_active (dev, 1);
+	ep0_start (dev);
+
+	DEBUG (dev, "%s ready, usbctl %08x stdrsp %08x\n",
+			driver->driver.name,
+			readl (&dev->usb->usbctl),
+			readl (&dev->usb->stdrsp));
+
+	/* pci writes may still be posted */
+	return 0;
+}
+EXPORT_SYMBOL (usb_gadget_register_driver);
+
+static void
+stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
+{
+	int			i;
+
+	/* don't disconnect if it's not connected */
+	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = 0;
+
+	/* stop hardware; prevent new request submissions;
+	 * and kill any outstanding requests.
+	 */
+	usb_reset (dev);
+	for (i = 0; i < 7; i++)
+		nuke (&dev->ep [i]);
+
+	/* report disconnect; the driver is already quiesced */
+	if (driver) {
+		spin_unlock (&dev->lock);
+		driver->disconnect (&dev->gadget);
+		spin_lock (&dev->lock);
+	}
+
+	usb_reinit (dev);
+}
+
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+{
+	struct net2280	*dev = the_controller;
+	unsigned long	flags;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver)
+		return -EINVAL;
+
+	spin_lock_irqsave (&dev->lock, flags);
+	stop_activity (dev, driver);
+	spin_unlock_irqrestore (&dev->lock, flags);
+
+	driver->unbind (&dev->gadget);
+	dev->driver = 0;
+
+	net2280_led_active (dev, 0);
+	device_remove_file (&dev->pdev->dev, &dev_attr_function);
+	device_remove_file (&dev->pdev->dev, &dev_attr_queues);
+
+	// FIXME
+	// device_unregister()
+	// driver_unregister (&driver->driver);
+
+	DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
+	return 0;
+}
+EXPORT_SYMBOL (usb_gadget_unregister_driver);
+
+
+/*-------------------------------------------------------------------------*/
+
+/* handle ep0, ep-e, ep-f with 64 byte packets: packet per irq.
+ * also works for dma-capable endpoints, in pio mode or just
+ * to manually advance the queue after short OUT transfers.
+ */
+static void handle_ep_small (struct net2280_ep *ep)
+{
+	struct net2280_request	*req;
+	u32			t;
+	/* 0 error, 1 mid-data, 2 done */
+	int			mode = 1;
+
+	if (!list_empty (&ep->queue))
+		req = list_entry (ep->queue.next,
+			struct net2280_request, queue);
+	else
+		req = 0;
+
+	/* ack all, and handle what we care about */
+	t = readl (&ep->regs->ep_stat);
+	ep->irqs++;
+#if 0
+	VDEBUG (ep->dev, "%s ack ep_stat %08x, req %p\n",
+			ep->ep.name, t, req ? &req->req : 0);
+#endif
+	writel (t & ~(1 << NAK_OUT_PACKETS), &ep->regs->ep_stat);
+
+	/* for ep0, monitor token irqs to catch data stage length errors
+	 * and to synchronize on status.
+	 *
+	 * also, to defer reporting of protocol stalls ... here's where
+	 * data or status first appears, handling stalls here should never
+	 * cause trouble on the host side..
+	 *
+	 * control requests could be slightly faster without token synch for
+	 * status, but status can jam up that way.
+	 */
+	if (unlikely (ep->num == 0)) {
+		if (ep->is_in) {
+			/* status; stop NAKing */
+			if (t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT)) {
+				if (ep->dev->protocol_stall)
+					set_halt (ep);
+				mode = 2;
+			/* reply to extra IN tokens with a zlp */
+			} else if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) {
+				if (ep->dev->protocol_stall) {
+					set_halt (ep);
+					mode = 2;
+				} else if (!req)
+					write_fifo (ep, 0);
+			}
+		} else {
+			/* status; stop NAKing */
+			if (t & (1 << DATA_IN_TOKEN_INTERRUPT)) {
+				if (ep->dev->protocol_stall)
+					set_halt (ep);
+				mode = 2;
+			/* an extra OUT token is an error */
+			} else if (((t & (1 << DATA_OUT_PING_TOKEN_INTERRUPT))
+					&& req
+					&& req->req.actual == req->req.length)
+					|| !req) {
+				ep->dev->protocol_stall = 1;
+				set_halt (ep);
+				ep->stopped = 1;
+				if (req)
+					done (ep, req, -EOVERFLOW);
+				req = 0;
+			}
+		}
+	}
+
+	if (unlikely (!req))
+		return;
+
+	/* manual DMA queue advance after short OUT */
+	if (likely (ep->dma != 0)) {
+		if (t & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
+			u32	count;
+
+			/* TRANSFERRED works around OUT_DONE erratum 0112.
+			 * we expect (N <= maxpacket) bytes; host wrote M.
+			 * iff (M < N) we won't ever see a DMA interrupt.
+			 */
+			count = readl (&ep->dma->dmacount);
+			count &= DMA_BYTE_COUNT_MASK;
+			if (!req->dma_done) {
+				/* dma can finish with the FIFO non-empty,
+				 * on (M > N) errors.
+				 */
+				while (count && (t & (1 << FIFO_EMPTY)) == 0) {
+					cpu_relax ();
+					t = readl (&ep->regs->ep_stat);
+					count = readl (&ep->dma->dmacount);
+					count &= DMA_BYTE_COUNT_MASK;
+				}
+			}
+
+			/* stop DMA, leave ep NAKing */
+			writel ((1 << DMA_ABORT), &ep->dma->dmastat);
+			spin_stop_dma (ep->dma);
+
+			/* buffer might have been too small */
+			t = readl (&ep->regs->ep_avail);
+			if (t != 0)
+				DEBUG (ep->dev, "%s dma, discard %d len %d\n",
+						ep->ep.name, t, count);
+			dma_done (ep, req, count, t ? -EOVERFLOW : 0);
+
+			/* also flush to prevent erratum 0106 trouble */
+			if (t || ep->dev->chiprev == 0x0100)
+				out_flush (ep);
+
+			/* restart dma (still NAKing OUT!) if needed */
+			if (!list_empty (&ep->queue))
+				restart_dma (ep);
+		} else
+			DEBUG (ep->dev, "%s dma ep_stat %08x ??\n",
+					ep->ep.name, t);
+		return;
+
+	/* data packet(s) received (in the fifo, OUT) */
+	} else if (t & (1 << DATA_PACKET_RECEIVED_INTERRUPT)) {
+		if (read_fifo (ep, req) && ep->num != 0)
+			mode = 2;
+
+	/* data packet(s) transmitted (IN) */
+	} else if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)) {
+		unsigned	len;
+
+		len = req->req.length - req->req.actual;
+		len = min (ep->ep.maxpacket, len);
+		req->req.actual += len;
+
+		/* if we wrote it all, we're usually done */
+		if (req->req.actual == req->req.length) {
+			if (ep->num == 0) {
+				/* wait for control status */
+				if (mode != 2)
+					req = 0;
+			} else if (!req->req.zero || len != ep->ep.maxpacket)
+				mode = 2;
+		}
+
+	/* there was nothing to do ...  */
+	} else if (mode == 1)
+		return;
+
+	/* done */
+	if (mode == 2) {
+		/* stream endpoints often resubmit/unlink in completion */
+		done (ep, req, 0);
+
+		/* maybe advance queue to next request */
+		if (ep->num == 0) {
+			allow_status (ep);
+			req = 0;
+		} else {
+			if (!list_empty (&ep->queue) && !ep->stopped)
+				req = list_entry (ep->queue.next,
+					struct net2280_request, queue);
+			else
+				req = 0;
+			if (req && !ep->is_in)
+				stop_out_naking (ep);
+		}
+	}
+
+	/* is there a buffer for the next packet?
+	 * for best streaming performance, make sure there is one.
+	 */
+	if (req && !ep->stopped) {
+
+		/* load IN fifo with next packet (may be zlp) */
+		if (t & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))
+			write_fifo (ep, &req->req);
+	}
+}
+
+static struct net2280_ep *
+get_ep_by_addr (struct net2280 *dev, u16 wIndex)
+{
+	struct net2280_ep	*ep;
+
+	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+		return &dev->ep [0];
+	list_for_each_entry (ep, &dev->gadget.ep_list, ep.ep_list) {
+		u8	bEndpointAddress;
+
+		if (!ep->desc)
+			continue;
+		bEndpointAddress = ep->desc->bEndpointAddress;
+		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+			continue;
+		if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f))
+			return ep;
+	}
+	return 0;
+}
+
+static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
+{
+	struct net2280_ep	*ep;
+	u32			num, scratch;
+
+	/* most of these don't need individual acks */
+	stat &= ~(1 << INTA_ASSERTED);
+	if (!stat)
+		return;
+	// DEBUG (dev, "irqstat0 %04x\n", stat);
+
+	/* starting a control request? */
+	if (unlikely (stat & (1 << SETUP_PACKET_INTERRUPT))) {
+		union {
+			u32			raw [2];
+			struct usb_ctrlrequest	r;
+		} u;
+		int				tmp = 0;
+		struct net2280_request		*req;
+
+		if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
+			if (readl (&dev->usb->usbstat) & (1 << HIGH_SPEED))
+				dev->gadget.speed = USB_SPEED_HIGH;
+			else
+				dev->gadget.speed = USB_SPEED_FULL;
+			net2280_led_speed (dev, dev->gadget.speed);
+			DEBUG (dev, "%s speed\n",
+				(dev->gadget.speed == USB_SPEED_HIGH)
+					? "high" : "full");
+		}
+
+		ep = &dev->ep [0];
+		ep->irqs++;
+
+		/* make sure any leftover request state is cleared */
+		stat &= ~(1 << ENDPOINT_0_INTERRUPT);
+		while (!list_empty (&ep->queue)) {
+			req = list_entry (ep->queue.next,
+					struct net2280_request, queue);
+			done (ep, req, (req->req.actual == req->req.length)
+						? 0 : -EPROTO);
+		}
+		ep->stopped = 0;
+		dev->protocol_stall = 0;
+		writel (  (1 << TIMEOUT)
+			| (1 << USB_STALL_SENT)
+			| (1 << USB_IN_NAK_SENT)
+			| (1 << USB_IN_ACK_RCVD)
+			| (1 << USB_OUT_PING_NAK_SENT)
+			| (1 << USB_OUT_ACK_SENT)
+			| (1 << FIFO_OVERFLOW)
+			| (1 << FIFO_UNDERFLOW)
+			| (1 << SHORT_PACKET_OUT_DONE_INTERRUPT)
+			| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)
+			| (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+			| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
+			| (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+			| (1 << DATA_IN_TOKEN_INTERRUPT)
+			, &ep->regs->ep_stat);
+		u.raw [0] = readl (&dev->usb->setup0123);
+		u.raw [1] = readl (&dev->usb->setup4567);
+		
+		cpu_to_le32s (&u.raw [0]);
+		cpu_to_le32s (&u.raw [1]);
+
+		le16_to_cpus (&u.r.wValue);
+		le16_to_cpus (&u.r.wIndex);
+		le16_to_cpus (&u.r.wLength);
+
+		/* ack the irq */
+		writel (1 << SETUP_PACKET_INTERRUPT, &dev->regs->irqstat0);
+		stat ^= (1 << SETUP_PACKET_INTERRUPT);
+
+		/* watch control traffic at the token level, and force
+		 * synchronization before letting the status stage happen.
+		 */
+		ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0;
+		if (ep->is_in)
+			scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
+				| (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+				| (1 << DATA_IN_TOKEN_INTERRUPT);
+		else
+			scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+				| (1 << DATA_OUT_PING_TOKEN_INTERRUPT)
+				| (1 << DATA_IN_TOKEN_INTERRUPT);
+		writel (scratch, &dev->epregs [0].ep_irqenb);
+
+		/* we made the hardware handle most lowlevel requests;
+		 * everything else goes uplevel to the gadget code.
+		 */
+		switch (u.r.bRequest) {
+		case USB_REQ_GET_STATUS: {
+			struct net2280_ep	*e;
+			u16			status;
+
+			if (u.r.bRequestType != (USB_DIR_IN|USB_RECIP_ENDPOINT))
+				goto delegate;
+			if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0
+					|| u.r.wLength > 2)
+				goto do_stall;
+
+			if (readl (&e->regs->ep_rsp)
+					& (1 << SET_ENDPOINT_HALT))
+				status = __constant_cpu_to_le16 (1);
+			else
+				status = __constant_cpu_to_le16 (0);
+
+			/* don't bother with a request object! */
+			writel (0, &dev->epregs [0].ep_irqenb);
+			set_fifo_bytecount (ep, u.r.wLength);
+			writel (status, &dev->epregs [0].ep_data);
+			allow_status (ep);
+			goto next_endpoints;
+			}
+			break;
+		case USB_REQ_CLEAR_FEATURE: {
+			struct net2280_ep	*e;
+
+			if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+				goto delegate;
+			if (u.r.wIndex != 0 /* HALT feature */
+					|| u.r.wLength != 0)
+				goto do_stall;
+			if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+				goto do_stall;
+			clear_halt (e);
+			}
+			break;
+		case USB_REQ_SET_FEATURE: {
+			struct net2280_ep	*e;
+
+			if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+				goto delegate;
+			if (u.r.wIndex != 0 /* HALT feature */
+					|| u.r.wLength != 0)
+				goto do_stall;
+			if ((e = get_ep_by_addr (dev, u.r.wIndex)) == 0)
+				goto do_stall;
+			set_halt (e);
+			}
+			break;
+		default:
+delegate:
+			VDEBUG (dev, "setup %02x.%02x v%04x i%04x "
+				"ep_cfg %08x\n",
+				u.r.bRequestType, u.r.bRequest,
+				u.r.wValue, u.r.wIndex,
+				readl (&ep->regs->ep_cfg));
+			spin_unlock (&dev->lock);
+			tmp = dev->driver->setup (&dev->gadget, &u.r);
+			spin_lock (&dev->lock);
+		}
+
+		/* stall ep0 on error */
+		if (tmp < 0) {
+do_stall:
+			VDEBUG (dev, "req %02x.%02x protocol STALL; stat %d\n",
+					u.r.bRequestType, u.r.bRequest, tmp);
+			dev->protocol_stall = 1;
+
+		/* when there's no data, queueing a response is optional */
+		} else if (list_empty (&ep->queue)) {
+			if (u.r.wLength == 0) {
+				/* done() not possible/requested */
+				allow_status (ep);
+			} else {
+				DEBUG (dev, "req %02x.%02x v%04x "
+					"gadget error, len %d, stat %d\n",
+					u.r.bRequestType, u.r.bRequest,
+					le16_to_cpu (u.r.wValue),
+					u.r.wLength, tmp);
+				dev->protocol_stall = 1;
+			}
+		}
+
+		/* some in/out token irq should follow; maybe stall then. */
+	}
+
+next_endpoints:
+	/* endpoint data irq ? */
+	scratch = stat & 0x7f;
+	stat &= ~0x7f;
+	for (num = 0; scratch; num++) {
+		u32		t;
+
+		/* do this endpoint's FIFO and queue need tending? */
+		t = 1 << num;
+		if ((scratch & t) == 0)
+			continue;
+		scratch ^= t;
+
+		ep = &dev->ep [num];
+		handle_ep_small (ep);
+	}
+
+	if (stat)
+		DEBUG (dev, "unhandled irqstat0 %08x\n", stat);
+}
+
+#define DMA_INTERRUPTS ( \
+		  (1 << DMA_D_INTERRUPT) \
+		| (1 << DMA_C_INTERRUPT) \
+		| (1 << DMA_B_INTERRUPT) \
+		| (1 << DMA_A_INTERRUPT))
+#define	PCI_ERROR_INTERRUPTS ( \
+		  (1 << PCI_MASTER_ABORT_RECEIVED_INTERRUPT) \
+		| (1 << PCI_TARGET_ABORT_RECEIVED_INTERRUPT) \
+		| (1 << PCI_RETRY_ABORT_INTERRUPT))
+
+static void handle_stat1_irqs (struct net2280 *dev, u32 stat)
+{
+	struct net2280_ep	*ep;
+	u32			tmp, num, scratch;
+
+	/* after disconnect there's nothing else to do! */
+	tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT);
+	if (stat & tmp) {
+		writel (tmp, &dev->regs->irqstat1);
+		if (((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) != 0
+			|| (readl (&dev->usb->usbctl) & (1 << VBUS_PIN)) == 0
+			) && dev->gadget.speed != USB_SPEED_UNKNOWN) {
+			DEBUG (dev, "disconnect %s\n",
+					dev->driver->driver.name);
+			stop_activity (dev, dev->driver);
+			ep0_start (dev);
+			return;
+		}
+		stat &= ~tmp;
+
+		/* vBUS can bounce ... one of many reasons to ignore the
+		 * notion of hotplug events on bus connect/disconnect!
+		 */
+		if (!stat)
+			return;
+	}
+
+	/* NOTE: we don't actually suspend the hardware; that starts to
+	 * interact with PCI power management, and needs something like a
+	 * controller->suspend() call to clear SUSPEND_REQUEST_INTERRUPT.
+	 * we shouldn't see resume interrupts.
+	 * for rev 0100, this also avoids erratum 0102.
+	 */
+	tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT);
+	if (stat & tmp) {
+		if (dev->driver->suspend)
+			dev->driver->suspend (&dev->gadget);
+		stat &= ~tmp;
+	}
+	stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
+
+	/* clear any other status/irqs */
+	if (stat)
+		writel (stat, &dev->regs->irqstat1);
+
+	/* some status we can just ignore */
+	stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
+			| (1 << RESUME_INTERRUPT)
+			| (1 << SOF_INTERRUPT));
+	if (!stat)
+		return;
+	// DEBUG (dev, "irqstat1 %08x\n", stat);
+
+	/* DMA status, for ep-{a,b,c,d} */
+	scratch = stat & DMA_INTERRUPTS;
+	stat &= ~DMA_INTERRUPTS;
+	scratch >>= 9;
+	for (num = 0; scratch; num++) {
+		struct net2280_dma_regs	*dma;
+
+		tmp = 1 << num;
+		if ((tmp & scratch) == 0)
+			continue;
+		scratch ^= tmp;
+
+		ep = &dev->ep [num + 1];
+		dma = ep->dma;
+
+		if (!dma)
+			continue;
+
+		/* clear ep's dma status */
+		tmp = readl (&dma->dmastat);
+		writel (tmp, &dma->dmastat);
+
+#ifdef USE_DMA_CHAINING
+		/* chaining should stop only on error (which?)
+		 * or (stat0 codepath) short OUT transfer.
+		 */
+#else
+		if ((tmp & (1 << DMA_TRANSACTION_DONE_INTERRUPT)) == 0) {
+			DEBUG (ep->dev, "%s no xact done? %08x\n",
+				ep->ep.name, tmp);
+			continue;
+		}
+		stop_dma (ep->dma);
+#endif
+
+		/* OUT transfers terminate when the data from the
+		 * host is in our memory.  Process whatever's done.
+		 * On this path, we know transfer's last packet wasn't
+		 * less than req->length. NAK_OUT_PACKETS may be set,
+		 * or the FIFO may already be holding new packets.
+		 *
+		 * IN transfers can linger in the FIFO for a very
+		 * long time ... we ignore that for now, accounting
+		 * precisely (like PIO does) needs per-packet irqs
+		 */
+		scan_dma_completions (ep);
+
+		/* disable dma on inactive queues; else maybe restart */
+		if (list_empty (&ep->queue)) {
+#ifdef USE_DMA_CHAINING
+			stop_dma (ep->dma);
+#endif
+		} else {
+			tmp = readl (&dma->dmactl);
+			if ((tmp & (1 << DMA_SCATTER_GATHER_ENABLE)) == 0
+					|| (tmp & (1 << DMA_ENABLE)) == 0)
+				restart_dma (ep);
+		}
+		ep->irqs++;
+	}
+
+	/* NOTE:  there are other PCI errors we might usefully notice.
+	 * if they appear very often, here's where to try recovering.
+	 */
+	if (stat & PCI_ERROR_INTERRUPTS) {
+		ERROR (dev, "pci dma error; stat %08x\n", stat);
+		stat &= ~PCI_ERROR_INTERRUPTS;
+		/* these are fatal errors, but "maybe" they won't
+		 * happen again ...
+		 */
+		stop_activity (dev, dev->driver);
+		ep0_start (dev);
+		stat = 0;
+	}
+
+	if (stat)
+		DEBUG (dev, "unhandled irqstat1 %08x\n", stat);
+}
+
+static irqreturn_t net2280_irq (int irq, void *_dev, struct pt_regs * r)
+{
+	struct net2280		*dev = _dev;
+
+	spin_lock (&dev->lock);
+
+	/* handle disconnect, dma, and more */
+	handle_stat1_irqs (dev, readl (&dev->regs->irqstat1));
+
+	/* control requests and PIO */
+	handle_stat0_irqs (dev, readl (&dev->regs->irqstat0));
+
+	spin_unlock (&dev->lock);
+
+	return IRQ_HANDLED;
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* tear down the binding between this driver and the pci device */
+
+static void net2280_remove (struct pci_dev *pdev)
+{
+	struct net2280		*dev = pci_get_drvdata (pdev);
+
+	/* start with the driver above us */
+	if (dev->driver) {
+		/* should have been done already by driver model core */
+		WARN (dev, "pci remove, driver '%s' is still registered\n",
+				dev->driver->driver.name);
+		usb_gadget_unregister_driver (dev->driver);
+	}
+
+	/* then clean up the resources we allocated during probe() */
+	net2280_led_shutdown (dev);
+	if (dev->requests) {
+		int		i;
+		for (i = 1; i < 5; i++) {
+			if (!dev->ep [i].dummy)
+				continue;
+			pci_pool_free (dev->requests, dev->ep [i].dummy,
+					dev->ep [i].td_dma);
+		}
+		pci_pool_destroy (dev->requests);
+	}
+	if (dev->got_irq)
+		free_irq (pdev->irq, dev);
+	if (dev->regs)
+		iounmap (dev->regs);
+	if (dev->region)
+		release_mem_region (pci_resource_start (pdev, 0),
+				pci_resource_len (pdev, 0));
+	if (dev->enabled)
+		pci_disable_device (pdev);
+	device_remove_file (&pdev->dev, &dev_attr_registers);
+	pci_set_drvdata (pdev, 0);
+
+	INFO (dev, "unbind from pci %s\n", pdev->slot_name);
+
+	kfree (dev);
+	the_controller = 0;
+}
+
+/* wrap this driver around the specified device, but
+ * don't respond over USB until a gadget driver binds to us.
+ */
+
+static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct net2280		*dev;
+	unsigned long		resource, len;
+	void			*base = 0;
+	int			retval, i;
+	char			buf [8], *bufp;
+
+	/* if you want to support more than one controller in a system,
+	 * usb_gadget_driver_{register,unregister}() must change.
+	 */
+	if (the_controller) {
+		WARN (the_controller, "ignoring %s\n", pdev->slot_name);
+		return -EBUSY;
+	}
+
+	/* alloc, and start init */
+	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+	if (dev == NULL){
+		retval = -ENOMEM;
+		goto done;
+	}
+
+	memset (dev, 0, sizeof *dev);
+	spin_lock_init (&dev->lock);
+	dev->pdev = pdev;
+	dev->gadget.ops = &net2280_ops;
+
+	strcpy (dev->gadget.dev.bus_id, pdev->slot_name);
+	strcpy (dev->gadget.dev.name, pdev->dev.name);
+	dev->gadget.dev.parent = &pdev->dev;
+	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
+	dev->gadget.name = driver_name;
+
+	/* now all the pci goodies ... */
+	if (pci_enable_device (pdev) < 0) {
+   	        retval = -ENODEV;
+		goto done;
+	}
+	dev->enabled = 1;
+
+	/* BAR 0 holds all the registers
+	 * BAR 1 is 8051 memory; unused here (note erratum 0103)
+	 * BAR 2 is fifo memory; unused here
+	 */
+	resource = pci_resource_start (pdev, 0);
+	len = pci_resource_len (pdev, 0);
+	if (!request_mem_region (resource, len, driver_name)) {
+		DEBUG (dev, "controller already in use\n");
+		retval = -EBUSY;
+		goto done;
+	}
+	dev->region = 1;
+
+	base = ioremap_nocache (resource, len);
+	if (base == NULL) {
+		DEBUG (dev, "can't map memory\n");
+		retval = -EFAULT;
+		goto done;
+	}
+	dev->regs = (struct net2280_regs *) base;
+	dev->usb = (struct net2280_usb_regs *) (base + 0x0080);
+	dev->pci = (struct net2280_pci_regs *) (base + 0x0100);
+	dev->dma = (struct net2280_dma_regs *) (base + 0x0180);
+	dev->dep = (struct net2280_dep_regs *) (base + 0x0200);
+	dev->epregs = (struct net2280_ep_regs *) (base + 0x0300);
+
+	/* put into initial config, link up all endpoints */
+	usb_reset (dev);
+	usb_reinit (dev);
+
+	/* irq setup after old hardware is cleaned up */
+	if (!pdev->irq) {
+		ERROR (dev, "No IRQ.  Check PCI setup!\n");
+		retval = -ENODEV;
+		goto done;
+	}
+#ifndef __sparc__
+	snprintf (buf, sizeof buf, "%d", pdev->irq);
+	bufp = buf;
+#else
+	bufp = __irq_itoa(pdev->irq);
+#endif
+	if (request_irq (pdev->irq, net2280_irq, SA_SHIRQ, driver_name, dev)
+			!= 0) {
+		ERROR (dev, "request interrupt %s failed\n", bufp);
+		retval = -EBUSY;
+		goto done;
+	}
+	dev->got_irq = 1;
+
+	/* DMA setup */
+	dev->requests = pci_pool_create ("requests", pdev,
+		sizeof (struct net2280_dma),
+		0 /* no alignment requirements */,
+		0 /* or page-crossing issues */);
+	if (!dev->requests) {
+		DEBUG (dev, "can't get request pool\n");
+		retval = -ENOMEM;
+		goto done;
+	}
+	for (i = 1; i < 5; i++) {
+		struct net2280_dma	*td;
+
+		td = pci_pool_alloc (dev->requests, GFP_KERNEL,
+				&dev->ep [i].td_dma);
+		if (!td) {
+			DEBUG (dev, "can't get dummy %d\n", i);
+			retval = -ENOMEM;
+			goto done;
+		}
+		td->dmacount = 0;	/* not VALID */
+		td->dmaaddr = __constant_cpu_to_le32 (DMA_ADDR_INVALID);
+		dev->ep [i].dummy = td;
+	}
+
+	/* enable lower-overhead pci memory bursts during DMA */
+	writel ((1 << PCI_RETRY_ABORT_ENABLE)
+			| (1 << DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE)
+			| (1 << DMA_READ_MULTIPLE_ENABLE)
+			| (1 << DMA_READ_LINE_ENABLE)
+			, &dev->pci->pcimstctl);
+	/* erratum 0115 shouldn't appear: Linux inits PCI_LATENCY_TIMER */
+	pci_set_master (pdev);
+	pci_set_mwi (pdev);
+
+	/* ... also flushes any posted pci writes */
+	dev->chiprev = get_idx_reg (dev->regs, REG_CHIPREV) & 0xffff;
+
+	/* done */
+	pci_set_drvdata (pdev, dev);
+	INFO (dev, "%s\n", driver_desc);
+	INFO (dev, "irq %s, pci mem %p, chip rev %04x\n",
+			bufp, base, dev->chiprev);
+	bufp = DRIVER_VERSION
+#ifndef USE_DMA_CHAINING
+		" (no dma chain)"
+#endif
+#ifdef NET2280_DMA_OUT_WORKAROUND
+		" (no dma out)"
+#endif
+		;
+	INFO (dev, "version: %s\n", bufp);
+	the_controller = dev;
+
+	device_create_file (&pdev->dev, &dev_attr_registers);
+
+	return 0;
+
+done:
+	if (dev)
+		net2280_remove (pdev);
+	return retval;
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+static struct pci_device_id __devinitdata pci_ids [] = { {
+	.class = 	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+	.class_mask = 	~0,
+	.vendor =	0x17cc,
+	.device =	0x2280,
+	.subvendor =	PCI_ANY_ID,
+	.subdevice =	PCI_ANY_ID,
+
+}, { /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver net2280_pci_driver = {
+	.name =		(char *) driver_name,
+	.id_table =	pci_ids,
+
+	.probe =	net2280_probe,
+	.remove =	net2280_remove,
+
+	/* FIXME add power management support */
+};
+
+MODULE_DESCRIPTION (DRIVER_DESC);
+MODULE_AUTHOR ("David Brownell");
+MODULE_LICENSE ("GPL");
+
+static int __init init (void)
+{
+	return pci_module_init (&net2280_pci_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void)
+{
+	pci_unregister_driver (&net2280_pci_driver);
+}
+module_exit (cleanup);
diff -Nru a/drivers/usb/gadget/net2280.h b/drivers/usb/gadget/net2280.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/net2280.h	Thu May  8 04:25:53 2003
@@ -0,0 +1,709 @@
+/*
+ * NetChip 2280 high/full speed USB device controller.
+ * Unlike many such controllers, this one talks PCI.
+ */
+
+/*
+ * Copyright (C) 2002 NetChip Technology, Inc. (http://www.netchip.com)
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the 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
+ */
+
+/*-------------------------------------------------------------------------*/
+
+/* NET2280 MEMORY MAPPED REGISTERS
+ *
+ * The register layout came from the chip documentation, and the bit
+ * number definitions were extracted from chip specification.
+ *
+ * Use the shift operator ('<<') to build bit masks, with readl/writel
+ * to access the registers through PCI.
+ */
+
+/* main registers, BAR0 + 0x0000 */
+struct net2280_regs {
+	// offset 0x0000
+	u32		devinit;
+#define     LOCAL_CLOCK_FREQUENCY                               8
+#define     FORCE_PCI_RESET                                     7
+#define     PCI_ID                                              6
+#define     PCI_ENABLE                                          5
+#define     FIFO_SOFT_RESET                                     4
+#define     CFG_SOFT_RESET                                      3
+#define     PCI_SOFT_RESET                                      2
+#define     USB_SOFT_RESET                                      1
+#define     M8051_RESET                                         0
+	u32		eectl;
+#define     EEPROM_ADDRESS_WIDTH                                23
+#define     EEPROM_CHIP_SELECT_ACTIVE                           22
+#define     EEPROM_PRESENT                                      21
+#define     EEPROM_VALID                                        20
+#define     EEPROM_BUSY                                         19
+#define     EEPROM_CHIP_SELECT_ENABLE                           18
+#define     EEPROM_BYTE_READ_START                              17
+#define     EEPROM_BYTE_WRITE_START                             16
+#define     EEPROM_READ_DATA                                    8
+#define     EEPROM_WRITE_DATA                                   0
+	u32		eeclkfreq;
+	u32		_unused0;
+	// offset 0x0010
+
+	u32		pciirqenb0;		/* interrupt PCI master ... */
+#define     SETUP_PACKET_INTERRUPT_ENABLE                       7
+#define     ENDPOINT_F_INTERRUPT_ENABLE                         6
+#define     ENDPOINT_E_INTERRUPT_ENABLE                         5
+#define     ENDPOINT_D_INTERRUPT_ENABLE                         4
+#define     ENDPOINT_C_INTERRUPT_ENABLE                         3
+#define     ENDPOINT_B_INTERRUPT_ENABLE                         2
+#define     ENDPOINT_A_INTERRUPT_ENABLE                         1
+#define     ENDPOINT_0_INTERRUPT_ENABLE                         0
+	u32		pciirqenb1;
+#define     PCI_INTERRUPT_ENABLE                                31
+#define     POWER_STATE_CHANGE_INTERRUPT_ENABLE                 27
+#define     PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE                26
+#define     PCI_PARITY_ERROR_INTERRUPT_ENABLE                   25
+#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE          20
+#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE          19
+#define     PCI_TARGET_ABORT_ASSERTED_INTERRUPT_ENABLE          18
+#define     PCI_RETRY_ABORT_INTERRUPT_ENABLE                    17
+#define     PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE              16
+#define     GPIO_INTERRUPT_ENABLE                               13
+#define     DMA_D_INTERRUPT_ENABLE                              12
+#define     DMA_C_INTERRUPT_ENABLE                              11
+#define     DMA_B_INTERRUPT_ENABLE                              10
+#define     DMA_A_INTERRUPT_ENABLE                              9
+#define     EEPROM_DONE_INTERRUPT_ENABLE                        8
+#define     VBUS_INTERRUPT_ENABLE                               7
+#define     CONTROL_STATUS_INTERRUPT_ENABLE                     6
+#define     ROOT_PORT_RESET_INTERRUPT_ENABLE                    4
+#define     SUSPEND_REQUEST_INTERRUPT_ENABLE                    3
+#define     SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE             2
+#define     RESUME_INTERRUPT_ENABLE                             1
+#define     SOF_INTERRUPT_ENABLE                                0
+	u32		cpu_irqenb0;		/* ... or onboard 8051 */
+#define     SETUP_PACKET_INTERRUPT_ENABLE                       7
+#define     ENDPOINT_F_INTERRUPT_ENABLE                         6
+#define     ENDPOINT_E_INTERRUPT_ENABLE                         5
+#define     ENDPOINT_D_INTERRUPT_ENABLE                         4
+#define     ENDPOINT_C_INTERRUPT_ENABLE                         3
+#define     ENDPOINT_B_INTERRUPT_ENABLE                         2
+#define     ENDPOINT_A_INTERRUPT_ENABLE                         1
+#define     ENDPOINT_0_INTERRUPT_ENABLE                         0
+	u32		cpu_irqenb1;
+#define     CPU_INTERRUPT_ENABLE                                31
+#define     POWER_STATE_CHANGE_INTERRUPT_ENABLE                 27
+#define     PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE                26
+#define     PCI_PARITY_ERROR_INTERRUPT_ENABLE                   25
+#define     PCI_INTA_INTERRUPT_ENABLE                           24
+#define     PCI_PME_INTERRUPT_ENABLE                            23
+#define     PCI_SERR_INTERRUPT_ENABLE                           22
+#define     PCI_PERR_INTERRUPT_ENABLE                           21
+#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE          20
+#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE          19
+#define     PCI_RETRY_ABORT_INTERRUPT_ENABLE                    17
+#define     PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE              16
+#define     GPIO_INTERRUPT_ENABLE                               13
+#define     DMA_D_INTERRUPT_ENABLE                              12
+#define     DMA_C_INTERRUPT_ENABLE                              11
+#define     DMA_B_INTERRUPT_ENABLE                              10
+#define     DMA_A_INTERRUPT_ENABLE                              9
+#define     EEPROM_DONE_INTERRUPT_ENABLE                        8
+#define     VBUS_INTERRUPT_ENABLE                               7
+#define     CONTROL_STATUS_INTERRUPT_ENABLE                     6
+#define     ROOT_PORT_RESET_INTERRUPT_ENABLE                    4
+#define     SUSPEND_REQUEST_INTERRUPT_ENABLE                    3
+#define     SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE             2
+#define     RESUME_INTERRUPT_ENABLE                             1
+#define     SOF_INTERRUPT_ENABLE                                0
+
+	// offset 0x0020
+	u32		_unused1;
+	u32		usbirqenb1;
+#define     USB_INTERRUPT_ENABLE                                31
+#define     POWER_STATE_CHANGE_INTERRUPT_ENABLE                 27
+#define     PCI_ARBITER_TIMEOUT_INTERRUPT_ENABLE                26
+#define     PCI_PARITY_ERROR_INTERRUPT_ENABLE                   25
+#define     PCI_INTA_INTERRUPT_ENABLE                           24
+#define     PCI_PME_INTERRUPT_ENABLE                            23
+#define     PCI_SERR_INTERRUPT_ENABLE                           22
+#define     PCI_PERR_INTERRUPT_ENABLE                           21
+#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT_ENABLE          20
+#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT_ENABLE          19
+#define     PCI_RETRY_ABORT_INTERRUPT_ENABLE                    17
+#define     PCI_MASTER_CYCLE_DONE_INTERRUPT_ENABLE              16
+#define     GPIO_INTERRUPT_ENABLE                               13
+#define     DMA_D_INTERRUPT_ENABLE                              12
+#define     DMA_C_INTERRUPT_ENABLE                              11
+#define     DMA_B_INTERRUPT_ENABLE                              10
+#define     DMA_A_INTERRUPT_ENABLE                              9
+#define     EEPROM_DONE_INTERRUPT_ENABLE                        8
+#define     VBUS_INTERRUPT_ENABLE                               7
+#define     CONTROL_STATUS_INTERRUPT_ENABLE                     6
+#define     ROOT_PORT_RESET_INTERRUPT_ENABLE                    4
+#define     SUSPEND_REQUEST_INTERRUPT_ENABLE                    3
+#define     SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE             2
+#define     RESUME_INTERRUPT_ENABLE                             1
+#define     SOF_INTERRUPT_ENABLE                                0
+	u32		irqstat0;
+#define     INTA_ASSERTED                                       12
+#define     SETUP_PACKET_INTERRUPT                              7
+#define     ENDPOINT_F_INTERRUPT                                6
+#define     ENDPOINT_E_INTERRUPT                                5
+#define     ENDPOINT_D_INTERRUPT                                4
+#define     ENDPOINT_C_INTERRUPT                                3
+#define     ENDPOINT_B_INTERRUPT                                2
+#define     ENDPOINT_A_INTERRUPT                                1
+#define     ENDPOINT_0_INTERRUPT                                0
+	u32		irqstat1;
+#define     POWER_STATE_CHANGE_INTERRUPT                        27
+#define     PCI_ARBITER_TIMEOUT_INTERRUPT                       26
+#define     PCI_PARITY_ERROR_INTERRUPT                          25
+#define     PCI_INTA_INTERRUPT                                  24
+#define     PCI_PME_INTERRUPT                                   23
+#define     PCI_SERR_INTERRUPT                                  22
+#define     PCI_PERR_INTERRUPT                                  21
+#define     PCI_MASTER_ABORT_RECEIVED_INTERRUPT                 20
+#define     PCI_TARGET_ABORT_RECEIVED_INTERRUPT                 19
+#define     PCI_RETRY_ABORT_INTERRUPT                           17
+#define     PCI_MASTER_CYCLE_DONE_INTERRUPT                     16
+#define     GPIO_INTERRUPT                                      13
+#define     DMA_D_INTERRUPT                                     12
+#define     DMA_C_INTERRUPT                                     11
+#define     DMA_B_INTERRUPT                                     10
+#define     DMA_A_INTERRUPT                                     9
+#define     EEPROM_DONE_INTERRUPT                               8
+#define     VBUS_INTERRUPT                                      7
+#define     CONTROL_STATUS_INTERRUPT                            6
+#define     ROOT_PORT_RESET_INTERRUPT                           4
+#define     SUSPEND_REQUEST_INTERRUPT                           3
+#define     SUSPEND_REQUEST_CHANGE_INTERRUPT                    2
+#define     RESUME_INTERRUPT                                    1
+#define     SOF_INTERRUPT                                       0
+	// offset 0x0030
+	u32		idxaddr;
+	u32		idxdata;
+	u32		fifoctl;
+#define     PCI_BASE2_RANGE                                     16
+#define     IGNORE_FIFO_AVAILABILITY                            3
+#define     PCI_BASE2_SELECT                                    2
+#define     FIFO_CONFIGURATION_SELECT                           0
+	u32		_unused2;
+	// offset 0x0040
+	u32		memaddr;
+#define     START                                               28
+#define     DIRECTION                                           27
+#define     FIFO_DIAGNOSTIC_SELECT                              24
+#define     MEMORY_ADDRESS                                      0
+	u32		memdata0;
+	u32		memdata1;
+	u32		_unused3;
+	// offset 0x0050
+	u32		gpioctl;
+#define     GPIO3_LED_SELECT                                    12
+#define     GPIO3_INTERRUPT_ENABLE                              11
+#define     GPIO2_INTERRUPT_ENABLE                              10
+#define     GPIO1_INTERRUPT_ENABLE                              9
+#define     GPIO0_INTERRUPT_ENABLE                              8
+#define     GPIO3_OUTPUT_ENABLE                                 7
+#define     GPIO2_OUTPUT_ENABLE                                 6
+#define     GPIO1_OUTPUT_ENABLE                                 5
+#define     GPIO0_OUTPUT_ENABLE                                 4
+#define     GPIO3_DATA                                          3
+#define     GPIO2_DATA                                          2
+#define     GPIO1_DATA                                          1
+#define     GPIO0_DATA                                          0
+	u32		gpiostat;
+#define     GPIO3_INTERRUPT                                     3
+#define     GPIO2_INTERRUPT                                     2
+#define     GPIO1_INTERRUPT                                     1
+#define     GPIO0_INTERRUPT                                     0
+} __attribute__ ((packed));
+
+/* usb control, BAR0 + 0x0080 */
+struct net2280_usb_regs {
+	// offset 0x0080
+	u32		stdrsp;
+#define     STALL_UNSUPPORTED_REQUESTS                          31
+#define     SET_TEST_MODE                                       16
+#define     GET_OTHER_SPEED_CONFIGURATION                       15
+#define     GET_DEVICE_QUALIFIER                                14
+#define     SET_ADDRESS                                         13
+#define     ENDPOINT_SET_CLEAR_HALT                             12
+#define     DEVICE_SET_CLEAR_DEVICE_REMOTE_WAKEUP               11
+#define     GET_STRING_DESCRIPTOR_2                             10
+#define     GET_STRING_DESCRIPTOR_1                             9
+#define     GET_STRING_DESCRIPTOR_0                             8
+#define     GET_SET_INTERFACE                                   6
+#define     GET_SET_CONFIGURATION                               5
+#define     GET_CONFIGURATION_DESCRIPTOR                        4
+#define     GET_DEVICE_DESCRIPTOR                               3
+#define     GET_ENDPOINT_STATUS                                 2
+#define     GET_INTERFACE_STATUS                                1
+#define     GET_DEVICE_STATUS                                   0
+	u32		prodvendid;
+#define     PRODUCT_ID                                          16
+#define     VENDOR_ID                                           0
+	u32		relnum;
+	u32		usbctl;
+#define     SERIAL_NUMBER_INDEX                                 16
+#define     PRODUCT_ID_STRING_ENABLE                            13
+#define     VENDOR_ID_STRING_ENABLE                             12
+#define     USB_ROOT_PORT_WAKEUP_ENABLE                         11
+#define     VBUS_PIN                                            10
+#define     TIMED_DISCONNECT                                    9
+#define     SUSPEND_IMMEDIATELY                                 7
+#define     SELF_POWERED_USB_DEVICE                             6
+#define     REMOTE_WAKEUP_SUPPORT                               5
+#define     PME_POLARITY                                        4
+#define     USB_DETECT_ENABLE                                   3
+#define     PME_WAKEUP_ENABLE                                   2
+#define     DEVICE_REMOTE_WAKEUP_ENABLE                         1
+#define     SELF_POWERED_STATUS                                 0
+	// offset 0x0090
+	u32		usbstat;
+#define     HIGH_SPEED                                          7
+#define     FULL_SPEED                                          6
+#define     GENERATE_RESUME                                     5
+#define     GENERATE_DEVICE_REMOTE_WAKEUP                       4
+	u32		xcvrdiag;
+#define     FORCE_HIGH_SPEED_MODE                               31
+#define     FORCE_FULL_SPEED_MODE                               30
+#define     USB_TEST_MODE                                       24
+#define     LINE_STATE                                          16
+#define     TRANSCEIVER_OPERATION_MODE                          2
+#define     TRANSCEIVER_SELECT                                  1
+#define     TERMINATION_SELECT                                  0
+	u32		setup0123;
+	u32		setup4567;
+	// offset 0x0090
+	u32		_unused0;
+	u32		ouraddr;
+#define     FORCE_IMMEDIATE                                     7
+#define     OUR_USB_ADDRESS                                     0
+	u32		ourconfig;
+} __attribute__ ((packed));
+
+/* pci control, BAR0 + 0x0100 */
+struct net2280_pci_regs {
+	// offset 0x0100
+	u32		 pcimstctl;
+#define     PCI_ARBITER_PARK_SELECT                             13
+#define     PCI_MULTI LEVEL_ARBITER                             12
+#define     PCI_RETRY_ABORT_ENABLE                              11
+#define     DMA_MEMORY_WRITE_AND_INVALIDATE_ENABLE              10
+#define     DMA_READ_MULTIPLE_ENABLE                            9
+#define     DMA_READ_LINE_ENABLE                                8
+#define     PCI_MASTER_COMMAND_SELECT                           6
+#define         MEM_READ_OR_WRITE                                   0
+#define         IO_READ_OR_WRITE                                    1
+#define         CFG_READ_OR_WRITE                                   2
+#define     PCI_MASTER_START                                    5
+#define     PCI_MASTER_READ_WRITE                               4
+#define         PCI_MASTER_WRITE                                    0
+#define         PCI_MASTER_READ                                     1
+#define     PCI_MASTER_BYTE_WRITE_ENABLES                       0
+	u32		 pcimstaddr;
+	u32		 pcimstdata;
+	u32		 pcimststat;
+#define     PCI_ARBITER_CLEAR                                   2
+#define     PCI_EXTERNAL_ARBITER                                1
+#define     PCI_HOST_MODE                                       0
+} __attribute__ ((packed));
+
+/* dma control, BAR0 + 0x0180 ... array of four structs like this,
+ * for channels 0..3.  see also struct net2280_dma:  descriptor
+ * that can be loaded into some of these registers.
+ */
+struct net2280_dma_regs {	/* [11.7] */
+	// offset 0x0180, 0x01a0, 0x01c0, 0x01e0, 
+	u32		dmactl;
+#define     DMA_SCATTER_GATHER_DONE_INTERRUPT_ENABLE            25
+#define     DMA_CLEAR_COUNT_ENABLE                              21
+#define     DESCRIPTOR_POLLING_RATE                             19
+#define         POLL_CONTINUOUS                                     0
+#define         POLL_1_USEC                                         1
+#define         POLL_100_USEC                                       2
+#define         POLL_1_MSEC                                         3
+#define     DMA_VALID_BIT_POLLING_ENABLE                        18
+#define     DMA_VALID_BIT_ENABLE                                17
+#define     DMA_SCATTER_GATHER_ENABLE                           16
+#define     DMA_OUT_AUTO_START_ENABLE                           4
+#define     DMA_PREEMPT_ENABLE                                  3
+#define     DMA_FIFO_VALIDATE                                   2
+#define     DMA_ENABLE                                          1
+#define     DMA_ADDRESS_HOLD                                    0
+	u32		dmastat;
+#define     DMA_SCATTER_GATHER_DONE_INTERRUPT                   25
+#define     DMA_TRANSACTION_DONE_INTERRUPT                      24
+#define     DMA_ABORT                                           1
+#define     DMA_START                                           0
+	u32		_unused0 [2];
+	// offset 0x0190, 0x01b0, 0x01d0, 0x01f0, 
+	u32		dmacount;
+#define     VALID_BIT                                           31
+#define     DMA_DIRECTION                                       30
+#define     DMA_DONE_INTERRUPT_ENABLE                           29
+#define     END_OF_CHAIN                                        28
+#define         DMA_BYTE_COUNT_MASK                                 ((1<<24)-1)
+#define     DMA_BYTE_COUNT                                      0
+	u32		dmaaddr;
+	u32		dmadesc;
+	u32		_unused1;
+} __attribute__ ((packed));
+
+/* dedicated endpoint registers, BAR0 + 0x0200 */
+
+struct net2280_dep_regs {	/* [11.8] */
+	// offset 0x0200, 0x0210, 0x220, 0x230, 0x240
+	u32		dep_cfg;
+	// offset 0x0204, 0x0214, 0x224, 0x234, 0x244
+	u32		dep_rsp;
+	u32		_unused [2];
+} __attribute__ ((packed));
+
+/* configurable endpoint registers, BAR0 + 0x0300 ... array of seven structs
+ * like this, for ep0 then the configurable endpoints A..F
+ * ep0 reserved for control; E and F have only 64 bytes of fifo
+ */
+struct net2280_ep_regs {	/* [11.9] */
+	// offset 0x0300, 0x0320, 0x0340, 0x0360, 0x0380, 0x03a0, 0x03c0
+	u32		ep_cfg;
+#define     ENDPOINT_BYTE_COUNT                                 16
+#define     ENDPOINT_ENABLE                                     10
+#define     ENDPOINT_TYPE                                       8
+#define     ENDPOINT_DIRECTION                                  7
+#define     ENDPOINT_NUMBER                                     0
+	u32		ep_rsp;
+#define     SET_NAK_OUT_PACKETS                                 15
+#define     SET_EP_HIDE_STATUS_PHASE                            14
+#define     SET_INTERRUPT_MODE                                  12
+#define     SET_CONTROL_STATUS_PHASE_HANDSHAKE                  11
+#define     SET_NAK_OUT_PACKETS_MODE                            10
+#define     SET_ENDPOINT_TOGGLE                                 9
+#define     SET_ENDPOINT_HALT                                   8
+#define     CLEAR_NAK_OUT_PACKETS                               7
+#define     CLEAR_EP_HIDE_STATUS_PHASE                          6
+#define     CLEAR_INTERRUPT_MODE                                4
+#define     CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE                3
+#define     CLEAR_NAK_OUT_PACKETS_MODE                          2
+#define     CLEAR_ENDPOINT_TOGGLE                               1
+#define     CLEAR_ENDPOINT_HALT                                 0
+	u32		ep_irqenb;
+#define     SHORT_PACKET_OUT_DONE_INTERRUPT_ENABLE              6
+#define     SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE           5
+#define     DATA_PACKET_RECEIVED_INTERRUPT_ENABLE               3
+#define     DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE            2
+#define     DATA_OUT_PING_TOKEN_INTERRUPT_ENABLE                1
+#define     DATA_IN_TOKEN_INTERRUPT_ENABLE                      0
+	u32		ep_stat;
+#define     FIFO_VALID_COUNT                                    24
+#define     HIGH_BANDWIDTH_OUT_TRANSACTION_PID                  22
+#define     TIMEOUT                                             21
+#define     USB_STALL_SENT                                      20
+#define     USB_IN_NAK_SENT                                     19
+#define     USB_IN_ACK_RCVD                                     18
+#define     USB_OUT_PING_NAK_SENT                               17
+#define     USB_OUT_ACK_SENT                                    16
+#define     FIFO_OVERFLOW                                       13
+#define     FIFO_UNDERFLOW                                      12
+#define     FIFO_FULL                                           11
+#define     FIFO_EMPTY                                          10
+#define     FIFO_FLUSH                                          9
+#define     SHORT_PACKET_OUT_DONE_INTERRUPT                     6
+#define     SHORT_PACKET_TRANSFERRED_INTERRUPT                  5
+#define     NAK_OUT_PACKETS                                     4
+#define     DATA_PACKET_RECEIVED_INTERRUPT                      3
+#define     DATA_PACKET_TRANSMITTED_INTERRUPT                   2
+#define     DATA_OUT_PING_TOKEN_INTERRUPT                       1
+#define     DATA_IN_TOKEN_INTERRUPT                             0
+	// offset 0x0310, 0x0330, 0x0350, 0x0370, 0x0390, 0x03b0, 0x03d0
+	u32		ep_avail;
+	u32		ep_data;
+	u32		_unused0 [2];
+} __attribute__ ((packed));
+
+/*-------------------------------------------------------------------------*/
+
+/* indexed registers [11.10] are accessed indirectly
+ * caller must own the device lock.
+ */
+
+static inline u32
+get_idx_reg (struct net2280_regs *regs, u32 index)
+{
+	writel (index, &regs->idxaddr);
+	/* NOTE:  synchs device/cpu memory views */
+	return readl (&regs->idxdata);
+}
+
+static inline void
+set_idx_reg (struct net2280_regs *regs, u32 index, u32 value)
+{
+	writel (index, &regs->idxaddr);
+	writel (value, &regs->idxdata);
+	/* posted, may not be visible yet */
+}
+
+#define REG_DIAG		0x0
+#define     RETRY_COUNTER                                       16
+#define     FORCE_PCI_SERR                                      11
+#define     FORCE_PCI_INTERRUPT                                 10
+#define     FORCE_USB_INTERRUPT                                 9
+#define     FORCE_CPU_INTERRUPT                                 8
+#define     ILLEGAL_BYTE_ENABLES                                5
+#define     FAST_TIMES                                          4
+#define     FORCE_RECEIVE_ERROR                                 2
+#define     FORCE_TRANSMIT_CRC_ERROR                            0
+#define REG_FRAME		0x02	/* from last sof */
+#define REG_CHIPREV		0x03	/* in bcd */
+#define	REG_HS_NAK_RATE		0x0a	/* NAK per N uframes */
+
+/* ep a-f highspeed and fullspeed maxpacket, addresses
+ * computed from ep->num
+ */
+#define REG_EP_MAXPKT(dev,num) (((num) + 1) * 0x10 + \
+		(((dev)->gadget.speed == USB_SPEED_HIGH) ? 0 : 1))
+
+/*-------------------------------------------------------------------------*/
+
+/* [8.3] for scatter/gather i/o
+ * use struct net2280_dma_regs bitfields
+ */
+struct net2280_dma {
+	u32		dmacount;
+	u32		dmaaddr;		/* the buffer */
+	u32		dmadesc;		/* next dma descriptor */
+	u32		_reserved;
+} __attribute__ ((aligned (16)));
+
+/*-------------------------------------------------------------------------*/
+
+/* DRIVER DATA STRUCTURES and UTILITIES */
+
+struct net2280_ep {
+	struct usb_ep				ep;
+	struct net2280_ep_regs			*regs;
+	struct net2280_dma_regs			*dma;
+	struct net2280_dma			*dummy;
+	dma_addr_t				td_dma;	/* of dummy */
+	struct net2280				*dev;
+	unsigned long				irqs;
+
+	/* analogous to a host-side qh */
+	struct list_head			queue;
+	const struct usb_endpoint_descriptor	*desc;
+	unsigned				num : 8,
+						fifo_size : 12,
+						in_fifo_validate : 1,
+						stopped : 1,
+						is_in : 1,
+						is_iso : 1;
+};
+
+static inline void allow_status (struct net2280_ep *ep)
+{
+	/* ep0 only */
+	writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+		| (1 << CLEAR_NAK_OUT_PACKETS_MODE)
+		, &ep->regs->ep_rsp);
+}
+
+static inline void set_halt (struct net2280_ep *ep)
+{
+	/* ep0 and bulk/intr endpoints */
+	writel (  (1 << CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE)
+		    /* set NAK_OUT for erratum 0114 */
+		| (1 << SET_NAK_OUT_PACKETS)
+		| (1 << SET_ENDPOINT_HALT)
+		, &ep->regs->ep_rsp);
+}
+
+static inline void clear_halt (struct net2280_ep *ep)
+{
+	/* bulk/intr endpoints */
+	writel (  (1 << CLEAR_ENDPOINT_HALT)
+		| (1 << CLEAR_ENDPOINT_TOGGLE)
+		, &ep->regs->ep_rsp);
+}
+
+/* count (<= 4) bytes in the next fifo write will be valid */
+static inline void set_fifo_bytecount (struct net2280_ep *ep, unsigned count)
+{
+	writeb (count, 2 + (u8 *) &ep->regs->ep_cfg);
+}
+
+struct net2280_request {
+	struct usb_request		req;
+	struct net2280_dma		*td;
+	dma_addr_t			td_dma;
+	struct list_head		queue;
+	unsigned			mapped : 1,
+					dma_done : 1,
+					valid : 1;
+};
+
+struct net2280 {
+	/* each pci device provides one gadget, several endpoints */
+	struct usb_gadget		gadget;
+	spinlock_t			lock;
+	struct net2280_ep		ep [7];
+	struct usb_gadget_driver 	*driver;
+	unsigned			enabled : 1,
+					protocol_stall : 1,
+					got_irq : 1,
+					region : 1,
+					selfpowered : 1;
+	u16				chiprev;
+
+	/* pci state used to access those endpoints */
+	struct pci_dev			*pdev;
+	struct net2280_regs		*regs;
+	struct net2280_usb_regs		*usb;
+	struct net2280_pci_regs		*pci;
+	struct net2280_dma_regs		*dma;
+	struct net2280_dep_regs		*dep;
+	struct net2280_ep_regs		*epregs;
+
+	struct pci_pool			*requests;
+	// statistics...
+};
+
+#ifdef USE_RDK_LEDS
+
+static inline void net2280_led_init (struct net2280 *dev)
+{
+	/* LED3 (green) is on during USB activity. note erratum 0113. */
+	writel ((1 << GPIO3_LED_SELECT)
+		| (1 << GPIO3_OUTPUT_ENABLE)
+		| (1 << GPIO2_OUTPUT_ENABLE)
+		| (1 << GPIO1_OUTPUT_ENABLE)
+		| (1 << GPIO0_OUTPUT_ENABLE)
+		, &dev->regs->gpioctl);
+}
+
+/* indicate speed with bi-color LED 0/1 */
+static inline
+void net2280_led_speed (struct net2280 *dev, enum usb_device_speed speed)
+{
+	u32	val = readl (&dev->regs->gpioctl);
+	switch (speed) {
+	case USB_SPEED_HIGH:		/* green */
+		val &= ~(1 << GPIO0_DATA);
+		val |= (1 << GPIO1_DATA);
+		break;
+	case USB_SPEED_FULL:		/* red */
+		val &= ~(1 << GPIO1_DATA);
+		val |= (1 << GPIO0_DATA);
+		break;
+	default:			/* (off/black) */
+		val &= ~((1 << GPIO1_DATA) | (1 << GPIO0_DATA));
+		break;
+	}
+	writel (val, &dev->regs->gpioctl);
+}
+
+/* indicate power with LED 2 */
+static inline void net2280_led_active (struct net2280 *dev, int is_active)
+{
+	u32	val = readl (&dev->regs->gpioctl);
+
+	// FIXME this LED never seems to turn on.
+	if (is_active)
+		val |= GPIO2_DATA;
+	else
+		val &= ~GPIO2_DATA;
+	writel (val, &dev->regs->gpioctl);
+}
+static inline void net2280_led_shutdown (struct net2280 *dev)
+{
+	/* turn off all four GPIO*_DATA bits */
+	writel (readl (&dev->regs->gpioctl) & ~0x0f,
+			&dev->regs->gpioctl);
+}
+
+#else
+
+#define net2280_led_init(dev)		do { } while (0)
+#define net2280_led_speed(dev, speed)	do { } while (0)
+#define net2280_led_shutdown(dev)	do { } while (0)
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#define xprintk(dev,level,fmt,args...) \
+	printk(level "%s %s: " fmt , driver_name , \
+			dev->pdev->slot_name , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(dev,fmt,args...) \
+	xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DEBUG(dev,fmt,args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDEBUG DEBUG
+#else
+#define VDEBUG(dev,fmt,args...) \
+	do { } while (0)
+#endif	/* VERBOSE */
+
+#define ERROR(dev,fmt,args...) \
+	xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+	xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+	xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+static inline void start_out_naking (struct net2280_ep *ep)
+{
+	/* NOTE:  hardware races lurk here, and PING protocol issues */
+	writel ((1 << SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+	/* synch with device */
+	readl (&ep->regs->ep_rsp);
+}
+
+#ifdef DEBUG
+static inline void assert_out_naking (struct net2280_ep *ep, const char *where)
+{
+	u32	tmp = readl (&ep->regs->ep_stat);
+
+	if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) {
+		DEBUG (ep->dev, "%s %s %08x !NAK\n",
+				ep->ep.name, where, tmp);
+		writel ((1 << SET_NAK_OUT_PACKETS),
+			&ep->regs->ep_rsp);
+	}
+}
+#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep,__FUNCTION__)
+#else
+#define ASSERT_OUT_NAKING(ep) do {} while (0)
+#endif
+
+static inline void stop_out_naking (struct net2280_ep *ep)
+{
+	u32	tmp;
+
+	tmp = readl (&ep->regs->ep_stat);
+	if ((tmp & (1 << NAK_OUT_PACKETS)) != 0)
+		writel ((1 << CLEAR_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+}
+
diff -Nru a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/usbstring.c	Thu May  8 04:25:02 2003
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2003 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/string.h>
+#include <linux/device.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+
+/**
+ * usb_gadget_get_string - fill out a string descriptor 
+ * @table: of c strings using iso latin/1 characters
+ * @id: string id, from low byte of wValue in get string descriptor
+ * @buf: at least 256 bytes
+ *
+ * Finds the iso latin/1 string matching the ID, and converts it into a
+ * string descriptor in utf16-le.
+ * Returns length of descriptor (always even) or negative errno
+ *
+ * If your driver needs stings in multiple languages, you'll need to
+ * to use some alternate solution for languages where the ISO 8859/1
+ * (latin/1) character set can't be used.  For example, they can't be
+ * used with Chinese (Big5, GB2312, etc), Japanese, Korean, or many other
+ * languages.  You'd likely "switch (wIndex) { ... }"  in your ep0
+ * string descriptor logic, using this routine in cases where "western
+ * european" characters suffice for the strings being returned.
+ */
+int
+usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
+{
+	struct usb_string	*s;
+	int			len;
+
+	/* descriptor 0 has the language id */
+	if (id == 0) {
+		buf [0] = 4;
+		buf [1] = USB_DT_STRING;
+		buf [2] = (u8) table->language;
+		buf [3] = (u8) (table->language >> 8);
+		return 4;
+	}
+	for (s = table->strings; s && s->s; s++)
+		if (s->id == id)
+			break;
+
+	/* unrecognized: stall. */
+	if (!s || !s->s)
+		return -EINVAL;
+
+	/* string descriptors have length, tag, then UTF16-LE text */
+	len = min ((size_t) 126, strlen (s->s));
+	buf [0] = (len + 1) * 2;
+	buf [1] = USB_DT_STRING;
+	memset (buf + 2, 0, 2 * len);	/* zero all the high bytes */
+	while (len) {
+		buf [2 * len] = s->s [len - 1];
+		len--;
+	}
+	return buf [0];
+}
+
diff -Nru a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/drivers/usb/gadget/zero.c	Sun May 11 11:12:52 2003
@@ -0,0 +1,1223 @@
+/*
+ * zero.c -- Gadget Zero, for USB development
+ *
+ * Copyright (C) 2003 David Brownell
+ * 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. 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 names of the above-listed copyright holders 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 General Public License ("GPL") as published by the Free Software
+ * Foundation, either version 2 of that License or (at your option) any
+ * later version.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
+ */
+
+
+/*
+ * Gadget Zero only needs two bulk endpoints, and is an example of how you
+ * can write a hardware-agnostic gadget driver running inside a USB device.
+ *
+ * Hardware details are visible (see CONFIG_USB_ZERO_* below) but don't
+ * affect most of the driver.
+ *
+ * Use it with the Linux host/master side "usbtest" driver to get a basic
+ * functional test of your device-side usb stack, or with "usb-skeleton".
+ *
+ * It supports two similar configurations.  One sinks whatever the usb host
+ * writes, and in return sources zeroes.  The other loops whatever the host
+ * writes back, so the host can read it.  Module options include:
+ *
+ *   buflen=N		default N=4096, buffer size used
+ *   qlen=N		default N=32, how many buffers in the loopback queue
+ *   loopdefault	default false, list loopback config first
+ *
+ * Many drivers will only have one configuration, letting them be much
+ * simpler if they also don't support high speed operation (like this
+ * driver does).
+ */
+
+#define DEBUG 1
+// #define VERBOSE
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/uts.h>
+#include <linux/version.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include <linux/usb_ch9.h>
+#include <linux/usb_gadget.h>
+
+
+/*-------------------------------------------------------------------------*/
+
+#define DRIVER_VERSION		"19 Feb 2003"
+
+static const char shortname [] = "zero";
+static const char longname [] = "Gadget Zero";
+
+static const char source_sink [] = "source and sink data";
+static const char loopback [] = "loop input to output";
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * hardware-specific configuration, controlled by which device
+ * controller driver was configured.
+ *
+ * CHIP ... hardware identifier
+ * DRIVER_VERSION_NUM ... alerts the host side driver to differences
+ * EP0_MAXPACKET ... controls packetization of control requests
+ * EP_*_NAME ... which endpoints do we use for which purpose?
+ * EP_*_NUM ... numbers for them (often limited by hardware)
+ * HIGHSPEED ... define if ep0 and descriptors need high speed support
+ * MAX_USB_POWER ... define if we use other than 100 mA bus current
+ * SELFPOWER ... unless we can run on bus power, USB_CONFIG_ATT_SELFPOWER
+ * WAKEUP ... if hardware supports remote wakeup AND we will issue the
+ * 	usb_gadget_wakeup() call to initiate it, USB_CONFIG_ATT_WAKEUP
+ *
+ * hw_optimize(gadget) ... for any hardware tweaks we want to kick in
+ * 	before we enable our endpoints
+ *
+ * add other defines for other portability issues, like hardware that
+ * for some reason doesn't handle full speed bulk maxpacket of 64.
+ */
+
+/*
+ * DRIVER_VERSION_NUM 0x0000 (?):  Martin Diehl's ezusb an21/fx code
+ */
+
+/*
+ * NetChip 2280, PCI based.
+ *
+ * This has half a dozen configurable endpoints, four with dedicated
+ * DMA channels to manage their FIFOs.  It supports high speed.
+ * Those endpoints can be arranged in any desired configuration.
+ */
+#ifdef	CONFIG_USB_ZERO_NET2280
+#define CHIP			"net2280"
+#define DRIVER_VERSION_NUM	0x0101
+#define EP0_MAXPACKET		64
+static const char EP_OUT_NAME [] = "ep-a";
+#define EP_OUT_NUM	2
+static const char EP_IN_NAME [] = "ep-b";
+#define EP_IN_NUM	2
+#define HIGHSPEED
+/* specific hardware configs could be bus-powered */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* supports remote wakeup, but this driver doesn't */
+
+extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
+
+static inline void hw_optimize (struct usb_gadget *gadget)
+{
+	/* we can have bigger ep-a/ep-b fifos (2KB each, 4 packets
+	 * for highspeed bulk) because we're not using ep-c/ep-d.
+	 */
+	net2280_set_fifo_mode (gadget, 1);
+}
+#endif
+
+/*
+ * PXA-250 UDC:  widely used in second gen Linux-capable PDAs.
+ *
+ * This has fifteen fixed-function full speed endpoints, and it
+ * can support all USB transfer types.
+ *
+ * It only supports three configurations (numbered 1, 2, or 3)
+ * with two interfaces each ... there's partial hardware support
+ * for set_configuration and set_interface, preventing some more
+ * interesting config/interface/endpoint arrangements.
+ */
+#ifdef	CONFIG_USB_ZERO_PXA250
+#define CHIP			"pxa250"
+#define DRIVER_VERSION_NUM	0x0103
+#define EP0_MAXPACKET		16
+static const char EP_OUT_NAME [] = "ep12out-bulk";
+#define EP_OUT_NUM	12
+static const char EP_IN_NAME [] = "ep11in-bulk";
+#define EP_IN_NUM	11
+/* doesn't support bus-powered operation */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* supports remote wakeup, but this driver doesn't */
+
+/* no hw optimizations to apply */
+#define hw_optimize(g) do {} while (0);
+#endif
+
+/*
+ * SA-1100 UDC:  widely used in first gen Linux-capable PDAs.
+ *
+ * This has only two fixed function endpoints, which can only
+ * be used for bulk (or interrupt) transfers.  (Plus control.)
+ *
+ * Since it can't flush its TX fifos without disabling the UDC,
+ * the current configuration or altsettings can't change except
+ * in special situations.  So this is a case of "choose it right
+ * during enumeration" ...
+ */
+#ifdef	CONFIG_USB_ZERO_SA1100
+#define CHIP			"sa1100"
+#define DRIVER_VERSION_NUM	0x0105
+#define EP0_MAXPACKET		8
+static const char EP_OUT_NAME [] = "ep1out-bulk";
+#define EP_OUT_NUM	1
+static const char EP_IN_NAME [] = "ep2in-bulk";
+#define EP_IN_NUM	2
+/* doesn't support bus-powered operation */
+#define SELFPOWER USB_CONFIG_ATT_SELFPOWER
+/* doesn't support remote wakeup? */
+
+/* no hw optimizations to apply */
+#define hw_optimize(g) do {} while (0);
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+#ifndef EP0_MAXPACKET
+#	error Configure some USB peripheral controller driver!
+#endif
+
+/* power usage is config specific.
+ * hardware that supports remote wakeup defaults to disabling it.
+ */
+
+#ifndef	SELFPOWER
+/* default: say we rely on bus power */
+#define SELFPOWER	0
+/* else:
+ * - SELFPOWER value must be USB_CONFIG_ATT_SELFPOWER
+ * - MAX_USB_POWER may be nonzero.
+ */
+#endif
+
+#ifndef	MAX_USB_POWER
+/* any hub supports this steady state bus power consumption */
+#define MAX_USB_POWER	100	/* mA */
+#endif
+
+#ifndef	WAKEUP
+/* default: this driver won't do remote wakeup */
+#define WAKEUP		0
+/* else value must be USB_CONFIG_ATT_WAKEUP */
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* big enough to hold our biggest descriptor */
+#define USB_BUFSIZ	256
+
+struct zero_dev {
+	spinlock_t		lock;
+	struct usb_gadget	*gadget;
+	struct usb_request	*req;		/* for control responses */
+
+	/* when configured, we have one of two configs:
+	 * - source data (in to host) and sink it (out from host)
+	 * - or loop it back (out from host back in to host)
+	 */
+	u8			config;
+	struct usb_ep		*in_ep, *out_ep;
+};
+
+#define xprintk(d,level,fmt,args...) \
+	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
+
+#ifdef DEBUG
+#undef DEBUG
+#define DEBUG(dev,fmt,args...) \
+	xprintk(dev , KERN_DEBUG , fmt , ## args)
+#else
+#define DEBUG(dev,fmt,args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#ifdef VERBOSE
+#define VDEBUG	DEBUG
+#else
+#define VDEBUG(dev,fmt,args...) \
+	do { } while (0)
+#endif /* DEBUG */
+
+#define ERROR(dev,fmt,args...) \
+	xprintk(dev , KERN_ERR , fmt , ## args)
+#define WARN(dev,fmt,args...) \
+	xprintk(dev , KERN_WARNING , fmt , ## args)
+#define INFO(dev,fmt,args...) \
+	xprintk(dev , KERN_INFO , fmt , ## args)
+
+/*-------------------------------------------------------------------------*/
+
+static unsigned buflen = 4096;
+static unsigned qlen = 32;
+
+module_param (buflen, uint, S_IRUGO|S_IWUSR);
+module_param (qlen, uint, S_IRUGO|S_IWUSR);
+
+/*
+ * Normally the "loopback" configuration is second (index 1) so
+ * it's not the default.  Here's where to change that order, to
+ * work better with hosts (like Linux ... for now!) where config
+ * changes are problematic.
+ */
+static int loopdefault = 0;
+
+module_param (loopdefault, bool, S_IRUGO|S_IWUSR);
+
+/*-------------------------------------------------------------------------*/
+
+/* Thanks to NetChip Technologies for donating this product ID.
+ *
+ * DO NOT REUSE THESE IDs with any other driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define DRIVER_VENDOR_NUM	0x0525		/* NetChip */
+#define DRIVER_PRODUCT_NUM	0xa4a0		/* Linux-USB "Gadget Zero" */
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DESCRIPTORS ... most are static, but strings and (full)
+ * configuration descriptors are built on demand.
+ */
+
+#define STRING_MANUFACTURER		25
+#define STRING_PRODUCT			42
+#define STRING_SERIAL			101
+#define STRING_SOURCE_SINK		250
+#define STRING_LOOPBACK			251
+
+/*
+ * This device advertises two configurations; these numbers work
+ * on a pxa250 as well as more flexible hardware.
+ */
+#define	CONFIG_SOURCE_SINK	3
+#define	CONFIG_LOOPBACK		2
+
+static const struct usb_device_descriptor
+device_desc = {
+	.bLength =		sizeof device_desc,
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
+	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,
+	.bMaxPacketSize0 =	EP0_MAXPACKET,
+
+	.idVendor =		__constant_cpu_to_le16 (DRIVER_VENDOR_NUM),
+	.idProduct =		__constant_cpu_to_le16 (DRIVER_PRODUCT_NUM),
+	.bcdDevice =		__constant_cpu_to_le16 (DRIVER_VERSION_NUM),
+	.iManufacturer =	STRING_MANUFACTURER,
+	.iProduct =		STRING_PRODUCT,
+	.iSerialNumber =	STRING_SERIAL,
+	.bNumConfigurations =	2,
+};
+
+static const struct usb_config_descriptor
+source_sink_config = {
+	.bLength =		sizeof source_sink_config,
+	.bDescriptorType =	USB_DT_CONFIG,
+
+	/* compute wTotalLength on the fly */
+	.bNumInterfaces =	1,
+	.bConfigurationValue =	CONFIG_SOURCE_SINK,
+	.iConfiguration =	STRING_SOURCE_SINK,
+	.bmAttributes =		USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
+	.bMaxPower =		(MAX_USB_POWER + 1) / 2,
+};
+
+static const struct usb_config_descriptor
+loopback_config = {
+	.bLength =		sizeof loopback_config,
+	.bDescriptorType =	USB_DT_CONFIG,
+
+	/* compute wTotalLength on the fly */
+	.bNumInterfaces =	1,
+	.bConfigurationValue =	CONFIG_LOOPBACK,
+	.iConfiguration =	STRING_LOOPBACK,
+	.bmAttributes =		USB_CONFIG_ATT_ONE | SELFPOWER | WAKEUP,
+	.bMaxPower =		(MAX_USB_POWER + 1) / 2,
+};
+
+/* one interface in each configuration */
+
+static const struct usb_interface_descriptor
+source_sink_intf = {
+	.bLength =		sizeof source_sink_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
+	.iInterface =		STRING_SOURCE_SINK,
+};
+
+static const struct usb_interface_descriptor
+loopback_intf = {
+	.bLength =		sizeof loopback_intf,
+	.bDescriptorType =	USB_DT_INTERFACE,
+
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
+	.iInterface =		STRING_LOOPBACK,
+};
+
+/* two full speed bulk endpoints; their use is config-dependent */
+
+static const struct usb_endpoint_descriptor
+fs_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_IN_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
+};
+
+static const struct usb_endpoint_descriptor
+fs_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_OUT_NUM,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (64),
+};
+
+#ifdef	HIGHSPEED
+
+/*
+ * usb 2.0 devices need to expose both high speed and full speed
+ * descriptors, unless they only run at full speed.
+ *
+ * that means alternate endpoint descriptors (bigger packets)
+ * and a "device qualifier" ... plus more construction options
+ * for the config descriptor.
+ */
+
+static const struct usb_endpoint_descriptor
+hs_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_IN_NUM | USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (512),
+};
+
+static const struct usb_endpoint_descriptor
+hs_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	EP_OUT_NUM,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	__constant_cpu_to_le16 (512),
+};
+
+static const struct usb_qualifier_descriptor
+dev_qualifier = {
+	.bLength =		sizeof dev_qualifier,
+	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
+
+	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
+	.bDeviceClass =		USB_CLASS_VENDOR_SPEC,
+
+	/* assumes ep0 uses the same value for both speeds ... */
+	.bMaxPacketSize0 =	EP0_MAXPACKET,
+
+	.bNumConfigurations =	2,
+};
+
+/* maxpacket and other transfer characteristics vary by speed. */
+#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
+
+#else
+
+/* if there's no high speed support, maxpacket doesn't change. */
+#define ep_desc(g,hs,fs) fs
+
+#endif	/* !HIGHSPEED */
+
+static char				serial [40];
+
+/* static strings, in iso 8859/1 */
+static struct usb_string		strings [] = {
+	{ STRING_MANUFACTURER, UTS_SYSNAME " " UTS_RELEASE " with " CHIP, },
+	{ STRING_PRODUCT, longname, },
+	{ STRING_SERIAL, serial, },
+	{ STRING_LOOPBACK, loopback, },
+	{ STRING_SOURCE_SINK, source_sink, },
+	{  }			/* end of list */
+};
+
+static struct usb_gadget_strings	stringtab = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= strings,
+};
+
+/*
+ * config descriptors are also handcrafted.  these must agree with code
+ * that sets configurations, and with code managing interface altsettings.
+ * other complexity may come from:
+ *
+ *  - high speed support, including "other speed config" rules
+ *  - multiple configurations
+ *  - interfaces with alternate settings
+ *  - embedded class or vendor-specific descriptors
+ *
+ * this handles high speed, and has a second config that could as easily
+ * have been an alternate interface setting.
+ *
+ * NOTE:  to demonstrate (and test) more USB capabilities, this driver
+ * should include an altsetting to test interrupt transfers, including
+ * high bandwidth modes at high speed.  (Maybe work like Intel's test
+ * device?)
+ */
+static int
+config_buf (enum usb_device_speed speed,
+		u8 *buf, u8 type, unsigned index)
+{
+	int		is_source_sink;
+	const unsigned	config_len = USB_DT_CONFIG_SIZE
+				+ USB_DT_INTERFACE_SIZE
+				+ 2 * USB_DT_ENDPOINT_SIZE;
+#ifdef HIGHSPEED
+	int		hs;
+#endif
+	/* two configurations will always be index 0 and index 1 */
+	if (index > 1)
+		return -EINVAL;
+	if (config_len > USB_BUFSIZ)
+		return -EDOM;
+	is_source_sink = loopdefault ? (index == 1) : (index == 0);
+
+	/* config (or other speed config) */
+	if (is_source_sink)
+		memcpy (buf, &source_sink_config, USB_DT_CONFIG_SIZE);
+	else
+		memcpy (buf, &loopback_config, USB_DT_CONFIG_SIZE);
+	buf [1] = type;
+	((struct usb_config_descriptor *) buf)->wTotalLength
+		= __constant_cpu_to_le16 (config_len);
+	buf += USB_DT_CONFIG_SIZE;
+
+	/* one interface */
+	if (is_source_sink)
+		memcpy (buf, &source_sink_intf, USB_DT_INTERFACE_SIZE);
+	else
+		memcpy (buf, &loopback_intf, USB_DT_INTERFACE_SIZE);
+	buf += USB_DT_INTERFACE_SIZE;
+
+	/* the endpoints in that interface (at that speed) */
+#ifdef HIGHSPEED
+	hs = (speed == USB_SPEED_HIGH);
+	if (type == USB_DT_OTHER_SPEED_CONFIG)
+		hs = !hs;
+	if (hs) {
+		memcpy (buf, &hs_source_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+		memcpy (buf, &hs_sink_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+	} else
+#endif
+	{
+		memcpy (buf, &fs_source_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+		memcpy (buf, &fs_sink_desc, USB_DT_ENDPOINT_SIZE);
+		buf += USB_DT_ENDPOINT_SIZE;
+	}
+
+	return config_len;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_request *
+alloc_ep_req (struct usb_ep *ep, unsigned length)
+{
+	struct usb_request	*req;
+
+	req = usb_ep_alloc_request (ep, GFP_ATOMIC);
+	if (req) {
+		req->length = length;
+		req->buf = usb_ep_alloc_buffer (ep, length,
+				&req->dma, GFP_ATOMIC);
+		if (!req->buf) {
+			usb_ep_free_request (ep, req);
+			req = 0;
+		}
+	}
+	return req;
+}
+
+static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->buf)
+		usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
+	usb_ep_free_request (ep, req);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* optionally require specific source/sink data patterns  */
+
+static inline int
+check_read_data (
+	struct zero_dev		*dev,
+	struct usb_ep		*ep,
+	struct usb_request	*req
+)
+{
+	int i;
+
+	for (i = 0; i < req->actual; i++) {
+		if (((u8 *)req->buf) [i] != 0) {
+			ERROR (dev, "nonzero OUT byte from host, "
+					"buf [%d] = %d\n",
+					i, ((u8 *)req->buf) [i]);
+			usb_ep_set_halt (ep);
+			return -EINVAL;
+		}
+	}
+	return 0;
+}
+
+static inline void
+reinit_write_data (
+	struct zero_dev		*dev,
+	struct usb_ep		*ep,
+	struct usb_request	*req
+)
+{
+	memset (req->buf, 0, req->length);
+}
+
+/* if there is only one request in the queue, there'll always be an
+ * irq delay between end of one request and start of the next.
+ * that prevents using hardware dma queues.
+ */
+static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
+{
+	struct zero_dev	*dev = ep->driver_data;
+	int		status = req->status;
+
+	switch (status) {
+
+	case 0: 			/* normal completion? */
+		if (ep == dev->out_ep)
+			check_read_data (dev, ep, req);
+		else
+			reinit_write_data (dev, ep, req);
+		break;
+
+	/* this endpoint is normally active while we're configured */
+	case -ECONNRESET:		/* request dequeued */
+	case -ESHUTDOWN:		/* disconnect from host */
+		DEBUG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
+				req->actual, req->length);
+		free_ep_req (ep, req);
+		return;
+
+	case -EOVERFLOW:		/* buffer overrun on read means that
+					 * we didn't provide a big enough
+					 * buffer.
+					 */
+	default:
+#if 1
+		DEBUG (dev, "%s complete --> %d, %d/%d\n", ep->name,
+				status, req->actual, req->length);
+#endif
+	case -EREMOTEIO:		/* short read */
+		break;
+	}
+
+	status = usb_ep_queue (ep, req, GFP_ATOMIC);
+	if (status) {
+		ERROR (dev, "kill %s:  resubmit %d bytes --> %d\n",
+				ep->name, req->length, status);
+		usb_ep_set_halt (ep);
+		/* FIXME recover later ... somehow */
+	}
+}
+
+static struct usb_request *
+source_sink_start_ep (struct usb_ep *ep, int gfp_flags)
+{
+	struct usb_request	*req;
+	int			status;
+
+	req = alloc_ep_req (ep, buflen);
+	if (!req)
+		return 0;
+
+	memset (req->buf, 0, req->length);
+	req->complete = source_sink_complete;
+
+	status = usb_ep_queue (ep, req, gfp_flags);
+	if (status) {
+		struct zero_dev	*dev = ep->driver_data;
+
+		ERROR (dev, "start %s --> %d\n", ep->name, status);
+		free_ep_req (ep, req);
+		req = 0;
+	}
+
+	return req;
+}
+
+static int
+set_source_sink_config (struct zero_dev *dev, int gfp_flags)
+{
+	int			result = 0;
+	struct usb_ep		*ep;
+	struct usb_gadget	*gadget = dev->gadget;
+
+	gadget_for_each_ep (ep, gadget) {
+		const struct usb_endpoint_descriptor	*d;
+
+		/* one endpoint writes (sources) zeroes in (to the host) */
+		if (strcmp (ep->name, EP_IN_NAME) == 0) {
+			d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
+			result = usb_ep_enable (ep, d);
+			if (result == 0) {
+				ep->driver_data = dev;
+				if (source_sink_start_ep (ep, gfp_flags) != 0) {
+					dev->in_ep = ep;
+					continue;
+				}
+				usb_ep_disable (ep);
+				result = -EIO;
+			}
+
+		/* one endpoint reads (sinks) anything out (from the host) */
+		} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
+			d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
+			result = usb_ep_enable (ep, d);
+			if (result == 0) {
+				ep->driver_data = dev;
+				if (source_sink_start_ep (ep, gfp_flags) != 0) {
+					dev->out_ep = ep;
+					continue;
+				}
+				usb_ep_disable (ep);
+				result = -EIO;
+			}
+
+		/* ignore any other endpoints */
+		} else
+			continue;
+
+		/* stop on error */
+		ERROR (dev, "can't start %s, result %d\n", ep->name, result);
+		break;
+	}
+	if (result == 0)
+		DEBUG (dev, "buflen %d\n", buflen);
+
+	/* caller is responsible for cleanup on error */
+	return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
+{
+	struct zero_dev	*dev = ep->driver_data;
+	int		status = req->status;
+
+	switch (status) {
+
+	case 0: 			/* normal completion? */
+		if (ep == dev->out_ep) {
+			/* loop this OUT packet back IN to the host */
+			req->zero = (req->actual < req->length);
+			req->length = req->actual;
+			status = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
+			if (status == 0)
+				return;
+
+			/* "should never get here" */
+			ERROR (dev, "can't loop %s to %s: %d\n",
+				ep->name, dev->in_ep->name,
+				status);
+		}
+
+		/* queue the buffer for some later OUT packet */
+		req->length = buflen;
+		status = usb_ep_queue (dev->out_ep, req, GFP_ATOMIC);
+		if (status == 0)
+			return;
+
+		/* "should never get here" */
+		/* FALLTHROUGH */
+
+	default:
+		ERROR (dev, "%s loop complete --> %d, %d/%d\n", ep->name,
+				status, req->actual, req->length);
+		/* FALLTHROUGH */
+
+	/* NOTE:  since this driver doesn't maintain an explicit record
+	 * of requests it submitted (just maintains qlen count), we
+	 * rely on the hardware driver to clean up on disconnect or
+	 * endpoint disable.
+	 */
+	case -ESHUTDOWN:		/* disconnect from host */
+		free_ep_req (ep, req);
+		return;
+	}
+}
+
+static int
+set_loopback_config (struct zero_dev *dev, int gfp_flags)
+{
+	int			result = 0;
+	struct usb_ep		*ep;
+	struct usb_gadget	*gadget = dev->gadget;
+
+	gadget_for_each_ep (ep, gadget) {
+		const struct usb_endpoint_descriptor	*d;
+
+		/* one endpoint writes data back IN to the host */
+		if (strcmp (ep->name, EP_IN_NAME) == 0) {
+			d = ep_desc (gadget, &hs_source_desc, &fs_source_desc);
+			result = usb_ep_enable (ep, d);
+			if (result == 0) {
+				ep->driver_data = dev;
+				dev->in_ep = ep;
+				continue;
+			}
+
+		/* one endpoint just reads OUT packets */
+		} else if (strcmp (ep->name, EP_OUT_NAME) == 0) {
+			d = ep_desc (gadget, &hs_sink_desc, &fs_sink_desc);
+			result = usb_ep_enable (ep, d);
+			if (result == 0) {
+				ep->driver_data = dev;
+				dev->out_ep = ep;
+				continue;
+			}
+
+		/* ignore any other endpoints */
+		} else
+			continue;
+
+		/* stop on error */
+		ERROR (dev, "can't enable %s, result %d\n", ep->name, result);
+		break;
+	}
+
+	/* allocate a bunch of read buffers and queue them all at once.
+	 * we buffer at most 'qlen' transfers; fewer if any need more
+	 * than 'buflen' bytes each.
+	 */
+	if (result == 0) {
+		struct usb_request	*req;
+		unsigned		i;
+
+		ep = dev->out_ep;
+		for (i = 0; i < qlen && result == 0; i++) {
+			req = alloc_ep_req (ep, buflen);
+			if (req) {
+				req->complete = loopback_complete;
+				result = usb_ep_queue (ep, req, GFP_ATOMIC);
+				if (result)
+					DEBUG (dev, "%s queue req --> %d\n",
+							ep->name, result);
+			} else
+				result = -ENOMEM;
+		}
+	}
+	if (result == 0)
+		DEBUG (dev, "qlen %d, buflen %d\n", qlen, buflen);
+
+	/* caller is responsible for cleanup on error */
+	return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void zero_reset_config (struct zero_dev *dev)
+{
+	if (dev->config == 0)
+		return;
+
+	DEBUG (dev, "reset config\n");
+
+	/* just disable endpoints, forcing completion of pending i/o.
+	 * all our completion handlers free their requests in this case.
+	 */
+	if (dev->in_ep) {
+		usb_ep_disable (dev->in_ep);
+		dev->in_ep = 0;
+	}
+	if (dev->out_ep) {
+		usb_ep_disable (dev->out_ep);
+		dev->out_ep = 0;
+	}
+	dev->config = 0;
+}
+
+/* change our operational config.  this code must agree with the code
+ * that returns config descriptors, and altsetting code.
+ *
+ * it's also responsible for power management interactions. some
+ * configurations might not work with our current power sources.
+ *
+ * note that some device controller hardware will constrain what this
+ * code can do, perhaps by disallowing more than one configuration or
+ * by limiting configuration choices (like the pxa250).
+ */
+static int
+zero_set_config (struct zero_dev *dev, unsigned number, int gfp_flags)
+{
+	int			result = 0;
+	struct usb_gadget	*gadget = dev->gadget;
+
+	if (number == dev->config)
+		return 0;
+
+#ifdef CONFIG_USB_ZERO_SA1100
+	if (dev->config) {
+		/* tx fifo is full, but we can't clear it...*/
+		INFO (dev, "can't change configurations\n");
+		return -ESPIPE;
+	}
+#endif
+	zero_reset_config (dev);
+	hw_optimize (gadget);
+
+	switch (number) {
+	case CONFIG_SOURCE_SINK:
+		result = set_source_sink_config (dev, gfp_flags);
+		break;
+	case CONFIG_LOOPBACK:
+		result = set_loopback_config (dev, gfp_flags);
+		break;
+	default:
+		result = -EINVAL;
+		/* FALL THROUGH */
+	case 0:
+		return result;
+	}
+
+	if (!result && (!dev->in_ep || !dev->out_ep))
+		result = -ENODEV;
+	if (result)
+		zero_reset_config (dev);
+	else {
+		char *speed;
+
+		switch (gadget->speed) {
+		case USB_SPEED_LOW:	speed = "low"; break;
+		case USB_SPEED_FULL:	speed = "full"; break;
+		case USB_SPEED_HIGH:	speed = "high"; break;
+		default: 		speed = "?"; break;
+		}
+
+		dev->config = number;
+		INFO (dev, "%s speed config #%d: %s\n", speed, number,
+				(number == CONFIG_SOURCE_SINK)
+					? source_sink : loopback);
+	}
+	return result;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void zero_setup_complete (struct usb_ep *ep, struct usb_request *req)
+{
+	if (req->status || req->actual != req->length)
+		DEBUG ((struct zero_dev *) ep->driver_data,
+				"setup complete --> %d, %d/%d\n",
+				req->status, req->actual, req->length);
+}
+
+/*
+ * The setup() callback implements all the ep0 functionality that's
+ * not handled lower down, in hardware or the hardware driver (like
+ * device and endpoint feature flags, and their status).  It's all
+ * housekeeping for the gadget function we're implementing.  Most of
+ * the work is in config-specific setup.
+ */
+static int
+zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
+{
+	struct zero_dev		*dev = get_gadget_data (gadget);
+	struct usb_request	*req = dev->req;
+	int			value = -EOPNOTSUPP;
+
+	/* usually this stores reply data in the pre-allocated ep0 buffer,
+	 * but config change events will reconfigure hardware.
+	 */
+	switch (ctrl->bRequest) {
+
+	case USB_REQ_GET_DESCRIPTOR:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			break;
+		switch (ctrl->wValue >> 8) {
+
+		case USB_DT_DEVICE:
+			value = min (ctrl->wLength, (u16) sizeof device_desc);
+			memcpy (req->buf, &device_desc, value);
+			break;
+#ifdef HIGHSPEED
+		case USB_DT_DEVICE_QUALIFIER:
+			value = min (ctrl->wLength, (u16) sizeof dev_qualifier);
+			memcpy (req->buf, &dev_qualifier, value);
+			break;
+
+		case USB_DT_OTHER_SPEED_CONFIG:
+			// FALLTHROUGH
+#endif /* HIGHSPEED */
+		case USB_DT_CONFIG:
+			value = config_buf (gadget->speed, req->buf,
+					ctrl->wValue >> 8,
+					ctrl->wValue & 0xff);
+			if (value >= 0)
+				value = min (ctrl->wLength, (u16) value);
+			break;
+
+		case USB_DT_STRING:
+			/* wIndex == language code.
+			 * this driver only handles one language, you can
+			 * add others even if they don't use iso8859/1
+			 */
+			value = usb_gadget_get_string (&stringtab,
+					ctrl->wValue & 0xff, req->buf);
+			if (value >= 0)
+				value = min (ctrl->wLength, (u16) value);
+			break;
+		}
+		break;
+
+	/* currently two configs, two speeds */
+	case USB_REQ_SET_CONFIGURATION:
+		if (ctrl->bRequestType != 0)
+			break;
+		spin_lock (&dev->lock);
+		/* change hardware configuration!
+		 * no response queued, just zero status == success
+		 */
+		value = zero_set_config (dev, ctrl->wValue, GFP_ATOMIC);
+		spin_unlock (&dev->lock);
+		break;
+	case USB_REQ_GET_CONFIGURATION:
+		if (ctrl->bRequestType != USB_DIR_IN)
+			break;
+		*(u8 *)req->buf = dev->config;
+		value = min (ctrl->wLength, (u16) 1);
+		break;
+
+	/* until we add altsetting support, or other interfaces,
+	 * only 0/0 are possible.
+	 */
+	case USB_REQ_SET_INTERFACE:
+		if (ctrl->bRequestType != USB_RECIP_INTERFACE)
+			break;
+		spin_lock (&dev->lock);
+		if (dev->config && ctrl->wIndex == 0 && ctrl->wValue == 0) {
+			u8		config = dev->config;
+
+			/* resets interface configuration, forgets about
+			 * previous transaction state (queued bufs, etc)
+			 * and re-inits endpoint state (toggle etc)
+			 * no response queued, just zero status == success.
+			 * if we had more than one interface we couldn't
+			 * use this "reset the config" shortcut.
+			 */
+			zero_reset_config (dev);
+			zero_set_config (dev, config, GFP_ATOMIC);
+			value = 0;
+		}
+		spin_unlock (&dev->lock);
+		break;
+	case USB_REQ_GET_INTERFACE:
+		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE))
+			break;
+		if (!dev->config)
+			break;
+		if (ctrl->wIndex != 0) {
+			value = -EDOM;
+			break;
+		}
+		*(u8 *)req->buf = 0;
+		value = min (ctrl->wLength, (u16) 1);
+		break;
+
+	default:
+		VDEBUG (dev,
+			"unknown control req%02x.%02x v%04x i%04x l%d\n",
+			ctrl->bRequestType, ctrl->bRequest,
+			ctrl->wValue, ctrl->wIndex, ctrl->wLength);
+	}
+
+	/* respond with data transfer before status phase? */
+	if (value > 0) {
+		req->length = value;
+		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
+		if (value < 0) {
+			DEBUG (dev, "ep_queue --> %d\n", value);
+			req->status = 0;
+			zero_setup_complete (gadget->ep0, req);
+		}
+	}
+
+	/* device either stalls (value < 0) or reports success */
+	return value;
+}
+
+static void
+zero_disconnect (struct usb_gadget *gadget)
+{
+	struct zero_dev		*dev = get_gadget_data (gadget);
+	unsigned long		flags;
+
+	spin_lock_irqsave (&dev->lock, flags);
+	zero_reset_config (dev);
+
+	/* a more significant application might have some non-usb
+	 * activities to quiesce here, saving resources like power
+	 * or pushing the notification up a network stack.
+	 */
+	spin_unlock_irqrestore (&dev->lock, flags);
+
+	/* next we may get setup() calls to enumerate new connections;
+	 * or an unbind() during shutdown (including removing module).
+	 */
+}
+
+/*-------------------------------------------------------------------------*/
+
+static void
+zero_unbind (struct usb_gadget *gadget)
+{
+	struct zero_dev		*dev = get_gadget_data (gadget);
+
+	DEBUG (dev, "unbind\n");
+
+	/* we've already been disconnected ... no i/o is active */
+	if (dev->req)
+		free_ep_req (gadget->ep0, dev->req);
+	kfree (dev);
+	set_gadget_data (gadget, 0);
+}
+
+static int
+zero_bind (struct usb_gadget *gadget)
+{
+	struct zero_dev		*dev;
+
+	dev = kmalloc (sizeof *dev, SLAB_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+	memset (dev, 0, sizeof *dev);
+	spin_lock_init (&dev->lock);
+	dev->gadget = gadget;
+	set_gadget_data (gadget, dev);
+
+	/* preallocate control response and buffer */
+	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
+	if (!dev->req)
+		goto enomem;
+	dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
+				&dev->req->dma, GFP_KERNEL);
+	if (!dev->req->buf)
+		goto enomem;
+
+	dev->req->complete = zero_setup_complete;
+
+	gadget->ep0->driver_data = dev;
+
+	INFO (dev, "%s, version: " DRIVER_VERSION "\n", longname);
+	return 0;
+
+enomem:
+	zero_unbind (gadget);
+	return -ENOMEM;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_gadget_driver zero_driver = {
+#ifdef HIGHSPEED
+	.speed		= USB_SPEED_HIGH,
+#else
+	.speed		= USB_SPEED_FULL,
+#endif
+	.function	= (char *) longname,
+	.bind		= zero_bind,
+	.unbind		= zero_unbind,
+
+	.setup		= zero_setup,
+	.disconnect	= zero_disconnect,
+
+	.driver 	= {
+		.name		= (char *) shortname,
+		// .shutdown = ...
+		// .suspend = ...
+		// .resume = ...
+	},
+};
+
+MODULE_AUTHOR ("David Brownell");
+MODULE_LICENSE ("Dual BSD/GPL");
+
+
+static int __init init (void)
+{
+	/* a real value would likely come through some id prom
+	 * or module option.  this one takes at least two packets.
+	 */
+	strncpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
+	serial [sizeof serial - 1] = 0;
+
+	return usb_gadget_register_driver (&zero_driver);
+}
+module_init (init);
+
+static void __exit cleanup (void)
+{
+	usb_gadget_unregister_driver (&zero_driver);
+}
+module_exit (cleanup);
+
diff -Nru a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
--- a/drivers/usb/host/ehci-hcd.c	Mon Apr 14 14:12:36 2003
+++ b/drivers/usb/host/ehci-hcd.c	Sun May 11 11:20:45 2003
@@ -116,8 +116,10 @@
 #define	EHCI_TUNE_MULT_TT	1
 #define	EHCI_TUNE_FLS		2	/* (small) 256 frame schedule */
 
-#define EHCI_WATCHDOG_JIFFIES	(HZ/100)	/* arbitrary; ~10 msec */
+#define EHCI_IAA_JIFFIES	(HZ/100)	/* arbitrary; ~10 msec */
+#define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
 #define EHCI_ASYNC_JIFFIES	(HZ/20)		/* async idle timeout */
+#define EHCI_SHRINK_JIFFIES	(HZ/200)	/* async qh unlink delay */
 
 /* Initial IRQ latency:  lower than default */
 static int log2_irq_thresh = 0;		// 0 to 6
@@ -266,16 +268,13 @@
 		}
 	}
 
+ 	/* stop async processing after it's idled a bit */
+	if (test_bit (TIMER_ASYNC_OFF, &ehci->actions))
+ 		start_unlink_async (ehci, ehci->async);
+
+	/* ehci could run by timer, without IRQs ... */
 	ehci_work (ehci, NULL);
-	if (ehci->reclaim && !timer_pending (&ehci->watchdog))
-		mod_timer (&ehci->watchdog,
-				jiffies + EHCI_WATCHDOG_JIFFIES);
 
- 	/* stop async processing after it's idled a while */
-	else if (ehci->async_idle) {
- 		start_unlink_async (ehci, ehci->async);
- 		ehci->async_idle = 0;
-	}
 	spin_unlock_irqrestore (&ehci->lock, flags);
 }
 
@@ -658,11 +657,18 @@
  */
 static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
 {
+	timer_action_done (ehci, TIMER_IO_WATCHDOG);
 	if (ehci->reclaim_ready)
 		end_unlink_async (ehci, regs);
 	scan_async (ehci, regs);
 	if (ehci->next_uframe != -1)
 		scan_periodic (ehci, regs);
+
+	/* the IO watchdog guards against hardware or driver bugs that
+	 * misplace IRQs, and should let us run completely without IRQs.
+	 */
+	if ((ehci->async->qh_next.ptr != 0) || (ehci->periodic_sched != 0))
+		timer_action (ehci, TIMER_IO_WATCHDOG);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -881,7 +887,6 @@
 	/* ASSERT:  any requests/urbs are being unlinked */
 	/* ASSERT:  nobody can be submitting urbs for this any more */
 
-	ehci_dbg (ehci, "ep %02x disable\n", ep);
 	epnum = ep & USB_ENDPOINT_NUMBER_MASK;
 	if (epnum != 0 && (ep & USB_DIR_IN))
 		epnum |= 0x10;
diff -Nru a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
--- a/drivers/usb/host/ehci-q.c	Thu Mar 27 08:40:58 2003
+++ b/drivers/usb/host/ehci-q.c	Mon May 19 02:10:48 2003
@@ -706,8 +706,7 @@
 
 	/* (re)start the async schedule? */
 	head = ehci->async;
-	if (ehci->async_idle)
-		del_timer (&ehci->watchdog);
+	timer_action_done (ehci, TIMER_ASYNC_OFF);
 	if (!head->qh_next.qh) {
 		u32	cmd = readl (&ehci->regs->command);
 
@@ -733,8 +732,6 @@
 
 	qh->qh_state = QH_STATE_LINKED;
 	/* qtd completions reported later by interrupt */
-
-	ehci->async_idle = 0;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -915,17 +912,17 @@
 	struct ehci_qh		*qh = ehci->reclaim;
 	struct ehci_qh		*next;
 
-	del_timer (&ehci->watchdog);
+	timer_action_done (ehci, TIMER_IAA_WATCHDOG);
 
 	// qh->hw_next = cpu_to_le32 (qh->qh_dma);
 	qh->qh_state = QH_STATE_IDLE;
 	qh->qh_next.qh = 0;
 	qh_put (ehci, qh);			// refcount from reclaim 
-	ehci->reclaim = 0;
-	ehci->reclaim_ready = 0;
 
 	/* other unlink(s) may be pending (in QH_STATE_UNLINK_WAIT) */
 	next = qh->reclaim;
+	ehci->reclaim = next;
+	ehci->reclaim_ready = 0;
 	qh->reclaim = 0;
 
 	qh_completions (ehci, qh, regs);
@@ -940,16 +937,14 @@
 		 * active but idle for a while once it empties.
 		 */
 		if (HCD_IS_RUNNING (ehci->hcd.state)
-				&& ehci->async->qh_next.qh == 0
-				&& !timer_pending (&ehci->watchdog)) {
-			ehci->async_idle = 1;
-			mod_timer (&ehci->watchdog,
-					jiffies + EHCI_ASYNC_JIFFIES);
-		}
+				&& ehci->async->qh_next.qh == 0)
+			timer_action (ehci, TIMER_ASYNC_OFF);
 	}
 
-	if (next)
+	if (next) {
+		ehci->reclaim = 0;
 		start_unlink_async (ehci, next);
+	}
 }
 
 /* makes sure the async qh will become idle */
@@ -980,6 +975,7 @@
 			wmb ();
 			// handshake later, if we need to
 		}
+		timer_action_done (ehci, TIMER_ASYNC_OFF);
 		return;
 	} 
 
@@ -1005,9 +1001,8 @@
 	ehci->reclaim_ready = 0;
 	cmd |= CMD_IAAD;
 	writel (cmd, &ehci->regs->command);
-	/* posted write need not be known to HC yet ... */
-
-	mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES);
+	(void) readl (&ehci->regs->command);
+	timer_action (ehci, TIMER_IAA_WATCHDOG);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -1016,10 +1011,11 @@
 scan_async (struct ehci_hcd *ehci, struct pt_regs *regs)
 {
 	struct ehci_qh		*qh;
-	int			unlink_delay = 0;
+	enum ehci_timer_action	action = TIMER_IO_WATCHDOG;
 
 	if (!++(ehci->stamp))
 		ehci->stamp++;
+	timer_action_done (ehci, TIMER_ASYNC_SHRINK);
 rescan:
 	qh = ehci->async->qh_next.qh;
 	if (likely (qh != 0)) {
@@ -1051,17 +1047,15 @@
 			 */
 			if (list_empty (&qh->qtd_list)) {
 				if (qh->stamp == ehci->stamp)
-					unlink_delay = 1;
-				else if (!ehci->reclaim) {
+					action = TIMER_ASYNC_SHRINK;
+				else if (!ehci->reclaim
+					    && qh->qh_state == QH_STATE_LINKED)
 					start_unlink_async (ehci, qh);
-					unlink_delay = 0;
-				}
 			}
 
 			qh = qh->qh_next.qh;
 		} while (qh);
 	}
-
-	if (unlink_delay && !timer_pending (&ehci->watchdog))
-		mod_timer (&ehci->watchdog, jiffies + EHCI_WATCHDOG_JIFFIES/2);
+	if (action == TIMER_ASYNC_SHRINK)
+		timer_action (ehci, TIMER_ASYNC_SHRINK);
 }
diff -Nru a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
--- a/drivers/usb/host/ehci.h	Mon Feb 24 03:30:38 2003
+++ b/drivers/usb/host/ehci.h	Thu Apr 24 06:29:02 2003
@@ -52,8 +52,7 @@
 	/* async schedule support */
 	struct ehci_qh		*async;
 	struct ehci_qh		*reclaim;
-	int			reclaim_ready : 1,
-				async_idle : 1;
+	int			reclaim_ready : 1;
 
 	/* periodic schedule support */
 #define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
@@ -83,6 +82,7 @@
 
 	struct timer_list	watchdog;
 	struct notifier_block	reboot_notifier;
+	unsigned long		actions;
 	unsigned		stamp;
 
 	/* irq statistics */
@@ -99,6 +99,53 @@
 
 /* NOTE:  urb->transfer_flags expected to not use this bit !!! */
 #define EHCI_STATE_UNLINK	0x8000		/* urb being unlinked */
+
+enum ehci_timer_action {
+	TIMER_IO_WATCHDOG,
+	TIMER_IAA_WATCHDOG,
+	TIMER_ASYNC_SHRINK,
+	TIMER_ASYNC_OFF,
+};
+
+static inline void
+timer_action_done (struct ehci_hcd *ehci, enum ehci_timer_action action)
+{
+	clear_bit (action, &ehci->actions);
+}
+
+static inline void
+timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
+{
+	if (!test_and_set_bit (action, &ehci->actions)) {
+		unsigned long t;
+
+		switch (action) {
+		case TIMER_IAA_WATCHDOG:
+			t = EHCI_IAA_JIFFIES;
+			break;
+		case TIMER_IO_WATCHDOG:
+			t = EHCI_IO_JIFFIES;
+			break;
+		case TIMER_ASYNC_OFF:
+			t = EHCI_ASYNC_JIFFIES;
+			break;
+		// case TIMER_ASYNC_SHRINK:
+		default:
+			t = EHCI_SHRINK_JIFFIES;
+			break;
+		}
+		t += jiffies;
+		// all timings except IAA watchdog can be overridden.
+		// async queue SHRINK often precedes IAA.  while it's ready
+		// to go OFF neither can matter, and afterwards the IO
+		// watchdog stops unless there's still periodic traffic.
+		if (action != TIMER_IAA_WATCHDOG
+				&& t > ehci->watchdog.expires
+				&& timer_pending (&ehci->watchdog))
+			return;
+		mod_timer (&ehci->watchdog, t);
+	}
+}
 
 /*-------------------------------------------------------------------------*/
 
diff -Nru a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
--- a/drivers/usb/host/ohci-hcd.c	Mon Apr 14 02:51:40 2003
+++ b/drivers/usb/host/ohci-hcd.c	Sun May 11 11:21:13 2003
@@ -323,7 +323,6 @@
 	/* ASSERT:  any requests/urbs are being unlinked */
 	/* ASSERT:  nobody can be submitting urbs for this any more */
 
-	ohci_dbg (ohci, "ep %02x disable\n", ep);
 	epnum <<= 1;
 	if (epnum != 0 && !(ep & USB_DIR_IN))
 		epnum |= 1;
diff -Nru a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
--- a/drivers/usb/host/ohci-sa1111.c	Mon Apr 14 02:51:40 2003
+++ b/drivers/usb/host/ohci-sa1111.c	Sat May 10 16:30:31 2003
@@ -209,7 +209,8 @@
 
  err2:
 	hcd_buffer_destroy (hcd);
-	if (hcd) driver->hcd_free(hcd);
+	if (hcd)
+		driver->hcd_free(hcd);
  err1:
 	sa1111_stop_hc(dev);
 	release_mem_region(dev->res.start, dev->res.end - dev->res.start + 1);
@@ -237,7 +238,8 @@
 
 	info ("remove: %s, state %x", hcd->self.bus_name, hcd->state);
 
-	if (in_interrupt ()) BUG ();
+	if (in_interrupt ())
+		BUG ();
 
 	hub = hcd->self.root_hub;
 	hcd->state = USB_STATE_QUIESCING;
diff -Nru a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
--- a/drivers/usb/image/mdc800.c	Sat Apr 19 13:06:23 2003
+++ b/drivers/usb/image/mdc800.c	Tue May  6 17:17:41 2003
@@ -118,12 +118,8 @@
 #define TO_READ_FROM_IRQ 		TO_DEFAULT_COMMAND
 #define TO_GET_READY			TO_DEFAULT_COMMAND
 
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define MDC800_DEVICE_MINOR_BASE 0
-#else
 /* Minor Number of the device (create with mknod /dev/mustek c 180 32) */
 #define MDC800_DEVICE_MINOR_BASE 32
-#endif
 
 
 /**************************************************************************
@@ -401,6 +397,13 @@
 
 static struct usb_driver mdc800_usb_driver;
 static struct file_operations mdc800_device_ops;
+static struct usb_class_driver mdc800_class = {
+	.name =		"usb/mdc800%d",
+	.fops =		&mdc800_device_ops,
+	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+	.minor_base =	MDC800_DEVICE_MINOR_BASE,
+};
+
 
 /*
  * Callback to search the Mustek MDC800 on the USB Bus
@@ -477,8 +480,8 @@
 
 	down (&mdc800->io_lock);
 
-	retval = usb_register_dev (&mdc800_device_ops, MDC800_DEVICE_MINOR_BASE, 1, &mdc800->minor);
-	if (retval && (retval != -ENODEV)) {
+	retval = usb_register_dev(intf, &mdc800_class);
+	if (retval) {
 		err ("Not able to get a minor for this device.");
 		return -ENODEV;
 	}
@@ -540,7 +543,7 @@
 		if (mdc800->state == NOT_CONNECTED)
 			return;
 
-		usb_deregister_dev (1, mdc800->minor);
+		usb_deregister_dev(intf, &mdc800_class);
 
 		mdc800->state=NOT_CONNECTED;
 
diff -Nru a/drivers/usb/image/scanner.c b/drivers/usb/image/scanner.c
--- a/drivers/usb/image/scanner.c	Fri Apr 18 11:54:05 2003
+++ b/drivers/usb/image/scanner.c	Tue May  6 17:17:47 2003
@@ -397,7 +397,6 @@
  */
 
 
-#include <linux/devfs_fs_kernel.h>
 #include <asm/byteorder.h>
 
 /* 
@@ -464,7 +463,7 @@
 
 	dbg("open_scanner: scn_minor:%d", scn_minor);
 
-	intf = usb_find_interface(&scanner_driver, mk_kdev(USB_MAJOR,scn_minor));
+	intf = usb_find_interface(&scanner_driver, scn_minor);
 	if (!intf) {
 		up(&scn_mutex);
 		err("open_scanner(%d): Unable to access minor data", scn_minor);
@@ -843,9 +842,6 @@
 	kfree(scn->ibuf);
 	kfree(scn->obuf);
 
-	dbg("%s: De-allocating minor:%d", __FUNCTION__, scn->scn_minor);
-	devfs_remove("usb/scanner%d", scn->scn_minor - SCN_BASE_MNR);
-	usb_deregister_dev(1, scn->scn_minor);
 	usb_free_urb(scn->scn_irq);
 	usb_put_dev(scn->scn_dev);
 	up (&(scn->sem));
@@ -867,6 +863,13 @@
 	.release =	close_scanner,
 };
 
+static struct usb_class_driver scanner_class = {
+	.name =		"usb/scanner%d",
+	.fops =		&usb_scanner_fops,
+	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
+	.minor_base =	SCN_BASE_MNR,
+};
+
 static int
 probe_scanner(struct usb_interface *intf,
 	      const struct usb_device_id *id)
@@ -878,7 +881,6 @@
 
 	int ep_cnt;
 	int ix;
-	int scn_minor;
 	int retval;
 
 	char valid_device = 0;
@@ -1011,14 +1013,14 @@
 	
 	down(&scn_mutex);
 
-	retval = usb_register_dev(&usb_scanner_fops, SCN_BASE_MNR, 1, &scn_minor);
+	retval = usb_register_dev(intf, &scanner_class);
 	if (retval) {
 		err ("Not able to get a minor for this device.");
 		up(&scn_mutex);
 		return -ENOMEM;
 	}
 
-	dbg("probe_scanner: Allocated minor:%d", scn_minor);
+	dbg("probe_scanner: Allocated minor:%d", intf->minor);
 
 	if (!(scn = kmalloc (sizeof (struct scn_usb_data), GFP_KERNEL))) {
 		err("probe_scanner: Out of memory.");
@@ -1038,11 +1040,11 @@
 
 	init_MUTEX(&(scn->sem)); /* Initializes to unlocked */
 
-	dbg ("probe_scanner(%d): Address of scn:%p", scn_minor, scn);
+	dbg ("probe_scanner(%d): Address of scn:%p", intf->minor, scn);
 
 /* Ok, if we detected an interrupt EP, setup a handler for it */
 	if (have_intr) {
-		dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", scn_minor, have_intr);
+		dbg("probe_scanner(%d): Configuring IRQ handler for intr EP:%d", intf->minor, have_intr);
 		usb_fill_int_urb(scn->scn_irq, dev,
 			     usb_rcvintpipe(dev, have_intr),
 			     &scn->button, 1, irq_scanner, scn,
@@ -1050,7 +1052,7 @@
 			     250);
 
 	        if (usb_submit_urb(scn->scn_irq, GFP_KERNEL)) {
-			err("probe_scanner(%d): Unable to allocate INT URB.", scn_minor);
+			err("probe_scanner(%d): Unable to allocate INT URB.", intf->minor);
                 	kfree(scn);
 			up(&scn_mutex);
                 	return -ENOMEM;
@@ -1060,21 +1062,21 @@
 
 /* Ok, now initialize all the relevant values */
 	if (!(scn->obuf = (char *)kmalloc(OBUF_SIZE, GFP_KERNEL))) {
-		err("probe_scanner(%d): Not enough memory for the output buffer.", scn_minor);
+		err("probe_scanner(%d): Not enough memory for the output buffer.", intf->minor);
 		kfree(scn);
 		up(&scn_mutex);
 		return -ENOMEM;
 	}
-	dbg("probe_scanner(%d): obuf address:%p", scn_minor, scn->obuf);
+	dbg("probe_scanner(%d): obuf address:%p", intf->minor, scn->obuf);
 
 	if (!(scn->ibuf = (char *)kmalloc(IBUF_SIZE, GFP_KERNEL))) {
-		err("probe_scanner(%d): Not enough memory for the input buffer.", scn_minor);
+		err("probe_scanner(%d): Not enough memory for the input buffer.", intf->minor);
 		kfree(scn->obuf);
 		kfree(scn);
 		up(&scn_mutex);
 		return -ENOMEM;
 	}
-	dbg("probe_scanner(%d): ibuf address:%p", scn_minor, scn->ibuf);
+	dbg("probe_scanner(%d): ibuf address:%p", intf->minor, scn->ibuf);
 	
 
 	switch (dev->descriptor.idVendor) { /* Scanner specific read timeout parameters */
@@ -1101,17 +1103,9 @@
 	scn->intr_ep = have_intr;
 	scn->present = 1;
 	scn->scn_dev = dev;
-	scn->scn_minor = scn_minor;
+	scn->scn_minor = intf->minor;
 	scn->isopen = 0;
 
-	sprintf(name, "usb/scanner%d", scn->scn_minor - SCN_BASE_MNR);
-	
-	devfs_register(NULL, name,
-				    DEVFS_FL_DEFAULT, USB_MAJOR,
-				    scn->scn_minor,
-				    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
-				    S_IWGRP | S_IROTH | S_IWOTH, &usb_scanner_fops, NULL);
-
 	info ("USB scanner device (0x%04x/0x%04x) now attached to %s",
 	      dev->descriptor.idVendor, dev->descriptor.idProduct, name);
 
@@ -1119,9 +1113,6 @@
 
 	usb_set_intfdata(intf, scn);
 
-	/* add device id so the device works when advertised */
-	intf->kdev = mk_kdev(USB_MAJOR,scn->scn_minor);
-
 	return 0;
 }
 
@@ -1130,8 +1121,9 @@
 {
 	struct scn_usb_data *scn = usb_get_intfdata(intf);
 
-	/* remove device id to disable open() */
-	intf->kdev = NODEV;
+	/* disable open() */
+	dbg("%s: De-allocating minor:%d", __FUNCTION__, scn->scn_minor);
+	usb_deregister_dev(intf, &scanner_class);
 
 	usb_set_intfdata(intf, NULL);
 	if(scn->intr_ep) {
diff -Nru a/drivers/usb/image/scanner.h b/drivers/usb/image/scanner.h
--- a/drivers/usb/image/scanner.h	Fri Apr 18 11:53:22 2003
+++ b/drivers/usb/image/scanner.h	Tue May  6 17:17:47 2003
@@ -323,13 +323,7 @@
    USB - Vivid III */
 #define SCN_CLASS_SCANJET 16
 
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define SCN_MAX_MNR 256
-#define SCN_BASE_MNR 0
-#else
-#define SCN_MAX_MNR 16		/* We're allocated 16 minors */
 #define SCN_BASE_MNR 48		/* USB Scanners start at minor 48 */
-#endif
 
 static DECLARE_MUTEX (scn_mutex); /* Initializes to unlocked */
 
diff -Nru a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
--- a/drivers/usb/input/hid-core.c	Mon Apr 28 23:32:21 2003
+++ b/drivers/usb/input/hid-core.c	Thu May  8 17:40:40 2003
@@ -61,7 +61,8 @@
 		return NULL;
 	memset(report, 0, sizeof(struct hid_report));
 
-	if (id != 0) report_enum->numbered = 1;
+	if (id != 0)
+		report_enum->numbered = 1;
 
 	report->id = id;
 	report->type = type;
@@ -539,11 +540,13 @@
 
 		for (j = 0; j < 256; j++) {
 			struct hid_report *report = report_enum->report_id_hash[j];
-			if (report) hid_free_report(report);
+			if (report)
+				hid_free_report(report);
 		}
 	}
 
-	if (device->rdesc) kfree(device->rdesc);
+	if (device->rdesc)
+		kfree(device->rdesc);
 	kfree(device);
 }
 
@@ -741,7 +744,8 @@
 static __inline__ __u32 s32ton(__s32 value, unsigned n)
 {
 	__s32 a = value >> (n - 1);
-	if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
+	if (a && a != -1)
+		return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
 	return value & ((1 << n) - 1);
 }
 
@@ -769,7 +773,10 @@
 
 static __inline__ int search(__s32 *array, __s32 value, unsigned n)
 {
-	while (n--) if (*array++ == value) return 0;
+	while (n--) {
+		if (*array++ == value)
+			return 0;
+	}
 	return -1;
 }
 
@@ -814,9 +821,11 @@
 		if (HID_MAIN_ITEM_VARIABLE & field->flags) {
 
 			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-				if (!value[n]) continue;
+				if (!value[n])
+					continue;
 			} else {
-				if (value[n] == field->value[n]) continue;
+				if (value[n] == field->value[n])
+					continue;
 			}	
 			hid_process_event(hid, field, &field->usage[n], value[n], regs);
 			continue;
@@ -1324,6 +1333,11 @@
 #define USB_VENDOR_ID_TOPMAX           0x0663
 #define USB_DEVICE_ID_TOPMAX_COBRAPAD  0x0103
 
+#define USB_VENDOR_ID_HAPP             0x078b
+#define USB_DEVICE_ID_UGCI_DRIVING     0x0010
+#define USB_DEVICE_ID_UGCI_FLYING      0x0020
+#define USB_DEVICE_ID_UGCI_FIGHTING    0x0030
+
 #define USB_VENDOR_ID_MGE              0x0463
 #define USB_DEVICE_ID_MGE_UPS          0xffff
 #define USB_DEVICE_ID_MGE_UPS1         0x0001
@@ -1357,11 +1371,11 @@
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE },
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 5, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_KBGEAR, USB_DEVICE_ID_KBGEAR_JAMSTUDIO, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_AIPTEK, USB_DEVICE_ID_AIPTEK_6000, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE },
@@ -1373,6 +1387,9 @@
 	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_HIDDEV },
 	{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS1, HID_QUIRK_HIDDEV },
 	{ USB_VENDOR_ID_TOPMAX, USB_DEVICE_ID_TOPMAX_COBRAPAD, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD },
+	{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD },
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 100, HID_QUIRK_IGNORE },
 	{ USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 200, HID_QUIRK_IGNORE },
@@ -1558,9 +1575,12 @@
 
 fail:
 
-	if (hid->urbin) usb_free_urb(hid->urbin);
-	if (hid->urbout) usb_free_urb(hid->urbout);
-	if (hid->urbctrl) usb_free_urb(hid->urbctrl);
+	if (hid->urbin)
+		usb_free_urb(hid->urbin);
+	if (hid->urbout)
+		usb_free_urb(hid->urbout);
+	if (hid->urbctrl)
+		usb_free_urb(hid->urbctrl);
 	hid_free_buffers(dev, hid);
 	hid_free_device(hid);
 
diff -Nru a/drivers/usb/input/hid-input.c b/drivers/usb/input/hid-input.c
--- a/drivers/usb/input/hid-input.c	Thu Mar 13 10:36:02 2003
+++ b/drivers/usb/input/hid-input.c	Sat May 10 16:30:31 2003
@@ -351,7 +351,8 @@
 		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
 	}
 
-	if (usage->code > max) return;
+	if (usage->code > max)
+		return;
 
 	if (usage->type == EV_ABS) {
 		int a = field->logical_minimum;
diff -Nru a/drivers/usb/input/hid-lgff.c b/drivers/usb/input/hid-lgff.c
--- a/drivers/usb/input/hid-lgff.c	Sun Jul 28 14:15:16 2002
+++ b/drivers/usb/input/hid-lgff.c	Sat May 10 16:30:31 2003
@@ -154,7 +154,8 @@
 	}
 
 	private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
-	if (!private) return -1;
+	if (!private)
+		return -1;
 	memset(private, 0, sizeof(struct lgff_device));
 	hid->ff_private = private;
 
@@ -216,7 +217,8 @@
 	struct hid_report* ret;
 
 	ret = kmalloc(sizeof(struct lgff_device), GFP_KERNEL);
-	if (!ret) return NULL;
+	if (!ret)
+		return NULL;
 	*ret = *report;
 
 	ret->field[0] = kmalloc(sizeof(struct hid_field), GFP_KERNEL);
diff -Nru a/drivers/usb/input/hid-tmff.c b/drivers/usb/input/hid-tmff.c
--- a/drivers/usb/input/hid-tmff.c	Wed Feb 12 02:05:01 2003
+++ b/drivers/usb/input/hid-tmff.c	Sat May 10 16:30:31 2003
@@ -112,7 +112,8 @@
 	struct list_head *pos;
 
 	private = kmalloc(sizeof(struct tmff_device), GFP_KERNEL);
-	if (!private) return -ENOMEM;
+	if (!private)
+		return -ENOMEM;
 
 	memset(private, 0, sizeof(struct tmff_device));
 	hid->ff_private = private;
diff -Nru a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
--- a/drivers/usb/input/hiddev.c	Thu Apr 24 13:24:53 2003
+++ b/drivers/usb/input/hiddev.c	Sat May 10 16:30:31 2003
@@ -53,6 +53,7 @@
 	wait_queue_head_t wait;
 	struct hid_device *hid;
 	struct hiddev_list *list;
+	struct usb_interface intf;
 };
 
 struct hiddev_list {
@@ -95,16 +96,19 @@
 
 	case HID_REPORT_ID_FIRST:
 		list = report_enum->report_list.next;
-		if (list == &report_enum->report_list) return NULL;
+		if (list == &report_enum->report_list)
+			return NULL;
 		rinfo->report_id = ((struct hid_report *) list)->id;
 		break;
 		
 	case HID_REPORT_ID_NEXT:
 		list = (struct list_head *)
 			report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK];
-		if (list == NULL) return NULL;
+		if (list == NULL)
+			return NULL;
 		list = list->next;
-		if (list == &report_enum->report_list) return NULL;
+		if (list == &report_enum->report_list)
+			return NULL;
 		rinfo->report_id = ((struct hid_report *) list)->id;
 		break;
 		
@@ -226,10 +230,10 @@
 /*
  * De-allocate a hiddev structure
  */
+static struct usb_class_driver hiddev_class;
 static void hiddev_cleanup(struct hiddev *hiddev)
 {
-	devfs_remove("usb/hid/hiddev%d", hiddev->minor);
-	usb_deregister_dev(1, hiddev->minor);
+	usb_deregister_dev(&hiddev->intf, &hiddev_class);
 	hiddev_table[hiddev->minor] = NULL;
 	kfree(hiddev);
 }
@@ -310,7 +314,8 @@
 	event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ?
 		sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event);
 
-	if (count < event_size) return 0;
+	if (count < event_size)
+		return 0;
 
 	while (retval == 0) {
 		if (list->head == list->tail) {
@@ -403,7 +408,8 @@
 	struct hid_field *field;
 	int i;
 
-	if (!hiddev->exist) return -EIO;
+	if (!hiddev->exist)
+		return -EIO;
 
 	switch (cmd) {
 
@@ -645,18 +651,22 @@
 
 		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
 			int len;
-			if (!hid->name) return 0;
+			if (!hid->name)
+				return 0;
 			len = strlen(hid->name) + 1;
-			if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+			if (len > _IOC_SIZE(cmd))
+				 len = _IOC_SIZE(cmd);
 			return copy_to_user((char *) arg, hid->name, len) ?
 				-EFAULT : len;
 		}
 
 		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
 			int len;
-			if (!hid->phys) return 0;
+			if (!hid->phys)
+				return 0;
 			len = strlen(hid->phys) + 1;
-			if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+			if (len > _IOC_SIZE(cmd))
+				len = _IOC_SIZE(cmd);
 			return copy_to_user((char *) arg, hid->phys, len) ?
 				-EFAULT : len;
 		}
@@ -675,15 +685,21 @@
 	.fasync =	hiddev_fasync,
 };
 
+static struct usb_class_driver hiddev_class = {
+	.name =		"usb/hid/hiddev%d",
+	.fops =		&hiddev_fops,
+	.mode =		S_IFCHR | S_IRUGO | S_IWUSR,
+       	.minor_base =	HIDDEV_MINOR_BASE,
+};
+
 /*
  * This is where hid.c calls us to connect a hid device to the hiddev driver
  */
 int hiddev_connect(struct hid_device *hid)
 {
 	struct hiddev *hiddev;
-	int minor, i;
+	int i;
 	int retval;
-	char devfs_name[24];
 
 	for (i = 0; i < hid->maxcollection; i++)
 		if (hid->collection[i].type == 
@@ -694,31 +710,25 @@
 	if (i == hid->maxcollection && (hid->quirks & HID_QUIRK_HIDDEV) == 0)
 		return -1;
 
-	retval = usb_register_dev(&hiddev_fops, HIDDEV_MINOR_BASE, 1, &minor);
-	if (retval) {
-		err("Not able to get a minor for this device.");
+ 	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
 		return -1;
-	}
+	memset(hiddev, 0, sizeof(struct hiddev));
 
-	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL))) {
-		usb_deregister_dev (1, minor);
+ 	retval = usb_register_dev(&hiddev->intf, &hiddev_class);
+	if (retval) {
+		err("Not able to get a minor for this device.");
 		return -1;
 	}
-	memset(hiddev, 0, sizeof(struct hiddev));
 
 	init_waitqueue_head(&hiddev->wait);
 
-	hiddev->minor = minor;
-	hiddev_table[minor - HIDDEV_MINOR_BASE] = hiddev;
+ 	hiddev->minor = hiddev->intf.minor;
+ 	hiddev_table[hiddev->intf.minor - HIDDEV_MINOR_BASE] = hiddev;
 
 	hiddev->hid = hid;
 	hiddev->exist = 1;
 
-	sprintf(devfs_name, "usb/hid/hiddev%d", minor);
-	devfs_register(NULL, devfs_name, 0,
-		USB_MAJOR, minor + HIDDEV_MINOR_BASE,
-		S_IFCHR | S_IRUGO | S_IWUSR, &hiddev_fops, NULL);
-	hid->minor = minor;
+ 	hid->minor = hiddev->intf.minor;
 	hid->hiddev = hiddev;
 
 	return 0;
diff -Nru a/drivers/usb/input/pid.c b/drivers/usb/input/pid.c
--- a/drivers/usb/input/pid.c	Thu Feb  6 06:49:36 2003
+++ b/drivers/usb/input/pid.c	Sat May 10 16:30:31 2003
@@ -117,7 +117,8 @@
 	unsigned wanted_report = HID_UP_PID | FF_PID_USAGE_BLOCK_FREE;  /*  PID Block Free Report */
 	int ret;
 
-	if (!CHECK_OWNERSHIP(id, pid)) return -EACCES;
+	if (!CHECK_OWNERSHIP(id, pid))
+		return -EACCES;
 
 	/* Find report */
 	ret =  hid_find_report_by_usage(hid, wanted_report, &report, HID_OUTPUT_REPORT);
@@ -214,7 +215,8 @@
 	}
 	else {
 		/* We want to update an effect */
-		if (!CHECK_OWNERSHIP(effect->id, pid_private)) return -EACCES;
+		if (!CHECK_OWNERSHIP(effect->id, pid_private))
+			return -EACCES;
 
 		/* Parameter type cannot be updated */
 		if (effect->type != pid_private->effects[effect->id].effect.type)
diff -Nru a/drivers/usb/input/usbkbd.c b/drivers/usb/input/usbkbd.c
--- a/drivers/usb/input/usbkbd.c	Wed Apr 30 04:55:06 2003
+++ b/drivers/usb/input/usbkbd.c	Sat May 10 16:30:31 2003
@@ -137,7 +137,8 @@
 {
 	struct usb_kbd *kbd = dev->private;
 
-	if (type != EV_LED) return -1;
+	if (type != EV_LED)
+		return -1;
 
 
 	kbd->newleds = (!!test_bit(LED_KANA,    dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
diff -Nru a/drivers/usb/input/xpad.c b/drivers/usb/input/xpad.c
--- a/drivers/usb/input/xpad.c	Wed Feb 12 01:41:01 2003
+++ b/drivers/usb/input/xpad.c	Tue May  6 17:18:42 2003
@@ -61,7 +61,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/usb.h>
 
 #define DRIVER_VERSION "v0.0.5"
diff -Nru a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
--- a/drivers/usb/media/dabusb.c	Fri Dec 27 05:20:06 2002
+++ b/drivers/usb/media/dabusb.c	Tue May  6 17:18:00 2003
@@ -712,12 +712,19 @@
 	.release =	dabusb_release,
 };
 
+static struct usb_class_driver dabusb_class = {
+	.name =		"usb/dabusb%d",
+	.fops =		&dabusb_fops,
+	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+	.minor_base =	DABUSB_MINOR,
+};
+
+
 /* --------------------------------------------------------------------- */
 static int dabusb_probe (struct usb_interface *intf, 
 			 const struct usb_device_id *id)
 {
 	struct usb_device *usbdev = interface_to_usbdev(intf);
-	int devnum;
 	int retval;
 	pdabusb_t s;
 
@@ -731,16 +738,16 @@
 	if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF && usbdev->descriptor.idProduct == 0x9999)
 		return -ENODEV;
 
-	retval = usb_register_dev (&dabusb_fops, DABUSB_MINOR, 1, &devnum);
+	retval = usb_register_dev(intf, &dabusb_class);
 	if (retval)
 		return -ENOMEM;
 
-	s = &dabusb[devnum];
+	s = &dabusb[intf->minor];
 
 	down (&s->mutex);
 	s->remove_pending = 0;
 	s->usbdev = usbdev;
-	s->devnum = devnum;
+	s->devnum = intf->minor;
 
 	if (usb_set_configuration (usbdev, usbdev->config[0].desc.bConfigurationValue) < 0) {
 		err("set_configuration failed");
@@ -778,7 +785,7 @@
 
 	usb_set_intfdata (intf, NULL);
 	if (s) {
-		usb_deregister_dev (1, s->devnum);
+		usb_deregister_dev (intf, &dabusb_class);
 		s->remove_pending = 1;
 		wake_up (&s->wait);
 		if (s->state == _started)
diff -Nru a/drivers/usb/media/dabusb.h b/drivers/usb/media/dabusb.h
--- a/drivers/usb/media/dabusb.h	Thu Apr 25 15:13:00 2002
+++ b/drivers/usb/media/dabusb.h	Tue May  6 17:18:00 2003
@@ -6,11 +6,7 @@
 	unsigned int pipe;
 }bulk_transfer_t,*pbulk_transfer_t;
 
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define DABUSB_MINOR 0
-#else
 #define DABUSB_MINOR 240		/* some unassigned USB minor */
-#endif
 #define DABUSB_VERSION 0x1000
 #define IOCTL_DAB_BULK              _IOWR('d', 0x30, bulk_transfer_t)
 #define IOCTL_DAB_OVERRUNS	    _IOR('d',  0x15, int)
diff -Nru a/drivers/usb/media/ov511.c b/drivers/usb/media/ov511.c
--- a/drivers/usb/media/ov511.c	Thu Apr 24 03:35:37 2003
+++ b/drivers/usb/media/ov511.c	Sat May 10 16:30:31 2003
@@ -876,15 +876,18 @@
 
 	/* Select camera register */
 	rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-	if (rc < 0) return rc;
+	if (rc < 0)
+		return rc;
 
 	/* Write "value" to I2C data port of OV511 */
 	rc = reg_w(ov, R51x_I2C_DATA, value);
-	if (rc < 0) return rc;
+	if (rc < 0)
+		return rc;
 
 	/* Initiate 3-byte write cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x01);
-	if (rc < 0) return rc;
+	if (rc < 0)
+		return rc;
 
 	return 0;
 }
@@ -903,33 +906,43 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
-		if (rc < 0) return rc;
+		if (rc < 0)
+			break;
 
 		/* Write "value" to I2C data port of OV511 */
 		rc = reg_w(ov, R51x_I2C_DATA, value);
-		if (rc < 0) return rc;
+		if (rc < 0)
+			break;
 
 		/* Initiate 3-byte write cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x01);
-		if (rc < 0) return rc;
+		if (rc < 0)
+			break;
 
-		do rc = reg_r(ov, R511_I2C_CTL);
-		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) return rc;
+		/* Retry until idle */
+		do
+			rc = reg_r(ov, R511_I2C_CTL);
+		while (rc > 0 && ((rc&1) == 0)); 
+		if (rc < 0)
+			break;
 
-		if ((rc&2) == 0) /* Ack? */
+		/* Ack? */
+		if ((rc&2) == 0) {
+			rc = 0;
 			break;
+		}
 #if 0
 		/* I2C abort */
 		reg_w(ov, R511_I2C_CTL, 0x10);
 #endif
 		if (--retries < 0) {
 			err("i2c write retries exhausted");
-			return -1;
+			rc = -1;
+			break;
 		}
 	}
 
-	return 0;
+	return rc;
 }
 
 /* NOTE: Do not call this function directly!
@@ -944,15 +957,18 @@
 
 	/* Select camera register */
 	rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-	if (rc < 0) return rc;
+	if (rc < 0)
+		return rc;
 
 	/* Initiate 2-byte write cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x03);
-	if (rc < 0) return rc;
+	if (rc < 0)
+		return rc;
 
 	/* Initiate 2-byte read cycle */
 	rc = reg_w(ov, R518_I2C_CTL, 0x05);
-	if (rc < 0) return rc;
+	if (rc < 0)
+		return rc;
 
 	value = reg_r(ov, R51x_I2C_DATA);
 
@@ -972,15 +988,20 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Select camera register */
 		rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
-		if (rc < 0) return rc;
+		if (rc < 0)
+			return rc;
 
 		/* Initiate 2-byte write cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x03);
-		if (rc < 0) return rc;
+		if (rc < 0)
+			return rc;
 
-		do rc = reg_r(ov, R511_I2C_CTL);
-		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) return rc;
+		/* Retry until idle */
+		do
+			 rc = reg_r(ov, R511_I2C_CTL);
+		while (rc > 0 && ((rc&1) == 0));
+		if (rc < 0)
+			return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
@@ -998,18 +1019,23 @@
 	for (retries = OV511_I2C_RETRIES; ; ) {
 		/* Initiate 2-byte read cycle */
 		rc = reg_w(ov, R511_I2C_CTL, 0x05);
-		if (rc < 0) return rc;
+		if (rc < 0)
+			return rc;
 
-		do rc = reg_r(ov, R511_I2C_CTL);
-		while (rc > 0 && ((rc&1) == 0)); /* Retry until idle */
-		if (rc < 0) return rc;
+		/* Retry until idle */
+		do
+			rc = reg_r(ov, R511_I2C_CTL);
+		while (rc > 0 && ((rc&1) == 0));
+		if (rc < 0)
+			return rc;
 
 		if ((rc&2) == 0) /* Ack? */
 			break;
 
 		/* I2C abort */
 		rc = reg_w(ov, R511_I2C_CTL, 0x10);
-		if (rc < 0) return rc;
+		if (rc < 0)
+			return rc;
 
 		if (--retries < 0) {
 			err("i2c read retries exhausted");
@@ -1127,10 +1153,12 @@
 	int rc;
 
 	rc = reg_w(ov, R51x_I2C_W_SID, slave);
-	if (rc < 0) return rc;
+	if (rc < 0)
+		return rc;
 
 	rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
-	if (rc < 0) return rc;
+	if (rc < 0)
+		return rc;
 
 	return 0;
 }
@@ -1149,7 +1177,8 @@
 
 	/* Set new slave IDs */
 	rc = i2c_set_slave_internal(ov, slave);
-	if (rc < 0) goto out;
+	if (rc < 0)
+		goto out;
 
 	rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
 
@@ -1174,7 +1203,8 @@
 
 	/* Set new slave IDs */
 	rc = i2c_set_slave_internal(ov, slave);
-	if (rc < 0) goto out;
+	if (rc < 0)
+		goto out;
 
 	if (ov->bclass == BCL_OV518)
 		rc = ov518_i2c_read_internal(ov, reg);
@@ -1199,12 +1229,11 @@
 	down(&ov->i2c_lock);
 
 	rc = i2c_set_slave_internal(ov, sid);
-	if (rc < 0) goto out;
+	if (rc < 0)
+		goto out;
 
 	// FIXME: Is this actually necessary?
 	rc = ov51x_reset(ov, OV511_RESET_NOREGS);
-	if (rc < 0) goto out;
-
 out:
 	up(&ov->i2c_lock);
 	return rc;
@@ -1403,7 +1432,8 @@
 	int i, success;
 
 	/* Reset the sensor */
-	if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
+	if (i2c_w(ov, 0x12, 0x80) < 0)
+		return -EIO;
 
 	/* Wait for it to initialize */
 	schedule_timeout(1 + 150 * HZ / 1000);
@@ -1416,11 +1446,13 @@
 		}
 
 		/* Reset the sensor */
-		if (i2c_w(ov, 0x12, 0x80) < 0) return -EIO;
+		if (i2c_w(ov, 0x12, 0x80) < 0)
+			return -EIO;
 		/* Wait for it to initialize */
 		schedule_timeout(1 + 150 * HZ / 1000);
 		/* Dummy read to sync I2C */
-		if (i2c_r(ov, 0x00) < 0) return -EIO;
+		if (i2c_r(ov, 0x00) < 0)
+			return -EIO;
 	}
 
 	if (!success)
@@ -1442,24 +1474,37 @@
 	mult = size >> 5;
 
 	if (ov->bridge == BRG_OV511) {
-		if (size == 0) alt = OV511_ALT_SIZE_0;
-		else if (size == 257) alt = OV511_ALT_SIZE_257;
-		else if (size == 513) alt = OV511_ALT_SIZE_513;
-		else if (size == 769) alt = OV511_ALT_SIZE_769;
-		else if (size == 993) alt = OV511_ALT_SIZE_993;
+		if (size == 0)
+			alt = OV511_ALT_SIZE_0;
+		else if (size == 257)
+			alt = OV511_ALT_SIZE_257;
+		else if (size == 513)
+			alt = OV511_ALT_SIZE_513;
+		else if (size == 769)
+			alt = OV511_ALT_SIZE_769;
+		else if (size == 993)
+			alt = OV511_ALT_SIZE_993;
 		else {
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
 		}
 	} else if (ov->bridge == BRG_OV511PLUS) {
-		if (size == 0) alt = OV511PLUS_ALT_SIZE_0;
-		else if (size == 33) alt = OV511PLUS_ALT_SIZE_33;
-		else if (size == 129) alt = OV511PLUS_ALT_SIZE_129;
-		else if (size == 257) alt = OV511PLUS_ALT_SIZE_257;
-		else if (size == 385) alt = OV511PLUS_ALT_SIZE_385;
-		else if (size == 513) alt = OV511PLUS_ALT_SIZE_513;
-		else if (size == 769) alt = OV511PLUS_ALT_SIZE_769;
-		else if (size == 961) alt = OV511PLUS_ALT_SIZE_961;
+		if (size == 0)
+			alt = OV511PLUS_ALT_SIZE_0;
+		else if (size == 33)
+			alt = OV511PLUS_ALT_SIZE_33;
+		else if (size == 129)
+			alt = OV511PLUS_ALT_SIZE_129;
+		else if (size == 257)
+			alt = OV511PLUS_ALT_SIZE_257;
+		else if (size == 385)
+			alt = OV511PLUS_ALT_SIZE_385;
+		else if (size == 513)
+			alt = OV511PLUS_ALT_SIZE_513;
+		else if (size == 769)
+			alt = OV511PLUS_ALT_SIZE_769;
+		else if (size == 961)
+			alt = OV511PLUS_ALT_SIZE_961;
 		else {
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
@@ -1502,14 +1547,22 @@
 		return -EIO;
 
 	if (ov->bclass == BCL_OV518) {
-		if (size == 0) alt = OV518_ALT_SIZE_0;
-		else if (size == 128) alt = OV518_ALT_SIZE_128;
-		else if (size == 256) alt = OV518_ALT_SIZE_256;
-		else if (size == 384) alt = OV518_ALT_SIZE_384;
-		else if (size == 512) alt = OV518_ALT_SIZE_512;
-		else if (size == 640) alt = OV518_ALT_SIZE_640;
-		else if (size == 768) alt = OV518_ALT_SIZE_768;
-		else if (size == 896) alt = OV518_ALT_SIZE_896;
+		if (size == 0)
+			alt = OV518_ALT_SIZE_0;
+		else if (size == 128)
+			alt = OV518_ALT_SIZE_128;
+		else if (size == 256)
+			alt = OV518_ALT_SIZE_256;
+		else if (size == 384)
+			alt = OV518_ALT_SIZE_384;
+		else if (size == 512)
+			alt = OV518_ALT_SIZE_512;
+		else if (size == 640)
+			alt = OV518_ALT_SIZE_640;
+		else if (size == 768)
+			alt = OV518_ALT_SIZE_768;
+		else if (size == 896)
+			alt = OV518_ALT_SIZE_896;
 		else {
 			err("Set packet size: invalid size (%d)", size);
 			return -EINVAL;
@@ -3939,28 +3992,40 @@
 	ov->curframe = -1;
 
 	if (ov->bridge == BRG_OV511) {
-		if (cams == 1)				size = 993;
-		else if (cams == 2)			size = 513;
-		else if (cams == 3 || cams == 4)	size = 257;
+		if (cams == 1)
+			size = 993;
+		else if (cams == 2)
+			size = 513;
+		else if (cams == 3 || cams == 4)
+			size = 257;
 		else {
 			err("\"cams\" parameter too high!");
 			return -1;
 		}
 	} else if (ov->bridge == BRG_OV511PLUS) {
-		if (cams == 1)				size = 961;
-		else if (cams == 2)			size = 513;
-		else if (cams == 3 || cams == 4)	size = 257;
-		else if (cams >= 5 && cams <= 8)	size = 129;
-		else if (cams >= 9 && cams <= 31)	size = 33;
+		if (cams == 1)
+			size = 961;
+		else if (cams == 2)
+			size = 513;
+		else if (cams == 3 || cams == 4)
+			size = 257;
+		else if (cams >= 5 && cams <= 8)
+			size = 129;
+		else if (cams >= 9 && cams <= 31)
+			size = 33;
 		else {
 			err("\"cams\" parameter too high!");
 			return -1;
 		}
 	} else if (ov->bclass == BCL_OV518) {
-		if (cams == 1)				size = 896;
-		else if (cams == 2)			size = 512;
-		else if (cams == 3 || cams == 4)	size = 256;
-		else if (cams >= 5 && cams <= 8)	size = 128;
+		if (cams == 1)
+			size = 896;
+		else if (cams == 2)
+			size = 512;
+		else if (cams == 3 || cams == 4)
+			size = 256;
+		else if (cams >= 5 && cams <= 8)
+			size = 128;
 		else {
 			err("\"cams\" parameter too high!");
 			return -1;
@@ -5016,7 +5081,7 @@
 	struct proc_dir_entry *pde = PDE(inode);
 	struct usb_ov511 *ov;
 	void *arg = (void *) ularg;
-	int rc;
+	int rc = 0;
 
 	if (!pde)
 		return -ENOENT;
@@ -5037,81 +5102,79 @@
 
 		PDEBUG(4, "Get interface version: %d", ver);
 		if (copy_to_user(arg, &ver, sizeof(ver)))
-			return -EFAULT;
-
-		return 0;
+			rc = -EFAULT;
+		break;
 	}
 	case OV511IOC_GUSHORT:
 	{
 		struct ov511_ushort_opt opt;
 
-		if (copy_from_user(&opt, arg, sizeof(opt)))
-			return -EFAULT;
+		if (copy_from_user(&opt, arg, sizeof(opt))) {
+			rc = -EFAULT;
+			break;
+		}
 
 		switch (opt.optnum) {
 		case OV511_USOPT_BRIGHT:
 			rc = sensor_get_brightness(ov, &(opt.val));
-			if (rc)	return rc;
 			break;
 		case OV511_USOPT_SAT:
 			rc = sensor_get_saturation(ov, &(opt.val));
-			if (rc)	return rc;
 			break;
 		case OV511_USOPT_HUE:
 			rc = sensor_get_hue(ov, &(opt.val));
-			if (rc)	return rc;
 			break;
 		case OV511_USOPT_CONTRAST:
 			rc = sensor_get_contrast(ov, &(opt.val));
-			if (rc)	return rc;
 			break;
 		default:
 			err("Invalid get short option number");
-			return -EINVAL;
+			rc = -EINVAL;
 		}
 
+		if (rc < 0)
+			break;
 		if (copy_to_user(arg, &opt, sizeof(opt)))
-			return -EFAULT;
-
-		return 0;
+			rc = -EFAULT;
+		break;
 	}
 	case OV511IOC_SUSHORT:
 	{
 		struct ov511_ushort_opt opt;
 
-		if (copy_from_user(&opt, arg, sizeof(opt)))
-			return -EFAULT;
+		if (copy_from_user(&opt, arg, sizeof(opt))) {
+			rc = -EFAULT;
+			break;
+		}
 
 		switch (opt.optnum) {
 		case OV511_USOPT_BRIGHT:
 			rc = sensor_set_brightness(ov, opt.val);
-			if (rc)	return rc;
 			break;
 		case OV511_USOPT_SAT:
 			rc = sensor_set_saturation(ov, opt.val);
-			if (rc)	return rc;
 			break;
 		case OV511_USOPT_HUE:
 			rc = sensor_set_hue(ov, opt.val);
-			if (rc)	return rc;
 			break;
 		case OV511_USOPT_CONTRAST:
 			rc = sensor_set_contrast(ov, opt.val);
-			if (rc)	return rc;
 			break;
 		default:
 			err("Invalid set short option number");
-			return -EINVAL;
+			rc = -EINVAL;
 		}
 
-		return 0;
+		break;
 	}
 	case OV511IOC_GUINT:
 	{
 		struct ov511_uint_opt opt;
 
-		if (copy_from_user(&opt, arg, sizeof(opt)))
-			return -EFAULT;
+		if (copy_from_user(&opt, arg, sizeof(opt))) {
+			rc = -EFAULT;
+			break;
+		}
 
 		switch (opt.optnum) {
 		case OV511_UIOPT_POWER_FREQ:
@@ -5131,29 +5194,31 @@
 			break;
 		default:
 			err("Invalid get int option number");
-			return -EINVAL;
+			rc = -EINVAL;
 		}
 
+		if (rc < 0)
+			break;
 		if (copy_to_user(arg, &opt, sizeof(opt)))
-			return -EFAULT;
+			rc = -EFAULT;
 
-		return 0;
+		break;
 	}
 	case OV511IOC_SUINT:
 	{
 		struct ov511_uint_opt opt;
 
-		if (copy_from_user(&opt, arg, sizeof(opt)))
-			return -EFAULT;
+		if (copy_from_user(&opt, arg, sizeof(opt))) {
+			rc = -EFAULT;
+			break;
+		}
 
 		switch (opt.optnum) {
 		case OV511_UIOPT_POWER_FREQ:
 			rc = sensor_set_light_freq(ov, opt.val);
-			if (rc)	return rc;
 			break;
 		case OV511_UIOPT_BFILTER:
 			rc = sensor_set_banding_filter(ov, opt.val);
-			if (rc)	return rc;
 			break;
 		case OV511_UIOPT_LED:
 			if (opt.val <= 2) {
@@ -5162,15 +5227,14 @@
 					ov51x_led_control(ov, 0);
 				else if (ov->led_policy == LED_ON)
 					ov51x_led_control(ov, 1);
-			} else {
-				return -EINVAL;
-			}
+			} else
+				rc = -EINVAL;
 			break;
 		case OV511_UIOPT_DEBUG:
 			if (opt.val <= 5)
 				debug = opt.val;
 			else
-				return -EINVAL;
+				rc = -EINVAL;
 			break;
 		case OV511_UIOPT_COMPRESS:
 			ov->compress = opt.val;
@@ -5183,43 +5247,48 @@
 			break;
 		default:
 			err("Invalid get int option number");
-			return -EINVAL;
+			rc = -EINVAL;
 		}
 
-		return 0;
+		break;
 	}
 	case OV511IOC_WI2C:
 	{
 		struct ov511_i2c_struct w;
 
-		if (copy_from_user(&w, arg, sizeof(w)))
-			return -EFAULT;
+		if (copy_from_user(&w, arg, sizeof(w))) {
+			rc = -EFAULT;
+			break;
+		}
 
-		return i2c_w_slave(ov, w.slave, w.reg, w.value,	w.mask);
+		rc = i2c_w_slave(ov, w.slave, w.reg, w.value, w.mask);
+		break;
 	}
 	case OV511IOC_RI2C:
 	{
 		struct ov511_i2c_struct r;
 
-		if (copy_from_user(&r, arg, sizeof(r)))
-			return -EFAULT;
+		if (copy_from_user(&r, arg, sizeof(r))) {
+			rc = -EFAULT;
+			break;
+		}
 
 		rc = i2c_r_slave(ov, r.slave, r.reg);
 		if (rc < 0)
-			return rc;
+			break;
 
 		r.value = rc;
 
 		if (copy_to_user(arg, &r, sizeof(r)))
-			return -EFAULT;
+			rc = -EFAULT;
 
-		return 0;
+		break;
 	}
 	default:
-		return -EINVAL;
+		rc = -EINVAL;
 	} /* end switch */
 
-	return 0;
+	return rc;
 }
 #endif
 
@@ -5358,7 +5427,8 @@
 		PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
 	} else {
 		/* Reset the 76xx */
-		if (i2c_w(ov, 0x12, 0x80) < 0) return -1;
+		if (i2c_w(ov, 0x12, 0x80) < 0)
+			return -1;
 
 		/* Wait for it to initialize */
 		schedule_timeout(1 + 150 * HZ / 1000);
@@ -5822,7 +5892,8 @@
 	if (ov->customid == 70)		/* USB Life TV (PAL/SECAM) */
 		ov->pal = 1;
 
-	if (write_regvals(ov, aRegvalsInit511)) goto error;
+	if (write_regvals(ov, aRegvalsInit511))
+		goto error;
 
 	if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
 		ov51x_led_control(ov, 0);
@@ -5830,14 +5901,17 @@
 	/* The OV511+ has undocumented bits in the flow control register.
 	 * Setting it to 0xff fixes the corruption with moving objects. */
 	if (ov->bridge == BRG_OV511) {
-		if (write_regvals(ov, aRegvalsNorm511)) goto error;
+		if (write_regvals(ov, aRegvalsNorm511))
+			goto error;
 	} else if (ov->bridge == BRG_OV511PLUS) {
-		if (write_regvals(ov, aRegvalsNorm511Plus)) goto error;
+		if (write_regvals(ov, aRegvalsNorm511Plus))
+			goto error;
 	} else {
 		err("Invalid bridge");
 	}
 
-	if (ov511_init_compression(ov)) goto error;
+	if (ov511_init_compression(ov))
+		goto error;
 
 	ov->packet_numbering = 1;
 	ov511_set_packet_size(ov, 0);
@@ -5975,10 +6049,12 @@
 	/* Give it the default description */
 	ov->desc = symbolic(camlist, 0);
 
-	if (write_regvals(ov, aRegvalsInit518)) goto error;
+	if (write_regvals(ov, aRegvalsInit518))
+		goto error;
 
 	/* Set LED GPIO pin to output mode */
-	if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0) goto error;
+	if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0)
+		goto error;
 
 	/* LED is off by default with OV518; have to explicitly turn it on */
 	if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
@@ -5994,16 +6070,20 @@
 	}
 
 	if (ov->bridge == BRG_OV518) {
-		if (write_regvals(ov, aRegvalsNorm518)) goto error;
+		if (write_regvals(ov, aRegvalsNorm518))
+			goto error;
 	} else if (ov->bridge == BRG_OV518PLUS) {
-		if (write_regvals(ov, aRegvalsNorm518Plus)) goto error;
+		if (write_regvals(ov, aRegvalsNorm518Plus))
+			goto error;
 	} else {
 		err("Invalid bridge");
 	}
 
-	if (reg_w(ov, 0x2f, 0x80) < 0) goto error;
+	if (reg_w(ov, 0x2f, 0x80) < 0)
+		goto error;
 
-	if (ov518_init_compression(ov)) goto error;
+	if (ov518_init_compression(ov))
+		goto error;
 
 	if (ov->bridge == BRG_OV518)
 	{
diff -Nru a/drivers/usb/media/se401.c b/drivers/usb/media/se401.c
--- a/drivers/usb/media/se401.c	Thu Apr 24 03:35:42 2003
+++ b/drivers/usb/media/se401.c	Sat May 10 16:30:31 2003
@@ -170,7 +170,8 @@
 	len -= off;
 	if (len < count) {
 		*eof = 1;
-			if (len <= 0) return 0;
+		if (len <= 0)
+			return 0;
 	} else
 		len = count;
 
@@ -749,7 +750,8 @@
 				}
 			} else {
 				if (vlc_cod==2) {
-					if (!bit) vlc_data=-(1<<vlc_size)+1;
+					if (!bit)
+						vlc_data =  -(1<<vlc_size) + 1;
 					vlc_cod--;
 				}
 				vlc_size--;
@@ -1046,15 +1048,12 @@
 
 	if (se401->user)
 		return -EBUSY;
-	se401->user=1;
-	se401->fbuf=rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
-	if(!se401->fbuf) err=-ENOMEM;
-
-        if (0 != err) {
-		se401->user = 0;
-	} else {
+	se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
+	if (se401->fbuf)
 		file->private_data = dev;
-	}
+	else 
+		err = -ENOMEM;
+	se401->user = !err;
 
 	return err;
 }
diff -Nru a/drivers/usb/media/vicam.c b/drivers/usb/media/vicam.c
--- a/drivers/usb/media/vicam.c	Tue Apr 29 23:20:31 2003
+++ b/drivers/usb/media/vicam.c	Sat May 10 16:30:31 2003
@@ -1101,28 +1101,6 @@
 				((struct vicam_camera *)data)->gain);
 }
 
-static int vicam_write_proc_shutter(struct file *file, const char *buffer,
-				unsigned long count, void *data)
-{
-	struct vicam_camera *cam = (struct vicam_camera *)data;
-	
-	cam->shutter_speed = simple_strtoul(buffer, NULL, 10);
-
-	return count;
-}
-
-static int vicam_write_proc_gain(struct file *file, const char *buffer,
-				unsigned long count, void *data)
-{
-	struct vicam_camera *cam = (struct vicam_camera *)data;
-	
-	cam->gain = simple_strtoul(buffer, NULL, 10);
-
-	return count;
-}
-
-
-
 static void
 vicam_create_proc_root(void)
 {
@@ -1161,24 +1139,21 @@
 
 	cam->proc_dir = create_proc_entry(name, S_IFDIR, vicam_proc_root);
 
-	if ( !cam->proc_dir ) return; // We should probably return an error here
+	if ( !cam->proc_dir )
+		return; // FIXME: We should probably return an error here
 	
 	ent =
-	    create_proc_entry("shutter", S_IFREG | S_IRUGO | S_IWUSR,
-			      cam->proc_dir);
+	    create_proc_entry("shutter", S_IFREG | S_IRUGO, cam->proc_dir);
 	if (ent) {
 		ent->data = cam;
 		ent->read_proc = vicam_read_proc_shutter;
-		ent->write_proc = vicam_write_proc_shutter;
 		ent->size = 64;
 	}
 
-	ent = create_proc_entry("gain", S_IFREG | S_IRUGO | S_IWUSR,
-					cam->proc_dir);
+	ent = create_proc_entry("gain", S_IFREG | S_IRUGO , cam->proc_dir);
 	if ( ent ) {
 		ent->data = cam;
 		ent->read_proc = vicam_read_proc_gain;
-		ent->write_proc = vicam_write_proc_gain;
 		ent->size = 64;
 	}
 }
diff -Nru a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
--- a/drivers/usb/misc/auerswald.c	Fri Apr 18 11:50:24 2003
+++ b/drivers/usb/misc/auerswald.c	Sat May 10 16:30:31 2003
@@ -29,7 +29,6 @@
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
-#include <linux/devfs_fs_kernel.h>
 #undef DEBUG   		/* include debug macros until it's done	*/
 #include <linux/usb.h>
 
@@ -60,16 +59,10 @@
 /* Auerswald Vendor ID */
 #define ID_AUERSWALD  	0x09BF
 
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-/* we can have up to 256 devices at once */
-#define AUER_MINOR_BASE	0
-#define AUER_MAX_DEVICES 256
-#else
 #define AUER_MINOR_BASE	112	/* auerswald driver minor number */
 
 /* we can have up to this number of device plugged in at once */
 #define AUER_MAX_DEVICES 16
-#endif
 
 
 /* Number of read buffers for each device */
@@ -256,12 +249,6 @@
 	wait_queue_head_t 	bufferwait;         /* wait for a control buffer */
 } auerswald_t,*pauerswald_t;
 
-/* array of pointers to our devices that are currently connected */
-static pauerswald_t dev_table[AUER_MAX_DEVICES];
-
-/* lock to protect the dev_table structure */
-static struct semaphore dev_table_mutex;
-
 /* ................................................................... */
 /* character device context */
 typedef struct
@@ -585,7 +572,8 @@
         /* fill the list of free elements */
         for (;numElements; numElements--) {
                 acep = (pauerchainelement_t) kmalloc (sizeof (auerchainelement_t), GFP_KERNEL);
-                if (!acep) goto ac_fail;
+                if (!acep)
+			goto ac_fail;
 		memset (acep, 0, sizeof (auerchainelement_t));
                 INIT_LIST_HEAD (&acep->list);
                 list_add_tail (&acep->list, &acp->free_list);
@@ -793,16 +781,20 @@
         /* fill the list of free elements */
         for (;numElements; numElements--) {
                 bep = (pauerbuf_t) kmalloc (sizeof (auerbuf_t), GFP_KERNEL);
-                if (!bep) goto bl_fail;
+                if (!bep)
+			goto bl_fail;
 	        memset (bep, 0, sizeof (auerbuf_t));
                 bep->list = bcp;
                 INIT_LIST_HEAD (&bep->buff_list);
                 bep->bufp = (char *) kmalloc (bufsize, GFP_KERNEL);
-                if (!bep->bufp) goto bl_fail;
+                if (!bep->bufp)
+			goto bl_fail;
                 bep->dr = (struct usb_ctrlrequest *) kmalloc (sizeof (struct usb_ctrlrequest), GFP_KERNEL);
-                if (!bep->dr) goto bl_fail;
+                if (!bep->dr)
+			goto bl_fail;
                 bep->urbp = usb_alloc_urb (0, GFP_KERNEL);
-                if (!bep->urbp) goto bl_fail;
+                if (!bep->urbp)
+			goto bl_fail;
                 list_add_tail (&bep->buff_list, &bcp->free_buff_list);
         }
         return 0;
@@ -1255,7 +1247,8 @@
 static void auerswald_delete( pauerswald_t cp)
 {
 	dbg( "auerswald_delete");
-	if (cp == NULL) return;
+	if (cp == NULL)
+		return;
 
 	/* Wake up all processes waiting for a buffer */
 	wake_up (&cp->bufferwait);
@@ -1274,7 +1267,8 @@
 static void auerchar_delete( pauerchar_t ccp)
 {
 	dbg ("auerchar_delete");
-	if (ccp == NULL) return;
+	if (ccp == NULL)
+		return;
 
         /* wake up pending synchronous reads */
 	ccp->removed = 1;
@@ -1348,7 +1342,8 @@
 	dbg ("auerswald_removeservice called");
 
 	/* check if we have a service allocated */
-	if (scp->id == AUH_UNASSIGNED) return;
+	if (scp->id == AUH_UNASSIGNED)
+		return;
 
 	/* If there is a device: close the channel */
 	if (cp->usbdev) {
@@ -1384,29 +1379,29 @@
 /* Open a new character device */
 static int auerchar_open (struct inode *inode, struct file *file)
 {
-	int dtindex = minor(inode->i_rdev) - AUER_MINOR_BASE;
+	int dtindex = minor(inode->i_rdev);
 	pauerswald_t cp = NULL;
 	pauerchar_t ccp = NULL;
+	struct usb_interface *intf;
         int ret;
 
         /* minor number in range? */
-	if ((dtindex < 0) || (dtindex >= AUER_MAX_DEVICES)) {
+	if (dtindex < 0) {
 		return -ENODEV;
         }
-	/* usb device available? */
-	if (down_interruptible (&dev_table_mutex)) {
-		return -ERESTARTSYS;
+	intf = usb_find_interface(&auerswald_driver, dtindex);
+	if (!intf) {
+		return -ENODEV;
 	}
-	cp = dev_table[dtindex];
+
+	/* usb device available? */
+	cp = usb_get_intfdata (intf);
 	if (cp == NULL) {
-		up (&dev_table_mutex);
 		return -ENODEV;
 	}
 	if (down_interruptible (&cp->mutex)) {
-		up (&dev_table_mutex);
 		return -ERESTARTSYS;
 	}
-	up (&dev_table_mutex);
 
 	/* we have access to the device. Now lets allocate memory */
 	ccp = (pauerchar_t) kmalloc(sizeof(auerchar_t), GFP_KERNEL);
@@ -1507,7 +1502,8 @@
 		u = 0;	/* no data */
 		if (ccp->readbuf) {
 			int restlen = ccp->readbuf->len - ccp->readoffset;
-			if (restlen > 0) u = 1;
+			if (restlen > 0)
+				u = 1;
 		}
 		if (!u) {
         		if (!list_empty (&ccp->bufctl.rec_buff_list)) {
@@ -1800,7 +1796,8 @@
 	}
 
 	/* protect against too big write requests */
-	if (len > cp->maxControlLength) len = cp->maxControlLength;
+	if (len > cp->maxControlLength)
+		len = cp->maxControlLength;
 
 	/* Fill the buffer */
 	if (copy_from_user ( bp->bufp+AUH_SIZE, buf, len)) {
@@ -1895,6 +1892,13 @@
 	.release =	auerchar_release,
 };
 
+static struct usb_class_driver auerswald_class = {
+	.name =		"usb/auer%d",
+	.fops =		&auerswald_fops,
+	.mode =		S_IFCHR | S_IRUGO | S_IWUGO,
+	.minor_base =	AUER_MINOR_BASE,
+};
+
 
 /* --------------------------------------------------------------------- */
 /* Special USB driver functions                                          */
@@ -1923,7 +1927,6 @@
 	struct usb_device *usbdev = interface_to_usbdev(intf);
 	pauerswald_t cp = NULL;
 	DECLARE_WAIT_QUEUE_HEAD (wqh);
-	unsigned int dtindex;
 	unsigned int u = 0;
 	char *pbuf;
 	int ret;
@@ -1954,27 +1957,17 @@
         auerbuf_init (&cp->bufctl);
 	init_waitqueue_head (&cp->bufferwait);
 
-	down (&dev_table_mutex);
-	ret = usb_register_dev (&auerswald_fops, AUER_MINOR_BASE, 1, &dtindex);
+	ret = usb_register_dev(intf, &auerswald_class);
 	if (ret) {
 		err ("Not able to get a minor for this device.");
-		up (&dev_table_mutex);
 		goto pfail;
 	}
 
 	/* Give the device a name */
-	sprintf (cp->name, "usb/auer%d", dtindex);
+	sprintf (cp->name, "usb/auer%d", intf->minor);
 
 	/* Store the index */
-	cp->dtindex = dtindex;
-	dev_table[dtindex] = cp;
-	up (&dev_table_mutex);
-
-	/* initialize the devfs node for this device and register it */
-	devfs_register(NULL, cp->name, 0, USB_MAJOR,
-				    AUER_MINOR_BASE + dtindex,
-				    S_IFCHR | S_IRUGO | S_IWUGO,
-				    &auerswald_fops, NULL);
+	cp->dtindex = intf->minor;
 
 	/* Get the usb version of the device */
 	cp->version = cp->usbdev->descriptor.bcdDevice;
@@ -2083,18 +2076,8 @@
 	down (&cp->mutex);
 	info ("device /dev/%s now disconnecting", cp->name);
 
-	/* remove from device table */
-	/* Nobody can open() this device any more */
-	down (&dev_table_mutex);
-	dev_table[cp->dtindex] = NULL;
-	up (&dev_table_mutex);
-
-	/* remove our devfs node */
-	/* Nobody can see this device any more */
-	devfs_remove(cp->name);
-
 	/* give back our USB minor number */
-	usb_deregister_dev (1, cp->dtindex);
+	usb_deregister_dev(intf, &auerswald_class);
 
 	/* Stop the interrupt endpoint */
 	auerswald_int_release (cp);
@@ -2123,7 +2106,8 @@
 		/* Inform all waiting readers */
 		for ( u = 0; u < AUH_TYPESIZE; u++) {
 			pauerscon_t scp = cp->services[u];
-			if (scp) scp->disconnect( scp);
+			if (scp)
+				scp->disconnect( scp);
 		}
 	}
 }
@@ -2162,10 +2146,6 @@
 {
 	int result;
 	dbg ("init");
-
-	/* initialize the device table */
-	memset (&dev_table, 0, sizeof(dev_table));
-	init_MUTEX (&dev_table_mutex);
 
 	/* register driver at the USB subsystem */
 	result = usb_register (&auerswald_driver);
diff -Nru a/drivers/usb/misc/brlvger.c b/drivers/usb/misc/brlvger.c
--- a/drivers/usb/misc/brlvger.c	Fri Apr 18 11:52:06 2003
+++ b/drivers/usb/misc/brlvger.c	Tue May  6 17:18:13 2003
@@ -50,7 +50,6 @@
 #include <asm/uaccess.h>
 #include <asm/atomic.h>
 #include <linux/poll.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/brlvger.h>
 
 MODULE_AUTHOR( DRIVER_AUTHOR );
@@ -180,12 +179,6 @@
 
 /* Globals */
 
-/* Table of connected devices, a different minor for each. */
-static struct brlvger_priv *display_table[ MAX_NR_BRLVGER_DEVS ];
-
-/* Mutex for the operation of removing a device from display_table */
-static DECLARE_MUTEX(disconnect_sem);
-
 /* For blocking open */
 static DECLARE_WAIT_QUEUE_HEAD(open_wait);
 
@@ -237,6 +230,13 @@
 	.poll =		brlvger_poll,
 };
 
+static struct usb_class_driver brlvger_class = {
+	.name =		"usb/brlvger%d",
+	.fops =		&brlvger_fops,
+	.mode =		S_IFCHR | S_IRUSR |S_IWUSR | S_IRGRP | S_IWGRP,
+	.minor_base =	BRLVGER_MINOR,
+};
+
 static struct usb_driver brlvger_driver =
 {
 	.owner =	THIS_MODULE,
@@ -254,8 +254,6 @@
 	if(stall_tries < 1 || write_repeats < 1)
 	  return -EINVAL;
 
-	memset(display_table, 0, sizeof(display_table));
-
 	if (usb_register(&brlvger_driver)) {
 		err("USB registration failed");
 		return -ENOSYS;
@@ -284,14 +282,12 @@
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
 	struct brlvger_priv *priv = NULL;
-	int i;
 	int retval;
 	struct usb_endpoint_descriptor *endpoint;
 	struct usb_host_interface *actifsettings;
 	/* protects against reentrance: once we've found a free slot
 	   we reserve it.*/
 	static DECLARE_MUTEX(reserve_sem);
-        char devfs_name[20];
 
 	actifsettings = dev->actconfig->interface->altsetting;
 
@@ -311,7 +307,7 @@
 
 	down(&reserve_sem);
 
-	retval = usb_register_dev(&brlvger_fops, BRLVGER_MINOR, 1, &i);
+	retval = usb_register_dev(intf, &brlvger_class);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		goto error;
@@ -331,7 +327,7 @@
 	init_MUTEX(&priv->open_sem);
 	init_MUTEX(&priv->dev_sem);
 
-	priv->subminor = i;
+	priv->subminor = intf->minor;
 
 	/* we found a interrupt in endpoint */
 	priv->in_interrupt = endpoint;
@@ -372,17 +368,9 @@
 	};
 	dbg("Display length: %d", priv->plength);
 
-	sprintf(devfs_name, "usb/brlvger%d", priv->subminor);
-	devfs_register(NULL, devfs_name,
-				     DEVFS_FL_DEFAULT, USB_MAJOR,
-				     BRLVGER_MINOR+priv->subminor,
-				     S_IFCHR |S_IRUSR|S_IWUSR |S_IRGRP|S_IWGRP,
-				     &brlvger_fops, NULL);
-
-	display_table[i] = priv;
-
+	usb_set_intfdata (intf, priv);
 	info( "Braille display %d is device major %d minor %d",
-				i, USB_MAJOR, BRLVGER_MINOR + i);
+				intf->minor, USB_MAJOR, BRLVGER_MINOR + intf->minor);
 
 	/* Tell anyone waiting on a blocking open */
 	wake_up_interruptible(&open_wait);
@@ -414,12 +402,7 @@
 	if(priv){
 		info("Display %d disconnecting", priv->subminor);
 
-		devfs_remove("usb/brlvger%d", priv->subminor);
-		usb_deregister_dev(1, priv->subminor);
-
-		down(&disconnect_sem);
-		display_table[priv->subminor] = NULL;
-		up(&disconnect_sem);
+		usb_deregister_dev(intf, &brlvger_class);
 
 		down(&priv->open_sem);
 		down(&priv->dev_sem);
@@ -450,21 +433,18 @@
 brlvger_open(struct inode *inode, struct file *file)
 {
 	int devnum = minor (inode->i_rdev);
-	struct brlvger_priv *priv;
+	struct usb_interface *intf = NULL;
+	struct brlvger_priv *priv = NULL;
 	int n, ret;
 
-	if (devnum < BRLVGER_MINOR
-	    || devnum >= (BRLVGER_MINOR + MAX_NR_BRLVGER_DEVS))
+	if (devnum < 0)
 		return -ENXIO;
 
 	n = devnum - BRLVGER_MINOR;
 
 	do {
-		down(&disconnect_sem);
-		priv = display_table[n];
-		
-		if(!priv) {
-			up(&disconnect_sem);
+		intf = usb_find_interface(&brlvger_driver, devnum);
+		if (!intf) {
 			if (file->f_flags & O_NONBLOCK) {
 				dbg3("Failing non-blocking open: "
 				     "device %d not connected", n);
@@ -475,19 +455,18 @@
 			   minor is connected. */
 			dbg2("Waiting for device %d to be connected", n);
 			ret = wait_event_interruptible(open_wait,
-						       display_table[n]
-						       != NULL);
-			if(ret) {
+						       (intf = usb_find_interface(&brlvger_driver, devnum)));
+			if (ret) {
 				dbg2("Interrupted wait for device %d", n);
 				return ret;
 			}
 		}
-	} while(!priv);
-	/* We grabbed an existing device. */
+	} while(!intf);
+	priv = usb_get_intfdata(intf);
 
+	/* We grabbed an existing device. */
 	if(down_interruptible(&priv->open_sem))
 		return -ERESTARTSYS;
-	up(&disconnect_sem);
 
 	/* Only one process can open each device, no sharing. */
 	ret = -EBUSY;
diff -Nru a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
--- a/drivers/usb/misc/rio500.c	Fri Apr 18 11:51:05 2003
+++ b/drivers/usb/misc/rio500.c	Tue May  6 17:18:21 2003
@@ -38,7 +38,6 @@
 #include <linux/spinlock.h>
 #include <linux/usb.h>
 #include <linux/smp_lock.h>
-#include <linux/devfs_fs_kernel.h>
 
 #include "rio500_usb.h"
 
@@ -49,11 +48,7 @@
 #define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>"
 #define DRIVER_DESC "USB Rio 500 driver"
 
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-	#define RIO_MINOR	0
-#else
-	#define RIO_MINOR	64
-#endif
+#define RIO_MINOR	64
 
 /* stall/wait timeout for rio */
 #define NAK_TIMEOUT (HZ)
@@ -68,7 +63,6 @@
         unsigned int ifnum;             /* Interface number of the USB device */
         int isopen;                     /* nz if open */
         int present;                    /* Device is present on the bus */
-	int minor;			/* minor number assigned to us */
         char *obuf, *ibuf;              /* transfer buffers */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         wait_queue_head_t wait_q;       /* for timeouts */
@@ -444,6 +438,13 @@
 	.release =	close_rio,
 };
 
+static struct usb_class_driver usb_rio_class = {
+	.name =		"usb/rio500%d",
+	.fops =		&usb_rio_fops,
+	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+	.minor_base =	RIO_MINOR,
+};
+
 static int probe_rio(struct usb_interface *intf,
 		     const struct usb_device_id *id)
 {
@@ -453,7 +454,7 @@
 
 	info("USB Rio found at address %d", dev->devnum);
 
-	retval = usb_register_dev(&usb_rio_fops, RIO_MINOR, 1, &rio->minor);
+	retval = usb_register_dev(intf, &usb_rio_class);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		return -ENOMEM;
@@ -464,23 +465,19 @@
 
 	if (!(rio->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) {
 		err("probe_rio: Not enough memory for the output buffer");
+		usb_deregister_dev(intf, &usb_rio_class);
 		return -ENOMEM;
 	}
 	dbg("probe_rio: obuf address:%p", rio->obuf);
 
 	if (!(rio->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) {
 		err("probe_rio: Not enough memory for the input buffer");
+		usb_deregister_dev(intf, &usb_rio_class);
 		kfree(rio->obuf);
 		return -ENOMEM;
 	}
 	dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
-	devfs_register(NULL, "usb/rio500",
-				    DEVFS_FL_DEFAULT, USB_MAJOR,
-				    RIO_MINOR,
-				    S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
-				    S_IWGRP, &usb_rio_fops, NULL);
-
 	init_MUTEX(&(rio->lock));
 
 	usb_set_intfdata (intf, rio);
@@ -493,8 +490,7 @@
 
 	usb_set_intfdata (intf, NULL);
 	if (rio) {
-		devfs_remove("usb/rio500");
-		usb_deregister_dev(1, rio->minor);
+		usb_deregister_dev(intf, &usb_rio_class);
 
 		down(&(rio->lock));
 		if (rio->isopen) {
diff -Nru a/drivers/usb/misc/speedtch.c b/drivers/usb/misc/speedtch.c
--- a/drivers/usb/misc/speedtch.c	Wed Apr 23 09:51:29 2003
+++ b/drivers/usb/misc/speedtch.c	Tue May 20 17:13:00 2003
@@ -74,20 +74,23 @@
 #include <linux/atm.h>
 #include <linux/atmdev.h>
 #include <linux/crc32.h>
+#include <linux/init.h>
 
 /*
-#define DEBUG 1
-#define DEBUG_PACKET 1
+#define DEBUG
+#define VERBOSE_DEBUG
 */
 
 #include <linux/usb.h>
 
 
-#ifdef DEBUG_PACKET
+#ifdef VERBOSE_DEBUG
 static int udsl_print_packet (const unsigned char *data, int len);
-#define PACKETDEBUG(arg...) udsl_print_packet (arg)
+#define PACKETDEBUG(arg...)	udsl_print_packet (arg)
+#define vdbg(arg...)		dbg (arg)
 #else
 #define PACKETDEBUG(arg...)
+#define vdbg(arg...)
 #endif
 
 #define DRIVER_AUTHOR	"Johan Verrept, Duncan Sands <duncan.sands@wanadoo.fr>"
@@ -264,7 +267,7 @@
 	struct udsl_vcc_data *vcc;
 
 	list_for_each_entry (vcc, &instance->vcc_list, list)
-		if ((vcc->vpi == vpi) && (vcc->vci == vci))
+		if ((vcc->vci == vci) && (vcc->vpi == vpi))
 			return vcc;
 	return NULL;
 }
@@ -286,8 +289,8 @@
 		vpi = ((cell[0] & 0x0f) << 4) | (cell[1] >> 4);
 		vci = ((cell[1] & 0x0f) << 12) | (cell[2] << 4) | (cell[3] >> 4);
 
-		dbg ("udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called", instance, skb, ctx);
-		dbg ("udsl_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail);
+		vdbg ("udsl_decode_rawcell (0x%p, 0x%p, 0x%p) called", instance, skb, ctx);
+		vdbg ("udsl_decode_rawcell skb->data %p, skb->tail %p", skb->data, skb->tail);
 
 		/* here should the header CRC check be... */
 
@@ -295,7 +298,7 @@
 			dbg ("udsl_decode_rawcell: no vcc found for packet on vpi %d, vci %d", vpi, vci);
 			__skb_pull (skb, min (skb->len, (unsigned) 53));
 		} else {
-			dbg ("udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d", vcc, vpi, vci);
+			vdbg ("udsl_decode_rawcell found vcc %p for packet on vpi %d, vci %d", vcc, vpi, vci);
 
 			if (skb->len >= 53) {
 				cell_payload = cell + 5;
@@ -327,7 +330,7 @@
 						tmp = vcc->reasBuffer;
 						vcc->reasBuffer = NULL;
 
-						dbg ("udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", tmp, tmp->len);
+						vdbg ("udsl_decode_rawcell returns ATM_AAL5 pdu 0x%p with length %d", tmp, tmp->len);
 						return tmp;
 					}
 				}
@@ -351,7 +354,7 @@
 	uint crc = 0xffffffff;
 	uint length, pdu_crc, pdu_length;
 
-	dbg ("udsl_decode_aal5 (0x%p, 0x%p) called", ctx, skb);
+	vdbg ("udsl_decode_aal5 (0x%p, 0x%p) called", ctx, skb);
 
 	if (skb->len && (skb->len % 48))
 		return NULL;
@@ -361,12 +364,11 @@
 	    (skb->tail[-4] << 24) + (skb->tail[-3] << 16) + (skb->tail[-2] << 8) + skb->tail[-1];
 	pdu_length = ((length + 47 + 8) / 48) * 48;
 
-	dbg ("udsl_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d", skb->len, length, pdu_crc, pdu_length);
+	vdbg ("udsl_decode_aal5: skb->len = %d, length = %d, pdu_crc = 0x%x, pdu_length = %d", skb->len, length, pdu_crc, pdu_length);
 
 	/* is skb long enough ? */
 	if (skb->len < pdu_length) {
-		if (ctx->vcc->stats)
-			atomic_inc (&ctx->vcc->stats->rx_err);
+		atomic_inc (&ctx->vcc->stats->rx_err);
 		return NULL;
 	}
 
@@ -385,8 +387,7 @@
 	/* check crc */
 	if (pdu_crc != crc) {
 		dbg ("udsl_decode_aal5: crc check failed!");
-		if (ctx->vcc->stats)
-			atomic_inc (&ctx->vcc->stats->rx_err);
+		atomic_inc (&ctx->vcc->stats->rx_err);
 		return NULL;
 	}
 
@@ -394,10 +395,9 @@
 	skb_trim (skb, length);
 
 	/* update stats */
-	if (ctx->vcc->stats)
-		atomic_inc (&ctx->vcc->stats->rx);
+	atomic_inc (&ctx->vcc->stats->rx);
 
-	dbg ("udsl_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len);
+	vdbg ("udsl_decode_aal5 returns pdu 0x%p with length %d", skb, skb->len);
 	return skb;
 }
 
@@ -453,7 +453,7 @@
 	unsigned char *target = *target_p;
 	unsigned int nc, ne, i;
 
-	dbg ("udsl_write_cells: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u", howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding);
+	vdbg ("udsl_write_cells: howmany=%u, skb->len=%d, num_cells=%u, num_entire=%u, pdu_padding=%u", howmany, skb->len, ctrl->num_cells, ctrl->num_entire, ctrl->pdu_padding);
 
 	nc = ctrl->num_cells;
 	ne = min (howmany, ctrl->num_entire);
@@ -520,7 +520,7 @@
 		return;
 	}
 
-	dbg ("udsl_complete_receive entered (urb 0x%p, status %d)", urb, urb->status);
+	vdbg ("udsl_complete_receive entered (urb 0x%p, status %d)", urb, urb->status);
 
 	/* may not be in_interrupt() */
 	spin_lock_irqsave (&instance->completed_receivers_lock, flags);
@@ -533,7 +533,6 @@
 {
 	struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
 	struct udsl_receiver *rcv;
-	unsigned long flags;
 	unsigned char *data_start;
 	struct sk_buff *skb;
 	struct urb *urb;
@@ -541,20 +540,20 @@
 	struct sk_buff *new = NULL, *tmp = NULL;
 	int err;
 
-	dbg ("udsl_process_receive entered");
+	vdbg ("udsl_process_receive entered");
 
-	spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+	spin_lock_irq (&instance->completed_receivers_lock);
 	while (!list_empty (&instance->completed_receivers)) {
 		rcv = list_entry (instance->completed_receivers.next, struct udsl_receiver, list);
 		list_del (&rcv->list);
-		spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+		spin_unlock_irq (&instance->completed_receivers_lock);
 
 		urb = rcv->urb;
-		dbg ("udsl_process_receive: got packet %p with length %d and status %d", urb, urb->actual_length, urb->status);
+		vdbg ("udsl_process_receive: got packet %p with length %d and status %d", urb, urb->actual_length, urb->status);
 
 		switch (urb->status) {
 		case 0:
-			dbg ("udsl_process_receive: processing urb with rcv %p, urb %p, skb %p", rcv, urb, rcv->skb);
+			vdbg ("udsl_process_receive: processing urb with rcv %p, urb %p, skb %p", rcv, urb, rcv->skb);
 
 			/* update the skb structure */
 			skb = rcv->skb;
@@ -562,18 +561,18 @@
 			skb_put (skb, urb->actual_length);
 			data_start = skb->data;
 
-			dbg ("skb->len = %d", skb->len);
+			vdbg ("skb->len = %d", skb->len);
 			PACKETDEBUG (skb->data, skb->len);
 
 			while ((new = udsl_decode_rawcell (instance, skb, &atmsar_vcc))) {
-				dbg ("(after cell processing)skb->len = %d", new->len);
+				vdbg ("(after cell processing)skb->len = %d", new->len);
 
 				tmp = new;
 				new = udsl_decode_aal5 (atmsar_vcc, new);
 
 				/* we can't send NULL skbs upstream, the ATM layer would try to close the vcc... */
 				if (new) {
-					dbg ("(after aal5 decap) skb->len = %d", new->len);
+					vdbg ("(after aal5 decap) skb->len = %d", new->len);
 					if (new->len && atm_charge (atmsar_vcc->vcc, new->truesize)) {
 						PACKETDEBUG (new->data, new->len);
 						atmsar_vcc->vcc->push (atmsar_vcc->vcc, new);
@@ -604,31 +603,30 @@
 			dbg ("udsl_process_receive: submission failed (%d)", err);
 			/* fall through */
 		default: /* error or urb unlinked */
-			dbg ("udsl_process_receive: adding to spare_receivers");
-			spin_lock_irqsave (&instance->spare_receivers_lock, flags);
+			vdbg ("udsl_process_receive: adding to spare_receivers");
+			spin_lock_irq (&instance->spare_receivers_lock);
 			list_add (&rcv->list, &instance->spare_receivers);
-			spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
+			spin_unlock_irq (&instance->spare_receivers_lock);
 			break;
 		} /* switch */
 
-		spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+		spin_lock_irq (&instance->completed_receivers_lock);
 	} /* while */
-	spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
-	dbg ("udsl_process_receive successful");
+	spin_unlock_irq (&instance->completed_receivers_lock);
+	vdbg ("udsl_process_receive successful");
 }
 
 static void udsl_fire_receivers (struct udsl_instance_data *instance)
 {
 	struct list_head receivers, *pos, *n;
-	unsigned long flags;
 
 	INIT_LIST_HEAD (&receivers);
 
 	down (&instance->serialize);
 
-	spin_lock_irqsave (&instance->spare_receivers_lock, flags);
+	spin_lock_irq (&instance->spare_receivers_lock);
 	list_splice_init (&instance->spare_receivers, &receivers);
-	spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
+	spin_unlock_irq (&instance->spare_receivers_lock);
 
 	list_for_each_safe (pos, n, &receivers) {
 		struct udsl_receiver *rcv = list_entry (pos, struct udsl_receiver, list);
@@ -645,9 +643,9 @@
 
 		if (usb_submit_urb (rcv->urb, GFP_KERNEL) < 0) {
 			dbg ("udsl_fire_receivers: submit failed!");
-			spin_lock_irqsave (&instance->spare_receivers_lock, flags);
+			spin_lock_irq (&instance->spare_receivers_lock);
 			list_move (pos, &instance->spare_receivers);
-			spin_unlock_irqrestore (&instance->spare_receivers_lock, flags);
+			spin_unlock_irq (&instance->spare_receivers_lock);
 		}
 	}
 
@@ -670,7 +668,7 @@
 		return;
 	}
 
-	dbg ("udsl_complete_send entered (urb 0x%p, status %d)", urb, urb->status);
+	vdbg ("udsl_complete_send: urb 0x%p, status %d, snd 0x%p, buf 0x%p", urb, urb->status, snd, snd->buffer);
 
 	/* may not be in_interrupt() */
 	spin_lock_irqsave (&instance->send_lock, flags);
@@ -684,30 +682,25 @@
 {
 	struct udsl_send_buffer *buf;
 	int err;
-	unsigned long flags;
 	struct udsl_instance_data *instance = (struct udsl_instance_data *) data;
 	unsigned int num_written;
 	struct sk_buff *skb;
 	struct udsl_sender *snd;
 
-	dbg ("udsl_process_send entered");
-
 made_progress:
-	spin_lock_irqsave (&instance->send_lock, flags);
+	spin_lock_irq (&instance->send_lock);
 	while (!list_empty (&instance->spare_senders)) {
 		if (!list_empty (&instance->filled_buffers)) {
 			buf = list_entry (instance->filled_buffers.next, struct udsl_send_buffer, list);
 			list_del (&buf->list);
-			dbg ("sending filled buffer (0x%p)", buf);
 		} else if ((buf = instance->current_buffer)) {
 			instance->current_buffer = NULL;
-			dbg ("sending current buffer (0x%p)", buf);
 		} else /* all buffers empty */
 			break;
 
 		snd = list_entry (instance->spare_senders.next, struct udsl_sender, list);
 		list_del (&snd->list);
-		spin_unlock_irqrestore (&instance->send_lock, flags);
+		spin_unlock_irq (&instance->send_lock);
 
 		snd->buffer = buf;
 	        usb_fill_bulk_urb (snd->urb,
@@ -718,39 +711,37 @@
 				   udsl_complete_send,
 				   snd);
 
-		dbg ("submitting urb 0x%p, contains %d cells", snd->urb, UDSL_SND_BUFFER_SIZE - buf->free_cells);
+		vdbg ("udsl_process_send: submitting urb 0x%p (%d cells), snd 0x%p, buf 0x%p", snd->urb, UDSL_SND_BUF_SIZE - buf->free_cells, snd, buf);
 
 		if ((err = usb_submit_urb(snd->urb, GFP_ATOMIC)) < 0) {
-			dbg ("submission failed (%d)!", err);
-			spin_lock_irqsave (&instance->send_lock, flags);
+			dbg ("udsl_process_send: urb submission failed (%d)!", err);
+			spin_lock_irq (&instance->send_lock);
 			list_add (&snd->list, &instance->spare_senders);
-			spin_unlock_irqrestore (&instance->send_lock, flags);
+			spin_unlock_irq (&instance->send_lock);
 			list_add (&buf->list, &instance->filled_buffers);
 			return;
 		}
 
-		spin_lock_irqsave (&instance->send_lock, flags);
+		spin_lock_irq (&instance->send_lock);
 	} /* while */
-	spin_unlock_irqrestore (&instance->send_lock, flags);
+	spin_unlock_irq (&instance->send_lock);
 
 	if (!instance->current_skb && !(instance->current_skb = skb_dequeue (&instance->sndqueue))) {
-		dbg ("done - no more skbs");
-		return;
+		return; /* done - no more skbs */
 	}
 
 	skb = instance->current_skb;
 
 	if (!(buf = instance->current_buffer)) {
-		spin_lock_irqsave (&instance->send_lock, flags);
+		spin_lock_irq (&instance->send_lock);
 		if (list_empty (&instance->spare_buffers)) {
 			instance->current_buffer = NULL;
-			spin_unlock_irqrestore (&instance->send_lock, flags);
-			dbg ("done - no more buffers");
-			return;
+			spin_unlock_irq (&instance->send_lock);
+			return; /* done - no more buffers */
 		}
 		buf = list_entry (instance->spare_buffers.next, struct udsl_send_buffer, list);
 		list_del (&buf->list);
-		spin_unlock_irqrestore (&instance->send_lock, flags);
+		spin_unlock_irq (&instance->send_lock);
 
 		buf->free_start = buf->base;
 		buf->free_cells = UDSL_SND_BUFFER_SIZE;
@@ -760,28 +751,25 @@
 
 	num_written = udsl_write_cells (buf->free_cells, skb, &buf->free_start);
 
-	dbg ("wrote %u cells from skb 0x%p to buffer 0x%p", num_written, skb, buf);
+	vdbg ("udsl_process_send: wrote %u cells from skb 0x%p to buffer 0x%p", num_written, skb, buf);
 
 	if (!(buf->free_cells -= num_written)) {
 		list_add_tail (&buf->list, &instance->filled_buffers);
 		instance->current_buffer = NULL;
-		dbg ("queued filled buffer");
 	}
 
-	dbg ("buffer contains %d cells, %d left", UDSL_SND_BUFFER_SIZE - buf->free_cells, buf->free_cells);
+	vdbg ("udsl_process_send: buffer contains %d cells, %d left", UDSL_SND_BUF_SIZE - buf->free_cells, buf->free_cells);
 
 	if (!UDSL_SKB (skb)->num_cells) {
 		struct atm_vcc *vcc = UDSL_SKB (skb)->atm_data.vcc;
 
-		dbg ("discarding empty skb");
 		if (vcc->pop)
 			vcc->pop (vcc, skb);
 		else
 			kfree_skb (skb);
 		instance->current_skb = NULL;
 
-		if (vcc->stats)
-			atomic_inc (&vcc->stats->tx);
+		atomic_inc (&vcc->stats->tx);
 	}
 
 	goto made_progress;
@@ -789,25 +777,24 @@
 
 static void udsl_cancel_send (struct udsl_instance_data *instance, struct atm_vcc *vcc)
 {
-	unsigned long flags;
 	struct sk_buff *skb, *n;
 
 	dbg ("udsl_cancel_send entered");
-	spin_lock_irqsave (&instance->sndqueue.lock, flags);
+	spin_lock_irq (&instance->sndqueue.lock);
 	for (skb = instance->sndqueue.next, n = skb->next; skb != (struct sk_buff *)&instance->sndqueue; skb = n, n = skb->next)
 		if (UDSL_SKB (skb)->atm_data.vcc == vcc) {
-			dbg ("popping skb 0x%p", skb);
+			dbg ("udsl_cancel_send: popping skb 0x%p", skb);
 			__skb_unlink (skb, &instance->sndqueue);
 			if (vcc->pop)
 				vcc->pop (vcc, skb);
 			else
 				kfree_skb (skb);
 		}
-	spin_unlock_irqrestore (&instance->sndqueue.lock, flags);
+	spin_unlock_irq (&instance->sndqueue.lock);
 
 	tasklet_disable (&instance->send_tasklet);
 	if ((skb = instance->current_skb) && (UDSL_SKB (skb)->atm_data.vcc == vcc)) {
-		dbg ("popping current skb (0x%p)", skb);
+		dbg ("udsl_cancel_send: popping current skb (0x%p)", skb);
 		instance->current_skb = NULL;
 		if (vcc->pop)
 			vcc->pop (vcc, skb);
@@ -822,23 +809,20 @@
 {
 	struct udsl_instance_data *instance = vcc->dev->dev_data;
 
-	dbg ("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len);
+	vdbg ("udsl_atm_send called (skb 0x%p, len %u)", skb, skb->len);
 
 	if (!instance || !instance->usb_dev) {
-		dbg ("NULL data!");
+		dbg ("udsl_atm_send: NULL data!");
 		return -ENODEV;
 	}
 
-	if (!instance->firmware_loaded)
-		return -EAGAIN;
-
 	if (vcc->qos.aal != ATM_AAL5) {
-		dbg ("unsupported ATM type %d!", vcc->qos.aal);
+		dbg ("udsl_atm_send: unsupported ATM type %d!", vcc->qos.aal);
 		return -EINVAL;
 	}
 
 	if (skb->len > ATM_MAX_AAL5_PDU) {
-		dbg ("packet too long (%d vs %d)!", skb->len, ATM_MAX_AAL5_PDU);
+		dbg ("udsl_atm_send: packet too long (%d vs %d)!", skb->len, ATM_MAX_AAL5_PDU);
 		return -EINVAL;
 	}
 
@@ -867,9 +851,7 @@
 
 	dbg ("udsl_atm_dev_close: queue has %u elements", instance->sndqueue.qlen);
 
-	dbg ("udsl_atm_dev_close: killing tasklet");
 	tasklet_kill (&instance->send_tasklet);
-	dbg ("udsl_atm_dev_close: freeing instance");
 	kfree (instance);
 	dev->dev_data = NULL;
 }
@@ -880,7 +862,7 @@
 	int left = *pos;
 
 	if (!instance) {
-		dbg ("NULL instance!");
+		dbg ("udsl_atm_proc_read: NULL instance!");
 		return -ENODEV;
 	}
 
@@ -932,10 +914,10 @@
 	struct udsl_instance_data *instance = vcc->dev->dev_data;
 	struct udsl_vcc_data *new;
 
-	dbg ("udsl_atm_open called");
+	dbg ("udsl_atm_open: vpi %hd, vci %d", vpi, vci);
 
 	if (!instance || !instance->usb_dev) {
-		dbg ("NULL data!");
+		dbg ("udsl_atm_open: NULL data!");
 		return -ENODEV;
 	}
 
@@ -947,23 +929,19 @@
 		return -EINVAL;
 
 	if (!instance->firmware_loaded) {
-		dbg ("firmware not loaded!");
+		dbg ("udsl_atm_open: firmware not loaded!");
 		return -EAGAIN;
 	}
 
-	MOD_INC_USE_COUNT;
-
 	down (&instance->serialize); /* vs self, udsl_atm_close */
 
 	if (udsl_find_vcc (instance, vpi, vci)) {
 		up (&instance->serialize);
-		MOD_DEC_USE_COUNT;
 		return -EADDRINUSE;
 	}
 
 	if (!(new = kmalloc (sizeof (struct udsl_vcc_data), GFP_KERNEL))) {
 		up (&instance->serialize);
-		MOD_DEC_USE_COUNT;
 		return -ENOMEM;
 	}
 
@@ -987,11 +965,9 @@
 
 	up (&instance->serialize);
 
-	dbg ("Allocated new SARLib vcc 0x%p with vpi %d vci %d", new, vpi, vci);
-
 	udsl_fire_receivers (instance);
 
-	dbg ("udsl_atm_open successful");
+	dbg ("udsl_atm_open: allocated vcc data 0x%p (max_pdu: %u)", new, new->max_pdu);
 
 	return 0;
 }
@@ -1004,11 +980,11 @@
 	dbg ("udsl_atm_close called");
 
 	if (!instance || !vcc_data) {
-		dbg ("NULL data!");
+		dbg ("udsl_atm_close: NULL data!");
 		return;
 	}
 
-	dbg ("Deallocating SARLib vcc 0x%p with vpi %d vci %d", vcc_data, vcc_data->vpi, vcc_data->vci);
+	dbg ("udsl_atm_close: deallocating vcc 0x%p with vpi %d vci %d", vcc_data, vcc_data->vpi, vcc_data->vci);
 
 	udsl_cancel_send (instance, vcc);
 
@@ -1033,8 +1009,6 @@
 
 	up (&instance->serialize);
 
-	MOD_DEC_USE_COUNT;
-
 	dbg ("udsl_atm_close successful");
 }
 
@@ -1060,7 +1034,7 @@
 		int ret;
 
 		if ((ret = usb_set_interface (instance->usb_dev, 1, 1)) < 0) {
-			dbg ("usb_set_interface returned %d!", ret);
+			dbg ("udsl_set_alternate: usb_set_interface returned %d!", ret);
 			up (&instance->serialize);
 			return ret;
 		}
@@ -1078,7 +1052,7 @@
 	dbg ("udsl_usb_ioctl entered");
 
 	if (!instance) {
-		dbg ("NULL instance!");
+		dbg ("udsl_usb_ioctl: NULL instance!");
 		return -ENODEV;
 	}
 
@@ -1103,19 +1077,19 @@
 	int i, length;
 	char *buf;
 
-	dbg ("Trying device with Vendor=0x%x, Product=0x%x, ifnum %d",
-		dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
+	dbg ("udsl_usb_probe: trying device with vendor=0x%x, product=0x%x, ifnum %d",
+	     dev->descriptor.idVendor, dev->descriptor.idProduct, ifnum);
 
 	if ((dev->descriptor.bDeviceClass != USB_CLASS_VENDOR_SPEC) ||
 	    (dev->descriptor.idVendor != SPEEDTOUCH_VENDORID) ||
 	    (dev->descriptor.idProduct != SPEEDTOUCH_PRODUCTID) || (ifnum != 1))
 		return -ENODEV;
 
-	dbg ("Device Accepted");
+	dbg ("udsl_usb_probe: device accepted");
 
 	/* instance init */
 	if (!(instance = kmalloc (sizeof (struct udsl_instance_data), GFP_KERNEL))) {
-		dbg ("No memory for Instance data!");
+		dbg ("udsl_usb_probe: no memory for instance data!");
 		return -ENOMEM;
 	}
 
@@ -1149,12 +1123,12 @@
 		struct udsl_receiver *rcv = &(instance->all_receivers[i]);
 
 		if (!(rcv->skb = dev_alloc_skb (UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE))) {
-			dbg ("No memory for skb %d!", i);
+			dbg ("udsl_usb_probe: no memory for skb %d!", i);
 			goto fail;
 		}
 
 		if (!(rcv->urb = usb_alloc_urb (0, GFP_KERNEL))) {
-			dbg ("No memory for receive urb %d!", i);
+			dbg ("udsl_usb_probe: no memory for receive urb %d!", i);
 			goto fail;
 		}
 
@@ -1162,7 +1136,7 @@
 
 		list_add (&rcv->list, &instance->spare_receivers);
 
-		dbg ("skb->truesize = %d (asked for %d)", rcv->skb->truesize, UDSL_RCV_BUFFER_SIZE * ATM_CELL_SIZE);
+		dbg ("udsl_usb_probe: skb->truesize = %d (asked for %d)", rcv->skb->truesize, UDSL_RCV_BUF_SIZE * ATM_CELL_SIZE);
 	}
 
 	/* send init */
@@ -1170,7 +1144,7 @@
 		struct udsl_sender *snd = &(instance->all_senders[i]);
 
 		if (!(snd->urb = usb_alloc_urb (0, GFP_KERNEL))) {
-			dbg ("No memory for send urb %d!", i);
+			dbg ("udsl_usb_probe: no memory for send urb %d!", i);
 			goto fail;
 		}
 
@@ -1183,7 +1157,7 @@
 		struct udsl_send_buffer *buf = &(instance->all_buffers[i]);
 
 		if (!(buf->base = kmalloc (UDSL_SND_BUFFER_SIZE * ATM_CELL_SIZE, GFP_KERNEL))) {
-			dbg ("No memory for send buffer %d!", i);
+			dbg ("udsl_usb_probe: no memory for send buffer %d!", i);
 			goto fail;
 		}
 
@@ -1192,7 +1166,7 @@
 
 	/* atm init */
 	if (!(instance->atm_dev = atm_dev_register (udsl_driver_name, &udsl_atm_devops, -1, 0))) {
-		dbg ("failed to register ATM device!");
+		dbg ("udsl_usb_probe: failed to register ATM device!");
 		goto fail;
 	}
 
@@ -1233,6 +1207,7 @@
 
 finish:
 	/* ready for ATM callbacks */
+	wmb ();
 	instance->atm_dev->dev_data = instance;
 
 	usb_set_intfdata (intf, instance);
@@ -1264,16 +1239,15 @@
 {
 	struct udsl_instance_data *instance = usb_get_intfdata (intf);
 	struct list_head *pos;
-	unsigned long flags;
 	unsigned int count = 0;
 	int result, i;
 
-	dbg ("disconnecting");
+	dbg ("udsl_usb_disconnect entered");
 
 	usb_set_intfdata (intf, NULL);
 
 	if (!instance) {
-		dbg ("NULL instance!");
+		dbg ("udsl_usb_disconnect: NULL instance!");
 		return;
 	}
 
@@ -1300,28 +1274,27 @@
 	do {
 		unsigned int completed = 0;
 
-		spin_lock_irqsave (&instance->completed_receivers_lock, flags);
+		spin_lock_irq (&instance->completed_receivers_lock);
 		list_for_each (pos, &instance->completed_receivers)
 			if (++completed > count)
 				panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
-		spin_unlock_irqrestore (&instance->completed_receivers_lock, flags);
+		spin_unlock_irq (&instance->completed_receivers_lock);
 
 		dbg ("udsl_usb_disconnect: found %u completed receivers", completed);
 
 		if (completed == count)
 			break;
 
-		yield ();
+		set_current_state (TASK_RUNNING);
+		schedule ();
 	} while (1);
 
-	dbg ("udsl_usb_disconnect: flushing");
 	/* no need to take the spinlock */
 	INIT_LIST_HEAD (&instance->completed_receivers);
 
 	tasklet_enable (&instance->receive_tasklet);
 	tasklet_kill (&instance->receive_tasklet);
 
-	dbg ("udsl_usb_disconnect: freeing receivers");
 	for (i = 0; i < UDSL_NUMBER_RCV_URBS; i++) {
 		struct udsl_receiver *rcv = &(instance->all_receivers[i]);
 
@@ -1339,21 +1312,21 @@
 	/* wait for completion handlers to finish */
 	do {
 		count = 0;
-		spin_lock_irqsave (&instance->send_lock, flags);
+		spin_lock (&instance->send_lock);
 		list_for_each (pos, &instance->spare_senders)
 			if (++count > UDSL_NUMBER_SND_URBS)
 				panic (__FILE__ ": memory corruption detected at line %d!\n", __LINE__);
-		spin_unlock_irqrestore (&instance->send_lock, flags);
+		spin_unlock (&instance->send_lock);
 
 		dbg ("udsl_usb_disconnect: found %u spare senders", count);
 
 		if (count == UDSL_NUMBER_SND_URBS)
 			break;
 
-		yield ();
+		set_current_state (TASK_RUNNING);
+		schedule ();
 	} while (1);
 
-	dbg ("udsl_usb_disconnect: flushing");
 	/* no need to take the spinlock */
 	INIT_LIST_HEAD (&instance->spare_senders);
 	INIT_LIST_HEAD (&instance->spare_buffers);
@@ -1361,14 +1334,13 @@
 
 	tasklet_enable (&instance->send_tasklet);
 
-	dbg ("udsl_usb_disconnect: freeing senders");
 	for (i = 0; i < UDSL_NUMBER_SND_URBS; i++)
 		usb_free_urb (instance->all_senders[i].urb);
 
-	dbg ("udsl_usb_disconnect: freeing buffers");
 	for (i = 0; i < UDSL_NUMBER_SND_BUFS; i++)
 		kfree (instance->all_buffers[i].base);
 
+	wmb ();
 	instance->usb_dev = NULL;
 
 	/* atm finalize */
@@ -1396,7 +1368,7 @@
 
 static void __exit udsl_usb_cleanup (void)
 {
-	dbg ("udsl_usb_cleanup");
+	dbg ("udsl_usb_cleanup entered");
 
 	usb_deregister (&udsl_usb_driver);
 }
@@ -1413,7 +1385,7 @@
 **  debug  **
 ************/
 
-#ifdef DEBUG_PACKET
+#ifdef VERBOSE_DEBUG
 static int udsl_print_packet (const unsigned char *data, int len)
 {
 	unsigned char buffer [256];
diff -Nru a/drivers/usb/misc/tiglusb.c b/drivers/usb/misc/tiglusb.c
--- a/drivers/usb/misc/tiglusb.c	Sat Mar 22 07:38:04 2003
+++ b/drivers/usb/misc/tiglusb.c	Thu May  8 01:08:09 2003
@@ -327,7 +327,6 @@
 	int minor = -1;
 	int i;
 	ptiglusb_t s;
-	char name[32];
 
 	dbg ("probing vendor id 0x%x, device id 0x%x",
 	     dev->descriptor.idVendor, dev->descriptor.idProduct);
@@ -371,12 +370,9 @@
 	up (&s->mutex);
 	dbg ("bound to interface");
 
-	sprintf (name, "ticables/usb/%d", s->minor);
-	dbg ("registering to devfs : major = %d, minor = %d, node = %s",
-	     TIUSB_MAJOR, (TIUSB_MINOR + s->minor), name);
-	devfs_register(NULL, name, DEVFS_FL_DEFAULT, TIUSB_MAJOR,
-		       TIUSB_MINOR + s->minor, S_IFCHR | S_IRUGO | S_IWUGO,
-		       &tiglusb_fops, NULL);
+	devfs_mk_cdev(MKDEV(TIUSB_MAJOR, TIUSB_MINOR) + s->minor,
+			S_IFCHR | S_IRUGO | S_IWUGO,
+			"ticables/usb/%d", s->minor);
 
 	/* Display firmware version */
 	info ("firmware revision %i.%02x",
@@ -390,8 +386,6 @@
 static void
 tiglusb_disconnect (struct usb_interface *intf)
 {
-	char name[32];
-
 	ptiglusb_t s = usb_get_intfdata (intf);
 
 	usb_set_intfdata (intf, NULL);
@@ -408,7 +402,7 @@
 	s->dev = NULL;
 	s->opened = 0;
 
-	devfs_remove (name, "ticables/usb/%d", s->minor);
+	devfs_remove("ticables/usb/%d", s->minor);
 
 	info ("device %d removed", s->minor);
 
diff -Nru a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
--- a/drivers/usb/misc/usblcd.c	Wed Feb 26 10:36:59 2003
+++ b/drivers/usb/misc/usblcd.c	Tue May  6 17:18:28 2003
@@ -34,7 +34,6 @@
 struct lcd_usb_data {
 	struct usb_device *lcd_dev;	/* init: probe_lcd */
 	unsigned int ifnum;		/* Interface number of the USB device */
-	int minor;			/* minor number for this device */
 	int isopen;			/* nz if open */
 	int present;			/* Device is present on the bus */
 	char *obuf, *ibuf;		/* transfer buffers */
@@ -245,6 +244,13 @@
 	.release =	close_lcd,
 };
 
+static struct usb_class_driver usb_lcd_class = {
+	.name =		"usb/lcd%d",
+	.fops =		&usb_lcd_fops,
+	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
+	.minor_base =	USBLCD_MINOR,
+};
+
 static int probe_lcd(struct usb_interface *intf, const struct usb_device_id *id)
 {
 	struct usb_device *dev = interface_to_usbdev(intf);
@@ -268,23 +274,25 @@
 		(i & 0xF000)>>12,(i & 0xF00)>>8,(i & 0xF0)>>4,(i & 0xF),
 		dev->devnum);
 
-	retval = usb_register_dev(&usb_lcd_fops, USBLCD_MINOR, 1, &lcd->minor);
+	retval = usb_register_dev(intf, &usb_lcd_class);
 	if (retval) {
 		err("Not able to get a minor for this device.");
 		return -ENOMEM;
 	}
-	
+
 	lcd->present = 1;
 	lcd->lcd_dev = dev;
 
 	if (!(lcd->obuf = (char *) kmalloc(OBUF_SIZE, GFP_KERNEL))) {
 		err("probe_lcd: Not enough memory for the output buffer");
+		usb_deregister_dev(intf, &usb_lcd_class);
 		return -ENOMEM;
 	}
 	dbg("probe_lcd: obuf address:%p", lcd->obuf);
 
 	if (!(lcd->ibuf = (char *) kmalloc(IBUF_SIZE, GFP_KERNEL))) {
 		err("probe_lcd: Not enough memory for the input buffer");
+		usb_deregister_dev(intf, &usb_lcd_class);
 		kfree(lcd->obuf);
 		return -ENOMEM;
 	}
@@ -300,7 +308,7 @@
 
 	usb_set_intfdata (intf, NULL);
 	if (lcd) {
-		usb_deregister_dev(1, lcd->minor);
+		usb_deregister_dev(intf, &usb_lcd_class);
 
 		if (lcd->isopen) {
 			lcd->isopen = 0;
diff -Nru a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
--- a/drivers/usb/misc/usbtest.c	Sun Mar 23 07:10:10 2003
+++ b/drivers/usb/misc/usbtest.c	Sat May 10 06:00:12 2003
@@ -1349,6 +1349,13 @@
 	.alt		= 0,
 };
 
+static struct usbtest_info um_info = {
+	.name		= "user mode test driver",
+	.ep_in		= 7,
+	.ep_out		= 3,
+	.alt		= -1,
+};
+
 #ifdef IBOT2
 /* this is a nice source of high speed bulk data;
  * uses an FX2, with firmware provided in the device
@@ -1412,6 +1419,11 @@
 	/* "Gadget Zero" firmware runs under Linux */
 	{ USB_DEVICE (0x0525, 0xa4a0),
 		.driver_info = (unsigned long) &fw_info,
+		},
+
+	/* so does a user-mode variant */
+	{ USB_DEVICE (0x0525, 0xa4a4),
+		.driver_info = (unsigned long) &um_info,
 		},
 
 #ifdef KEYSPAN_19Qi
diff -Nru a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
--- a/drivers/usb/misc/uss720.c	Wed Apr  9 08:44:34 2003
+++ b/drivers/usb/misc/uss720.c	Tue May 13 05:34:40 2003
@@ -146,7 +146,7 @@
 	if (m <= ECR_PS2 && !(priv->reg[1] & 0x20)) {
 		/* This mode resets the FIFO, so we may
 		 * have to wait for it to drain first. */
-		long expire = jiffies + pp->physport->cad->timeout;
+		unsigned long expire = jiffies + pp->physport->cad->timeout;
 		switch (mode) {
 		case ECR_PPF: /* Parallel Port FIFO mode */
 		case ECR_ECP: /* ECP Parallel Port mode */
diff -Nru a/drivers/usb/net/catc.c b/drivers/usb/net/catc.c
--- a/drivers/usb/net/catc.c	Fri Dec 27 05:19:31 2002
+++ b/drivers/usb/net/catc.c	Sat May 10 16:30:31 2003
@@ -828,10 +828,14 @@
 	if ((!catc->ctrl_urb) || (!catc->tx_urb) || 
 	    (!catc->rx_urb) || (!catc->irq_urb)) {
 		err("No free urbs available.");
-		if (catc->ctrl_urb) usb_free_urb(catc->ctrl_urb);
-		if (catc->tx_urb)   usb_free_urb(catc->tx_urb);
-		if (catc->rx_urb)   usb_free_urb(catc->rx_urb);
-		if (catc->irq_urb)  usb_free_urb(catc->irq_urb);
+		if (catc->ctrl_urb)
+			usb_free_urb(catc->ctrl_urb);
+		if (catc->tx_urb)
+			usb_free_urb(catc->tx_urb);
+		if (catc->rx_urb)
+			usb_free_urb(catc->rx_urb);
+		if (catc->irq_urb)
+			usb_free_urb(catc->irq_urb);
 		kfree(netdev);
 		kfree(catc);
 		return -ENOMEM;
diff -Nru a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
--- a/drivers/usb/net/kaweth.c	Mon Apr 21 01:26:37 2003
+++ b/drivers/usb/net/kaweth.c	Sat May 10 16:30:31 2003
@@ -811,7 +811,8 @@
 {
 	__u16 packet_filter_bitmap = kaweth->packet_filter_bitmap;
 	kaweth->packet_filter_bitmap = 0;
-	if(packet_filter_bitmap == 0) return;
+	if (packet_filter_bitmap == 0)
+		return;
 
 	{
 	int result;
diff -Nru a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
--- a/drivers/usb/net/rtl8150.c	Thu Apr 10 16:58:41 2003
+++ b/drivers/usb/net/rtl8150.c	Tue May  6 17:18:42 2003
@@ -16,7 +16,6 @@
 #include <linux/etherdevice.h>
 #include <linux/mii.h>
 #include <linux/ethtool.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/usb.h>
 #include <asm/uaccess.h>
 
@@ -106,7 +105,6 @@
 
 typedef struct rtl8150 rtl8150_t;
 
-/* the global usb devfs handle */
 unsigned long multicast_filter_limit = 32;
 
 static void fill_skb_pool(rtl8150_t *);
@@ -160,7 +158,7 @@
 	clear_bit(RX_REG_SET, &dev->flags);
 }
 
-static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
+static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size)
 {
 	int ret;
 
@@ -537,7 +535,8 @@
 		warn("%s - device reset failed", __FUNCTION__);
 	}
 	/* RCR bit7=1 attach Rx info at the end;  =0 HW CRC (which is broken) */
-	dev->rx_creg = rcr = 0x9e;
+	rcr = 0x9e;	/* bit7=1 attach Rx info at the end */
+	dev->rx_creg = cpu_to_le16(rcr);
 	tcr = 0xd8;
 	cr = 0x0c;
 	if (!(rcr & 0x80))
@@ -584,18 +583,18 @@
 	dev = netdev->priv;
 	netif_stop_queue(netdev);
 	if (netdev->flags & IFF_PROMISC) {
-		dev->rx_creg |= 0x0001;
+		dev->rx_creg |= cpu_to_le16(0x0001);
 		info("%s: promiscuous mode", netdev->name);
 	} else if ((netdev->mc_count > multicast_filter_limit) ||
 		   (netdev->flags & IFF_ALLMULTI)) {
-		dev->rx_creg &= 0xfffe;
-		dev->rx_creg |= 0x0002;
+		dev->rx_creg &= cpu_to_le16(0xfffe);
+		dev->rx_creg |= cpu_to_le16(0x0002);
 		info("%s: allmulti set", netdev->name);
 	} else {
 		/* ~RX_MULTICAST, ~RX_PROMISCUOUS */
-		dev->rx_creg &= 0x00fc;
+		dev->rx_creg &= cpu_to_le16(0x00fc);
 	}
-	async_set_registers(dev, RCR, 2, &dev->rx_creg);
+	async_set_registers(dev, RCR, 2);
 	netif_wake_queue(netdev);
 }
 
diff -Nru a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
--- a/drivers/usb/net/usbnet.c	Mon Apr 28 16:23:14 2003
+++ b/drivers/usb/net/usbnet.c	Tue May 20 20:02:20 2003
@@ -2597,7 +2597,8 @@
 		return status;
 	}
 	dev->maxpacket = usb_maxpacket (dev->udev, dev->out, 1);
-
+	
+	SET_NETDEV_DEV(&dev->net, &dev->udev->dev);
 	register_netdev (&dev->net);
 	devinfo (dev, "register usbnet at usb-%s-%s, %s",
 		xdev->bus->bus_name, xdev->devpath,
diff -Nru a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
--- a/drivers/usb/serial/belkin_sa.c	Wed Apr 23 10:33:12 2003
+++ b/drivers/usb/serial/belkin_sa.c	Sat May 10 16:30:31 2003
@@ -285,10 +285,13 @@
 		goto exit;
 	}
 
-	if (port_paranoia_check (port, __FUNCTION__)) return;
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
 
 	serial = port->serial;
-	if (serial_paranoia_check (serial, __FUNCTION__)) return;
+
+	if (serial_paranoia_check (serial, __FUNCTION__))
+		return;
 	
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
diff -Nru a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
--- a/drivers/usb/serial/bus.c	Mon Apr 28 23:51:37 2003
+++ b/drivers/usb/serial/bus.c	Wed May  7 15:52:47 2003
@@ -23,18 +23,6 @@
 
 #include "usb-serial.h"
 
-static ssize_t show_dev (struct device *dev, char *buf)
-{
-	struct usb_serial_port *port= to_usb_serial_port(dev);
-	dev_t base;
-
-	port = to_usb_serial_port(dev);
-
-	base = MKDEV(SERIAL_TTY_MAJOR, port->number);
-	return sprintf(buf, "%04x\n", base);
-}
-static DEVICE_ATTR(dev, S_IRUGO, show_dev, NULL);
-
 static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
 {
 	struct usb_serial_device_type *driver;
@@ -88,10 +76,7 @@
 	}
 
 	minor = port->number;
-
-	tty_register_device (&usb_serial_tty_driver, minor);
-	device_create_file (dev, &dev_attr_dev);
-
+	tty_register_device (&usb_serial_tty_driver, minor, dev);
 	dev_info(&port->serial->dev->dev, 
 		 "%s converter now attached to ttyUSB%d (or usb/tts/%d for devfs)\n",
 		 driver->name, minor, minor);
diff -Nru a/drivers/usb/serial/console.c b/drivers/usb/serial/console.c
--- a/drivers/usb/serial/console.c	Tue Feb 18 07:50:39 2003
+++ b/drivers/usb/serial/console.c	Sat May 10 16:30:31 2003
@@ -76,9 +76,12 @@
 		s = options;
 		while (*s >= '0' && *s <= '9')
 			s++;
-		if (*s)	parity = *s++;
-		if (*s)	bits   = *s++ - '0';
-		if (*s)	doflow = (*s++ == 'r');
+		if (*s)
+			parity = *s++;
+		if (*s)
+			bits   = *s++ - '0';
+		if (*s)
+			doflow = (*s++ == 'r');
 	}
 
 	/* build a cflag setting */
@@ -133,7 +136,7 @@
 	co->cflag = cflag;
 
 	/* grab the first serial port that happens to be connected */
-	serial = usb_serial_get_by_minor (0);
+	serial = usb_serial_get_by_index(0);
 	if (serial_paranoia_check (serial, __FUNCTION__)) {
 		/* no device is connected yet, sorry :( */
 		err ("No USB device connected to ttyUSB0");
diff -Nru a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
--- a/drivers/usb/serial/cyberjack.c	Thu Mar 13 10:36:02 2003
+++ b/drivers/usb/serial/cyberjack.c	Sat May 10 16:30:31 2003
@@ -284,7 +284,8 @@
 	struct usb_serial *serial;
 	unsigned char *data = urb->transfer_buffer;
 
-	if (port_paranoia_check (port, __FUNCTION__)) return;
+	if (port_paranoia_check (port, __FUNCTION__))
+		return;
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
@@ -293,7 +294,8 @@
 		return;
 
 	serial = port->serial;
-	if (serial_paranoia_check (serial, __FUNCTION__)) return;
+	if (serial_paranoia_check (serial, __FUNCTION__))
+		return;
 
 	usb_serial_debug_data (__FILE__, __FUNCTION__, urb->actual_length, data);
 
@@ -372,7 +374,8 @@
 	/* Reduce urbs to do by one. */
 	priv->rdtodo-=urb->actual_length;
 	/* Just to be sure */
-	if( priv->rdtodo<0 ) priv->rdtodo=0;
+	if ( priv->rdtodo<0 )
+		priv->rdtodo = 0;
 
 	dbg("%s - rdtodo: %d", __FUNCTION__, priv->rdtodo);
 
diff -Nru a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
--- a/drivers/usb/serial/io_ti.c	Wed Apr 23 10:33:34 2003
+++ b/drivers/usb/serial/io_ti.c	Sat May 10 16:40:02 2003
@@ -1553,7 +1553,8 @@
 	__u8 lsr = 0;
 
 #define MAP_FLAG(flagUmp, flagUart)    \
-	if (ti_lsr & flagUmp) lsr |= flagUart;
+	if (ti_lsr & flagUmp) \
+		lsr |= flagUart;
 
 	MAP_FLAG(UMP_UART_LSR_OV_MASK, LSR_OVER_ERR)	/* overrun */
 	MAP_FLAG(UMP_UART_LSR_PE_MASK, LSR_PAR_ERR)	/* parity error */
diff -Nru a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
--- a/drivers/usb/serial/ir-usb.c	Thu Mar 13 10:36:02 2003
+++ b/drivers/usb/serial/ir-usb.c	Sat May 10 16:30:31 2003
@@ -461,7 +461,8 @@
 			 * contains a busy indicator and baud rate change.
 			 * See section 5.4.1.2 of the USB IrDA spec.
 			 */
-			if((*data & 0x0f) > 0) ir_baud = *data & 0x0f;
+			if ((*data & 0x0f) > 0)
+				ir_baud = *data & 0x0f;
 
 			usb_serial_debug_data (
 				__FILE__,
diff -Nru a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
--- a/drivers/usb/serial/pl2303.c	Thu Apr 24 07:53:32 2003
+++ b/drivers/usb/serial/pl2303.c	Tue May 13 06:16:49 2003
@@ -579,7 +579,7 @@
 		state = BREAK_ON;
 	dbg("%s - turning break %s", state==BREAK_OFF ? "off" : "on", __FUNCTION__);
 
-	result = usb_control_msg (serial->dev, usb_rcvctrlpipe (serial->dev, 0),
+	result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0),
 				  BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 
 				  0, NULL, 0, 100);
 	if (result)
diff -Nru a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
--- a/drivers/usb/serial/usb-serial.c	Thu Apr 24 16:01:59 2003
+++ b/drivers/usb/serial/usb-serial.c	Wed May  7 04:49:36 2003
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2003 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (c) 2000 Peter Berger (pberger@brimson.com)
  * Copyright (c) 2000 Al Borchers (borchers@steinerpoint.com)
  *
diff -Nru a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
--- a/drivers/usb/serial/usb-serial.h	Thu Apr 24 21:19:31 2003
+++ b/drivers/usb/serial/usb-serial.h	Wed May  7 04:49:36 2003
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- *	Copyright (C) 1999 - 2002
+ *	Copyright (C) 1999 - 2003
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
@@ -280,7 +280,7 @@
 #endif
 
 /* Functions needed by other parts of the usbserial core */
-extern struct usb_serial *usb_serial_get_by_minor (unsigned int minor);
+extern struct usb_serial *usb_serial_get_by_index (unsigned int minor);
 extern int usb_serial_generic_open (struct usb_serial_port *port, struct file *filp);
 extern int usb_serial_generic_write (struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
 extern void usb_serial_generic_close (struct usb_serial_port *port, struct file *filp);
diff -Nru a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
--- a/drivers/usb/serial/visor.h	Tue Mar 11 09:34:45 2003
+++ b/drivers/usb/serial/visor.h	Wed May  7 04:49:36 2003
@@ -1,7 +1,7 @@
 /*
  * USB HandSpring Visor driver
  *
- *	Copyright (C) 1999 - 2002
+ *	Copyright (C) 1999 - 2003
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
diff -Nru a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
--- a/drivers/usb/storage/freecom.c	Mon Feb 24 10:18:11 2003
+++ b/drivers/usb/storage/freecom.c	Fri May 16 16:41:19 2003
@@ -134,7 +134,8 @@
 
 	/* Now transfer all of our blocks. */
 	US_DEBUGP("Start of read\n");
-	result = usb_stor_bulk_transfer_srb(us, ipipe, srb, count);
+	result = usb_stor_bulk_transfer_sg(us, ipipe, srb->request_buffer,
+			count, srb->use_sg, &srb->resid);
 	US_DEBUGP("freecom_readdata done!\n");
 
 	if (result > USB_STOR_XFER_SHORT)
@@ -168,7 +169,8 @@
 
 	/* Now transfer all of our blocks. */
 	US_DEBUGP("Start of write\n");
-	result = usb_stor_bulk_transfer_srb(us, opipe, srb, count);
+	result = usb_stor_bulk_transfer_sg(us, opipe, srb->request_buffer,
+			count, srb->use_sg, &srb->resid);
 
 	US_DEBUGP("freecom_writedata done!\n");
 	if (result > USB_STOR_XFER_SHORT)
diff -Nru a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
--- a/drivers/usb/storage/sddr09.c	Tue Mar 11 15:59:21 2003
+++ b/drivers/usb/storage/sddr09.c	Fri May 16 16:41:18 2003
@@ -1562,8 +1562,10 @@
 			  "sending" : "receiving",
 			  srb->request_bufflen);
 
-		result = usb_stor_bulk_transfer_srb(us, pipe, srb,
-							srb->request_bufflen);
+		result = usb_stor_bulk_transfer_sg(us, pipe,
+					srb->request_buffer,
+					srb->request_bufflen,
+					srb->use_sg, &srb->resid);
 
 		return (result == USB_STOR_XFER_GOOD ?
 			USB_STOR_TRANSPORT_GOOD : USB_STOR_TRANSPORT_ERROR);
diff -Nru a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
--- a/drivers/usb/storage/transport.c	Sun Apr  6 04:58:47 2003
+++ b/drivers/usb/storage/transport.c	Fri May 16 16:41:18 2003
@@ -511,9 +511,8 @@
 	 * short-circuit all other processing
 	 */
 	if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
-		US_DEBUGP("-- transport indicates command was aborted\n");
-		srb->result = DID_ABORT << 16;
-		return;
+		US_DEBUGP("-- command was aborted\n");
+		goto Handle_Abort;
 	}
 
 	/* if there is a transport error, reset and don't auto-sense */
@@ -634,8 +633,7 @@
 
 		if (atomic_read(&us->sm_state) == US_STATE_ABORTING) {
 			US_DEBUGP("-- auto-sense aborted\n");
-			srb->result = DID_ABORT << 16;
-			return;
+			goto Handle_Abort;
 		}
 		if (temp_result != USB_STOR_TRANSPORT_GOOD) {
 			US_DEBUGP("-- auto-sense failure\n");
@@ -688,6 +686,15 @@
 	    (result == USB_STOR_TRANSPORT_GOOD) &&
 	    ((srb->sense_buffer[2] & 0xf) == 0x0))
 		srb->sense_buffer[0] = 0x0;
+	return;
+
+	/* abort processing: the bulk-only transport requires a reset
+	 * following an abort */
+	Handle_Abort:
+	srb->result = DID_ABORT << 16;
+	if (us->protocol == US_PR_BULK) {
+		us->transport_reset(us);
+	}
 }
 
 /* Abort the currently running scsi command or device reset.
@@ -772,8 +779,9 @@
 	if (transfer_length) {
 		unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? 
 				us->recv_bulk_pipe : us->send_bulk_pipe;
-		result = usb_stor_bulk_transfer_srb(us, pipe, srb,
-					transfer_length);
+		result = usb_stor_bulk_transfer_sg(us, pipe,
+					srb->request_buffer, transfer_length,
+					srb->use_sg, &srb->resid);
 		US_DEBUGP("CBI data stage result is 0x%x\n", result);
 		if (result == USB_STOR_XFER_ERROR)
 			return USB_STOR_TRANSPORT_ERROR;
@@ -862,8 +870,9 @@
 	if (transfer_length) {
 		unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? 
 				us->recv_bulk_pipe : us->send_bulk_pipe;
-		result = usb_stor_bulk_transfer_srb(us, pipe, srb,
-					transfer_length);
+		result = usb_stor_bulk_transfer_sg(us, pipe,
+					srb->request_buffer, transfer_length,
+					srb->use_sg, &srb->resid);
 		US_DEBUGP("CB data stage result is 0x%x\n", result);
 		if (result == USB_STOR_XFER_ERROR)
 			return USB_STOR_TRANSPORT_ERROR;
@@ -944,8 +953,9 @@
 	if (transfer_length) {
 		unsigned int pipe = srb->sc_data_direction == SCSI_DATA_READ ? 
 				us->recv_bulk_pipe : us->send_bulk_pipe;
-		result = usb_stor_bulk_transfer_srb(us, pipe, srb,
-					transfer_length);
+		result = usb_stor_bulk_transfer_sg(us, pipe,
+					srb->request_buffer, transfer_length,
+					srb->use_sg, &srb->resid);
 		US_DEBUGP("Bulk data transfer result 0x%x\n", result);
 		if (result == USB_STOR_XFER_ERROR)
 			return USB_STOR_TRANSPORT_ERROR;
diff -Nru a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
--- a/drivers/usb/storage/transport.h	Sun Apr  6 04:58:47 2003
+++ b/drivers/usb/storage/transport.h	Fri May 16 16:41:18 2003
@@ -178,10 +178,4 @@
 extern int usb_stor_bulk_transfer_sg(struct us_data *us, unsigned int pipe,
 		void *buf, unsigned int length, int use_sg, int *residual);
 
-static __inline__ int usb_stor_bulk_transfer_srb(struct us_data *us,
-		unsigned int pipe, Scsi_Cmnd *srb, unsigned int length) {
-	return usb_stor_bulk_transfer_sg(us, pipe, srb->request_buffer,
-			length, srb->use_sg, &srb->resid);
-}
-
 #endif
diff -Nru a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
--- a/drivers/usb/storage/unusual_devs.h	Mon Oct 14 09:55:17 2002
+++ b/drivers/usb/storage/unusual_devs.h	Mon May 12 10:25:31 2003
@@ -98,6 +98,18 @@
 		"Nex II Digital",
 		US_SC_SCSI, US_PR_BULK, NULL, US_FL_START_STOP),
 
+/* Patch submitted by Philipp Friedrich <philipp@void.at> */
+UNUSUAL_DEV(  0x0482, 0x0100, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam S3x",
+		US_SC_8070, US_PR_CB, NULL, US_FL_FIX_INQUIRY),
+
+/* Patch submitted by Philipp Friedrich <philipp@void.at> */
+UNUSUAL_DEV(  0x0482, 0x0101, 0x0100, 0x0100,
+		"Kyocera",
+		"Finecam S4",
+		US_SC_8070, US_PR_CB, NULL, US_FL_FIX_INQUIRY),
+
 /* Reported by Paul Stewart <stewart@wetlogic.net>
  * This entry is needed because the device reports Sub=ff */
 UNUSUAL_DEV(  0x04a4, 0x0004, 0x0001, 0x0001,
@@ -237,14 +249,6 @@
 		US_SC_8070, US_PR_BULK, NULL,
 		US_FL_FIX_INQUIRY | US_FL_START_STOP ),
 
-/* Submitted by Lars Gemeinhardt <linux-usb@gemeinhardt.info>
- * Needed for START_STOP flag */
-UNUSUAL_DEV(  0x0547, 0x2810, 0x0001, 0x0001,
-                "Mello",
-                "MP3 Player",
-		US_SC_SCSI, US_PR_BULK, NULL,
-		US_FL_START_STOP),
-
 /* This entry is needed because the device reports Sub=ff */
 UNUSUAL_DEV(  0x054c, 0x0010, 0x0106, 0x0450, 
 		"Sony",
@@ -328,6 +332,15 @@
                 US_SC_8070, US_PR_CBI, NULL,
                 US_FL_FIX_INQUIRY ),
 
+/* Pentax Optio S digital camera
+ * submitted by Stefan M. Brandl <smb@smbnet.de>
+ */
+UNUSUAL_DEV( 0x0a17, 0x0006, 0x0000, 0xffff,
+		"Pentax",
+		"Optio S",
+		US_SC_8070, US_PR_CB, NULL,
+		US_FL_MODE_XLATE|US_FL_FIX_INQUIRY),
+
 #ifdef CONFIG_USB_STORAGE_ISD200
 UNUSUAL_DEV(  0x05ab, 0x0031, 0x0100, 0x0110,
 		"In-System",
@@ -626,6 +639,26 @@
 		US_SC_SCSI, US_PR_BULK, NULL,
 		US_FL_MODE_XLATE | US_FL_START_STOP | US_FL_FIX_INQUIRY ),
 
+/* This Pentax still camera is not conformant
+ * to the USB storage specification: -
+ * - It does not like the INQUIRY command. So we must handle this command
+ *   of the SCSI layer ourselves.
+ * Tested on Rev. 10.00 (0x1000)
+ * Submitted by James Courtier-Dutton <James@superbug.demon.co.uk>
+ */
+UNUSUAL_DEV( 0x0a17, 0x0004, 0x1000, 0x1000,
+                "Pentax",
+                "Optio 2/3/400",
+                US_SC_8070, US_PR_CBI, NULL,
+                US_FL_FIX_INQUIRY ),
+
+/* Submitted by Per Winkvist <per.winkvist@uk.com> */
+UNUSUAL_DEV( 0x0a17, 0x006, 0x1000, 0x9009,
+                "Pentax",
+                "Optio S",
+                US_SC_8070, US_PR_CBI, NULL,
+                US_FL_FIX_INQUIRY ),
+
 /* Submitted by Brian Hall <brihall@pcisys.net>
  * Needed for START_STOP flag */
 UNUSUAL_DEV(  0x0c76, 0x0003, 0x0100, 0x0100,
@@ -657,3 +690,13 @@
 		US_SC_SCSI, US_PR_SDDR55, NULL,
 		US_FL_SINGLE_LUN),
 #endif
+
+/* Aiptek PocketCAM 3Mega
+ * Nicolas DUPEUX <nicolas@dupeux.net> 
+ */
+UNUSUAL_DEV(  0x08ca, 0x2011, 0x0000, 0x9999,
+	"AIPTEK",
+	"PocketCAM 3Mega",
+	US_SC_SCSI, US_PR_BULK, NULL,
+	US_FL_MODE_XLATE | US_FL_START_STOP),
+
diff -Nru a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
--- a/drivers/usb/usb-skeleton.c	Fri Apr 18 11:49:59 2003
+++ b/drivers/usb/usb-skeleton.c	Sat May 17 14:55:52 2003
@@ -1,7 +1,7 @@
 /*
- * USB Skeleton driver - 1.0
+ * USB Skeleton driver - 1.1
  *
- * Copyright (c) 2001-2002 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (c) 2001-2003 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
@@ -18,6 +18,7 @@
  *
  * History:
  *
+ * 2003-05-06 - 1.1 - changes due to usb core changes with usb_register_dev()
  * 2003-02-25 - 1.0 - fix races involving urb->status, unlink_urb(), and
  *			disconnect.  Fix transfer amount in read().  Use
  *			macros instead of magic numbers in probe().  Change
@@ -47,7 +48,6 @@
 #include <linux/module.h>
 #include <linux/smp_lock.h>
 #include <linux/completion.h>
-#include <linux/devfs_fs_kernel.h>
 #include <asm/uaccess.h>
 #include <linux/usb.h>
 
@@ -87,12 +87,8 @@
 MODULE_DEVICE_TABLE (usb, skel_table);
 
 
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define USB_SKEL_MINOR_BASE	0
-#else
 /* Get a minor range for your devices from the usb maintainer */
 #define USB_SKEL_MINOR_BASE	192
-#endif
 
 /* Structure to hold all of our device specific stuff */
 struct usb_skel {
@@ -130,8 +126,8 @@
 static int skel_open		(struct inode *inode, struct file *file);
 static int skel_release		(struct inode *inode, struct file *file);
 
-static int skel_probe		(struct usb_interface *intf, const struct usb_device_id *id);
-static void skel_disconnect	(struct usb_interface *intf);
+static int skel_probe		(struct usb_interface *interface, const struct usb_device_id *id);
+static void skel_disconnect	(struct usb_interface *interface);
 
 static void skel_write_bulk_callback	(struct urb *urb, struct pt_regs *regs);
 
@@ -153,16 +149,6 @@
 	 * This also means that the kernel can decrement
 	 * the use-counter again before calling release()
 	 * or should the open() function fail.
-	 *
-	 * Not all device structures have an "owner" field
-	 * yet. "struct file_operations" and "struct net_device"
-	 * do, while "struct tty_driver" does not. If the struct
-	 * has an "owner" field, then initialize it to the value
-	 * THIS_MODULE and the kernel will handle all module
-	 * locking for you automatically. Otherwise, you must
-	 * increment the use-counter in the open() function
-	 * and decrement it again in the release() function
-	 * yourself.
 	 */
 	.owner =	THIS_MODULE,
 
@@ -173,6 +159,16 @@
 	.release =	skel_release,
 };
 
+/* 
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with devfs and the driver core
+ */
+static struct usb_class_driver skel_class = {
+	.name =		"usb/skel%d",
+	.fops =		&skel_fops,
+	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
+	.minor_base =	USB_SKEL_MINOR_BASE,
+};
 
 /* usb specific object needed to register this driver with the usb subsystem */
 static struct usb_driver skel_driver = {
@@ -236,8 +232,7 @@
 	/* prevent disconnects */
 	down (&disconnect_sem);
 
-	interface = usb_find_interface (&skel_driver,
-					mk_kdev(USB_MAJOR, subminor));
+	interface = usb_find_interface (&skel_driver, subminor);
 	if (!interface) {
 		err ("%s - error, can't find device for minor %d",
 		     __FUNCTION__, subminor);
@@ -508,7 +503,6 @@
 	struct usb_skel *dev = NULL;
 	struct usb_host_interface *iface_desc;
 	struct usb_endpoint_descriptor *endpoint;
-	int minor;
 	size_t buffer_size;
 	int i;
 	int retval;
@@ -521,7 +515,7 @@
 		return -ENODEV;
 	}
 
-	retval = usb_register_dev (&skel_fops, USB_SKEL_MINOR_BASE, 1, &minor);
+	retval = usb_register_dev (interface, &skel_class);
 	if (retval) {
 		/* something prevented us from registering this driver */
 		err ("Not able to get a minor for this device.");
@@ -539,7 +533,7 @@
 	init_MUTEX (&dev->sem);
 	dev->udev = udev;
 	dev->interface = interface;
-	dev->minor = minor;
+	dev->minor = interface->minor;
 
 	/* set up the endpoint information */
 	/* check out the endpoints */
@@ -606,22 +600,9 @@
 		goto error;
 	}
 
-	/* initialize the devfs node for this device and register it */
-	sprintf(name, "usb/skel%d", dev->minor);
-
-	devfs = devfs_register(NULL, name,
-				     DEVFS_FL_DEFAULT, USB_MAJOR,
-				     dev->minor,
-				     S_IFCHR | S_IRUSR | S_IWUSR |
-				     S_IRGRP | S_IWGRP | S_IROTH,
-				     &skel_fops, NULL);
-
 	/* let the user know what node this device is now attached to */
 	info ("USB Skeleton device now attached to USBSkel-%d", dev->minor);
 
-	/* add device id so the device works when advertised */
-	interface->kdev = mk_kdev(USB_MAJOR, dev->minor);
-
 	goto exit;
 
 error:
@@ -629,7 +610,7 @@
 	dev = NULL;
 
 exit_minor:
-	usb_deregister_dev (1, minor);
+	usb_deregister_dev (interface, &skel_class);
 
 exit:
 	if (dev) {
@@ -667,16 +648,13 @@
 
 	down (&dev->sem);
 
-	/* remove device id to disable open() */
-	interface->kdev = NODEV;
+	/* disable open() */
+	interface->minor = -1;
 
 	minor = dev->minor;
 
-	/* remove our devfs node */
-	devfs_remove("usb/skel%d", dev->minor);
-
-	/* give back our dynamic minor */
-	usb_deregister_dev (1, minor);
+	/* give back our minor */
+	usb_deregister_dev (interface, &skel_class);
 
 	/* terminate an ongoing write */
 	if (atomic_read (&dev->write_busy)) {
diff -Nru a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
--- a/drivers/video/console/fbcon.c	Mon Apr 21 01:18:58 2003
+++ b/drivers/video/console/fbcon.c	Mon May 12 09:38:57 2003
@@ -294,13 +294,16 @@
  *	Maps a virtual console @unit to a frame buffer device
  *	@newidx.
  */
-void set_con2fb_map(int unit, int newidx)
+int set_con2fb_map(int unit, int newidx)
 {
 	struct vc_data *vc = vc_cons[unit].d;
 
+	if (!vc)
+		return -ENODEV;
 	con2fb_map[unit] = newidx;
 	fbcon_is_default = (vc->vc_sw == &fb_con) ? 1 : 0;
 	take_over_console(&fb_con, unit, unit, fbcon_is_default);
+	return 0;
 }
 
 /*
@@ -1045,6 +1048,11 @@
 			cursor.image.height = vc->vc_font.height;
 			cursor.image.width = vc->vc_font.width;
 			cursor.set |= FB_CUR_SETSIZE;
+		}
+
+		if (info->cursor.hot.x || info->cursor.hot.y) {
+			cursor.hot.x = cursor.hot.y = 0;
+			cursor.set |= FB_CUR_SETHOT;
 		}
 
 		if ((cursor.set & FB_CUR_SETSIZE) || ((vc->vc_cursor_type & 0x0f) != p->cursor_shape)) {
diff -Nru a/drivers/video/console/fbcon.h b/drivers/video/console/fbcon.h
--- a/drivers/video/console/fbcon.h	Wed Apr  2 04:37:53 2003
+++ b/drivers/video/console/fbcon.h	Mon May 12 09:38:57 2003
@@ -38,7 +38,7 @@
 
 /* drivers/video/console/fbcon.c */
 extern char con2fb_map[MAX_NR_CONSOLES];
-extern void set_con2fb_map(int unit, int newidx);
+extern int set_con2fb_map(int unit, int newidx);
 
     /*
      *  Attribute Decoding
diff -Nru a/drivers/video/cyber2000fb.c b/drivers/video/cyber2000fb.c
--- a/drivers/video/cyber2000fb.c	Fri Apr 25 10:59:54 2003
+++ b/drivers/video/cyber2000fb.c	Sat May 17 07:20:46 2003
@@ -146,7 +146,7 @@
  * Hardware Cyber2000 Acceleration
  */
 static void
-cyber2000fb_fillrect(struct fb_info *info, struct fb_fillrect *rect)
+cyber2000fb_fillrect(struct fb_info *info, const struct fb_fillrect *rect)
 {
 	struct cfb_info *cfb = (struct cfb_info *)info;
 	unsigned long dst, col;
@@ -178,7 +178,7 @@
 }
 
 static void
-cyber2000fb_copyarea(struct fb_info *info, struct fb_copyarea *region)
+cyber2000fb_copyarea(struct fb_info *info, const struct fb_copyarea *region)
 {
 	struct cfb_info *cfb = (struct cfb_info *)info;
 	unsigned int cmd = CO_CMD_L_PATTERN_FGCOL;
@@ -189,24 +189,25 @@
 		return;
 	}
 
+	cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
+	cyber2000fb_writew(region->width - 1, CO_REG_PIXWIDTH, cfb);
+	cyber2000fb_writew(region->height - 1, CO_REG_PIXHEIGHT, cfb);
+
+	src = region->sx + region->sy * cfb->fb.var.xres_virtual;
+	dst = region->dx + region->dy * cfb->fb.var.xres_virtual;
+
 	if (region->sx < region->dx) {
-		region->sx += region->width - 1;
-		region->dx += region->width - 1;
+		src += region->width - 1;
+		dst += region->width - 1;
 		cmd |= CO_CMD_L_INC_LEFT;
 	}
 
 	if (region->sy < region->dy) {
-		region->sy += region->height - 1;
-		region->dy += region->height - 1;
+		src += (region->height - 1) * cfb->fb.var.xres_virtual;
+		dst += (region->height - 1) * cfb->fb.var.xres_virtual;
 		cmd |= CO_CMD_L_INC_UP;
 	}
 
-	cyber2000fb_writeb(0, CO_REG_CONTROL, cfb);
-	cyber2000fb_writew(region->width - 1, CO_REG_PIXWIDTH, cfb);
-	cyber2000fb_writew(region->height - 1, CO_REG_PIXHEIGHT, cfb);
-
-	src = region->sx + region->sy * cfb->fb.var.xres_virtual;
-	dst = region->dx + region->dy * cfb->fb.var.xres_virtual;
 	if (cfb->fb.var.bits_per_pixel == 24) {
 		cyber2000fb_writeb(dst, CO_REG_X_PHASE, cfb);
 		src *= 3;
@@ -221,9 +222,9 @@
 }
 
 static void
-cyber2000fb_imageblit(struct fb_info *info, struct fb_image *image)
+cyber2000fb_imageblit(struct fb_info *info, const struct fb_image *image)
 {
-	struct cfb_info *cfb = (struct cfb_info *)info;
+//	struct cfb_info *cfb = (struct cfb_info *)info;
 
 //	if (!(cfb->fb.var.accel_flags & FB_ACCELF_TEXT)) {
 		cfb_imageblit(info, image);
@@ -754,7 +755,6 @@
 	var->blue.msb_right	= 0;
 
 	switch (var->bits_per_pixel) {
-#ifdef FBCON_HAS_CFB8
 	case 8:	/* PSEUDOCOLOUR, 256 */
 		var->transp.offset	= 0;
 		var->transp.length	= 0;
@@ -765,8 +765,7 @@
 		var->blue.offset	= 0;
 		var->blue.length	= 8;
 		break;
-#endif
-#ifdef FBCON_HAS_CFB16
+
 	case 16:/* DIRECTCOLOUR, 64k or 32k */
 		switch (var->green.length) {
 		case 6: /* RGB565, 64k */
@@ -804,8 +803,7 @@
 			break;
 		}
 		break;
-#endif
-#ifdef FBCON_HAS_CFB24
+
 	case 24:/* TRUECOLOUR, 16m */
 		var->transp.offset	= 0;
 		var->transp.length	= 0;
@@ -816,8 +814,7 @@
 		var->blue.offset	= 0;
 		var->blue.length	= 8;
 		break;
-#endif
-#ifdef FBCON_HAS_CFB32
+
 	case 32:/* TRUECOLOUR, 16m */
 		var->transp.offset	= 24;
 		var->transp.length	= 8;
@@ -828,7 +825,7 @@
 		var->blue.offset	= 0;
 		var->blue.length	= 8;
 		break;
-#endif
+
 	default:
 		return -EINVAL;
 	}
@@ -1601,15 +1598,17 @@
 	/*
 	 * Use MCLK from BIOS. FIXME: what about hotplug?
 	 */
-#ifndef __arm__
 	cfb->mclk_mult = cyber2000_grphr(EXT_MCLK_MULT, cfb);
 	cfb->mclk_div  = cyber2000_grphr(EXT_MCLK_DIV, cfb);
-#else
+
+#ifdef __arm__
 	/*
 	 * MCLK on the NetWinder and the Shark is fixed at 75MHz
 	 */
-	cfb->mclk_mult = 0xdb;
-	cfb->mclk_div  = 0x54;
+	if (machine_is_netwinder()) {
+		cfb->mclk_mult = 0xdb;
+		cfb->mclk_div  = 0x54;
+	}
 #endif
 
 	err = cyberpro_common_probe(cfb);
diff -Nru a/drivers/video/fbmem.c b/drivers/video/fbmem.c
--- a/drivers/video/fbmem.c	Thu Apr 24 03:30:41 2003
+++ b/drivers/video/fbmem.c	Sat May 17 12:39:13 2003
@@ -839,10 +839,7 @@
 #ifdef CONFIG_KMOD
 static void try_to_load(int fb)
 {
-	char modname[16];
-
-	sprintf(modname, "fb%d", fb);
-	request_module(modname);
+	request_module("fb%d", fb);
 }
 #endif /* CONFIG_KMOD */
 
@@ -1214,7 +1211,6 @@
 int
 register_framebuffer(struct fb_info *fb_info)
 {
-	char name_buf[12];
 	int i;
 
 	if (num_registered_fb == FB_MAX)
@@ -1242,10 +1238,9 @@
 	spin_lock_init(&fb_info->pixmap.lock);
 
 	registered_fb[i] = fb_info;
-	sprintf(name_buf, "fb/%d", i);
-	devfs_register(NULL, name_buf, DEVFS_FL_DEFAULT,
-			FB_MAJOR, i, S_IFCHR | S_IRUGO | S_IWUGO,
-			&fb_fops, NULL);
+
+	devfs_mk_cdev(MKDEV(FB_MAJOR, i),
+			S_IFCHR | S_IRUGO | S_IWUGO, "fb/%d", i);
 	return 0;
 }
 
diff -Nru a/drivers/video/logo/logo.c b/drivers/video/logo/logo.c
--- a/drivers/video/logo/logo.c	Sun Apr 20 02:43:30 2003
+++ b/drivers/video/logo/logo.c	Mon May 12 21:23:19 2003
@@ -79,8 +79,10 @@
 		logo = &logo_parisc_clut224;
 #endif
 #ifdef CONFIG_LOGO_SGI_CLUT224
-		/* SGI Linux logo on MIPS/MIPS64 */
+		/* SGI Linux logo on MIPS/MIPS64 and VISWS */
+#ifndef CONFIG_X86_VISWS
 		if (mips_machgroup == MACH_GROUP_SGI)
+#endif
 			logo = &logo_sgi_clut224;
 #endif
 #ifdef CONFIG_LOGO_SUN_CLUT224
diff -Nru a/drivers/video/radeonfb.c b/drivers/video/radeonfb.c
--- a/drivers/video/radeonfb.c	Thu Apr 24 03:30:41 2003
+++ b/drivers/video/radeonfb.c	Sat May 17 14:09:48 2003
@@ -2840,8 +2840,7 @@
 	}
 
 	/* map the regions */
-	rinfo->mmio_base = (u32) ioremap (rinfo->mmio_base_phys,
-				    		    RADEON_REGSIZE);
+	rinfo->mmio_base = (unsigned long) ioremap (rinfo->mmio_base_phys, RADEON_REGSIZE);
 	if (!rinfo->mmio_base) {
 		printk ("radeonfb: cannot map MMIO\n");
 		release_mem_region (rinfo->mmio_base_phys,
@@ -2978,8 +2977,7 @@
 		}
 	}
 
-	rinfo->fb_base = (u32) ioremap (rinfo->fb_base_phys,
-				  		  rinfo->video_ram);
+	rinfo->fb_base = (unsigned long) ioremap (rinfo->fb_base_phys, rinfo->video_ram);
 	if (!rinfo->fb_base) {
 		printk ("radeonfb: cannot map FB\n");
 		iounmap ((void*)rinfo->mmio_base);
diff -Nru a/drivers/video/riva/fbdev.c b/drivers/video/riva/fbdev.c
--- a/drivers/video/riva/fbdev.c	Thu Apr 24 03:30:41 2003
+++ b/drivers/video/riva/fbdev.c	Mon May 12 07:53:32 2003
@@ -1469,10 +1469,10 @@
 static int rivafb_cursor(struct fb_info *info, struct fb_cursor *cursor)
 {
 	struct riva_par *par = (struct riva_par *) info->par;
-	int i, j, d_idx = 0, s_idx = 0;
 	u8 data[MAX_CURS * MAX_CURS/8];
 	u8 mask[MAX_CURS * MAX_CURS/8];
 	u16 fg, bg;
+	int i;
 
 	par->riva.ShowHideCursor(&par->riva, 0);
 
diff -Nru a/drivers/video/vesafb.c b/drivers/video/vesafb.c
--- a/drivers/video/vesafb.c	Thu Apr 24 03:30:41 2003
+++ b/drivers/video/vesafb.c	Mon May 12 07:26:05 2003
@@ -215,7 +215,6 @@
 int __init vesafb_init(void)
 {
 	int video_cmap_len;
-	char *edid = 0;
 	int i;
 
 	if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB)
@@ -300,18 +299,10 @@
 		ypan = 0;
 	}
 
-#ifdef __i386__
-	edid = get_EDID_from_BIOS(0);
-	if (edid)
-		parse_edid(edid, &vesafb_defined);	
-	else		
-#endif
-	{	
-		/* some dummy values for timing to make fbset happy */
-		vesafb_defined.pixclock     = 10000000 / vesafb_defined.xres * 1000 / vesafb_defined.yres;
-		vesafb_defined.left_margin  = (vesafb_defined.xres / 8) & 0xf8;
-		vesafb_defined.hsync_len    = (vesafb_defined.xres / 8) & 0xf8;
-	}
+	/* some dummy values for timing to make fbset happy */
+	vesafb_defined.pixclock     = 10000000 / vesafb_defined.xres * 1000 / vesafb_defined.yres;
+	vesafb_defined.left_margin  = (vesafb_defined.xres / 8) & 0xf8;
+	vesafb_defined.hsync_len    = (vesafb_defined.xres / 8) & 0xf8;
 	
 	if (vesafb_defined.bits_per_pixel > 8) {
 		vesafb_defined.red.offset    = screen_info.red_pos;
diff -Nru a/fs/Kconfig b/fs/Kconfig
--- a/fs/Kconfig	Thu Apr 24 07:01:15 2003
+++ b/fs/Kconfig	Mon May  5 06:19:21 2003
@@ -73,6 +73,18 @@
 
 	  If you don't know what Access Control Lists are, say N
 
+config EXT2_FS_SECURITY
+	bool "Ext2 Security Labels"
+	depends on EXT2_FS_XATTR
+	help
+	  Security labels support alternative access control models
+	  implemented by security modules like SELinux.  This option
+	  enables an extended attribute handler for file security
+	  labels in the ext2 filesystem.
+
+	  If you are not using a security module that requires using
+	  extended attributes for file security labels, say N.
+
 config EXT3_FS
 	tristate "Ext3 journalling file system support"
 	help
@@ -130,6 +142,18 @@
 	  Linux website <http://acl.bestbits.at/>.
 
 	  If you don't know what Access Control Lists are, say N
+
+config EXT3_FS_SECURITY
+	bool "Ext3 Security Labels"
+	depends on EXT3_FS_XATTR
+	help
+	  Security labels support alternative access control models
+	  implemented by security modules like SELinux.  This option
+	  enables an extended attribute handler for file security
+	  labels in the ext3 filesystem.
+
+	  If you are not using a security module that requires using
+	  extended attributes for file security labels, say N.
 
 config JBD
 # CONFIG_JBD could be its own option (even modular), but until there are
diff -Nru a/fs/bfs/dir.c b/fs/bfs/dir.c
--- a/fs/bfs/dir.c	Sat Sep 28 08:36:28 2002
+++ b/fs/bfs/dir.c	Sun May  4 22:49:54 2003
@@ -65,7 +65,7 @@
 		brelse(bh);
 	}
 
-	UPDATE_ATIME(dir);
+	update_atime(dir);
 	unlock_kernel();
 	return 0;	
 }
diff -Nru a/fs/binfmt_elf.c b/fs/binfmt_elf.c
--- a/fs/binfmt_elf.c	Wed Apr 23 05:54:07 2003
+++ b/fs/binfmt_elf.c	Tue May  6 06:16:37 2003
@@ -1105,7 +1105,7 @@
 
 	i = p->state ? ffz(~p->state) + 1 : 0;
 	psinfo->pr_state = i;
-	psinfo->pr_sname = (i < 0 || i > 5) ? '.' : "RSDZTD"[i];
+	psinfo->pr_sname = (i < 0 || i > 5) ? '.' : "RSDTZW"[i];
 	psinfo->pr_zomb = psinfo->pr_sname == 'Z';
 	psinfo->pr_nice = task_nice(p);
 	psinfo->pr_flag = p->flags;
diff -Nru a/fs/bio.c b/fs/bio.c
--- a/fs/bio.c	Thu Apr 24 03:23:09 2003
+++ b/fs/bio.c	Thu May  8 02:16:24 2003
@@ -728,6 +728,7 @@
 	}
 
 	bio->bi_size -= bytes_done;
+	bio->bi_sector += (bytes_done >> 9);
 
 	if (bio->bi_end_io)
 		bio->bi_end_io(bio, bytes_done, error);
diff -Nru a/fs/block_dev.c b/fs/block_dev.c
--- a/fs/block_dev.c	Tue Apr 29 06:28:09 2003
+++ b/fs/block_dev.c	Tue May 13 13:42:27 2003
@@ -681,18 +681,18 @@
 	return blkdev_put(inode->i_bdev, BDEV_FILE);
 }
 
-static ssize_t blkdev_file_write(struct file *file, const char *buf,
+static ssize_t blkdev_file_write(struct file *file, const char __user *buf,
 				   size_t count, loff_t *ppos)
 {
-	struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count };
+	struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
 
 	return generic_file_write_nolock(file, &local_iov, 1, ppos);
 }
 
-static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char *buf,
+static ssize_t blkdev_file_aio_write(struct kiocb *iocb, const char __user *buf,
 				   size_t count, loff_t pos)
 {
-	struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count };
+	struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
 
 	return generic_file_aio_write_nolock(iocb, &local_iov, 1, &iocb->ki_pos);
 }
diff -Nru a/fs/buffer.c b/fs/buffer.c
--- a/fs/buffer.c	Wed Apr 30 00:03:42 2003
+++ b/fs/buffer.c	Mon May 12 21:23:22 2003
@@ -244,16 +244,28 @@
  * sync everything.  Start out by waking pdflush, because that writes back
  * all queues in parallel.
  */
-asmlinkage long sys_sync(void)
+static void do_sync(unsigned long wait)
 {
 	wakeup_bdflush(0);
 	sync_inodes(0);		/* All mappings, inodes and their blockdevs */
 	DQUOT_SYNC(NULL);
 	sync_supers();		/* Write the superblocks */
 	sync_filesystems(0);	/* Start syncing the filesystems */
-	sync_filesystems(1);	/* Waitingly sync the filesystems */
-	sync_inodes(1);		/* Mappings, inodes and blockdevs, again. */
+	sync_filesystems(wait);	/* Waitingly sync the filesystems */
+	sync_inodes(wait);	/* Mappings, inodes and blockdevs, again. */
+	if (!wait)
+		printk("Emergency Sync complete\n");
+}
+
+asmlinkage long sys_sync(void)
+{
+	do_sync(1);
 	return 0;
+}
+
+void emergency_sync(void)
+{
+	pdflush_operation(do_sync, 0);
 }
 
 /*
diff -Nru a/fs/char_dev.c b/fs/char_dev.c
--- a/fs/char_dev.c	Thu Mar 27 21:16:46 2003
+++ b/fs/char_dev.c	Sat May 17 12:39:13 2003
@@ -102,9 +102,7 @@
 
 #ifdef CONFIG_KMOD
 	if (!ret) {
-		char name[32];
-		sprintf(name, "char-major-%d", major);
-		request_module(name);
+		request_module("char-major-%d", major);
 
 		read_lock(&chrdevs_lock);
 		ret = lookup_chrfops(major, minor);
diff -Nru a/fs/cifs/AUTHORS b/fs/cifs/AUTHORS
--- a/fs/cifs/AUTHORS	Thu Oct 31 14:10:07 2002
+++ b/fs/cifs/AUTHORS	Fri May 16 09:07:43 2003
@@ -20,3 +20,9 @@
 Zwane Mwaikambo
 Andi Kleen
 
+Test case and Bug Report contributors
+-------------------------------------
+Thanks to those in the community who have submitted detailed bug reports
+and debug of problems they have found:  Jochen Dolze, David Blaine,
+Rene Scharfe, Martin Josefsson and others. 
+
diff -Nru a/fs/cifs/CHANGES b/fs/cifs/CHANGES
--- a/fs/cifs/CHANGES	Sat Apr 26 22:25:27 2003
+++ b/fs/cifs/CHANGES	Fri May 16 09:07:44 2003
@@ -1,3 +1,16 @@
+Version 0.77
+------------
+Fix display of NTFS DFS junctions to display as symlinks.
+They are the network equivalent.  Fix oops in 
+cifs_partialpagewrite caused by missing spinlock protection
+of openfile linked list.  Allow writebehind caching errors to 
+be returned to the application at file close.
+
+Version 0.76
+------------
+Clean up options displayed in /proc/mounts by show_options to
+be more consistent with other filesystems.
+
 Version 0.75
 ------------
 Fix delete of readonly file to Windows servers.  Reflect
diff -Nru a/fs/cifs/TODO b/fs/cifs/TODO
--- a/fs/cifs/TODO	Fri Mar  7 15:01:07 2003
+++ b/fs/cifs/TODO	Fri May 16 09:07:44 2003
@@ -18,6 +18,8 @@
 d) Kerberos/SPNEGO session setup support - (started)
 
 e) NTLMv2 authentication and MD5-HMAC signing SMB PDUs - (mostly implemented)
+	signing necessary for some Windows 2003 servers in domain 
+	controller mode.
 
 f) oplock support (ie safe CIFS distributed file caching) is not quite complete.
 In addition Directory entry caching relies on a 1 second timer, rather than 
@@ -52,7 +54,8 @@
 than resending (helps reduce server resource utilization and avoid
 spurious oplock breaks).
 
-KNOWN BUGS (updated March 7, 2003)
+
+KNOWN BUGS (updated May 16, 2003)
 ====================================
 1) existing symbolic links (Windows reparse points) are recognized but
 can not be created remotely. They are implemented for Samba and those that
@@ -60,6 +63,11 @@
 symlink text beginning with slash
 2) delete of file with read-only attribute set will fail (may be ok)
 3) mount helper syntax not quite matching man page
+4) follow_link and readdir code does not follow dfs junctions
+but recognizes them
+5) create of new files to FAT partitions on Windows servers can
+succeed but still return access denied (appears to be Windows 
+not client problem).  NTFS partitions do not have this problem.
 
 Misc testing to do
 =================
@@ -68,6 +76,6 @@
 
 2) Run dbench
 
-3) Finish FSX testing on SMP now that we workaround the Samba bug
+3) Finish high stress fsx testing on SMP clients
 
 4) Additional performance testing and optimization
diff -Nru a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
--- a/fs/cifs/cifs_debug.c	Mon Mar 31 19:52:27 2003
+++ b/fs/cifs/cifs_debug.c	Fri May 16 09:07:44 2003
@@ -56,7 +56,7 @@
 	}
 }
 
-#if CONFIG_PROC_FS
+#ifdef CONFIG_PROC_FS
 int
 cifs_debug_data_read(char *buf, char **beginBuffer, off_t offset,
 		     int count, int *eof, void *data)
@@ -89,8 +89,8 @@
 				ses->serverOS, ses->serverNOS, ses->capabilities);
 		buf += length;
 		if(ses->server)
-		buf += sprintf(buf, "\tLocal Users To Same Server: %d ",
-			atomic_read(&ses->server->socketUseCount));
+			buf += sprintf(buf, "\tLocal Users To Same Server: %d ",
+				atomic_read(&ses->server->socketUseCount));
 	}
 	read_unlock(&GlobalSMBSeslock);
 	sprintf(buf, "\n");
diff -Nru a/fs/cifs/cifs_fs_sb.h b/fs/cifs/cifs_fs_sb.h
--- a/fs/cifs/cifs_fs_sb.h	Fri Mar  7 15:01:07 2003
+++ b/fs/cifs/cifs_fs_sb.h	Sun Apr 27 14:44:53 2003
@@ -22,7 +22,7 @@
 	struct cifsTconInfo *tcon;	/* primary mount */
 	struct list_head nested_tcon_q;
 	struct nls_table *local_nls;
-    unsigned int rsize;
-    unsigned int wsize;
+	unsigned int rsize;
+	unsigned int wsize;
 };
 #endif				/* _CIFS_FS_SB_H */
diff -Nru a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
--- a/fs/cifs/cifsfs.c	Wed Apr  9 09:38:32 2003
+++ b/fs/cifs/cifsfs.c	Fri May 16 09:07:44 2003
@@ -209,8 +209,8 @@
 
 /*
  * cifs_show_options() is for displaying mount options in /proc/mounts.
- * It tries to avoid showing settings that were not changed from their
- * defaults.
+ * Not all settable options are displayed but most of the important
+ * ones are.
  */
 static int
 cifs_show_options(struct seq_file *s, struct vfsmount *m)
@@ -219,15 +219,19 @@
 
 	cifs_sb = CIFS_SB(m->mnt_sb);
 
-	if (cifs_sb)
+	if (cifs_sb) {
 		if (cifs_sb->tcon) {
-			seq_printf(s, ", TARGET: %s ", cifs_sb->tcon->treeName);
-			seq_printf(s, "FS TYPE: %s ",
-				   cifs_sb->tcon->nativeFileSystem);
+			seq_printf(s, ",unc=%s", cifs_sb->tcon->treeName);
 			if (cifs_sb->tcon->ses->userName)
-				seq_printf(s, " USER: %s ",
+				seq_printf(s, ",username=%s",
 					   cifs_sb->tcon->ses->userName);
+			if(cifs_sb->tcon->ses->domainName)
+				seq_printf(s, ",domain=%s",
+					cifs_sb->tcon->ses->domainName);
 		}
+		seq_printf(s, ",rsize=%d",cifs_sb->rsize);
+		seq_printf(s, ",wsize=%d",cifs_sb->wsize);
+	}
 	return 0;
 }
 
@@ -423,6 +427,7 @@
 static int cifs_oplock_thread(void * dummyarg)
 {
 	struct list_head * tmp;
+	struct list_head * tmp1;
 	struct oplock_q_entry * oplock_item;
 	struct file * pfile;
 	struct cifsTconInfo *pTcon;
@@ -438,9 +443,8 @@
 		/* BB add missing code */
 		cFYI(1,("oplock thread woken up - flush inode")); /* BB remove */
 		write_lock(&GlobalMid_Lock); 
-		list_for_each(tmp, &GlobalOplock_Q) {
-			oplock_item = list_entry(tmp, struct
-							       oplock_q_entry,
+		list_for_each_safe(tmp, tmp1, &GlobalOplock_Q) {
+			oplock_item = list_entry(tmp, struct oplock_q_entry,
 							       qhead);
 			if(oplock_item) {
 				pTcon = oplock_item->tcon;
@@ -449,6 +453,9 @@
 				DeleteOplockQEntry(oplock_item);
 				write_unlock(&GlobalMid_Lock);
 				rc = filemap_fdatawrite(pfile->f_dentry->d_inode->i_mapping);
+				if(rc)
+					CIFS_I(pfile->f_dentry->d_inode)->write_behind_rc 
+						= rc;
 				cFYI(1,("Oplock flush file %p rc %d",pfile,rc));
 				/* send oplock break */
 				write_lock(&GlobalMid_Lock);
@@ -465,7 +472,7 @@
 init_cifs(void)
 {
 	int rc = 0;
-#if CONFIG_PROC_FS
+#ifdef CONFIG_PROC_FS
 	cifs_proc_init();
 #endif
 	INIT_LIST_HEAD(&GlobalServerList);	/* BB not implemented yet */
@@ -503,7 +510,7 @@
 		}
 		cifs_destroy_inodecache();
 	}
-#if CONFIG_PROC_FS
+#ifdef CONFIG_PROC_FS
 	cifs_proc_clean();
 #endif
 	return rc;
@@ -513,7 +520,7 @@
 exit_cifs(void)
 {
 	cFYI(0, ("In unregister ie exit_cifs"));
-#if CONFIG_PROC_FS
+#ifdef CONFIG_PROC_FS
 	cifs_proc_clean();
 #endif
 	unregister_filesystem(&cifs_fs_type);
diff -Nru a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
--- a/fs/cifs/cifsglob.h	Tue Apr  1 15:34:09 2003
+++ b/fs/cifs/cifsglob.h	Fri May 16 09:07:44 2003
@@ -157,8 +157,8 @@
 	int capabilities;
 	char serverName[SERVER_NAME_LEN_WITH_NULL * 2];	/* BB make bigger for tcp names - will ipv6 and sctp addresses fit here?? */
 	char userName[MAX_USERNAME_SIZE + 1];
-    char domainName[MAX_USERNAME_SIZE + 1];
-    char password_with_pad[CIFS_ENCPWD_SIZE];
+	char domainName[MAX_USERNAME_SIZE + 1];
+	char password_with_pad[CIFS_ENCPWD_SIZE];
 };
 
 /*
@@ -204,7 +204,7 @@
 	__u16 netfid;		/* file id from remote */
 	/* BB add lock scope info here if needed */ ;
 	/* lock scope id (0 if none) */
-    	struct file * pfile; /* needed for writepage */
+	struct file * pfile; /* needed for writepage */
 	int endOfSearch:1;	/* we have reached end of search */
 	int closePend:1;	/* file is marked to close */
 	int emptyDir:1;
@@ -221,6 +221,7 @@
 	struct list_head lockList;
 	/* BB add in lists for dirty pages - i.e. write caching info for oplock */
 	struct list_head openFileList;
+	int write_behind_rc;
 	__u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
 	atomic_t inUse;	 /* num concurrent users (local openers cifs) of file*/
 	unsigned long time;	/* jiffies of last update/check of inode */
diff -Nru a/fs/cifs/cifspdu.h b/fs/cifs/cifspdu.h
--- a/fs/cifs/cifspdu.h	Mon Mar 31 19:52:27 2003
+++ b/fs/cifs/cifspdu.h	Tue May 13 11:00:10 2003
@@ -1263,6 +1263,7 @@
 	__u16 ServerType;	/* 0x0001 = CIFS server */
 	__u16 ReferralFlags;	/* or proximity - not clear which since always set to zero - SNIA spec says 0x01 means strip off PathConsumed chars before submitting RequestFileName to remote node */
 	__u16 TimeToLive;
+	__u16 Proximity;
 	__u16 DfsPathOffset;
 	__u16 DfsAlternatePathOffset;
 	__u16 NetworkAddressOffset;
diff -Nru a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
--- a/fs/cifs/cifsproto.h	Mon Mar 31 19:52:27 2003
+++ b/fs/cifs/cifsproto.h	Tue May 13 11:00:10 2003
@@ -127,13 +127,15 @@
 extern int CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
 			const unsigned char *searchName,
 			unsigned char **targetUNCs,
-			int *number_of_UNC_in_array,
+			unsigned int *number_of_UNC_in_array,
 			const struct nls_table *nls_codepage);
 
 extern int connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 			const char *old_path,
 			const struct nls_table *nls_codepage);
-
+extern int get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+			const char *old_path, const struct nls_table *nls_codepage, 
+			unsigned int *pnum_referrals, unsigned char ** preferrals);
 extern int CIFSSMBQFSInfo(const int xid, struct cifsTconInfo *tcon,
 			struct statfs *FSData,
 			const struct nls_table *nls_codepage);
diff -Nru a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
--- a/fs/cifs/cifssmb.c	Sat Apr 26 22:25:27 2003
+++ b/fs/cifs/cifssmb.c	Tue May 13 11:00:11 2003
@@ -1625,15 +1625,18 @@
 CIFSGetDFSRefer(const int xid, struct cifsSesInfo *ses,
 		const unsigned char *searchName,
 		unsigned char **targetUNCs,
-		int *number_of_UNC_in_array,
+		unsigned int *number_of_UNC_in_array,
 		const struct nls_table *nls_codepage)
 {
 /* TRANS2_GET_DFS_REFERRAL */
 	TRANSACTION2_GET_DFS_REFER_REQ *pSMB = NULL;
 	TRANSACTION2_GET_DFS_REFER_RSP *pSMBr = NULL;
+	struct dfs_referral_level_3 * referrals = NULL;
 	int rc = 0;
 	int bytes_returned;
 	int name_len;
+	unsigned int i;
+	char * temp;
 	*number_of_UNC_in_array = 0;
 	*targetUNCs = NULL;
 
@@ -1654,8 +1657,8 @@
 	if (ses->capabilities & CAP_DFS) {
 		pSMB->hdr.Flags2 |= SMBFLG2_DFS;
 	}
-    if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
-       pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
+	if(ses->server->secMode & (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED))
+		pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE;
 
 	if (ses->capabilities & CAP_UNICODE) {
 		pSMB->hdr.Flags2 |= SMBFLG2_UNICODE;
@@ -1701,6 +1704,76 @@
 		cFYI(1, ("Send error in GetDFSRefer = %d", rc));
 	} else {		/* decode response */
 /* BB Add logic to parse referrals here */
+		pSMBr->DataOffset = le16_to_cpu(pSMBr->DataOffset);
+		pSMBr->DataCount = le16_to_cpu(pSMBr->DataCount);
+		cFYI(1,
+		     ("Decoding GetDFSRefer response.  BCC: %d  Offset %d",
+		      pSMBr->ByteCount, pSMBr->DataOffset));
+		if ((pSMBr->ByteCount < 17) || (pSMBr->DataOffset > 512))	/* BB also check enough total bytes returned */
+			rc = -EIO;	/* bad smb */
+		else {
+			referrals = 
+			    (struct dfs_referral_level_3 *) 
+					(8 /* sizeof start of data block */ +
+					pSMBr->DataOffset +
+					(char *) &pSMBr->hdr.Protocol); 
+			cFYI(1,("num_referrals: %d dfs flags: 0x%x ... \nfor referral one refer size: 0x%x srv type: 0x%x refer flags: 0x%x ttl: 0x%x",pSMBr->NumberOfReferrals,pSMBr->DFSFlags, referrals->ReferralSize,referrals->ServerType,referrals->ReferralFlags,referrals->TimeToLive));
+			/* BB This field is actually two bytes in from start of
+			   data block so we could do safety check that DataBlock
+			   begins at address of pSMBr->NumberOfReferrals */
+			*number_of_UNC_in_array = le16_to_cpu(pSMBr->NumberOfReferrals);
+
+			/* BB Fix below so can return more than one referral */
+			if(*number_of_UNC_in_array > 1)
+				*number_of_UNC_in_array = 1;
+
+			/* get the length of the strings describing refs */
+			name_len = 0;
+			for(i=0;i<*number_of_UNC_in_array;i++) {
+				/* make sure that DfsPathOffset not past end */
+				referrals->DfsPathOffset = le16_to_cpu(referrals->DfsPathOffset);
+				if(referrals->DfsPathOffset > pSMBr->DataCount) {
+					/* if invalid referral, stop here and do 
+					not try to copy any more */
+					*number_of_UNC_in_array = i;
+					break;
+				} 
+				temp = ((char *)referrals) + referrals->DfsPathOffset;
+
+				if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+					name_len += UniStrnlen((wchar_t *)temp,pSMBr->DataCount);
+				} else {
+					name_len += strnlen(temp,pSMBr->DataCount);
+				}
+				referrals++;
+				/* BB add check that referral pointer does not fall off end PDU */
+				
+			}
+			/* BB add check for name_len bigger than bcc */
+			*targetUNCs = 
+				kmalloc(name_len+1+ (*number_of_UNC_in_array),GFP_KERNEL);
+			/* copy the ref strings */
+			referrals =  
+			    (struct dfs_referral_level_3 *) 
+					(8 /* sizeof data hdr */ +
+					pSMBr->DataOffset + 
+					(char *) &pSMBr->hdr.Protocol);
+
+			for(i=0;i<*number_of_UNC_in_array;i++) {
+				temp = ((char *)referrals) + referrals->DfsPathOffset;
+				if (pSMBr->hdr.Flags2 & SMBFLG2_UNICODE) {
+					cifs_strfromUCS_le(*targetUNCs,
+						(wchar_t *) temp, name_len, nls_codepage);
+				} else {
+					strncpy(*targetUNCs,temp,name_len);
+				}
+				/*  BB update target_uncs pointers */
+				referrals++;
+			}
+			temp = *targetUNCs;
+			temp[name_len] = 0;
+		}
+
 	}
 	if (pSMB)
 		buf_release(pSMB);
diff -Nru a/fs/cifs/connect.c b/fs/cifs/connect.c
--- a/fs/cifs/connect.c	Mon Mar 31 19:52:27 2003
+++ b/fs/cifs/connect.c	Tue May 13 11:00:11 2003
@@ -57,8 +57,8 @@
 	mode_t file_mode;
 	mode_t dir_mode;
 	int rw;
-    unsigned int rsize;
-    unsigned int wsize;
+	unsigned int rsize;
+	unsigned int wsize;
 	unsigned short int port;
 };
 
@@ -572,10 +572,31 @@
 connect_to_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
 		    const char *old_path, const struct nls_table *nls_codepage)
 {
+	unsigned char *referrals = NULL;
+	unsigned int num_referrals;
+	int rc = 0;
+
+	rc = get_dfs_path(xid, pSesInfo,old_path, nls_codepage, 
+			&num_referrals, &referrals);
+
+	/* BB Add in code to: if valid refrl, if not ip address contact
+		the helper that resolves tcp names, mount to it, try to 
+		tcon to it unmount it if fail */
+
+	/* BB free memory for referrals string BB */
+
+	return rc;
+}
+
+int
+get_dfs_path(int xid, struct cifsSesInfo *pSesInfo,
+			const char *old_path, const struct nls_table *nls_codepage, 
+			unsigned int *pnum_referrals, unsigned char ** preferrals)
+{
 	char *temp_unc;
 	int rc = 0;
-	int num_referrals = 0;
-	unsigned char *referrals = NULL;
+
+	*pnum_referrals = 0;
 
 	if (pSesInfo->ipc_tid == 0) {
 		temp_unc = kmalloc(2 /* for slashes */ +
@@ -594,11 +615,10 @@
 		kfree(temp_unc);
 	}
 	if (rc == 0)
-		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, &referrals,
-				     &num_referrals, nls_codepage);
-
-	return -ENODEV;	/* BB remove and add return code processing */
+		rc = CIFSGetDFSRefer(xid, pSesInfo, old_path, preferrals,
+				     pnum_referrals, nls_codepage);
 
+	return rc;
 }
 
 int setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, struct nls_table * nls_info)
diff -Nru a/fs/cifs/file.c b/fs/cifs/file.c
--- a/fs/cifs/file.c	Sat Apr 26 22:25:27 2003
+++ b/fs/cifs/file.c	Fri May 16 09:07:44 2003
@@ -110,10 +110,14 @@
 			pCifsFile->netfid = netfid;
 			pCifsFile->pid = current->pid;
 			pCifsFile->pfile = file; /* needed for writepage */
+			write_lock(&file->f_owner.lock);
+			write_lock(&GlobalSMBSeslock);
 			list_add(&pCifsFile->tlist,&pTcon->openFileList);
 			pCifsInode = CIFS_I(file->f_dentry->d_inode);
 			if(pCifsInode->openFileList.next)
 				list_add(&pCifsFile->flist,&pCifsInode->openFileList);
+			write_unlock(&GlobalSMBSeslock);
+			write_unlock(&file->f_owner.lock);
 			if(file->f_flags & O_CREAT) {           
 				/* time to set mode which we can not set earlier due
 				 to problems creating new read-only files */
@@ -152,11 +156,13 @@
 {
 	int rc = 0;
 	struct cifsFileInfo *open_file = NULL;
-    struct file * file = NULL;
+	struct file * file = NULL;
 	struct list_head *tmp;
+	struct list_head *tmp1;
 
 /* list all files open on tree connection */
-	list_for_each(tmp, &pTcon->openFileList) {            
+	read_lock(&GlobalSMBSeslock);
+	list_for_each_safe(tmp, tmp1, &pTcon->openFileList) {            
 		open_file = list_entry(tmp,struct cifsFileInfo, flist);
 		if(open_file) {
 			if(open_file->search_resume_name) {
@@ -166,7 +172,9 @@
 			kfree(open_file);
 			if(file) {                
 				file->private_data = NULL;
+				read_unlock(&GlobalSMBSeslock);
 				rc = cifs_open(file->f_dentry->d_inode,file);
+				read_lock(&GlobalSMBSeslock);
 				if(rc) {
 					cFYI(1,("reconnecting file %s failed with %d",
 						file->f_dentry->d_name.name,rc));
@@ -177,6 +185,7 @@
 			} 
 		}
 	}
+	read_unlock(&GlobalSMBSeslock);
 	return rc;
 }
 
@@ -195,9 +204,11 @@
 	cifs_sb = CIFS_SB(inode->i_sb);
 	pTcon = cifs_sb->tcon;
 	if (pSMBFile) {
+		write_lock(&file->f_owner.lock);
 		if(pSMBFile->flist.next)
 			list_del(&pSMBFile->flist);
 		list_del(&pSMBFile->tlist);
+		write_unlock(&file->f_owner.lock);
 		rc = CIFSSMBClose(xid, pTcon, pSMBFile->netfid);
 		if(pSMBFile->search_resume_name)
 			kfree(pSMBFile->search_resume_name);
@@ -206,6 +217,8 @@
 	} else
 		rc = -EBADF;
 
+	if((rc ==0) && CIFS_I(inode)->write_behind_rc)
+		rc = CIFS_I(inode)->write_behind_rc;
 	FreeXid(xid);
 	return rc;
 }
@@ -407,6 +420,7 @@
 	struct cifsInodeInfo *cifsInode;
 	struct cifsFileInfo *open_file = NULL;
 	struct list_head *tmp;
+	struct list_head *tmp1;
 	int xid;
 
 	xid = GetXid();
@@ -445,14 +459,17 @@
 		
 
 	cifsInode = CIFS_I(mapping->host);
-	list_for_each(tmp, &cifsInode->openFileList) {            
+	read_lock(&GlobalSMBSeslock);
+	list_for_each_safe(tmp, tmp1, &cifsInode->openFileList) {            
 		open_file = list_entry(tmp,struct cifsFileInfo, flist);           
 	/* We could check if file is open for writing first */
 		if((open_file->pfile) && 
 		   ((open_file->pfile->f_flags & O_RDWR) || 
 			(open_file->pfile->f_flags & O_WRONLY))) {
+			read_unlock(&GlobalSMBSeslock);
 			bytes_written = cifs_write(open_file->pfile, write_data,
-					   to-from, &offset);
+					to-from, &offset);
+			read_lock(&GlobalSMBSeslock);
 		/* Does mm or vfs already set times? */
 			inode->i_atime = inode->i_mtime = CURRENT_TIME;
 			if ((bytes_written > 0) && (offset)) {
@@ -462,6 +479,7 @@
 			}
 		}
 	}
+	read_unlock(&GlobalSMBSeslock);
 	if(open_file == NULL) {
 		cFYI(1,("No writeable filehandles for inode"));
 		rc = -EIO;
@@ -548,7 +566,8 @@
 		dentry->d_name.name, datasync));
 	
 	rc = filemap_fdatawrite(inode->i_mapping);
-
+	if(rc == 0)
+		CIFS_I(inode)->write_behind_rc = 0;
 	FreeXid(xid);
 	return rc;
 }
@@ -600,6 +619,9 @@
 	/* filemapfdatawrite appears easier for the time being */
 
 	rc = filemap_fdatawrite(inode->i_mapping);
+	if(rc == 0) /* reset wb rc if we were able to write out dirty pages */
+		CIFS_I(inode)->write_behind_rc = 0;
+		
 	cFYI(1,("Flush inode %p file %p rc %d",inode,file,rc));
 
 	return rc;
@@ -678,12 +700,16 @@
 	while (bytes_read > 0) {
 		if(list_empty(pages))
 			break;
+
+		spin_lock(&mapping->page_lock);
 		page = list_entry(pages->prev, struct page, list);
 
 		list_del(&page->list);
+		spin_unlock(&mapping->page_lock);
+
 		if (add_to_page_cache(page, mapping, page->index, GFP_KERNEL)) {
 			page_cache_release(page);
-            cFYI(1,("Add page cache failed"));
+			cFYI(1,("Add page cache failed"));
 			continue;
 		}
 
@@ -739,12 +765,14 @@
 	pagevec_init(&lru_pvec, 0);
 
 	for(i = 0;i<num_pages;) {
-
+		spin_lock(&mapping->page_lock);
 		if(list_empty(page_list)) {
 			break;
 		}
 		page = list_entry(page_list->prev, struct page, list);
 		offset = (loff_t)page->index << PAGE_CACHE_SHIFT;
+	        spin_unlock(&mapping->page_lock);
+
 		/* for reads over a certain size could initiate async read ahead */
 
 		cFYI(0,("Read %d pages into cache at offset %ld ",
@@ -762,12 +790,15 @@
 		if ((rc < 0) || (smb_read_data == NULL)) {
 			cFYI(1,("Read error in readpages: %d",rc));
 			/* clean up remaing pages off list */
+            
+			spin_lock(&mapping->page_lock);
 			while (!list_empty(page_list) && (i < num_pages)) {
 				page = list_entry(page_list->prev, struct page, list);
 				list_del(&page->list);
 			}
+			spin_unlock(&mapping->page_lock);
 			break;
-		} else if (bytes_read > 0){
+		} else if (bytes_read > 0) {
 			pSMBr = (struct smb_com_read_rsp *)smb_read_data;
 			cifs_copy_cache_pages(mapping, page_list, bytes_read,
 				smb_read_data + 4 /* RFC1000 hdr */ +
@@ -783,9 +814,9 @@
 		}
 		if(smb_read_data) {
 			buf_release(smb_read_data);
-            smb_read_data = 0;
-        }
-        bytes_read = 0;
+			smb_read_data = 0;
+		}
+		bytes_read = 0;
 	}
 
 	pagevec_lru_add(&lru_pvec);
diff -Nru a/fs/cifs/inode.c b/fs/cifs/inode.c
--- a/fs/cifs/inode.c	Sat Apr 26 22:25:27 2003
+++ b/fs/cifs/inode.c	Tue May 13 11:00:11 2003
@@ -53,10 +53,6 @@
 	/* dump_mem("\nUnixQPathInfo return data", &findData, sizeof(findData)); */
 	if (rc) {
 		if (rc == -EREMOTE) {
-/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
-	&referrals,
-	&num_referrals,
-	cifs_sb->local_nls); */
 			tmp_path =
 			    kmalloc(strnlen
 				    (pTcon->treeName,
@@ -180,11 +176,6 @@
 	/* dump_mem("\nQPathInfo return data",&findData, sizeof(findData)); */
 	if (rc) {
 		if (rc == -EREMOTE) {
-			/* BB add call to new func rc = GetDFSReferral(); */
-/* rc = *//* CIFSGetDFSRefer(xid, pTcon->ses, search_path,
-	&referrals,
-	&num_referrals,
-	cifs_sb->local_nls); */
 			tmp_path =
 			    kmalloc(strnlen
 				    (pTcon->treeName,
diff -Nru a/fs/cifs/link.c b/fs/cifs/link.c
--- a/fs/cifs/link.c	Mon Mar 31 19:52:27 2003
+++ b/fs/cifs/link.c	Tue May 13 11:00:11 2003
@@ -113,6 +113,9 @@
 	/* BB Should we be using page symlink ops here? */
 
 	if (rc == 0) {
+
+/* BB Add special case check for Samba DFS symlinks */
+
 		target_path[PATH_MAX-1] = 0;
 		rc = vfs_follow_link(nd, target_path);
 	}
@@ -186,7 +189,10 @@
 	struct cifs_sb_info *cifs_sb;
 	struct cifsTconInfo *pTcon;
 	char *full_path = NULL;
+	char *tmp_path =  NULL;
 	char * tmpbuffer;
+	unsigned char * referrals = NULL;
+	int num_referrals = 0;
 	int len;
 	__u16 fid;
 
@@ -206,6 +212,7 @@
 		FreeXid(xid);
 		return -ENOMEM;
 	}
+
 /* BB add read reparse point symlink code and Unix extensions symlink code here BB */
 	if (cifs_sb->tcon->ses->capabilities & CAP_UNIX)
 		rc = CIFSSMBUnixQuerySymLink(xid, pTcon, full_path,
@@ -224,8 +231,36 @@
 			if(CIFSSMBClose(xid, pTcon, fid)) {
 				cFYI(1,("Error closing junction point (open for ioctl)"));
 			}
+			if(rc == -EIO) {
+				/* Query if DFS Junction */
+				tmp_path =
+					kmalloc(MAX_TREE_SIZE + MAX_PATHCONF + 1,
+						GFP_KERNEL);
+				if (tmp_path) {
+					strncpy(tmp_path, pTcon->treeName, MAX_TREE_SIZE);
+					strncat(tmp_path, full_path, MAX_PATHCONF);
+					rc = get_dfs_path(xid, pTcon->ses, tmp_path,
+						cifs_sb->local_nls, &num_referrals, &referrals);
+					cFYI(1,("Get DFS for %s rc = %d ",tmp_path, rc));
+					if((num_referrals == 0) && (rc == 0))
+						rc = -EACCES;
+					else {
+						cFYI(1,("num referral: %d",num_referrals));
+						if(referrals) {
+							cFYI(1,("referral string: %s ",referrals));
+							strncpy(tmpbuffer, referrals, len-1);
+						}
+					}
+
+					kfree(tmp_path);
+					if(referrals) {
+						kfree(referrals);
+					}
+				}
+				/* BB add code like else decode referrals then memcpy to
+				  tmpbuffer and free referrals string array BB */
+			}
 		}
-
 	}
 	/* BB Anything else to do to handle recursive links? */
 	/* BB Should we be using page ops here? */
@@ -238,10 +273,12 @@
 		      rc));
 	}
 
-	if (tmpbuffer)
+	if (tmpbuffer) {
 		kfree(tmpbuffer);
-	if (full_path)
+	}
+	if (full_path) {
 		kfree(full_path);
+	}
 	FreeXid(xid);
 	return rc;
 }
diff -Nru a/fs/cifs/md5.c b/fs/cifs/md5.c
--- a/fs/cifs/md5.c	Sun Nov 17 12:33:26 2002
+++ b/fs/cifs/md5.c	Sat May 17 14:09:51 2003
@@ -148,7 +148,7 @@
 	MD5Transform(ctx->buf, (__u32 *) ctx->in);
 	byteReverse((unsigned char *) ctx->buf, 4);
 	memmove(digest, ctx->buf, 16);
-	memset(ctx, 0, sizeof (ctx));	/* In case it's sensitive */
+	memset(ctx, 0, sizeof(*ctx));	/* In case it's sensitive */
 }
 
 /* The four core functions - F1 is optimized somewhat */
diff -Nru a/fs/cifs/transport.c b/fs/cifs/transport.c
--- a/fs/cifs/transport.c	Mon Mar 31 19:52:27 2003
+++ b/fs/cifs/transport.c	Fri May 16 09:07:44 2003
@@ -115,7 +115,7 @@
 		list_add_tail(&temp->qhead, &GlobalOplock_Q);
 		write_unlock(&GlobalMid_Lock);
 	}
-    return temp;
+	return temp;
 
 }
 
diff -Nru a/fs/coda/psdev.c b/fs/coda/psdev.c
--- a/fs/coda/psdev.c	Tue Apr 15 20:05:04 2003
+++ b/fs/coda/psdev.c	Wed May  7 08:47:30 2003
@@ -373,16 +373,10 @@
 	}
 	devfs_mk_dir ("coda");
 	for (i = 0; i < MAX_CODADEVS; i++) {
-		char name[16];
-		sprintf(name, "coda/%d", i);
-		devfs_register(NULL, name, DEVFS_FL_NONE,
-			       CODA_PSDEV_MAJOR, i,
-			       S_IFCHR | S_IRUSR | S_IWUSR,
-			       &coda_psdev_fops, NULL);
+		devfs_mk_cdev(MKDEV(CODA_PSDEV_MAJOR, i),
+				S_IFCHR|S_IRUSR|S_IWUSR, "coda/%d", i);
 	}
-
 	coda_sysctl_init();
-
 	return 0;
 }
 
diff -Nru a/fs/coda/sysctl.c b/fs/coda/sysctl.c
--- a/fs/coda/sysctl.c	Sat Oct  5 15:24:05 2002
+++ b/fs/coda/sysctl.c	Mon May 12 18:59:23 2003
@@ -244,7 +244,7 @@
 	}
 #endif
 
-#if CONFIG_PROC_FS
+#ifdef CONFIG_PROC_FS
         remove_proc_entry("cache_inv_stats", proc_fs_coda);
         remove_proc_entry("vfs_stats", proc_fs_coda);
 	remove_proc_entry("coda", proc_root_fs);
diff -Nru a/fs/dcache.c b/fs/dcache.c
--- a/fs/dcache.c	Sat Apr 19 23:22:23 2003
+++ b/fs/dcache.c	Mon May 19 08:22:48 2003
@@ -770,12 +770,12 @@
 void d_instantiate(struct dentry *entry, struct inode * inode)
 {
 	if (!list_empty(&entry->d_alias)) BUG();
-	security_d_instantiate(entry, inode);
 	spin_lock(&dcache_lock);
 	if (inode)
 		list_add(&entry->d_alias, &inode->i_dentry);
 	entry->d_inode = inode;
 	spin_unlock(&dcache_lock);
+	security_d_instantiate(entry, inode);
 }
 
 /**
@@ -903,12 +903,12 @@
 	struct dentry *new = NULL;
 
 	if (inode && S_ISDIR(inode->i_mode)) {
-		security_d_instantiate(dentry, inode);
 		spin_lock(&dcache_lock);
 		if (!list_empty(&inode->i_dentry)) {
 			new = list_entry(inode->i_dentry.next, struct dentry, d_alias);
 			__dget_locked(new);
 			spin_unlock(&dcache_lock);
+			security_d_instantiate(dentry, inode);
 			d_rehash(dentry);
 			d_move(new, dentry);
 			iput(inode);
@@ -917,6 +917,7 @@
 			list_add(&dentry->d_alias, &inode->i_dentry);
 			dentry->d_inode = inode;
 			spin_unlock(&dcache_lock);
+			security_d_instantiate(dentry, inode);
 			d_rehash(dentry);
 		}
 	} else
@@ -1274,7 +1275,7 @@
  * the string " (deleted)" is appended. Note that this is ambiguous. Returns
  * the buffer.
  *
- * "buflen" should be %PAGE_SIZE or more. Caller holds the dcache_lock.
+ * "buflen" should be positive. Caller holds the dcache_lock.
  */
 static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt,
 			struct dentry *root, struct vfsmount *rootmnt,
@@ -1289,9 +1290,13 @@
 	if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
 		buflen -= 10;
 		end -= 10;
+		if (buflen < 0)
+			goto Elong;
 		memcpy(end, " (deleted)", 10);
 	}
 
+	if (buflen < 1)
+		goto Elong;
 	/* Get '/' right */
 	retval = end-1;
 	*retval = '/';
@@ -1314,7 +1319,7 @@
 		namelen = dentry->d_name.len;
 		buflen -= namelen + 1;
 		if (buflen < 0)
-			return ERR_PTR(-ENAMETOOLONG);
+			goto Elong;
 		end -= namelen;
 		memcpy(end, dentry->d_name.name, namelen);
 		*--end = '/';
@@ -1327,12 +1332,13 @@
 global_root:
 	namelen = dentry->d_name.len;
 	buflen -= namelen;
-	if (buflen >= 0) {
-		retval -= namelen-1;	/* hit the slash */
-		memcpy(retval, dentry->d_name.name, namelen);
-	} else
-		retval = ERR_PTR(-ENAMETOOLONG);
+	if (buflen < 0)
+		goto Elong;
+	retval -= namelen-1;	/* hit the slash */
+	memcpy(retval, dentry->d_name.name, namelen);
 	return retval;
+Elong:
+	return ERR_PTR(-ENAMETOOLONG);
 }
 
 /* write full pathname into buffer and return start of pathname */
diff -Nru a/fs/devfs/base.c b/fs/devfs/base.c
--- a/fs/devfs/base.c	Sun Apr 20 16:54:18 2003
+++ b/fs/devfs/base.c	Mon May 12 21:23:09 2003
@@ -752,6 +752,7 @@
 #  define DPRINTK(flag, format, args...)
 #endif
 
+typedef struct devfs_entry *devfs_handle_t;
 
 struct directory_type
 {
@@ -1424,106 +1425,60 @@
 			 current->egid, &fs_info);
 } 
 
+int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
+{
+	struct devfs_entry *dir = NULL, *de;
+	char buf[64];
+	va_list args;
+	int error, n;
 
-/**
- *	devfs_register - Register a device entry.
- *	@dir: The handle to the parent devfs directory entry. If this is %NULL the
- *		new name is relative to the root of the devfs.
- *	@name: The name of the entry.
- *	@flags: Must be 0
- *	@major: The major number. Not needed for regular files.
- *	@minor: The minor number. Not needed for regular files.
- *	@mode: The default file mode.
- *	@ops: The &file_operations or &block_device_operations structure.
- *		This must not be externally deallocated.
- *	@info: An arbitrary pointer which will be written to the @private_data
- *		field of the &file structure passed to the device driver. You can set
- *		this to whatever you like, and change it once the file is opened (the next
- *		file opened will not see this change).
- *
- *	On failure %NULL is returned.
- */
+	if (!S_ISBLK(mode)) {
+		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
+				__FUNCTION__, mode, buf);
+		return -EINVAL;
+	}
 
-devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
-			       unsigned int flags,
-			       unsigned int major, unsigned int minor,
-			       umode_t mode, void *ops, void *info)
-{
-    int err;
-    dev_t devnum = 0, dev = MKDEV(major, minor);
-    struct devfs_entry *de;
+	va_start(args, fmt);
+	n = vsnprintf(buf, 64, fmt, args);
+	if (n >= 64 || !buf[0]) {
+		printk(KERN_WARNING "%s: invalid format string\n",
+				__FUNCTION__);
+		return -EINVAL;
+	}
 
-    /* we don't accept any flags anymore.  prototype will change soon. */
-    WARN_ON(flags);
-    WARN_ON(dir);
-    WARN_ON(!S_ISCHR(mode));
+	de = _devfs_prepare_leaf(&dir, buf, mode);
+	if (!de) {
+		printk(KERN_WARNING "%s: could not prepare leaf for %s\n",
+				__FUNCTION__, buf);
+		return -ENOMEM;		/* could be more accurate... */
+	}
 
-    if (name == NULL)
-    {
-	PRINTK ("(): NULL name pointer\n");
-	return NULL;
-    }
-    if (ops == NULL)
-    {
-	PRINTK ("(%s): NULL ops pointer\n", name);
-	return NULL;
-    }
-    if ( S_ISDIR (mode) )
-    {
-	PRINTK ("(%s): creating directories is not allowed\n", name);
-	return NULL;
-    }
-    if ( S_ISLNK (mode) )
-    {
-	PRINTK ("(%s): creating symlinks is not allowed\n", name);
-	return NULL;
-    }
-    if ( ( de = _devfs_prepare_leaf (&dir, name, mode) ) == NULL )
-    {
-	PRINTK ("(%s): could not prepare leaf\n", name);
-	if (devnum) devfs_dealloc_devnum (mode, devnum);
-	return NULL;
-    }
-    if (S_ISCHR (mode)) {
-	de->u.cdev.dev = dev;
-	de->u.cdev.autogen = devnum != 0;
-	de->u.cdev.ops = ops;
-    } else if (S_ISBLK (mode)) {
 	de->u.bdev.dev = dev;
-	de->u.cdev.autogen = devnum != 0;
-    } else {
-	PRINTK ("(%s): illegal mode: %x\n", name, mode);
-	devfs_put (de);
-	devfs_put (dir);
-	return (NULL);
-    }
-    de->info = info;
-    de->inode.uid = 0;
-    de->inode.gid = 0;
-    err = _devfs_append_entry(dir, de, NULL);
-    if (err)
-    {
-	PRINTK ("(%s): could not append to parent, err: %d\n", name, err);
-	devfs_put (dir);
-	if (devnum) devfs_dealloc_devnum (mode, devnum);
-	return NULL;
-    }
-    DPRINTK (DEBUG_REGISTER, "(%s): de: %p dir: %p \"%s\"  pp: %p\n",
-	     name, de, dir, dir->name, dir->parent);
-    devfsd_notify (de, DEVFSD_NOTIFY_REGISTERED);
-    devfs_put (dir);
-    return de;
-}   /*  End Function devfs_register  */
 
+	error = _devfs_append_entry(dir, de, NULL);
+	if (error) {
+		printk(KERN_WARNING "%s: could not append to parent for %s\n",
+				__FUNCTION__, buf);
+		goto out;
+	}
 
-int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
+	devfsd_notify(de, DEVFSD_NOTIFY_REGISTERED);
+ out:
+	devfs_put(dir);
+	return error;
+}
+
+EXPORT_SYMBOL(devfs_mk_bdev);
+
+
+int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...)
 {
 	struct devfs_entry *dir = NULL, *de;
 	char buf[64];
 	va_list args;
 	int error, n;
 
-	if (!S_ISBLK(mode)) {
+	if (!S_ISCHR(mode)) {
 		printk(KERN_WARNING "%s: invalide mode (%u) for %s\n",
 				__FUNCTION__, mode, buf);
 		return -EINVAL;
@@ -1544,7 +1499,7 @@
 		return -ENOMEM;		/* could be more accurate... */
 	}
 
-	de->u.bdev.dev = dev;
+	de->u.cdev.dev = dev;
 
 	error = _devfs_append_entry(dir, de, NULL);
 	if (error) {
@@ -1559,7 +1514,7 @@
 	return error;
 }
 
-EXPORT_SYMBOL(devfs_mk_bdev);
+EXPORT_SYMBOL(devfs_mk_cdev);
 
 
 /**
@@ -1889,7 +1844,6 @@
 __setup("devfs=", devfs_setup);
 
 EXPORT_SYMBOL(devfs_put);
-EXPORT_SYMBOL(devfs_register);
 EXPORT_SYMBOL(devfs_mk_symlink);
 EXPORT_SYMBOL(devfs_mk_dir);
 EXPORT_SYMBOL(devfs_remove);
diff -Nru a/fs/dquot.c b/fs/dquot.c
--- a/fs/dquot.c	Sat Apr 19 23:22:37 2003
+++ b/fs/dquot.c	Mon May 12 21:23:16 2003
@@ -1011,9 +1011,12 @@
 	spin_unlock(&dq_data_lock);
 	flush_warnings(transfer_to, warntype);
 	
-	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		if (transfer_from[cnt] != NODQUOT)
+	for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+		if (ret == QUOTA_OK && transfer_from[cnt] != NODQUOT)
 			dqput(transfer_from[cnt]);
+		if (ret == NO_QUOTA && transfer_to[cnt] != NODQUOT)
+			dqput(transfer_to[cnt]);
+	}
 	up_write(&sb_dqopt(inode->i_sb)->dqptr_sem);
 	return ret;
 }
diff -Nru a/fs/exec.c b/fs/exec.c
--- a/fs/exec.c	Wed Apr 16 15:34:51 2003
+++ b/fs/exec.c	Sat May 17 12:39:13 2003
@@ -287,7 +287,8 @@
  *
  * tsk->mmap_sem is held for writing.
  */
-void put_dirty_page(struct task_struct * tsk, struct page *page, unsigned long address)
+void put_dirty_page(struct task_struct *tsk, struct page *page,
+			unsigned long address, pgprot_t prot)
 {
 	pgd_t * pgd;
 	pmd_t * pmd;
@@ -295,7 +296,8 @@
 	struct pte_chain *pte_chain;
 
 	if (page_count(page) != 1)
-		printk(KERN_ERR "mem_map disagrees with %p at %08lx\n", page, address);
+		printk(KERN_ERR "mem_map disagrees with %p at %08lx\n",
+				page, address);
 
 	pgd = pgd_offset(tsk->mm, address);
 	pte_chain = pte_chain_alloc(GFP_KERNEL);
@@ -314,7 +316,7 @@
 	}
 	lru_cache_add_active(page);
 	flush_dcache_page(page);
-	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, PAGE_COPY))));
+	set_pte(pte, pte_mkdirty(pte_mkwrite(mk_pte(page, prot))));
 	pte_chain = page_add_rmap(page, pte, pte_chain);
 	pte_unmap(pte);
 	tsk->mm->rss++;
@@ -421,7 +423,8 @@
 		struct page *page = bprm->page[i];
 		if (page) {
 			bprm->page[i] = NULL;
-			put_dirty_page(current,page,stack_base);
+			put_dirty_page(current, page, stack_base,
+					mpnt->vm_page_prot);
 		}
 		stack_base += PAGE_SIZE;
 	}
@@ -434,8 +437,6 @@
 
 #else
 
-#define put_dirty_page(tsk, page, address)
-#define setup_arg_pages(bprm)			(0)
 static inline void free_arg_pages(struct linux_binprm *bprm)
 {
 	int i;
@@ -1033,14 +1034,12 @@
 #ifdef CONFIG_KMOD
 		}else{
 #define printable(c) (((c)=='\t') || ((c)=='\n') || (0x20<=(c) && (c)<=0x7e))
-			char modname[20];
 			if (printable(bprm->buf[0]) &&
 			    printable(bprm->buf[1]) &&
 			    printable(bprm->buf[2]) &&
 			    printable(bprm->buf[3]))
 				break; /* -ENOEXEC */
-			sprintf(modname, "binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
-			request_module(modname);
+			request_module("binfmt-%04x", *(unsigned short *)(&bprm->buf[2]));
 #endif
 		}
 	}
diff -Nru a/fs/ext2/Makefile b/fs/ext2/Makefile
--- a/fs/ext2/Makefile	Fri Feb 14 18:24:04 2003
+++ b/fs/ext2/Makefile	Mon May  5 06:19:21 2003
@@ -14,3 +14,7 @@
 ifeq ($(CONFIG_EXT2_FS_POSIX_ACL),y)
 ext2-objs += acl.o
 endif
+
+ifeq ($(CONFIG_EXT2_FS_SECURITY),y)
+ext2-objs += xattr_security.o
+endif
diff -Nru a/fs/ext2/dir.c b/fs/ext2/dir.c
--- a/fs/ext2/dir.c	Sat Mar 22 22:14:09 2003
+++ b/fs/ext2/dir.c	Sun May  4 22:49:54 2003
@@ -310,7 +310,7 @@
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
 	filp->f_version = inode->i_version;
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 	return 0;
 }
 
diff -Nru a/fs/ext2/xattr.c b/fs/ext2/xattr.c
--- a/fs/ext2/xattr.c	Mon Apr  7 05:49:40 2003
+++ b/fs/ext2/xattr.c	Mon May  5 06:19:21 2003
@@ -1102,22 +1102,33 @@
 				  &ext2_xattr_trusted_handler);
 	if (err)
 		goto out;
+#ifdef CONFIG_EXT2_FS_SECURITY
+	err = ext2_xattr_register(EXT2_XATTR_INDEX_SECURITY,
+				  &ext2_xattr_security_handler);
+	if (err)
+		goto out1;
+#endif
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
 	err = init_ext2_acl();
 	if (err)
-		goto out1;
+		goto out2;
 #endif
 	ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL,
 		sizeof(struct mb_cache_entry) +
 		sizeof(struct mb_cache_entry_index), 1, 6);
 	if (!ext2_xattr_cache) {
 		err = -ENOMEM;
-		goto out2;
+		goto out3;
 	}
 	return 0;
-out2:
+out3:
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
 	exit_ext2_acl();
+out2:
+#endif
+#ifdef CONFIG_EXT2_FS_SECURITY
+	ext2_xattr_unregister(EXT2_XATTR_INDEX_SECURITY,
+			      &ext2_xattr_security_handler);
 out1:
 #endif
 	ext2_xattr_unregister(EXT2_XATTR_INDEX_TRUSTED,
@@ -1134,6 +1145,10 @@
 	mb_cache_destroy(ext2_xattr_cache);
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
 	exit_ext2_acl();
+#endif
+#ifdef CONFIG_EXT2_FS_SECURITY
+	ext2_xattr_unregister(EXT2_XATTR_INDEX_SECURITY,
+			      &ext2_xattr_security_handler);
 #endif
 	ext2_xattr_unregister(EXT2_XATTR_INDEX_TRUSTED,
 			      &ext2_xattr_trusted_handler);
diff -Nru a/fs/ext2/xattr.h b/fs/ext2/xattr.h
--- a/fs/ext2/xattr.h	Tue Feb 25 08:21:08 2003
+++ b/fs/ext2/xattr.h	Mon May 12 22:05:41 2003
@@ -22,6 +22,8 @@
 #define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS	2
 #define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT	3
 #define EXT2_XATTR_INDEX_TRUSTED		4
+#define	EXT2_XATTR_INDEX_LUSTRE			5
+#define EXT2_XATTR_INDEX_SECURITY	        6
 
 struct ext2_xattr_header {
 	__u32	h_magic;	/* magic number for identification */
@@ -134,4 +136,5 @@
 
 extern struct ext2_xattr_handler ext2_xattr_user_handler;
 extern struct ext2_xattr_handler ext2_xattr_trusted_handler;
+extern struct ext2_xattr_handler ext2_xattr_security_handler;
 
diff -Nru a/fs/ext2/xattr_security.c b/fs/ext2/xattr_security.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/ext2/xattr_security.c	Mon May  5 06:19:21 2003
@@ -0,0 +1,54 @@
+/*
+ * linux/fs/ext2/xattr_security.c
+ * Handler for storing security labels as extended attributes.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/ext2_fs.h>
+#include "xattr.h"
+
+#define XATTR_SECURITY_PREFIX "security."
+
+static size_t
+ext2_xattr_security_list(char *list, struct inode *inode,
+			const char *name, int name_len)
+{
+	const int prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
+
+	if (list) {
+		memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
+		memcpy(list+prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+	return prefix_len + name_len + 1;
+}
+
+static int
+ext2_xattr_security_get(struct inode *inode, const char *name,
+		       void *buffer, size_t size)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return ext2_xattr_get(inode, EXT2_XATTR_INDEX_SECURITY, name,
+			      buffer, size);
+}
+
+static int
+ext2_xattr_security_set(struct inode *inode, const char *name,
+		       const void *value, size_t size, int flags)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return ext2_xattr_set(inode, EXT2_XATTR_INDEX_SECURITY, name,
+			      value, size, flags);
+}
+
+struct ext2_xattr_handler ext2_xattr_security_handler = {
+	.prefix	= XATTR_SECURITY_PREFIX,
+	.list	= ext2_xattr_security_list,
+	.get	= ext2_xattr_security_get,
+	.set	= ext2_xattr_security_set,
+};
diff -Nru a/fs/ext3/Makefile b/fs/ext3/Makefile
--- a/fs/ext3/Makefile	Fri Feb 14 18:24:04 2003
+++ b/fs/ext3/Makefile	Mon May  5 06:18:48 2003
@@ -14,3 +14,7 @@
 ifeq ($(CONFIG_EXT3_FS_POSIX_ACL),y)
 ext3-objs += acl.o
 endif
+
+ifeq ($(CONFIG_EXT3_FS_SECURITY),y)
+ext3-objs += xattr_security.o
+endif
diff -Nru a/fs/ext3/dir.c b/fs/ext3/dir.c
--- a/fs/ext3/dir.c	Sat Mar 22 22:14:09 2003
+++ b/fs/ext3/dir.c	Mon May 12 21:23:29 2003
@@ -103,7 +103,11 @@
 
 	sb = inode->i_sb;
 
-	if (is_dx(inode)) {
+#ifdef CONFIG_EXT3_INDEX
+	if (EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
+				    EXT3_FEATURE_COMPAT_DIR_INDEX) &&
+	    ((EXT3_I(inode)->i_flags & EXT3_INDEX_FL) ||
+	     ((inode->i_size >> sb->s_blocksize_bits) == 1))) {
 		err = ext3_dx_readdir(filp, dirent, filldir);
 		if (err != ERR_BAD_DX_DIR) {
 			ret = err;
@@ -115,6 +119,7 @@
 		 */
 		EXT3_I(filp->f_dentry->d_inode)->i_flags &= ~EXT3_INDEX_FL;
 	}
+#endif
 	stored = 0;
 	bh = NULL;
 	offset = filp->f_pos & (sb->s_blocksize - 1);
@@ -216,7 +221,7 @@
 		offset = 0;
 		brelse (bh);
 	}
-	UPDATE_ATIME(inode);
+       update_atime(inode);
 out:
 	return ret;
 }
@@ -434,6 +439,9 @@
 		filp->private_data = info;
 	}
 
+	if (filp->f_pos == EXT3_HTREE_EOF)
+		return 0;	/* EOF */
+
 	/* Some one has messed with f_pos; reset the world */
 	if (info->last_pos != filp->f_pos) {
 		free_rb_tree_fname(&info->root);
@@ -470,8 +478,10 @@
 						   &info->next_hash);
 			if (ret < 0)
 				return ret;
-			if (ret == 0)
+			if (ret == 0) {
+				filp->f_pos = EXT3_HTREE_EOF;
 				break;
+			}
 			info->curr_node = rb_first(&info->root);
 		}
 
@@ -483,19 +493,23 @@
 
 		info->curr_node = rb_next(info->curr_node);
 		if (!info->curr_node) {
+			if (info->next_hash == ~0) {
+				filp->f_pos = EXT3_HTREE_EOF;
+				break;
+			}
 			info->curr_hash = info->next_hash;
 			info->curr_minor_hash = 0;
 		}
 	}
 finished:
 	info->last_pos = filp->f_pos;
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 	return 0;
 }
 
 static int ext3_release_dir (struct inode * inode, struct file * filp)
 {
-       if (is_dx(inode) && filp->private_data)
+       if (filp->private_data)
 		ext3_htree_free_dir_info(filp->private_data);
 
 	return 0;
diff -Nru a/fs/ext3/fsync.c b/fs/ext3/fsync.c
--- a/fs/ext3/fsync.c	Wed Apr  2 22:51:44 2003
+++ b/fs/ext3/fsync.c	Wed May  7 21:17:51 2003
@@ -27,8 +27,6 @@
 #include <linux/jbd.h>
 #include <linux/ext3_fs.h>
 #include <linux/ext3_jbd.h>
-#include <linux/jbd.h>
-#include <linux/smp_lock.h>
 
 /*
  * akpm: A new design for ext3_sync_file().
diff -Nru a/fs/ext3/hash.c b/fs/ext3/hash.c
--- a/fs/ext3/hash.c	Mon Oct  7 11:39:24 2002
+++ b/fs/ext3/hash.c	Mon May 12 21:23:29 2003
@@ -209,7 +209,10 @@
 		hinfo->hash = 0;
 		return -1;
 	}
-	hinfo->hash = hash & ~1;
+	hash = hash & ~1;
+	if (hash == (EXT3_HTREE_EOF << 1))
+		hash = (EXT3_HTREE_EOF-1) << 1;
+	hinfo->hash = hash;
 	hinfo->minor_hash = minor_hash;
 	return 0;
 }
diff -Nru a/fs/ext3/namei.c b/fs/ext3/namei.c
--- a/fs/ext3/namei.c	Sat Mar 22 22:14:52 2003
+++ b/fs/ext3/namei.c	Mon May 12 21:23:28 2003
@@ -170,7 +170,7 @@
 static void dx_insert_block (struct dx_frame *frame, u32 hash, u32 block);
 static int ext3_htree_next_block(struct inode *dir, __u32 hash,
 				 struct dx_frame *frame,
-				 struct dx_frame *frames, int *err,
+				 struct dx_frame *frames, 
 				 __u32 *start_hash);
 static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
 		       struct ext3_dir_entry_2 **res_dir, int *err);
@@ -239,6 +239,17 @@
  * Debug
  */
 #ifdef DX_DEBUG
+static void dx_show_index (char * label, struct dx_entry *entries)
+{
+        int i, n = dx_get_count (entries);
+        printk("%s index ", label);
+        for (i = 0; i < n; i++)
+        {
+                printk("%x->%u ", i? dx_get_hash(entries + i): 0, dx_get_block(entries + i));
+        }
+        printk("\n");
+}
+
 struct stats
 { 
 	unsigned names;
@@ -447,22 +458,21 @@
  *
  * This function returns 1 if the caller should continue to search,
  * or 0 if it should not.  If there is an error reading one of the
- * index blocks, it will return -1.
+ * index blocks, it will a negative error code.
  *
  * If start_hash is non-null, it will be filled in with the starting
  * hash of the next page.
  */
 static int ext3_htree_next_block(struct inode *dir, __u32 hash,
 				 struct dx_frame *frame,
-				 struct dx_frame *frames, int *err,
+				 struct dx_frame *frames, 
 				 __u32 *start_hash)
 {
 	struct dx_frame *p;
 	struct buffer_head *bh;
-	int num_frames = 0;
+	int err, num_frames = 0;
 	__u32 bhash;
 
-	*err = ENOENT;
 	p = frame;
 	/*
 	 * Find the next leaf page by incrementing the frame pointer.
@@ -500,8 +510,8 @@
 	 */
 	while (num_frames--) {
 		if (!(bh = ext3_bread(NULL, dir, dx_get_block(p->at),
-				      0, err)))
-			return -1; /* Failure */
+				      0, &err)))
+			return err; /* Failure */
 		p++;
 		brelse (p->bh);
 		p->bh = bh;
@@ -521,6 +531,46 @@
 
 /*
  * This function fills a red-black tree with information from a
+ * directory block.  It returns the number directory entries loaded
+ * into the tree.  If there is an error it is returned in err.
+ */
+static int htree_dirblock_to_tree(struct file *dir_file,
+				  struct inode *dir, int block,
+				  struct dx_hash_info *hinfo,
+				  __u32 start_hash, __u32 start_minor_hash)
+{
+	struct buffer_head *bh;
+	struct ext3_dir_entry_2 *de, *top;
+	int err, count = 0;
+
+	dxtrace(printk("In htree dirblock_to_tree: block %d\n", block));
+	if (!(bh = ext3_bread (NULL, dir, block, 0, &err)))
+		return err;
+	
+	de = (struct ext3_dir_entry_2 *) bh->b_data;
+	top = (struct ext3_dir_entry_2 *) ((char *) de +
+					   dir->i_sb->s_blocksize -
+					   EXT3_DIR_REC_LEN(0));
+	for (; de < top; de = ext3_next_entry(de)) {
+		ext3fs_dirhash(de->name, de->name_len, hinfo);
+		if ((hinfo->hash < start_hash) ||
+		    ((hinfo->hash == start_hash) &&
+		     (hinfo->minor_hash < start_minor_hash)))
+			continue;
+		if ((err = ext3_htree_store_dirent(dir_file,
+				   hinfo->hash, hinfo->minor_hash, de)) != 0) {
+			brelse(bh);
+			return err;
+		}
+		count++;
+	}
+	brelse(bh);
+	return count;
+}
+
+
+/*
+ * This function fills a red-black tree with information from a
  * directory.  We start scanning the directory in hash order, starting
  * at start_hash and start_minor_hash.
  *
@@ -531,8 +581,7 @@
 			 __u32 start_minor_hash, __u32 *next_hash)
 {
 	struct dx_hash_info hinfo;
-	struct buffer_head *bh;
-	struct ext3_dir_entry_2 *de, *top;
+	struct ext3_dir_entry_2 *de;
 	struct dx_frame frames[2], *frame;
 	struct inode *dir;
 	int block, err;
@@ -543,6 +592,14 @@
 	dxtrace(printk("In htree_fill_tree, start hash: %x:%x\n", start_hash,
 		       start_minor_hash));
 	dir = dir_file->f_dentry->d_inode;
+	if (!(EXT3_I(dir)->i_flags & EXT3_INDEX_FL)) {	
+		hinfo.hash_version = EXT3_SB(dir->i_sb)->s_def_hash_version;
+		hinfo.seed = EXT3_SB(dir->i_sb)->s_hash_seed;
+		count = htree_dirblock_to_tree(dir_file, dir, 0, &hinfo,
+					       start_hash, start_minor_hash);
+		*next_hash = ~0;
+		return count;
+	}
 	hinfo.hash = start_hash;
 	hinfo.minor_hash = 0;
 	frame = dx_probe(0, dir_file->f_dentry->d_inode, &hinfo, frames, &err);
@@ -562,34 +619,21 @@
 
 	while (1) {
 		block = dx_get_block(frame->at);
-		dxtrace(printk("Reading block %d\n", block));
-		if (!(bh = ext3_bread (NULL, dir, block, 0, &err)))
+		ret = htree_dirblock_to_tree(dir_file, dir, block, &hinfo,
+					     start_hash, start_minor_hash);
+		if (ret < 0) {
+			err = ret;
 			goto errout;
-	
-		de = (struct ext3_dir_entry_2 *) bh->b_data;
-		top = (struct ext3_dir_entry_2 *) ((char *) de + dir->i_sb->s_blocksize -
-				       EXT3_DIR_REC_LEN(0));
-		for (; de < top; de = ext3_next_entry(de)) {
-			ext3fs_dirhash(de->name, de->name_len, &hinfo);
-			if ((hinfo.hash < start_hash) ||
-			    ((hinfo.hash == start_hash) &&
-			     (hinfo.minor_hash < start_minor_hash)))
-				continue;
-			if ((err = ext3_htree_store_dirent(dir_file,
-				   hinfo.hash, hinfo.minor_hash, de)) != 0) {
-				brelse(bh);
-				goto errout;
-			}
-			count++;
 		}
-		brelse (bh);
-		hashval = ~1;
+		count += ret;
+		hashval = ~0;
 		ret = ext3_htree_next_block(dir, HASH_NB_ALWAYS, 
-					    frame, frames, &err, &hashval);
-		if (next_hash)
-			*next_hash = hashval;
-		if (ret == -1)
+					    frame, frames, &hashval);
+		*next_hash = hashval;
+		if (ret < 0) {
+			err = ret;
 			goto errout;
+		}
 		/*
 		 * Stop if:  (a) there are no more entries, or
 		 * (b) we have inserted at least one entry and the
@@ -600,7 +644,8 @@
 			break;
 	}
 	dx_release(frames);
-	dxtrace(printk("Fill tree: returned %d entries\n", count));
+	dxtrace(printk("Fill tree: returned %d entries, next hash: %x\n", 
+		       count, *next_hash));
 	return count;
 errout:
 	dx_release(frames);
@@ -909,11 +954,12 @@
 		brelse (bh);
 		/* Check to see if we should continue to search */
 		retval = ext3_htree_next_block(dir, hash, frame,
-					       frames, err, 0);
-		if (retval == -1) {
+					       frames, 0);
+		if (retval < 0) {
 			ext3_warning(sb, __FUNCTION__,
 			     "error reading index page in directory #%lu",
 			     dir->i_ino);
+			*err = retval;
 			goto errout;
 		}
 	} while (retval == 1);
diff -Nru a/fs/ext3/super.c b/fs/ext3/super.c
--- a/fs/ext3/super.c	Tue Apr 29 06:27:58 2003
+++ b/fs/ext3/super.c	Mon May 12 21:23:16 2003
@@ -1988,8 +1988,10 @@
 
 #ifdef CONFIG_QUOTA
 
-#define EXT3_OLD_QFMT_BLOCKS 2
-#define EXT3_V0_QFMT_BLOCKS 6
+/* Blocks: (2 data blocks) * (3 indirect + 1 descriptor + 1 bitmap) + superblock */
+#define EXT3_OLD_QFMT_BLOCKS 11
+/* Blocks: quota info + (4 pointer blocks + 1 entry block) * (3 indirect + 1 descriptor + 1 bitmap) + superblock */
+#define EXT3_V0_QFMT_BLOCKS 27
 
 static int (*old_sync_dquot)(struct dquot *dquot);
 
diff -Nru a/fs/ext3/xattr.c b/fs/ext3/xattr.c
--- a/fs/ext3/xattr.c	Mon Apr  7 05:49:40 2003
+++ b/fs/ext3/xattr.c	Mon May  5 06:18:48 2003
@@ -1142,22 +1142,33 @@
 				  &ext3_xattr_trusted_handler);
 	if (err)
 		goto out;
+#ifdef CONFIG_EXT3_FS_SECURITY
+	err = ext3_xattr_register(EXT3_XATTR_INDEX_SECURITY,
+				  &ext3_xattr_security_handler);
+	if (err)
+		goto out1;
+#endif
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
 	err = init_ext3_acl();
 	if (err)
-		goto out1;
+		goto out2;
 #endif
 	ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL,
 		sizeof(struct mb_cache_entry) +
 		sizeof(struct mb_cache_entry_index), 1, 6);
 	if (!ext3_xattr_cache) {
 		err = -ENOMEM;
-		goto out2;
+		goto out3;
 	}
 	return 0;
-out2:
+out3:
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
 	exit_ext3_acl();
+out2:
+#endif
+#ifdef CONFIG_EXT3_FS_SECURITY
+	ext3_xattr_unregister(EXT3_XATTR_INDEX_SECURITY,
+			      &ext3_xattr_security_handler);
 out1:
 #endif
 	ext3_xattr_unregister(EXT3_XATTR_INDEX_TRUSTED,
@@ -1176,6 +1187,10 @@
 	ext3_xattr_cache = NULL;
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
 	exit_ext3_acl();
+#endif
+#ifdef CONFIG_EXT3_FS_SECURITY
+	ext3_xattr_unregister(EXT3_XATTR_INDEX_SECURITY,
+			      &ext3_xattr_security_handler);
 #endif
 	ext3_xattr_unregister(EXT3_XATTR_INDEX_TRUSTED,
 			      &ext3_xattr_trusted_handler);
diff -Nru a/fs/ext3/xattr.h b/fs/ext3/xattr.h
--- a/fs/ext3/xattr.h	Tue Feb 25 08:21:08 2003
+++ b/fs/ext3/xattr.h	Mon May 12 22:05:41 2003
@@ -21,6 +21,8 @@
 #define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS	2
 #define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT	3
 #define EXT3_XATTR_INDEX_TRUSTED		4
+#define	EXT3_XATTR_INDEX_LUSTRE			5
+#define EXT3_XATTR_INDEX_SECURITY	        6
 
 struct ext3_xattr_header {
 	__u32	h_magic;	/* magic number for identification */
@@ -141,3 +143,4 @@
 
 extern struct ext3_xattr_handler ext3_xattr_user_handler;
 extern struct ext3_xattr_handler ext3_xattr_trusted_handler;
+extern struct ext3_xattr_handler ext3_xattr_security_handler;
diff -Nru a/fs/ext3/xattr_security.c b/fs/ext3/xattr_security.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/ext3/xattr_security.c	Mon May  5 06:18:48 2003
@@ -0,0 +1,55 @@
+/*
+ * linux/fs/ext3/xattr_security.c
+ * Handler for storing security labels as extended attributes.
+ */
+
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/fs.h>
+#include <linux/smp_lock.h>
+#include <linux/ext3_jbd.h>
+#include <linux/ext3_fs.h>
+#include "xattr.h"
+
+#define XATTR_SECURITY_PREFIX "security."
+
+static size_t
+ext3_xattr_security_list(char *list, struct inode *inode,
+		    const char *name, int name_len)
+{
+	const int prefix_len = sizeof(XATTR_SECURITY_PREFIX)-1;
+
+	if (list) {
+		memcpy(list, XATTR_SECURITY_PREFIX, prefix_len);
+		memcpy(list+prefix_len, name, name_len);
+		list[prefix_len + name_len] = '\0';
+	}
+	return prefix_len + name_len + 1;
+}
+
+static int
+ext3_xattr_security_get(struct inode *inode, const char *name,
+		       void *buffer, size_t size)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return ext3_xattr_get(inode, EXT3_XATTR_INDEX_SECURITY, name,
+			      buffer, size);
+}
+
+static int
+ext3_xattr_security_set(struct inode *inode, const char *name,
+		       const void *value, size_t size, int flags)
+{
+	if (strcmp(name, "") == 0)
+		return -EINVAL;
+	return ext3_xattr_set(inode, EXT3_XATTR_INDEX_SECURITY, name,
+			      value, size, flags);
+}
+
+struct ext3_xattr_handler ext3_xattr_security_handler = {
+	.prefix	= XATTR_SECURITY_PREFIX,
+	.list	= ext3_xattr_security_list,
+	.get	= ext3_xattr_security_get,
+	.set	= ext3_xattr_security_set,
+};
diff -Nru a/fs/fat/inode.c b/fs/fat/inode.c
--- a/fs/fat/inode.c	Sat Apr 19 23:22:23 2003
+++ b/fs/fat/inode.c	Mon May 12 21:23:11 2003
@@ -897,6 +897,7 @@
 			       sbi->fsinfo_sector);
 		} else {
 			sbi->free_clusters = CF_LE_L(fsinfo->free_clusters);
+			sbi->prev_free = CF_LE_L(fsinfo->next_cluster);
 		}
 
 		brelse(fsinfo_bh);
diff -Nru a/fs/fat/misc.c b/fs/fat/misc.c
--- a/fs/fat/misc.c	Sun Oct 27 09:25:09 2002
+++ b/fs/fat/misc.c	Mon May 12 21:23:11 2003
@@ -74,6 +74,7 @@
 		       MSDOS_SB(sb)->fsinfo_sector);
 	} else {
 		fsinfo->free_clusters = CF_LE_L(MSDOS_SB(sb)->free_clusters);
+		fsinfo->next_cluster = CF_LE_L(MSDOS_SB(sb)->prev_free);
 		mark_buffer_dirty(bh);
 	}
 	brelse(bh);
@@ -130,19 +131,23 @@
 		unlock_fat(sb);
 		return -ENOSPC;
 	}
-	limit = MSDOS_SB(sb)->clusters;
-	for (count = 0; count < limit; count++) {
-		nr = ((count + MSDOS_SB(sb)->prev_free) % limit) + 2;
+
+	limit = MSDOS_SB(sb)->clusters + 2;
+	nr = MSDOS_SB(sb)->prev_free + 1;
+	for (count = 0; count < MSDOS_SB(sb)->clusters; count++, nr++) {
+		nr = nr % limit;
+		if (nr < 2)
+			nr = 2;
 		if (fat_access(sb, nr, -1) == FAT_ENT_FREE)
 			break;
 	}
-	if (count >= limit) {
+	if (count >= MSDOS_SB(sb)->clusters) {
 		MSDOS_SB(sb)->free_clusters = 0;
 		unlock_fat(sb);
 		return -ENOSPC;
 	}
-	
-	MSDOS_SB(sb)->prev_free = (count + MSDOS_SB(sb)->prev_free + 1) % limit;
+	MSDOS_SB(sb)->prev_free = nr;
+
 	fat_access(sb, nr, FAT_ENT_EOF);
 	if (MSDOS_SB(sb)->free_clusters != -1)
 		MSDOS_SB(sb)->free_clusters--;
diff -Nru a/fs/fcntl.c b/fs/fcntl.c
--- a/fs/fcntl.c	Wed Apr  9 06:42:36 2003
+++ b/fs/fcntl.c	Tue May 13 13:42:27 2003
@@ -305,11 +305,11 @@
 			err = setfl(fd, filp, arg);
 			break;
 		case F_GETLK:
-			err = fcntl_getlk(filp, (struct flock *) arg);
+			err = fcntl_getlk(filp, (struct flock __user *) arg);
 			break;
 		case F_SETLK:
 		case F_SETLKW:
-			err = fcntl_setlk(filp, cmd, (struct flock *) arg);
+			err = fcntl_setlk(filp, cmd, (struct flock __user *) arg);
 			break;
 		case F_GETOWN:
 			/*
@@ -393,11 +393,11 @@
 	
 	switch (cmd) {
 		case F_GETLK64:
-			err = fcntl_getlk64(filp, (struct flock64 *) arg);
+			err = fcntl_getlk64(filp, (struct flock64 __user *) arg);
 			break;
 		case F_SETLK64:
 		case F_SETLKW64:
-			err = fcntl_setlk64(filp, cmd, (struct flock64 *) arg);
+			err = fcntl_setlk64(filp, cmd, (struct flock64 __user *) arg);
 			break;
 		default:
 			err = do_fcntl(fd, cmd, arg, filp);
diff -Nru a/fs/file_table.c b/fs/file_table.c
--- a/fs/file_table.c	Wed Apr  9 06:42:36 2003
+++ b/fs/file_table.c	Wed May  7 21:20:31 2003
@@ -141,7 +141,7 @@
 	security_file_free(file);
 }
 
-void fput(struct file * file)
+void fput(struct file *file)
 {
 	if (atomic_dec_and_test(&file->f_count))
 		__fput(file);
@@ -189,6 +189,34 @@
 	spin_unlock(&files->file_lock);
 	return file;
 }
+
+/*
+ * Lightweight file lookup - no refcnt increment if fd table isn't shared. 
+ * You can use this only if it is guranteed that the current task already 
+ * holds a refcnt to that file. That check has to be done at fget() only
+ * and a flag is returned to be passed to the corresponding fput_light().
+ * There must not be a cloning between an fget_light/fput_light pair.
+ */
+struct file *fget_light(unsigned int fd, int *fput_needed)
+{
+	struct file *file;
+	struct files_struct *files = current->files;
+
+	*fput_needed = 0;
+	if (likely((atomic_read(&files->count) == 1))) {
+		file = fcheck(fd);
+	} else {
+		spin_lock(&files->file_lock);
+		file = fcheck(fd);
+		if (file) {
+			get_file(file);
+			*fput_needed = 1;
+		}
+		spin_unlock(&files->file_lock);
+	}
+	return file;
+}
+
 
 void put_filp(struct file *file)
 {
diff -Nru a/fs/filesystems.c b/fs/filesystems.c
--- a/fs/filesystems.c	Sun Apr 13 22:44:36 2003
+++ b/fs/filesystems.c	Sat May 17 12:39:13 2003
@@ -174,7 +174,7 @@
 		register_fs_subsys(*p);
 }
 
-static int fs_index(const char * __name)
+static int fs_index(const char __user * __name)
 {
 	struct file_system_type * tmp;
 	char * name;
@@ -198,7 +198,7 @@
 	return err;
 }
 
-static int fs_name(unsigned int index, char * buf)
+static int fs_name(unsigned int index, char __user * buf)
 {
 	struct file_system_type * tmp;
 	int len, res;
@@ -239,11 +239,11 @@
 
 	switch (option) {
 		case 1:
-			retval = fs_index((const char *) arg1);
+			retval = fs_index((const char __user *) arg1);
 			break;
 
 		case 2:
-			retval = fs_name(arg1, (char *) arg2);
+			retval = fs_name(arg1, (char __user *) arg2);
 			break;
 
 		case 3:
@@ -279,7 +279,7 @@
 	if (fs && !try_module_get(fs->owner))
 		fs = NULL;
 	read_unlock(&file_systems_lock);
-	if (!fs && (request_module(name) == 0)) {
+	if (!fs && (request_module("%s", name) == 0)) {
 		read_lock(&file_systems_lock);
 		fs = *(find_filesystem(name));
 		if (fs && !try_module_get(fs->owner))
diff -Nru a/fs/fs-writeback.c b/fs/fs-writeback.c
--- a/fs/fs-writeback.c	Tue Apr  8 03:16:30 2003
+++ b/fs/fs-writeback.c	Wed May  7 03:31:18 2003
@@ -367,7 +367,8 @@
 	};
 
 	get_page_state(&ps);
-	wbc.nr_to_write = ps.nr_dirty + ps.nr_dirty / 4;
+	wbc.nr_to_write = ps.nr_dirty + ps.nr_unstable +
+		(ps.nr_dirty + ps.nr_unstable) / 4;
 	spin_lock(&inode_lock);
 	sync_sb_inodes(sb, &wbc);
 	spin_unlock(&inode_lock);
diff -Nru a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c
--- a/fs/hugetlbfs/inode.c	Thu Mar  6 13:34:27 2003
+++ b/fs/hugetlbfs/inode.c	Sun May  4 22:49:54 2003
@@ -62,7 +62,7 @@
 
 	down(&inode->i_sem);
 
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 	vma->vm_flags |= VM_HUGETLB | VM_RESERVED;
 	vma->vm_ops = &hugetlb_vm_ops;
 	ret = hugetlb_prefault(mapping, vma);
diff -Nru a/fs/intermezzo/methods.c b/fs/intermezzo/methods.c
--- a/fs/intermezzo/methods.c	Tue Mar 18 09:08:23 2003
+++ b/fs/intermezzo/methods.c	Mon May 12 18:59:22 2003
@@ -145,7 +145,7 @@
 {
         if ( strlen(cache_type) == strlen("ext2") &&
              memcmp(cache_type, "ext2", strlen("ext2")) == 0 ) {
-#if CONFIG_EXT2_FS
+#ifdef CONFIG_EXT2_FS
                 ops->o_trops = &presto_ext2_journal_ops;
 #else
                 ops->o_trops = NULL;
diff -Nru a/fs/intermezzo/sysctl.c b/fs/intermezzo/sysctl.c
--- a/fs/intermezzo/sysctl.c	Thu Mar 13 16:52:26 2003
+++ b/fs/intermezzo/sysctl.c	Mon May 12 18:59:22 2003
@@ -358,7 +358,7 @@
 	 */
 	PRESTO_FREE(presto_table[PRESTO_PRIMARY_CTLCNT].child, sizeof(ctl_table) * total_entries);
 
-#if CONFIG_PROC_FS
+#ifdef CONFIG_PROC_FS
 	remove_proc_entry("mounts", proc_fs_intermezzo);
 	remove_proc_entry("intermezzo", proc_root_fs);
 #endif
diff -Nru a/fs/ioctl.c b/fs/ioctl.c
--- a/fs/ioctl.c	Wed Jan  8 12:38:51 2003
+++ b/fs/ioctl.c	Tue May 13 13:42:27 2003
@@ -75,7 +75,7 @@
 			break;
 
 		case FIONBIO:
-			if ((error = get_user(on, (int *)arg)) != 0)
+			if ((error = get_user(on, (int __user *)arg)) != 0)
 				break;
 			flag = O_NONBLOCK;
 #ifdef __sparc__
@@ -90,7 +90,7 @@
 			break;
 
 		case FIOASYNC:
-			if ((error = get_user(on, (int *)arg)) != 0)
+			if ((error = get_user(on, (int __user *)arg)) != 0)
 				break;
 			flag = on ? FASYNC : 0;
 
@@ -114,7 +114,7 @@
 			    S_ISREG(filp->f_dentry->d_inode->i_mode) ||
 			    S_ISLNK(filp->f_dentry->d_inode->i_mode)) {
 				loff_t res = inode_get_bytes(filp->f_dentry->d_inode);
-				error = copy_to_user((loff_t *)arg, &res, sizeof(res)) ? -EFAULT : 0;
+				error = copy_to_user((loff_t __user *)arg, &res, sizeof(res)) ? -EFAULT : 0;
 			}
 			else
 				error = -ENOTTY;
diff -Nru a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c
--- a/fs/jffs/inode-v23.c	Tue Dec 31 17:25:46 2002
+++ b/fs/jffs/inode-v23.c	Mon May 12 18:59:23 2003
@@ -55,7 +55,7 @@
 
 #include "jffs_fm.h"
 #include "intrep.h"
-#if CONFIG_JFFS_PROC_FS
+#ifdef CONFIG_JFFS_PROC_FS
 #include "jffs_proc.h"
 #endif
 
diff -Nru a/fs/libfs.c b/fs/libfs.c
--- a/fs/libfs.c	Fri Apr 25 15:16:53 2003
+++ b/fs/libfs.c	Tue May 13 13:42:27 2003
@@ -157,7 +157,7 @@
 	return 0;
 }
 
-ssize_t generic_read_dir(struct file *filp, char *buf, size_t siz, loff_t *ppos)
+ssize_t generic_read_dir(struct file *filp, char __user *buf, size_t siz, loff_t *ppos)
 {
 	return -EISDIR;
 }
diff -Nru a/fs/lockd/host.c b/fs/lockd/host.c
--- a/fs/lockd/host.c	Tue Sep 10 18:28:27 2002
+++ b/fs/lockd/host.c	Wed May  7 04:03:10 2003
@@ -187,15 +187,7 @@
 					host->h_nextrebind - jiffies);
 		}
 	} else {
-		uid_t saved_fsuid = current->fsuid;
-		kernel_cap_t saved_cap = current->cap_effective;
-
-		/* Create RPC socket as root user so we get a priv port */
-		current->fsuid = 0;
-		cap_raise (current->cap_effective, CAP_NET_BIND_SERVICE);
 		xprt = xprt_create_proto(host->h_proto, &host->h_addr, NULL);
-		current->fsuid = saved_fsuid;
-		current->cap_effective = saved_cap;
 		if (xprt == NULL)
 			goto forgetit;
 
@@ -209,6 +201,7 @@
 		}
 		clnt->cl_autobind = 1;	/* turn on pmap queries */
 		xprt->nocong = 1;	/* No congestion control for NLM */
+		xprt->resvport = 1;	/* NLM requires a reserved port */
 
 		host->h_rpcclnt = clnt;
 	}
@@ -276,7 +269,7 @@
 	dprintk("lockd: nuking all hosts...\n");
 	for (i = 0; i < NLM_HOST_NRHASH; i++) {
 		for (host = nlm_hosts[i]; host; host = host->h_next)
-			host->h_expires = 0;
+			host->h_expires = jiffies - 1;
 	}
 
 	/* Then, perform a garbage collection pass */
@@ -323,6 +316,9 @@
 		while ((host = *q) != NULL) {
 			if (host->h_count || host->h_inuse
 			 || time_before(jiffies, host->h_expires)) {
+				dprintk("nlm_gc_hosts skipping %s (cnt %d use %d exp %ld)\n",
+					host->h_name, host->h_count,
+					host->h_inuse, host->h_expires);
 				q = &host->h_next;
 				continue;
 			}
diff -Nru a/fs/lockd/mon.c b/fs/lockd/mon.c
--- a/fs/lockd/mon.c	Sun Nov 17 13:19:59 2002
+++ b/fs/lockd/mon.c	Wed May  7 04:03:10 2003
@@ -123,6 +123,7 @@
 	clnt->cl_softrtry = 1;
 	clnt->cl_chatty   = 1;
 	clnt->cl_oneshot  = 1;
+	xprt->resvport = 1;	/* NSM requires a reserved port */
 out:
 	return clnt;
 
diff -Nru a/fs/locks.c b/fs/locks.c
--- a/fs/locks.c	Mon Mar 17 21:32:01 2003
+++ b/fs/locks.c	Tue May 13 13:42:28 2003
@@ -1342,7 +1342,7 @@
 /* Report the first existing lock that would conflict with l.
  * This implements the F_GETLK command of fcntl().
  */
-int fcntl_getlk(struct file *filp, struct flock *l)
+int fcntl_getlk(struct file *filp, struct flock __user *l)
 {
 	struct file_lock *fl, file_lock;
 	struct flock flock;
@@ -1404,7 +1404,7 @@
 /* Apply the lock described by l to an open file descriptor.
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
  */
-int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock *l)
+int fcntl_setlk(struct file *filp, unsigned int cmd, struct flock __user *l)
 {
 	struct file_lock *file_lock = locks_alloc_lock();
 	struct flock flock;
@@ -1492,7 +1492,7 @@
 /* Report the first existing lock that would conflict with l.
  * This implements the F_GETLK command of fcntl().
  */
-int fcntl_getlk64(struct file *filp, struct flock64 *l)
+int fcntl_getlk64(struct file *filp, struct flock64 __user *l)
 {
 	struct file_lock *fl, file_lock;
 	struct flock64 flock;
@@ -1542,7 +1542,7 @@
 /* Apply the lock described by l to an open file descriptor.
  * This implements both the F_SETLK and F_SETLKW commands of fcntl().
  */
-int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 *l)
+int fcntl_setlk64(struct file *filp, unsigned int cmd, struct flock64 __user *l)
 {
 	struct file_lock *file_lock = locks_alloc_lock();
 	struct flock64 flock;
diff -Nru a/fs/minix/dir.c b/fs/minix/dir.c
--- a/fs/minix/dir.c	Sat Sep 28 08:36:22 2002
+++ b/fs/minix/dir.c	Sun May  4 22:49:54 2003
@@ -127,7 +127,7 @@
 
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 	unlock_kernel();
 	return 0;
 }
diff -Nru a/fs/namei.c b/fs/namei.c
--- a/fs/namei.c	Wed Apr 16 03:18:40 2003
+++ b/fs/namei.c	Sun May  4 22:49:54 2003
@@ -405,7 +405,7 @@
 		goto loop;
 	current->link_count++;
 	current->total_link_count++;
-	UPDATE_ATIME(dentry->d_inode);
+	update_atime(dentry->d_inode);
 	err = dentry->d_inode->i_op->follow_link(dentry, nd);
 	current->link_count--;
 	return err;
@@ -1327,7 +1327,7 @@
 	error = security_inode_follow_link(dentry, nd);
 	if (error)
 		goto exit_dput;
-	UPDATE_ATIME(dentry->d_inode);
+	update_atime(dentry->d_inode);
 	error = dentry->d_inode->i_op->follow_link(dentry, nd);
 	dput(dentry);
 	if (error)
diff -Nru a/fs/namespace.c b/fs/namespace.c
--- a/fs/namespace.c	Sat Apr 19 16:17:34 2003
+++ b/fs/namespace.c	Mon May 19 08:42:59 2003
@@ -24,7 +24,6 @@
 #include <asm/uaccess.h>
 
 extern struct vfsmount *do_kern_mount(const char *type, int flags, char *name, void *data);
-extern int do_remount_sb(struct super_block *sb, int flags, void * data);
 extern int __init init_rootfs(void);
 extern int __init fs_subsys_init(void);
 
@@ -212,17 +211,10 @@
 		{ 0, NULL }
 	};
 	struct proc_fs_info *fs_infop;
-	char *path_buf, *path;
-
-	path_buf = (char *) __get_free_page(GFP_KERNEL);
-	if (!path_buf)
-		return -ENOMEM;
-	path = d_path(mnt->mnt_root, mnt, path_buf, PAGE_SIZE);
 
 	mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
 	seq_putc(m, ' ');
-	mangle(m, path);
-	free_page((unsigned long) path_buf);
+	seq_path(m, mnt, mnt->mnt_root, " \t\n\\");
 	seq_putc(m, ' ');
 	mangle(m, mnt->mnt_sb->s_type->name);
 	seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
@@ -326,7 +318,7 @@
 		down_write(&sb->s_umount);
 		if (!(sb->s_flags & MS_RDONLY)) {
 			lock_kernel();
-			retval = do_remount_sb(sb, MS_RDONLY, 0);
+			retval = do_remount_sb(sb, MS_RDONLY, 0, 0);
 			unlock_kernel();
 		}
 		up_write(&sb->s_umount);
@@ -419,36 +411,54 @@
 #endif
 }
 
+static int
+lives_below_in_same_fs(struct dentry *d, struct dentry *dentry)
+{
+	while (1) {
+		if (d == dentry)
+			return 1;
+		if (d == NULL || d == d->d_parent)
+			return 0;
+		d = d->d_parent;
+	}
+}
+
 static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry)
 {
-	struct vfsmount *p, *next, *q, *res;
+	struct vfsmount *res, *p, *q, *r, *s;
+	struct list_head *h;
 	struct nameidata nd;
 
-	p = mnt;
-	res = nd.mnt = q = clone_mnt(p, dentry);
+	res = q = clone_mnt(mnt, dentry);
 	if (!q)
 		goto Enomem;
-	q->mnt_parent = q;
-	q->mnt_mountpoint = p->mnt_mountpoint;
+	q->mnt_mountpoint = mnt->mnt_mountpoint;
 
-	while ( (next = next_mnt(p, mnt)) != NULL) {
-		while (p != next->mnt_parent) {
-			p = p->mnt_parent;
-			q = q->mnt_parent;
+	p = mnt;
+	for (h = mnt->mnt_mounts.next; h != &mnt->mnt_mounts; h = h->next) {
+		r = list_entry(h, struct vfsmount, mnt_child);
+		if (!lives_below_in_same_fs(r->mnt_mountpoint, dentry))
+			continue;
+
+		for (s = r; s; s = next_mnt(s, r)) {
+			while (p != s->mnt_parent) {
+				p = p->mnt_parent;
+				q = q->mnt_parent;
+			}
+			p = s;
+			nd.mnt = q;
+			nd.dentry = p->mnt_mountpoint;
+			q = clone_mnt(p, p->mnt_root);
+			if (!q)
+				goto Enomem;
+			spin_lock(&dcache_lock);
+			list_add_tail(&q->mnt_list, &res->mnt_list);
+			attach_mnt(q, &nd);
+			spin_unlock(&dcache_lock);
 		}
-		p = next;
-		nd.mnt = q;
-		nd.dentry = p->mnt_mountpoint;
-		q = clone_mnt(p, p->mnt_root);
-		if (!q)
-			goto Enomem;
-		spin_lock(&dcache_lock);
-		list_add_tail(&q->mnt_list, &res->mnt_list);
-		attach_mnt(q, &nd);
-		spin_unlock(&dcache_lock);
 	}
 	return res;
-Enomem:
+ Enomem:
 	if (res) {
 		spin_lock(&dcache_lock);
 		umount_tree(res);
@@ -555,7 +565,7 @@
 		return -EINVAL;
 
 	down_write(&sb->s_umount);
-	err = do_remount_sb(sb, flags, data);
+	err = do_remount_sb(sb, flags, data, 0);
 	if (!err)
 		nd->mnt->mnt_flags=mnt_flags;
 	up_write(&sb->s_umount);
diff -Nru a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
--- a/fs/ncpfs/ncplib_kernel.c	Fri Sep 20 11:22:15 2002
+++ b/fs/ncpfs/ncplib_kernel.c	Mon May 12 18:59:23 2003
@@ -695,7 +695,7 @@
 	__u32 dirent;
 
 	if (!inode) {
-#if CONFIG_NCPFS_DEBUGDENTRY
+#ifdef CONFIG_NCPFS_DEBUGDENTRY
 		PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n");
 #endif
 		return 0xFF;	/* Any error */
diff -Nru a/fs/nfs/dir.c b/fs/nfs/dir.c
--- a/fs/nfs/dir.c	Fri Apr 11 11:52:04 2003
+++ b/fs/nfs/dir.c	Wed May  7 03:34:41 2003
@@ -83,7 +83,7 @@
 
 	lock_kernel();
 	/* Do cto revalidation */
-	if (server->flags & NFS_MOUNT_NOCTO)
+	if (!(server->flags & NFS_MOUNT_NOCTO))
 		res = __nfs_revalidate_inode(server, inode);
 	/* Call generic open code in order to cache credentials */
 	if (!res)
diff -Nru a/fs/nfs/file.c b/fs/nfs/file.c
--- a/fs/nfs/file.c	Mon Apr  7 15:22:57 2003
+++ b/fs/nfs/file.c	Wed May  7 03:34:41 2003
@@ -83,7 +83,7 @@
 	if ((open = server->rpc_ops->file_open) != NULL)
 		res = open(inode, filp);
 	/* Do cto revalidation */
-	else if (server->flags & NFS_MOUNT_NOCTO)
+	else if (!(server->flags & NFS_MOUNT_NOCTO))
 		res = __nfs_revalidate_inode(server, inode);
 	/* Call generic open code in order to cache credentials */
 	if (!res)
diff -Nru a/fs/nfs/inode.c b/fs/nfs/inode.c
--- a/fs/nfs/inode.c	Mon Apr  7 15:46:22 2003
+++ b/fs/nfs/inode.c	Sun May  4 22:49:54 2003
@@ -682,7 +682,7 @@
 		 * such as stat(2) */
 		inode->i_ino = hash;
 
-		/* We can't support UPDATE_ATIME(), since the server will reset it */
+		/* We can't support update_atime(), since the server will reset it */
 		inode->i_flags |= S_NOATIME;
 		inode->i_mode = fattr->mode;
 		/* Why so? Because we want revalidate for devices/FIFOs, and
diff -Nru a/fs/nfs/symlink.c b/fs/nfs/symlink.c
--- a/fs/nfs/symlink.c	Tue Sep 10 02:10:40 2002
+++ b/fs/nfs/symlink.c	Tue May 13 13:42:28 2003
@@ -75,7 +75,7 @@
 	return (char*)page;
 }
 
-static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
+static int nfs_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 {
 	struct inode *inode = dentry->d_inode;
 	struct page *page = NULL;
diff -Nru a/fs/nfs/write.c b/fs/nfs/write.c
--- a/fs/nfs/write.c	Mon Apr 14 19:46:02 2003
+++ b/fs/nfs/write.c	Wed May  7 03:31:18 2003
@@ -280,8 +280,6 @@
 		err = nfs_wb_all(inode);
 	} else
 		nfs_commit_file(inode, NULL, 0, 0, 0);
-	/* Avoid races. Tell upstream we've done all we were told to do */
-	wbc->nr_to_write = 0;
 out:
 	return err;
 }
@@ -490,7 +488,6 @@
 	int	res;
 	res = nfs_scan_list(&nfsi->commit, dst, file, idx_start, npages);
 	nfsi->ncommit -= res;
-	sub_page_state(nr_unstable,res);
 	if ((nfsi->ncommit == 0) != list_empty(&nfsi->commit))
 		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
 	return res;
@@ -1009,6 +1006,7 @@
 {
 	struct nfs_write_data	*data = (struct nfs_write_data *)task->tk_calldata;
 	struct nfs_page		*req;
+	int res = 0;
 
         dprintk("NFS: %4d nfs_commit_done (status %d)\n",
                                 task->tk_pid, task->tk_status);
@@ -1043,7 +1041,9 @@
 		nfs_mark_request_dirty(req);
 	next:
 		nfs_unlock_request(req);
+		res++;
 	}
+	sub_page_state(nr_unstable,res);
 }
 #endif
 
diff -Nru a/fs/nfsd/export.c b/fs/nfsd/export.c
--- a/fs/nfsd/export.c	Sat Apr 12 23:14:46 2003
+++ b/fs/nfsd/export.c	Mon May 19 23:34:38 2003
@@ -848,12 +848,18 @@
  * export point with fsid==0
  */
 int
-exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp)
+exp_pseudoroot(struct auth_domain *clp, struct svc_fh *fhp,
+	       struct cache_req *creq)
 {
 	struct svc_expkey *fsid_key;
 	int rv;
+	u32 fsidv[2];
 
-	fsid_key = exp_get_fsid_key(clp, 0);
+	mk_fsid_v1(fsidv, 0);
+
+	fsid_key = exp_find_key(clp, 1, fsidv, creq);
+	if (IS_ERR(fsid_key) && PTR_ERR(fsid_key) == -EAGAIN)
+		return nfserr_dropit;
 	if (!fsid_key || IS_ERR(fsid_key))
 		return nfserr_perm;
 
diff -Nru a/fs/nfsd/nfs4proc.c b/fs/nfsd/nfs4proc.c
--- a/fs/nfsd/nfs4proc.c	Sat Apr 12 23:15:50 2003
+++ b/fs/nfsd/nfs4proc.c	Mon May 19 23:34:38 2003
@@ -50,6 +50,7 @@
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/cache.h>
 #include <linux/nfs4.h>
+#include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
@@ -80,14 +81,14 @@
 		 * Note: create modes (UNCHECKED,GUARDED...) are the same
 		 * in NFSv4 as in v3.
 		 */
-		status = nfsd_create_v3(rqstp, current_fh, open->op_name,
-					open->op_namelen, &open->op_iattr,
+		status = nfsd_create_v3(rqstp, current_fh, open->op_fname.data,
+					open->op_fname.len, &open->op_iattr,
 					&resfh, open->op_createmode,
 					(u32 *)open->op_verf, &open->op_truncate);
 	}
 	else {
 		status = nfsd_lookup(rqstp, current_fh,
-				     open->op_name, open->op_namelen, &resfh);
+				     open->op_fname.data, open->op_fname.len, &resfh);
 		fh_unlock(current_fh);
 	}
 
@@ -107,45 +108,25 @@
 	return status;
 }
 
-static int
-nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
-{
-	struct iattr iattr;
-	int status;
-
-	if (open->op_truncate) {
-		iattr.ia_valid = ATTR_SIZE;
-		iattr.ia_size = 0;
-		status = nfsd_setattr(rqstp, current_fh, &iattr, 0, (time_t)0);
-		if (status)
-			return status;
-	}
-
-	memset(&open->op_stateid, 0xff, sizeof(stateid_t));
-	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
-	return 0;
-}
-
 static inline int
 nfsd4_open(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
 {
 	int status;
+	dprintk("NFSD: nfsd4_open filename %.*s\n",open->op_fname.len, open->op_fname.data);
 
 	/* This check required by spec. */
 	if (open->op_create && open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
 		return nfserr_inval;
 
-	/*
-	 * For now, we have no state, so we may as well implement an
-	 * even stronger check...
-	 */
-	if (open->op_claim_type != NFS4_OPEN_CLAIM_NULL)
-		return nfserr_notsupp;
-
+	/* check seqid for replay. set nfs4_owner */
+	status = nfsd4_process_open1(open);
+	if (status)
+		return status;
 	/*
 	 * This block of code will (1) set CURRENT_FH to the file being opened,
-	 * creating it if necessary, (2) set open->op_cinfo, (3) set open->op_truncate
-	 * if the file is to be truncated after opening, (4) do permission checking.
+	 * creating it if necessary, (2) set open->op_cinfo, 
+	 * (3) set open->op_truncate if the file is to be truncated 
+	 * after opening, (4) do permission checking.
 	 */
 	status = do_open_lookup(rqstp, current_fh, open);
 	if (status)
@@ -159,7 +140,6 @@
 	status = nfsd4_process_open2(rqstp, current_fh, open);
 	if (status)
 		return status;
-
 	/*
 	 * To finish the open response, we just need to set the rflags.
 	 */
@@ -199,7 +179,8 @@
 nfsd4_putrootfh(struct svc_rqst *rqstp, struct svc_fh *current_fh)
 {
 	fh_put(current_fh);
-	return exp_pseudoroot(rqstp->rq_client, current_fh);
+	return exp_pseudoroot(rqstp->rq_client, current_fh,
+			      &rqstp->rq_chandle);
 }
 
 static inline int
diff -Nru a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
--- a/fs/nfsd/nfs4state.c	Sat Apr 12 23:15:50 2003
+++ b/fs/nfsd/nfs4state.c	Mon May 19 23:34:37 2003
@@ -42,15 +42,24 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/cache.h>
+#include <linux/mount.h>
 #include <linux/nfs4.h>
-#include <linux/nfsd/xdr4.h>
 #include <linux/nfsd/state.h>
+#include <linux/nfsd/xdr4.h>
 
 #define NFSDDBG_FACILITY                NFSDDBG_PROC
 
 /* Globals */
 time_t boot_time;
 static u32 current_clientid = 1;
+static u32 current_ownerid = 0;
+static u32 current_fileid = 0;
+
+/* debug counters */
+u32 list_add_perfile = 0; 
+u32 list_del_perfile = 0;
+u32 add_perclient = 0;
+u32 del_perclient = 0;
 
 /* Locking:
  *
@@ -73,6 +82,14 @@
 	return x;
 }
 
+/* forward declarations */
+static void release_stateowner(struct nfs4_stateowner *sop);
+static void release_stateid(struct nfs4_stateid *stp);
+
+/* 
+ * SETCLIENTID state 
+ */
+
 /* Hash tables for nfs4_clientid state */
 #define CLIENT_HASH_BITS                 4
 #define CLIENT_HASH_SIZE                (1 << CLIENT_HASH_BITS)
@@ -138,9 +155,15 @@
 static void
 expire_client(struct nfs4_client *clp)
 {
+	struct nfs4_stateowner *sop;
+
 	dprintk("NFSD: expire_client\n");
 	list_del(&clp->cl_idhash);
 	list_del(&clp->cl_strhash);
+	while (!list_empty(&clp->cl_perclient)) {
+		sop = list_entry(clp->cl_perclient.next, struct nfs4_stateowner, so_perclient);
+		release_stateowner(sop);
+	}
 	free_client(clp);
 }
 
@@ -152,6 +175,7 @@
 		goto out;
 	INIT_LIST_HEAD(&clp->cl_idhash);
 	INIT_LIST_HEAD(&clp->cl_strhash);
+	INIT_LIST_HEAD(&clp->cl_perclient);
 out:
 	return clp;
 }
@@ -225,7 +249,7 @@
 
 	if (name.len == 0) 
 		return 0;
-	if (name.len > NFSD4_CLIENT_MAXNAME) {
+	if (name.len > NFS4_OPAQUE_LIMIT) {
 		printk("NFSD: check_name: name too long(%d)!\n", name.len);
 		return 0;
 	}
@@ -590,7 +614,442 @@
 	return status;
 }
 
-void
+/* 
+ * Open owner state (share locks)
+ */
+
+/* hash tables for nfs4_stateowner */
+#define OWNER_HASH_BITS              8
+#define OWNER_HASH_SIZE             (1 << OWNER_HASH_BITS)
+#define OWNER_HASH_MASK             (OWNER_HASH_SIZE - 1)
+
+#define ownerstr_hashval(clientid, ownername) \
+        (((clientid) + opaque_hashval((ownername.data), (ownername.len))) & OWNER_HASH_MASK)
+
+static struct list_head	ownerstr_hashtbl[OWNER_HASH_SIZE];
+
+/* hash table for nfs4_file */
+#define FILE_HASH_BITS                   8
+#define FILE_HASH_SIZE                  (1 << FILE_HASH_BITS)
+#define FILE_HASH_MASK                  (FILE_HASH_SIZE - 1)
+
+#define file_hashval(x) \
+        ((unsigned int)((x)->dev + (x)->ino + (x)->generation) & FILE_HASH_MASK)
+
+static struct list_head file_hashtbl[FILE_HASH_SIZE];
+
+/* OPEN Share state helper functions */
+static inline struct nfs4_file *
+alloc_init_file(unsigned int hashval, nfs4_ino_desc_t *ino) {
+	struct nfs4_file *fp;
+	if ((fp = kmalloc(sizeof(struct nfs4_file),GFP_KERNEL))) {
+		INIT_LIST_HEAD(&fp->fi_hash);
+		INIT_LIST_HEAD(&fp->fi_perfile);
+		list_add(&fp->fi_hash, &file_hashtbl[hashval]);
+		memcpy(&fp->fi_ino, ino, sizeof(nfs4_ino_desc_t));
+		fp->fi_id = current_fileid++;
+		return fp;
+	}
+	return (struct nfs4_file *)NULL;
+}
+
+static void
+release_all_files(void)
+{
+	int i;
+	struct nfs4_file *fp;
+
+	for (i=0;i<FILE_HASH_SIZE;i++) {
+		while (!list_empty(&file_hashtbl[i])) {
+			fp = list_entry(file_hashtbl[i].next, struct nfs4_file, fi_hash);
+			/* this should never be more than once... */
+			if(!list_empty(&fp->fi_perfile)) {
+				printk("ERROR: release_all_files: file %p is open, creating dangling state !!!\n",fp);
+			}
+			list_del_init(&fp->fi_hash);
+			kfree(fp);
+		}
+	}
+}
+
+static inline struct nfs4_stateowner *
+alloc_stateowner(struct xdr_netobj *owner)
+{
+	struct nfs4_stateowner *sop;
+
+	if ((sop = kmalloc(sizeof(struct nfs4_stateowner),GFP_KERNEL))) {
+		if((sop->so_owner.data = kmalloc(owner->len, GFP_KERNEL))) {
+			memcpy(sop->so_owner.data, owner->data, owner->len);
+			sop->so_owner.len = owner->len;
+			return sop;
+		} 
+		kfree(sop);
+	}
+	return (struct nfs4_stateowner *)NULL;
+}
+
+/* should use a slab cache */
+static void
+free_stateowner(struct nfs4_stateowner *sop) {
+	if(sop) {
+		kfree(sop->so_owner.data);
+		kfree(sop);
+		sop = NULL;
+	}
+}
+
+static struct nfs4_stateowner *
+alloc_init_stateowner(unsigned int strhashval, struct nfs4_client *clp, struct nfsd4_open *open) {
+	struct nfs4_stateowner *sop;
+
+	if (!(sop = alloc_stateowner(&open->op_owner)))
+		return (struct nfs4_stateowner *)NULL;
+	INIT_LIST_HEAD(&sop->so_strhash);
+	INIT_LIST_HEAD(&sop->so_perclient);
+	INIT_LIST_HEAD(&sop->so_peropenstate);
+	list_add(&sop->so_strhash, &ownerstr_hashtbl[strhashval]);
+	list_add(&sop->so_perclient, &clp->cl_perclient);
+	add_perclient++;
+	sop->so_id = current_ownerid++;
+	sop->so_client = clp;
+	sop->so_seqid = open->op_seqid;
+	/* until open_confirm is coded, pretend it happened! */
+	sop->so_confirmed = 1;
+	return sop;
+}
+
+static void
+release_stateowner(struct nfs4_stateowner *sop)
+{
+	struct nfs4_stateid *stp;
+
+	list_del_init(&sop->so_strhash);
+	list_del_init(&sop->so_perclient);
+	del_perclient++;
+	while (!list_empty(&sop->so_peropenstate)) {
+		stp = list_entry(sop->so_peropenstate.next, 
+			struct nfs4_stateid, st_peropenstate);
+		release_stateid(stp);
+	}
+	free_stateowner(sop);
+}
+
+static inline void
+init_stateid(struct nfs4_stateid *stp, struct nfs4_file *fp, struct nfs4_stateowner *sop, struct nfsd4_open *open) {
+
+	INIT_LIST_HEAD(&stp->st_peropenstate);
+	INIT_LIST_HEAD(&stp->st_perfile);
+	list_add(&stp->st_peropenstate, &sop->so_peropenstate);
+	list_add_perfile++;
+	list_add(&stp->st_perfile, &fp->fi_perfile);
+	stp->st_stateowner = sop;
+	stp->st_file = fp;
+	stp->st_stateid.si_boot = boot_time;
+	stp->st_stateid.si_stateownerid = sop->so_id;
+	stp->st_stateid.si_fileid = fp->fi_id;
+	stp->st_stateid.si_generation = 0;
+	stp->st_share_access = open->op_share_access;
+	stp->st_share_deny = open->op_share_deny;
+}
+
+static void
+release_stateid(struct nfs4_stateid *stp) {
+
+	list_del_perfile++;
+	list_del_init(&stp->st_perfile);
+	list_del_init(&stp->st_peropenstate);
+	if(stp->st_vfs_set) {
+		nfsd_close(&stp->st_vfs_file);
+		dput(stp->st_vfs_file.f_dentry);
+		mntput(stp->st_vfs_file.f_vfsmnt);
+	}
+	/* should use a slab cache */
+	kfree(stp);
+	stp = NULL;
+}
+
+static int
+cmp_owner_str(struct nfs4_stateowner *sop, struct nfsd4_open *open) {
+	return ((sop->so_owner.len == open->op_owner.len) && 
+	 !memcmp(sop->so_owner.data, open->op_owner.data, sop->so_owner.len) && 
+	  (sop->so_client->cl_clientid.cl_id == open->op_clientid.cl_id));
+}
+
+/* search ownerstr_hashtbl[] for owner */
+static int
+find_stateowner_str(unsigned int hashval, struct nfsd4_open *open, struct nfs4_stateowner **op) {
+	struct list_head *pos, *next;
+	struct nfs4_stateowner *local = NULL;
+
+	list_for_each_safe(pos, next, &ownerstr_hashtbl[hashval]) {
+		local = list_entry(pos, struct nfs4_stateowner, so_strhash);
+		if(!cmp_owner_str(local, open)) 
+			continue;
+		*op = local;
+		return(1);
+	}
+	return 0;
+}
+
+/* see if clientid is in confirmed hash table */
+static int
+verify_clientid(struct nfs4_client **client, clientid_t *clid) {
+
+	struct list_head *pos, *next;
+	struct nfs4_client *clp;
+	unsigned int idhashval = clientid_hashval(clid->cl_id);
+
+	list_for_each_safe(pos, next, &conf_id_hashtbl[idhashval]) {
+		clp = list_entry(pos, struct nfs4_client, cl_idhash);
+		if (!cmp_clid(&clp->cl_clientid, clid))
+			continue;
+		*client = clp;
+		return 1;
+	}
+	*client = NULL;
+	return 0;
+}
+
+/* search file_hashtbl[] for file */
+static int
+find_file(unsigned int hashval, nfs4_ino_desc_t *ino, struct nfs4_file **fp) {
+	struct list_head *pos, *next;
+	struct nfs4_file *local = NULL;
+
+	list_for_each_safe(pos, next, &file_hashtbl[hashval]) {
+		local = list_entry(pos, struct nfs4_file, fi_hash);
+		if(!memcmp(&local->fi_ino, ino, sizeof(nfs4_ino_desc_t))) {
+			*fp = local;
+			return(1);
+		}
+	}
+	return 0;
+}
+
+static int
+test_share(struct nfs4_stateid *stp, struct nfsd4_open *open) {
+	if ((stp->st_share_access & open->op_share_deny) ||
+	    (stp->st_share_deny & open->op_share_access)) {
+		return 0;
+	}
+	return 1;
+}
+
+static inline void
+nfs4_init_ino(nfs4_ino_desc_t *ino, struct svc_fh *fhp)
+{
+	struct inode *inode;
+	if (!fhp->fh_dentry)
+		BUG();
+	inode = fhp->fh_dentry->d_inode;
+	if (!inode)
+		BUG();
+	ino->dev = inode->i_sb->s_dev;
+	ino->ino = inode->i_ino;
+	ino->generation = inode->i_generation;
+}
+
+static inline int
+nfs4_file_upgrade(struct file *filp, unsigned int share_access)
+{
+int status;
+
+	if (share_access & NFS4_SHARE_ACCESS_WRITE) {
+		status = get_write_access(filp->f_dentry->d_inode);
+		if (!status)
+			filp->f_mode = FMODE_WRITE;
+		else
+			return nfserrno(status);
+	}
+	return nfs_ok;
+}
+
+
+/*
+ * nfsd4_process_open1()
+ * 	lookup stateowner.
+ * 		found:
+ * 			check confirmed 
+ * 				confirmed:
+ * 					check seqid
+ * 				not confirmed:
+ * 					delete owner
+ * 					create new owner
+ * 		notfound:
+ * 			verify clientid
+ * 			create new owner
+ */
+int
+nfsd4_process_open1(struct nfsd4_open *open)
+{
+	int status;
+	clientid_t *clientid = &open->op_clientid;
+	struct nfs4_client *clp = NULL;
+	unsigned int strhashval;
+	struct nfs4_stateowner *sop = NULL;
+
+	status = nfserr_inval;
+	if (!check_name(open->op_owner))
+		goto out;
+
+	status = nfserr_stale_clientid;
+	if (STALE_CLIENTID(&open->op_clientid))
+		goto out;
+
+	down(&client_sema); /* XXX need finer grained locking */
+	strhashval = ownerstr_hashval(clientid->cl_id, open->op_owner);
+	if (find_stateowner_str(strhashval, open, &sop)) {
+		open->op_stateowner = sop;
+		if (open->op_seqid == sop->so_seqid){
+			/* XXX retplay: for now, return bad seqid */
+			status = nfserr_bad_seqid;
+			goto out;
+		}
+		if (sop->so_confirmed) {
+			if (open->op_seqid == sop->so_seqid + 1) { 
+				status = nfs_ok;
+				goto renew;
+			} 
+			status = nfserr_bad_seqid;
+			goto out;
+		}
+		/* If we get here, we received and OPEN for an unconfirmed
+		 * nfs4_stateowner. If seqid's are the same then this 
+		 * is a replay.
+		 * If the sequid's are different, then purge the 
+		 * existing nfs4_stateowner, and instantiate a new one.
+		 */
+		clp = sop->so_client;
+		release_stateowner(sop);
+		goto instantiate_new_owner;
+	} 
+	/* nfs4_stateowner not found. 
+	* verify clientid and instantiate new nfs4_stateowner
+	* if verify fails this is presumably the result of the 
+	* client's lease expiring.
+	*
+	* XXX compare clp->cl_addr with rqstp addr? 
+	*/
+	status = nfserr_expired;
+	if (!verify_clientid(&clp, clientid))
+		goto out;
+instantiate_new_owner:
+	status = nfserr_resource;
+	if (!(sop = alloc_init_stateowner(strhashval, clp, open))) 
+		goto out;
+	open->op_stateowner = sop;
+	status = nfs_ok;
+renew:
+	/* XXX implement LRU and state recovery thread 
+	 * renew will place nfs4_client at end of LRU 
+	 */
+out:
+	up(&client_sema); /*XXX need finer grained locking */
+	return status;
+}
+
+int
+nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open)
+{
+	struct iattr iattr;
+	struct nfs4_stateowner *sop = open->op_stateowner;
+	struct nfs4_file *fp;
+	nfs4_ino_desc_t ino;
+	unsigned int fi_hashval;
+	struct list_head *pos, *next;
+	struct nfs4_stateid *stq, *stp = NULL;
+	int status;
+
+
+	status = nfserr_resource;
+	if (!sop)
+		goto out;
+
+	nfs4_init_ino(&ino, current_fh);
+
+	down(&client_sema); /*XXX need finer grained locking */
+	fi_hashval = file_hashval(&ino);
+	if (find_file(fi_hashval, &ino, &fp)) {
+		/* Search for conflicting share reservations */
+		status = nfserr_share_denied;
+		list_for_each_safe(pos, next, &fp->fi_perfile) {
+		stq = list_entry(pos, struct nfs4_stateid, st_perfile);
+			if(stq->st_stateowner == sop) {
+				stp = stq;
+				continue;
+			}
+			if (!test_share(stq,open))	
+				goto out;
+		}
+	} else {
+	/* No nfs4_file found; allocate and init a new one */
+		status = nfserr_resource;
+		if ((fp = alloc_init_file(fi_hashval, &ino)) == NULL)
+			goto out;
+	}
+
+	if (!stp) {
+		int flags = 0;
+
+		status = nfserr_resource;
+		if ((stp = kmalloc(sizeof(struct nfs4_stateid),
+						GFP_KERNEL)) == NULL)
+			goto out;
+
+		if (open->op_share_access && NFS4_SHARE_ACCESS_WRITE)
+			flags = MAY_WRITE;
+		else
+			flags = MAY_READ;
+		if ((status = nfsd_open(rqstp, current_fh,  S_IFREG,
+			                      flags,
+			                      &stp->st_vfs_file)) != 0)
+			goto out_free;
+
+		dget(stp->st_vfs_file.f_dentry);
+		mntget(stp->st_vfs_file.f_vfsmnt);
+
+		init_stateid(stp, fp, sop, open);
+		stp->st_vfs_set = 1;
+	} else {
+		/* This is an upgrade of an existing OPEN. 
+		 * OR the incoming share with the existing 
+		 * nfs4_stateid share */
+		int share_access = open->op_share_access;
+
+		share_access &= ~(stp->st_share_access);
+
+		/* update the struct file */
+		if ((status = nfs4_file_upgrade(&stp->st_vfs_file, share_access)))
+			goto out;
+		stp->st_share_access |= share_access;
+		stp->st_share_deny |= open->op_share_deny;
+		/* bump the stateid */
+		update_stateid(&stp->st_stateid);
+	}
+	dprintk("nfs4_process_open2: stateid=(%08x/%08x/%08x/%08x)\n\n",
+	            stp->st_stateid.si_boot, stp->st_stateid.si_stateownerid,
+	            stp->st_stateid.si_fileid, stp->st_stateid.si_generation);
+
+	if (open->op_truncate) {
+		iattr.ia_valid = ATTR_SIZE;
+		iattr.ia_size = 0;
+		status = nfsd_setattr(rqstp, current_fh, &iattr, 0, (time_t)0);
+		if (status)
+			goto out;
+	}
+	memcpy(&open->op_stateid, &stp->st_stateid, sizeof(stateid_t));
+
+	open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE;
+	status = nfs_ok;
+out:
+	up(&client_sema); /*XXX need finer grained locking */
+	return status;
+out_free:
+	kfree(stp);
+	goto out;
+}
+
+void 
 nfs4_state_init(void)
 {
 	struct timespec 	tv;
@@ -602,6 +1061,12 @@
 		INIT_LIST_HEAD(&unconf_str_hashtbl[i]);
 		INIT_LIST_HEAD(&unconf_id_hashtbl[i]);
 	}
+	for (i = 0; i < FILE_HASH_SIZE; i++) {
+		INIT_LIST_HEAD(&file_hashtbl[i]);
+	}
+	for (i = 0; i < OWNER_HASH_SIZE; i++) {
+		INIT_LIST_HEAD(&ownerstr_hashtbl[i]);
+	}
 	init_MUTEX(&client_sema);
 	tv = CURRENT_TIME;
 	boot_time = tv.tv_sec;
@@ -623,6 +1088,11 @@
 			expire_client(clp);
 		}
 	}
+	release_all_files();
+	dprintk("NFSD: list_add_perfile %d list_del_perfile %d\n",
+			list_add_perfile, list_del_perfile);
+	dprintk("NFSD: add_perclient %d del_perclient %d\n",
+			add_perclient, del_perclient);
 }
 
 void
diff -Nru a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
--- a/fs/nfsd/nfs4xdr.c	Thu Apr  3 15:03:46 2003
+++ b/fs/nfsd/nfs4xdr.c	Mon May 19 23:34:36 2003
@@ -53,6 +53,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/name_lookup.h>
 #include <linux/nfsd/nfsd.h>
+#include <linux/nfsd/state.h>
 #include <linux/nfsd/xdr4.h>
 
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
@@ -483,8 +484,8 @@
 
 	READ_BUF(4 + sizeof(stateid_t));
 	READ32(close->cl_seqid);
-	READ32(close->cl_stateid.st_generation);
-	COPYMEM(&close->cl_stateid.st_other, sizeof(stateid_other_t));
+	READ32(close->cl_stateid.si_generation);
+	COPYMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
 
 	DECODE_TAIL;
 }
@@ -595,11 +596,11 @@
 	READ32(open->op_share_access);
 	READ32(open->op_share_deny);
 	COPYMEM(&open->op_clientid, sizeof(clientid_t));
-	READ32(open->op_ownerlen);
+	READ32(open->op_owner.len);
 
 	/* owner, open_flag */
-	READ_BUF(open->op_ownerlen + 4);
-	SAVEMEM(open->op_owner, open->op_ownerlen);
+	READ_BUF(open->op_owner.len + 4);
+	SAVEMEM(open->op_owner.data, open->op_owner.len);
 	READ32(open->op_create);
 	switch (open->op_create) {
 	case NFS4_OPEN_NOCREATE:
@@ -632,10 +633,10 @@
 	case NFS4_OPEN_CLAIM_NULL:
 	case NFS4_OPEN_CLAIM_DELEGATE_PREV:
 		READ_BUF(4);
-		READ32(open->op_namelen);
-		READ_BUF(open->op_namelen);
-		SAVEMEM(open->op_name, open->op_namelen);
-		if ((status = check_filename(open->op_name, open->op_namelen, nfserr_inval)))
+		READ32(open->op_fname.len);
+		READ_BUF(open->op_fname.len);
+		SAVEMEM(open->op_fname.data, open->op_fname.len);
+		if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval)))
 			return status;
 		break;
 	case NFS4_OPEN_CLAIM_PREVIOUS:
@@ -645,10 +646,10 @@
 	case NFS4_OPEN_CLAIM_DELEGATE_CUR:
 		READ_BUF(sizeof(delegation_stateid_t) + 4);
 		COPYMEM(&open->op_delegate_stateid, sizeof(delegation_stateid_t));
-		READ32(open->op_namelen);
-		READ_BUF(open->op_namelen);
-		SAVEMEM(open->op_name, open->op_namelen);
-		if ((status = check_filename(open->op_name, open->op_namelen, nfserr_inval)))
+		READ32(open->op_fname.len);
+		READ_BUF(open->op_fname.len);
+		SAVEMEM(open->op_fname.data, open->op_fname.len);
+		if ((status = check_filename(open->op_fname.data, open->op_fname.len, nfserr_inval)))
 			return status;
 		break;
 	default:
@@ -679,8 +680,8 @@
 	DECODE_HEAD;
 
 	READ_BUF(sizeof(stateid_t) + 12);
-	READ32(read->rd_stateid.st_generation);
-	COPYMEM(&read->rd_stateid.st_other, sizeof(stateid_other_t));
+	READ32(read->rd_stateid.si_generation);
+	COPYMEM(&read->rd_stateid.si_opaque, sizeof(stateid_opaque_t));
 	READ64(read->rd_offset);
 	READ32(read->rd_length);
 
@@ -755,8 +756,8 @@
 	DECODE_HEAD;
 
 	READ_BUF(sizeof(stateid_t));
-	READ32(setattr->sa_stateid.st_generation);
-	COPYMEM(&setattr->sa_stateid.st_other, sizeof(stateid_other_t));
+	READ32(setattr->sa_stateid.si_generation);
+	COPYMEM(&setattr->sa_stateid.si_opaque, sizeof(stateid_opaque_t));
 	if ((status = nfsd4_decode_fattr(argp, setattr->sa_bmval, &setattr->sa_iattr)))
 		goto out;
 
@@ -825,8 +826,8 @@
 	DECODE_HEAD;
 
 	READ_BUF(sizeof(stateid_t) + 16);
-	READ32(write->wr_stateid.st_generation);
-	COPYMEM(&write->wr_stateid.st_other, sizeof(stateid_other_t));
+	READ32(write->wr_stateid.si_generation);
+	COPYMEM(&write->wr_stateid.si_opaque, sizeof(stateid_opaque_t));
 	READ64(write->wr_offset);
 	READ32(write->wr_stable_how);
 	if (write->wr_stable_how > 2)
@@ -1543,8 +1544,8 @@
 
 	if (!nfserr) {
 		RESERVE_SPACE(sizeof(stateid_t));
-		WRITE32(close->cl_stateid.st_generation);
-		WRITEMEM(&close->cl_stateid.st_other, sizeof(stateid_other_t));
+		WRITE32(close->cl_stateid.si_generation);
+		WRITEMEM(&close->cl_stateid.si_opaque, sizeof(stateid_opaque_t));
 		ADJUST_ARGS();
 	}
 }
@@ -1632,8 +1633,8 @@
 		return;
 
 	RESERVE_SPACE(36 + sizeof(stateid_t));
-	WRITE32(open->op_stateid.st_generation);
-	WRITEMEM(&open->op_stateid.st_other, sizeof(stateid_other_t));
+	WRITE32(open->op_stateid.si_generation);
+	WRITEMEM(&open->op_stateid.si_opaque, sizeof(stateid_opaque_t));
 	WRITECINFO(open->op_cinfo);
 	WRITE32(open->op_rflags);
 	WRITE32(2);
diff -Nru a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
--- a/fs/nfsd/nfsctl.c	Fri Apr 25 15:17:59 2003
+++ b/fs/nfsd/nfsctl.c	Mon May 19 23:34:37 2003
@@ -472,7 +472,6 @@
 	remove_proc_entry("fs/nfs", NULL);
 	nfsd_stat_shutdown();
 	nfsd_lockd_shutdown();
-	nfs4_state_shutdown();
 	unregister_filesystem(&nfsd_fs_type);
 }
 
diff -Nru a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c
--- a/fs/nfsd/nfssvc.c	Mon Feb 17 13:48:44 2003
+++ b/fs/nfsd/nfssvc.c	Mon May 19 23:34:37 2003
@@ -103,7 +103,7 @@
 		if (error < 0)
 			goto failure;
 
-#if CONFIG_NFSD_TCP
+#ifdef CONFIG_NFSD_TCP
 		error = svc_makesock(nfsd_serv, IPPROTO_TCP, port);
 		if (error < 0)
 			goto failure;
@@ -132,6 +132,7 @@
 	if (none_left) {
 		nfsd_serv = NULL;
 		nfsd_racache_shutdown();
+		nfs4_state_shutdown();
 	}
  out:
 	unlock_kernel();
@@ -247,6 +248,7 @@
 		}
 		nfsd_serv = NULL;
 	        nfsd_racache_shutdown();	/* release read-ahead cache */
+		nfs4_state_shutdown();
 	}
 	list_del(&me.list);
 	nfsdstats.th_cnt --;
diff -Nru a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
--- a/fs/nfsd/vfs.c	Sat Apr 12 23:15:09 2003
+++ b/fs/nfsd/vfs.c	Sun May  4 22:49:54 2003
@@ -1124,7 +1124,7 @@
 	if (!inode->i_op || !inode->i_op->readlink)
 		goto out;
 
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 	/* N.B. Why does this call need a get_fs()??
 	 * Remove the set_fs and watch the fireworks:-) --okir
 	 */
diff -Nru a/fs/nls/nls_base.c b/fs/nls/nls_base.c
--- a/fs/nls/nls_base.c	Mon Dec 30 09:07:50 2002
+++ b/fs/nls/nls_base.c	Sat May 17 12:39:13 2003
@@ -217,7 +217,6 @@
 {
 	struct nls_table *nls;
 #ifdef CONFIG_KMOD
-	char buf[40];
 	int ret;
 #endif
 
@@ -226,14 +225,7 @@
 		return nls;
 
 #ifdef CONFIG_KMOD
-	if (strlen(charset) > sizeof(buf) - sizeof("nls_")) {
-		printk("Unable to load NLS charset %s: name too long\n",
-			charset);
-		return NULL;
-	}
-		
-	sprintf(buf, "nls_%s", charset);
-	ret = request_module(buf);
+	ret = request_module("nls_%s", charset);
 	if (ret != 0) {
 		printk("Unable to load NLS charset %s\n", charset);
 		return NULL;
diff -Nru a/fs/ntfs/inode.c b/fs/ntfs/inode.c
--- a/fs/ntfs/inode.c	Wed Apr 30 05:51:58 2003
+++ b/fs/ntfs/inode.c	Sun May  4 22:49:54 2003
@@ -1736,7 +1736,7 @@
  * @vi:		inode to mark dirty
  *
  * This is called from fs/inode.c::__mark_inode_dirty(), when the inode itself
- * is being marked dirty. An example is when UPDATE_ATIME() is invoked.
+ * is being marked dirty. An example is when update_atime() is invoked.
  *
  * We mark the inode dirty by setting both the page in which the mft record
  * resides and the buffer heads in that page which correspond to the mft record
diff -Nru a/fs/open.c b/fs/open.c
--- a/fs/open.c	Wed Apr  9 06:42:36 2003
+++ b/fs/open.c	Tue May 20 17:23:23 2003
@@ -280,7 +280,7 @@
  * must be owner or have write permission.
  * Else, update from *times, must be owner or super user.
  */
-long do_utimes(char __user * filename, struct timeval __user * times)
+long do_utimes(char __user * filename, struct timeval * times)
 {
 	int error;
 	struct nameidata nd;
@@ -671,8 +671,8 @@
 	if (f->f_flags & O_DIRECT) {
 		if (!inode->i_mapping || !inode->i_mapping->a_ops ||
 			!inode->i_mapping->a_ops->direct_IO) {
-				error = -EINVAL;
-				goto cleanup_all;
+				fput(f);
+				f = ERR_PTR(-EINVAL);
 		}
 	}
 
@@ -902,7 +902,7 @@
 
 /*
  * Called when an inode is about to be open.
- * We use this to disallow opening RW large files on 32bit systems if
+ * We use this to disallow opening large files on 32bit systems if
  * the caller didn't specify O_LARGEFILE.  On 64bit systems we force
  * on this flag in sys_open.
  */
diff -Nru a/fs/partitions/check.c b/fs/partitions/check.c
--- a/fs/partitions/check.c	Sun May  4 01:37:43 2003
+++ b/fs/partitions/check.c	Mon May 12 18:59:23 2003
@@ -38,7 +38,7 @@
 #include "ultrix.h"
 #include "efi.h"
 
-#if CONFIG_BLK_DEV_MD
+#ifdef CONFIG_BLK_DEV_MD
 extern void md_autodetect_dev(dev_t dev);
 #endif
 
@@ -96,19 +96,6 @@
 
 char *disk_name(struct gendisk *hd, int part, char *buf)
 {
-#ifdef CONFIG_DEVFS_FS
-	if (hd->devfs_name[0] != '\0') {
-		if (part)
-			snprintf(buf, BDEVNAME_SIZE, "%s/part%d",
-					hd->devfs_name, part);
-		else if (hd->minors != 1)
-			snprintf(buf, BDEVNAME_SIZE, "%s/disc", hd->devfs_name);
-		else
-			snprintf(buf, BDEVNAME_SIZE, "%s", hd->devfs_name);
-		return buf;
-	}
-#endif
-
 	if (!part)
 		snprintf(buf, BDEVNAME_SIZE, "%s", hd->disk_name);
 	else if (isdigit(hd->disk_name[strlen(hd->disk_name)-1]))
@@ -353,7 +340,7 @@
 			if (!size)
 				continue;
 			add_partition(disk, j, from, size);
-#if CONFIG_BLK_DEV_MD
+#ifdef CONFIG_BLK_DEV_MD
 			if (!state->parts[j].flags)
 				continue;
 			md_autodetect_dev(bdev->bd_dev+j);
@@ -387,7 +374,7 @@
 		if (!size)
 			continue;
 		add_partition(disk, p, from, size);
-#if CONFIG_BLK_DEV_MD
+#ifdef CONFIG_BLK_DEV_MD
 		if (state->parts[p].flags)
 			md_autodetect_dev(bdev->bd_dev+p);
 #endif
@@ -443,53 +430,3 @@
 	}
 	kobject_del(&disk->kobj);
 }
-
-struct dev_name {
-	struct list_head list;
-	dev_t dev;
-	char namebuf[BDEVNAME_SIZE];
-	char *name;
-};
-
-static LIST_HEAD(device_names);
-
-char *partition_name(dev_t dev)
-{
-	struct gendisk *hd;
-	static char nomem [] = "<nomem>";
-	char b[BDEVNAME_SIZE];
-	struct dev_name *dname;
-	struct list_head *tmp;
-	int part;
-
-	list_for_each(tmp, &device_names) {
-		dname = list_entry(tmp, struct dev_name, list);
-		if (dname->dev == dev)
-			return dname->name;
-	}
-
-	dname = kmalloc(sizeof(*dname), GFP_KERNEL);
-
-	if (!dname)
-		return nomem;
-	/*
-	 * ok, add this new device name to the list
-	 */
-	hd = get_gendisk(dev, &part);
-	dname->name = NULL;
-	if (hd) {
-		dname->name = disk_name(hd, part, dname->namebuf);
-		module_put(hd->fops->owner);
-		put_disk(hd);
-	}
-	if (!dname->name) {
-		sprintf(dname->namebuf, "[dev %s]", __bdevname(dev, b));
-		dname->name = dname->namebuf;
-	}
-
-	dname->dev = dev;
-	list_add(&dname->list, &device_names);
-
-	return dname->name;
-}
-
diff -Nru a/fs/pipe.c b/fs/pipe.c
--- a/fs/pipe.c	Sun Nov 17 11:00:17 2002
+++ b/fs/pipe.c	Tue May 13 13:42:28 2003
@@ -44,7 +44,7 @@
 }
 
 static ssize_t
-pipe_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+pipe_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	int do_wakeup;
@@ -121,12 +121,12 @@
 		kill_fasync(PIPE_FASYNC_WRITERS(*inode), SIGIO, POLL_OUT);
 	}
 	if (ret > 0)
-		UPDATE_ATIME(inode);
+		update_atime(inode);
 	return ret;
 }
 
 static ssize_t
-pipe_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
+pipe_write(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	ssize_t ret;
@@ -216,13 +216,13 @@
 }
 
 static ssize_t
-bad_pipe_r(struct file *filp, char *buf, size_t count, loff_t *ppos)
+bad_pipe_r(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
 {
 	return -EBADF;
 }
 
 static ssize_t
-bad_pipe_w(struct file *filp, const char *buf, size_t count, loff_t *ppos)
+bad_pipe_w(struct file *filp, const char __user *buf, size_t count, loff_t *ppos)
 {
 	return -EBADF;
 }
@@ -233,7 +233,7 @@
 {
 	switch (cmd) {
 		case FIONREAD:
-			return put_user(PIPE_LEN(*pino), (int *)arg);
+			return put_user(PIPE_LEN(*pino), (int __user *)arg);
 		default:
 			return -EINVAL;
 	}
diff -Nru a/fs/proc/base.c b/fs/proc/base.c
--- a/fs/proc/base.c	Wed Apr  9 06:42:36 2003
+++ b/fs/proc/base.c	Mon May 19 12:20:10 2003
@@ -322,21 +322,23 @@
 	return proc_check_root(inode);
 }
 
-extern ssize_t proc_pid_read_maps(struct task_struct *, struct file *,
-				  char *, size_t, loff_t *);
-static ssize_t pid_maps_read(struct file * file, char * buf,
-			      size_t count, loff_t *ppos)
+extern struct seq_operations proc_pid_maps_op;
+static int maps_open(struct inode *inode, struct file *file)
 {
-	struct inode * inode = file->f_dentry->d_inode;
 	struct task_struct *task = proc_task(inode);
-	ssize_t res;
-
-	res = proc_pid_read_maps(task, file, buf, count, ppos);
-	return res;
+	int ret = seq_open(file, &proc_pid_maps_op);
+	if (!ret) {
+		struct seq_file *m = file->private_data;
+		m->private = task;
+	}
+	return ret;
 }
 
 static struct file_operations proc_maps_operations = {
-	.read		= pid_maps_read,
+	.open		= maps_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release,
 };
 
 extern struct seq_operations mounts_op;
diff -Nru a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
--- a/fs/proc/task_mmu.c	Tue Apr  8 07:25:14 2003
+++ b/fs/proc/task_mmu.c	Mon May 19 12:40:47 2003
@@ -1,6 +1,6 @@
-
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
+#include <linux/seq_file.h>
 #include <asm/uaccess.h>
 
 char *task_mem(struct mm_struct *mm, char *buffer)
@@ -75,167 +75,86 @@
 	return size;
 }
 
-/*
- * The way we support synthetic files > 4K
- * - without storing their contents in some buffer and
- * - without walking through the entire synthetic file until we reach the
- *   position of the requested data
- * is to cleverly encode the current position in the file's f_pos field.
- * There is no requirement that a read() call which returns `count' bytes
- * of data increases f_pos by exactly `count'.
- *
- * This idea is Linus' one. Bruno implemented it.
- */
-
-/*
- * For the /proc/<pid>/maps file, we use fixed length records, each containing
- * a single line.
- *
- * f_pos = (number of the vma in the task->mm->mmap list) * PAGE_SIZE
- *         + (index into the line)
- */
-/* for systems with sizeof(void*) == 4: */
-#define MAPS_LINE_FORMAT4	  "%08lx-%08lx %s %08lx %02x:%02x %lu"
-#define MAPS_LINE_MAX4	49 /* sum of 8  1  8  1 4 1 8 1 5 1 10 1 */
-
-/* for systems with sizeof(void*) == 8: */
-#define MAPS_LINE_FORMAT8	  "%016lx-%016lx %s %016lx %02x:%02x %lu"
-#define MAPS_LINE_MAX8	73 /* sum of 16  1  16  1 4 1 16 1 5 1 10 1 */
-
-#define MAPS_LINE_FORMAT	(sizeof(void*) == 4 ? MAPS_LINE_FORMAT4 : MAPS_LINE_FORMAT8)
-#define MAPS_LINE_MAX	(sizeof(void*) == 4 ?  MAPS_LINE_MAX4 :  MAPS_LINE_MAX8)
-
-static int proc_pid_maps_get_line (char *buf, struct vm_area_struct *map)
-{
-	/* produce the next line */
-	char *line;
-	char str[5];
-	int flags;
-	dev_t dev;
-	unsigned long ino;
+static int show_map(struct seq_file *m, void *v)
+{
+	struct vm_area_struct *map = v;
+	struct file *file = map->vm_file;
+	int flags = map->vm_flags;
+	unsigned long ino = 0;
+	dev_t dev = 0;
 	int len;
 
-	flags = map->vm_flags;
-
-	str[0] = flags & VM_READ ? 'r' : '-';
-	str[1] = flags & VM_WRITE ? 'w' : '-';
-	str[2] = flags & VM_EXEC ? 'x' : '-';
-	str[3] = flags & VM_MAYSHARE ? 's' : 'p';
-	str[4] = 0;
-
-	dev = 0;
-	ino = 0;
-	if (map->vm_file != NULL) {
+	if (file) {
 		struct inode *inode = map->vm_file->f_dentry->d_inode;
 		dev = inode->i_sb->s_dev;
 		ino = inode->i_ino;
-		line = d_path(map->vm_file->f_dentry,
-			      map->vm_file->f_vfsmnt,
-			      buf, PAGE_SIZE);
-		buf[PAGE_SIZE-1] = '\n';
-		line -= MAPS_LINE_MAX;
-		if(line < buf)
-			line = buf;
-	} else
-		line = buf;
-
-	len = sprintf(line,
-		      MAPS_LINE_FORMAT,
-		      map->vm_start, map->vm_end, str, map->vm_pgoff << PAGE_SHIFT,
-		      MAJOR(dev), MINOR(dev), ino);
-
-	if(map->vm_file) {
-		int i;
-		for(i = len; i < MAPS_LINE_MAX; i++)
-			line[i] = ' ';
-		len = buf + PAGE_SIZE - line;
-		memmove(buf, line, len);
-	} else
-		line[len++] = '\n';
-	return len;
+	}
+
+	seq_printf(m, "%0*lx-%0*lx %c%c%c%c %0*lx %02x:%02x %lu %n",
+			2*sizeof(void*), map->vm_start,
+			2*sizeof(void*), map->vm_end,
+			flags & VM_READ ? 'r' : '-',
+			flags & VM_WRITE ? 'w' : '-',
+			flags & VM_EXEC ? 'x' : '-',
+			flags & VM_MAYSHARE ? 's' : 'p',
+			2*sizeof(void*), map->vm_pgoff << PAGE_SHIFT,
+			MAJOR(dev), MINOR(dev), ino, &len);
+
+	if (map->vm_file) {
+		len = 25 + sizeof(void*) * 6 - len;
+		if (len < 1)
+			len = 1;
+		seq_printf(m, "%*c", len, ' ');
+		seq_path(m, file->f_vfsmnt, file->f_dentry, " \t\n\\");
+	}
+	seq_putc(m, '\n');
+	return 0;
 }
 
-ssize_t proc_pid_read_maps(struct task_struct *task, struct file *file,
-			   char *buf, size_t count, loff_t *ppos)
+static void *m_start(struct seq_file *m, loff_t *pos)
 {
-	struct mm_struct *mm;
+	struct task_struct *task = m->private;
+	struct mm_struct *mm = get_task_mm(task);
 	struct vm_area_struct * map;
-	char *tmp, *kbuf;
-	long retval;
-	int off, lineno, loff;
-
-	/* reject calls with out of range parameters immediately */
-	retval = 0;
-	if (*ppos > LONG_MAX)
-		goto out;
-	if (count == 0)
-		goto out;
-	off = (long)*ppos;
-	/*
-	 * We might sleep getting the page, so get it first.
-	 */
-	retval = -ENOMEM;
-	kbuf = (char*)__get_free_page(GFP_KERNEL);
-	if (!kbuf)
-		goto out;
-
-	tmp = (char*)__get_free_page(GFP_KERNEL);
-	if (!tmp)
-		goto out_free1;
-
-	mm = get_task_mm(task);
- 
-	retval = 0;
+	loff_t l = *pos;
+
 	if (!mm)
-		goto out_free2;
+		return NULL;
 
 	down_read(&mm->mmap_sem);
 	map = mm->mmap;
-	lineno = 0;
-	loff = 0;
-	if (count > PAGE_SIZE)
-		count = PAGE_SIZE;
-	while (map) {
-		int len;
-		if (off > PAGE_SIZE) {
-			off -= PAGE_SIZE;
-			goto next;
-		}
-		len = proc_pid_maps_get_line(tmp, map);
-		len -= off;
-		if (len > 0) {
-			if (retval+len > count) {
-				/* only partial line transfer possible */
-				len = count - retval;
-				/* save the offset where the next read
-				 * must start */
-				loff = len+off;
-			}
-			memcpy(kbuf+retval, tmp+off, len);
-			retval += len;
-		}
-		off = 0;
-next:
-		if (!loff)
-			lineno++;
-		if (retval >= count)
-			break;
-		if (loff) BUG();
+	while (l-- && map)
 		map = map->vm_next;
+	if (!map) {
+		up_read(&mm->mmap_sem);
+		mmput(mm);
 	}
-	up_read(&mm->mmap_sem);
-	mmput(mm);
+	return map;
+}
+
+static void m_stop(struct seq_file *m, void *v)
+{
+	struct vm_area_struct *map = v;
+	if (map) {
+		struct mm_struct *mm = map->vm_mm;
+		up_read(&mm->mmap_sem);
+		mmput(mm);
+	}
+}
 
-	if (retval > count) BUG();
-	if (copy_to_user(buf, kbuf, retval))
-		retval = -EFAULT;
-	else
-		*ppos = (lineno << PAGE_SHIFT) + loff;
-
-out_free2:
-	free_page((unsigned long)tmp);
-out_free1:
-	free_page((unsigned long)kbuf);
-out:
-	return retval;
+static void *m_next(struct seq_file *m, void *v, loff_t *pos)
+{
+	struct vm_area_struct *map = v;
+	(*pos)++;
+	if (map->vm_next)
+		return map->vm_next;
+	m_stop(m, v);
+	return NULL;
 }
+
+struct seq_operations proc_pid_maps_op = {
+	.start	= m_start,
+	.next	= m_next,
+	.stop	= m_stop,
+	.show	= show_map
+};
diff -Nru a/fs/qnx4/dir.c b/fs/qnx4/dir.c
--- a/fs/qnx4/dir.c	Sat Oct  5 14:20:21 2002
+++ b/fs/qnx4/dir.c	Sun May  4 22:49:54 2003
@@ -76,7 +76,7 @@
 		}
 		brelse(bh);
 	}
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 
 out:
 	unlock_kernel();
diff -Nru a/fs/read_write.c b/fs/read_write.c
--- a/fs/read_write.c	Wed Apr 16 15:09:57 2003
+++ b/fs/read_write.c	Wed May  7 21:20:23 2003
@@ -115,9 +115,10 @@
 {
 	off_t retval;
 	struct file * file;
+	int fput_needed;
 
 	retval = -EBADF;
-	file = fget(fd);
+	file = fget_light(fd, &fput_needed);
 	if (!file)
 		goto bad;
 
@@ -128,7 +129,7 @@
 		if (res != (loff_t)retval)
 			retval = -EOVERFLOW;	/* LFS: should only happen on 32 bit platforms */
 	}
-	fput(file);
+	fput_light(file, fput_needed);
 bad:
 	return retval;
 }
@@ -141,9 +142,10 @@
 	int retval;
 	struct file * file;
 	loff_t offset;
+	int fput_needed;
 
 	retval = -EBADF;
-	file = fget(fd);
+	file = fget_light(fd, &fput_needed);
 	if (!file)
 		goto bad;
 
@@ -161,7 +163,7 @@
 			retval = 0;
 	}
 out_putf:
-	fput(file);
+	fput_light(file, fput_needed);
 bad:
 	return retval;
 }
@@ -251,11 +253,12 @@
 {
 	struct file *file;
 	ssize_t ret = -EBADF;
+	int fput_needed;
 
-	file = fget(fd);
+	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = vfs_read(file, buf, count, &file->f_pos);
-		fput(file);
+		fput_light(file, fput_needed);
 	}
 
 	return ret;
@@ -265,11 +268,12 @@
 {
 	struct file *file;
 	ssize_t ret = -EBADF;
+	int fput_needed;
 
-	file = fget(fd);
+	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = vfs_write(file, buf, count, &file->f_pos);
-		fput(file);
+		fput_light(file, fput_needed);
 	}
 
 	return ret;
@@ -280,14 +284,15 @@
 {
 	struct file *file;
 	ssize_t ret = -EBADF;
+	int fput_needed;
 
 	if (pos < 0)
 		return -EINVAL;
 
-	file = fget(fd);
+	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = vfs_read(file, buf, count, &pos);
-		fput(file);
+		fput_light(file, fput_needed);
 	}
 
 	return ret;
@@ -298,14 +303,15 @@
 {
 	struct file *file;
 	ssize_t ret = -EBADF;
+	int fput_needed;
 
 	if (pos < 0)
 		return -EINVAL;
 
-	file = fget(fd);
+	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = vfs_write(file, buf, count, &pos);
-		fput(file);
+		fput_light(file, fput_needed);
 	}
 
 	return ret;
@@ -479,11 +485,12 @@
 {
 	struct file *file;
 	ssize_t ret = -EBADF;
+	int fput_needed;
 
-	file = fget(fd);
+	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = vfs_readv(file, vec, vlen, &file->f_pos);
-		fput(file);
+		fput_light(file, fput_needed);
 	}
 
 	return ret;
@@ -494,11 +501,12 @@
 {
 	struct file *file;
 	ssize_t ret = -EBADF;
+	int fput_needed;
 
-	file = fget(fd);
+	file = fget_light(fd, &fput_needed);
 	if (file) {
 		ret = vfs_writev(file, vec, vlen, &file->f_pos);
-		fput(file);
+		fput_light(file, fput_needed);
 	}
 
 	return ret;
@@ -511,12 +519,13 @@
 	struct inode * in_inode, * out_inode;
 	loff_t pos;
 	ssize_t retval;
+	int fput_needed_in, fput_needed_out;
 
 	/*
 	 * Get input file, and verify that it is ok..
 	 */
 	retval = -EBADF;
-	in_file = fget(in_fd);
+	in_file = fget_light(in_fd, &fput_needed_in);
 	if (!in_file)
 		goto out;
 	if (!(in_file->f_mode & FMODE_READ))
@@ -539,7 +548,7 @@
 	 * Get output file, and verify that it is ok..
 	 */
 	retval = -EBADF;
-	out_file = fget(out_fd);
+	out_file = fget_light(out_fd, &fput_needed_out);
 	if (!out_file)
 		goto fput_in;
 	if (!(out_file->f_mode & FMODE_WRITE))
@@ -579,9 +588,9 @@
 		retval = -EOVERFLOW;
 
 fput_out:
-	fput(out_file);
+	fput_light(out_file, fput_needed_out);
 fput_in:
-	fput(in_file);
+	fput_light(in_file, fput_needed_in);
 out:
 	return retval;
 }
diff -Nru a/fs/reiserfs/bitmap.c b/fs/reiserfs/bitmap.c
--- a/fs/reiserfs/bitmap.c	Mon Dec 30 20:26:13 2002
+++ b/fs/reiserfs/bitmap.c	Sat May 17 14:09:36 2003
@@ -9,6 +9,7 @@
 #include <linux/errno.h>
 #include <linux/buffer_head.h>
 #include <linux/kernel.h>
+#include <linux/pagemap.h>
 #include <linux/reiserfs_fs_sb.h>
 #include <linux/reiserfs_fs_i.h>
 
@@ -733,7 +734,7 @@
     int rest = amount_needed;
     int nr_allocated;
   
-    while (rest > 0) {
+    while (rest > 0 && start <= finish) {
 	nr_allocated = scan_bitmap (hint->th, &start, finish, 1,
 				    rest + prealloc_size, !hint->formatted_node,
 				    hint->block);
@@ -879,7 +880,9 @@
     if ( !blocks )
 	return;
 
+    spin_lock(&REISERFS_SB(sb)->bitmap_lock);
     REISERFS_SB(sb)->reserved_blocks += blocks;
+    spin_unlock(&REISERFS_SB(sb)->bitmap_lock);
 }
 
 /* Unreserve @blocks amount of blocks in fs pointed by @sb */
@@ -896,6 +899,22 @@
     if ( !blocks )
 	return;
 
+    spin_lock(&REISERFS_SB(sb)->bitmap_lock);
     REISERFS_SB(sb)->reserved_blocks -= blocks;
+    spin_unlock(&REISERFS_SB(sb)->bitmap_lock);
     RFALSE( REISERFS_SB(sb)->reserved_blocks < 0, "amount of blocks reserved became zero?");
+}
+
+/* This function estimates how much pages we will be able to write to FS
+   used for reiserfs_file_write() purposes for now. */
+int reiserfs_can_fit_pages ( struct super_block *sb /* superblock of filesystem
+						       to estimate space */ )
+{
+	unsigned long space;
+
+	spin_lock(&REISERFS_SB(sb)->bitmap_lock);
+	space = (SB_FREE_BLOCKS(sb) - REISERFS_SB(sb)->reserved_blocks) >> ( PAGE_CACHE_SHIFT - sb->s_blocksize_bits);
+	spin_unlock(&REISERFS_SB(sb)->bitmap_lock);
+
+	return space;
 }
diff -Nru a/fs/reiserfs/dir.c b/fs/reiserfs/dir.c
--- a/fs/reiserfs/dir.c	Sat Dec  7 02:19:52 2002
+++ b/fs/reiserfs/dir.c	Sun May  4 22:49:54 2003
@@ -185,7 +185,7 @@
     filp->f_pos = next_pos;
     pathrelse (&path_to_entry);
     reiserfs_check_path(&path_to_entry) ;
-    UPDATE_ATIME(inode) ;
+    update_atime(inode) ;
  out:
     reiserfs_write_unlock(inode->i_sb);
     return ret;
diff -Nru a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c
--- a/fs/reiserfs/do_balan.c	Mon Feb 24 10:10:13 2003
+++ b/fs/reiserfs/do_balan.c	Sat May 17 14:09:35 2003
@@ -319,8 +319,6 @@
 		    int new_item_len;
 		    int version;
 
-		    RFALSE (!is_direct_le_ih (ih),
-			    "PAP-12075: only direct inserted item can be broken. %h", ih);
 		    ret_val = leaf_shift_left (tb, tb->lnum[0]-1, -1);
 
 		    /* Calculate item length to insert to S[0] */
@@ -343,7 +341,7 @@
 		    version = ih_version (ih);
 
 		    /* Calculate key component, item length and body to insert into S[0] */
-                    set_le_ih_k_offset( ih, le_ih_k_offset( ih ) + tb->lbytes );
+                    set_le_ih_k_offset( ih, le_ih_k_offset( ih ) + (tb->lbytes << (is_indirect_le_ih(ih)?tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT:0)) );
 
 		    put_ih_item_len( ih, new_item_len );
 		    if ( tb->lbytes >  zeros_num ) {
@@ -452,23 +450,28 @@
 				ih_item_len( B_N_PITEM_HEAD(tb->L[0],n+item_pos-ret_val)),
 				l_n,body, zeros_num > l_n ? l_n : zeros_num
 				);
-
-			    RFALSE( l_n && 
-				    is_indirect_le_ih(B_N_PITEM_HEAD
-						      (tb->L[0],
-						       n + item_pos - ret_val)),
-				    "PAP-12110: pasting more than 1 unformatted node pointer into indirect item");
-
 			    /* 0-th item in S0 can be only of DIRECT type when l_n != 0*/
 			    {
-			      int version;
-
-			      version = ih_version (B_N_PITEM_HEAD (tbS0, 0));
-			      set_le_key_k_offset (version, B_N_PKEY (tbS0, 0), 
-						   le_key_k_offset (version, B_N_PKEY (tbS0, 0)) + l_n);
-			      version = ih_version (B_N_PITEM_HEAD(tb->CFL[0],tb->lkey[0]));
-			      set_le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]),
-						   le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0])) + l_n);
+				int version;
+				int temp_l = l_n;
+				
+				RFALSE (ih_item_len (B_N_PITEM_HEAD (tbS0, 0)),
+					"PAP-12106: item length must be 0");
+				RFALSE (comp_short_le_keys (B_N_PKEY (tbS0, 0),
+							    B_N_PKEY (tb->L[0],
+									    n + item_pos - ret_val)),
+					"PAP-12107: items must be of the same file");
+				if (is_indirect_le_ih(B_N_PITEM_HEAD (tb->L[0],
+								      n + item_pos - ret_val)))	{
+				    temp_l = l_n << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT);
+				}
+				/* update key of first item in S0 */
+				version = ih_version (B_N_PITEM_HEAD (tbS0, 0));
+				set_le_key_k_offset (version, B_N_PKEY (tbS0, 0), 
+						     le_key_k_offset (version, B_N_PKEY (tbS0, 0)) + temp_l);
+				/* update left delimiting key */
+				set_le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0]),
+						     le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFL[0],tb->lkey[0])) + temp_l);
 			    }
 
 			    /* Calculate new body, position in item and insert_size[0] */
@@ -537,7 +540,7 @@
 			    );
 		    /* if appended item is indirect item, put unformatted node into un list */
 		    if (is_indirect_le_ih (pasted))
-			set_ih_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+			set_ih_free_space (pasted, 0);
 		    tb->insert_size[0] = 0;
 		    zeros_num = 0;
 		}
@@ -565,15 +568,11 @@
 	    { /* new item or its part falls to R[0] */
 		if ( item_pos == n - tb->rnum[0] + 1 && tb->rbytes != -1 )
 		{ /* part of new item falls into R[0] */
-		    int old_key_comp, old_len, r_zeros_number;
+		    loff_t old_key_comp, old_len, r_zeros_number;
 		    const char * r_body;
 		    int version;
 		    loff_t offset;
 
-		    RFALSE( !is_direct_le_ih (ih),
-			    "PAP-12135: only direct item can be split. (%h)", 
-			    ih);
-
 		    leaf_shift_right(tb,tb->rnum[0]-1,-1);
 
 		    version = ih_version(ih);
@@ -582,7 +581,7 @@
 		    old_len = ih_item_len(ih);
 
 		    /* Calculate key component and item length to insert into R[0] */
-                    offset = le_ih_k_offset( ih ) + (old_len - tb->rbytes );
+                    offset = le_ih_k_offset( ih ) + ((old_len - tb->rbytes )<<(is_indirect_le_ih(ih)?tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT:0));
                     set_le_ih_k_offset( ih, offset );
 		    put_ih_item_len( ih, tb->rbytes);
 		    /* Insert part of the item into R[0] */
@@ -590,13 +589,13 @@
 		    bi.bi_bh = tb->R[0];
 		    bi.bi_parent = tb->FR[0];
 		    bi.bi_position = get_right_neighbor_position (tb, 0);
-		    if ( offset - old_key_comp > zeros_num ) {
+		    if ( (old_len - tb->rbytes) > zeros_num ) {
 			r_zeros_number = 0;
-			r_body = body + offset - old_key_comp - zeros_num;
+			r_body = body + (old_len - tb->rbytes) - zeros_num;
 		    }
 		    else {
 			r_body = body;
-			r_zeros_number = zeros_num - (offset - old_key_comp);
+			r_zeros_number = zeros_num - (old_len - tb->rbytes);
 			zeros_num -= r_zeros_number;
 		    }
 
@@ -707,12 +706,17 @@
 			
 			{
 			  int version;
+			  unsigned long temp_rem = n_rem;
 			  
 			  version = ih_version (B_N_PITEM_HEAD (tb->R[0],0));
+			  if (is_indirect_le_key(version,B_N_PKEY(tb->R[0],0))){
+			      temp_rem = n_rem << (tb->tb_sb->s_blocksize_bits -
+					 UNFM_P_SHIFT);
+			  }
 			  set_le_key_k_offset (version, B_N_PKEY(tb->R[0],0), 
-					       le_key_k_offset (version, B_N_PKEY(tb->R[0],0)) + n_rem);
+					       le_key_k_offset (version, B_N_PKEY(tb->R[0],0)) + temp_rem);
 			  set_le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0]), 
-					       le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) + n_rem);
+					       le_key_k_offset (version, B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) + temp_rem);
 			}
 /*		  k_offset (B_N_PKEY(tb->R[0],0)) += n_rem;
 		  k_offset (B_N_PDELIM_KEY(tb->CFR[0],tb->rkey[0])) += n_rem;*/
@@ -736,13 +740,12 @@
 			leaf_paste_in_buffer(&bi, 0, n_shift, tb->insert_size[0] - n_rem, r_body, r_zeros_number);
 
 			if (is_indirect_le_ih (B_N_PITEM_HEAD(tb->R[0],0))) {
-
+#if 0
 			    RFALSE( n_rem,
 				    "PAP-12160: paste more than one unformatted node pointer");
-
-			    set_ih_free_space (B_N_PITEM_HEAD(tb->R[0],0), ((struct unfm_nodeinfo*)body)->unfm_freespace);
+#endif
+			    set_ih_free_space (B_N_PITEM_HEAD(tb->R[0],0), 0);
 			}
-
 			tb->insert_size[0] = n_rem;
 			if ( ! n_rem )
 			    pos_in_item ++;
@@ -781,7 +784,7 @@
 		    }
 
 		    if (is_indirect_le_ih (pasted))
-			set_ih_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+			set_ih_free_space (pasted, 0);
 		    zeros_num = tb->insert_size[0] = 0;
 		}
 	    }
@@ -858,12 +861,6 @@
 		    const char * r_body;
 		    int version;
 
-		    RFALSE( !is_direct_le_ih(ih),
-			/* The items which can be inserted are:
-			   Stat_data item, direct item, indirect item and directory item which consist of only two entries "." and "..".
-			   These items must not be broken except for a direct one. */
-			    "PAP-12205: non-direct item can not be broken when inserting");
-
 		    /* Move snum[i]-1 items from S[0] to S_new[i] */
 		    leaf_move_items (LEAF_FROM_S_TO_SNEW, tb, snum[i] - 1, -1, S_new[i]);
 		    /* Remember key component and item length */
@@ -873,7 +870,7 @@
 
 		    /* Calculate key component and item length to insert into S_new[i] */
                     set_le_ih_k_offset( ih,
-                                le_ih_k_offset(ih) + (old_len - sbytes[i] ) );
+                                le_ih_k_offset(ih) + ((old_len - sbytes[i] )<<(is_indirect_le_ih(ih)?tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT:0)) );
 
 		    put_ih_item_len( ih, sbytes[i] );
 
@@ -883,13 +880,13 @@
 		    bi.bi_parent = 0;
 		    bi.bi_position = 0;
 
-		    if ( le_ih_k_offset (ih) - old_key_comp > zeros_num ) {
+		    if ( (old_len - sbytes[i]) > zeros_num ) {
 			r_zeros_number = 0;
-			r_body = body + (le_ih_k_offset(ih) - old_key_comp) - zeros_num;
+			r_body = body + (old_len - sbytes[i]) - zeros_num;
 		    }
 		    else {
 			r_body = body;
-			r_zeros_number = zeros_num - (le_ih_k_offset (ih) - old_key_comp);
+			r_zeros_number = zeros_num - (old_len - sbytes[i]);
 			zeros_num -= r_zeros_number;
 		    }
 
@@ -1010,11 +1007,13 @@
 
 			    tmp = B_N_PITEM_HEAD(S_new[i],0);
 			    if (is_indirect_le_ih (tmp)) {
-				if (n_rem)
-				    reiserfs_panic (tb->tb_sb, "PAP-12230: balance_leaf: invalid action with indirect item");
-				set_ih_free_space (tmp, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+				set_ih_free_space (tmp, 0);
+				set_le_ih_k_offset( tmp, le_ih_k_offset(tmp) + 
+					            (n_rem << (tb->tb_sb->s_blocksize_bits - UNFM_P_SHIFT)));
+			    } else {
+				set_le_ih_k_offset( tmp, le_ih_k_offset(tmp) + 
+				                    n_rem );
 			    }
-                            set_le_ih_k_offset( tmp, le_ih_k_offset(tmp) + n_rem );
 			}
 
 			tb->insert_size[0] = n_rem;
@@ -1060,7 +1059,7 @@
 
 		    /* if we paste to indirect item update ih_free_space */
 		    if (is_indirect_le_ih (pasted))
-			set_ih_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+			set_ih_free_space (pasted, 0);
 		    zeros_num = tb->insert_size[0] = 0;
 		}
 	    }
@@ -1152,11 +1151,12 @@
 		    leaf_paste_in_buffer (&bi, item_pos, pos_in_item, tb->insert_size[0], body, zeros_num);
 
 		    if (is_indirect_le_ih (pasted)) {
-
+#if 0
 			RFALSE( tb->insert_size[0] != UNFM_P_SIZE,
 				"PAP-12280: insert_size for indirect item must be %d, not %d",
 				UNFM_P_SIZE, tb->insert_size[0]);
-			set_ih_free_space (pasted, ((struct unfm_nodeinfo*)body)->unfm_freespace);
+#endif
+			set_ih_free_space (pasted, 0);
 		    }
 		    tb->insert_size[0] = 0;
 		}
diff -Nru a/fs/reiserfs/file.c b/fs/reiserfs/file.c
--- a/fs/reiserfs/file.c	Tue Jul 30 02:57:27 2002
+++ b/fs/reiserfs/file.c	Sat May 17 14:09:36 2003
@@ -6,6 +6,8 @@
 #include <linux/time.h>
 #include <linux/reiserfs_fs.h>
 #include <linux/smp_lock.h>
+#include <asm/uaccess.h>
+#include <linux/pagemap.h>
 
 /*
 ** We pack the tails of files on file close, not at the time they are written.
@@ -140,9 +142,1018 @@
     return error ;
 }
 
+/* I really do not want to play with memory shortage right now, so
+   to simplify the code, we are not going to write more than this much pages at
+   a time. This still should considerably improve performance compared to 4k
+   at a time case. This is 32 pages of 4k size. */
+#define REISERFS_WRITE_PAGES_AT_A_TIME (128 * 1024) / PAGE_CACHE_SIZE
+
+/* Allocates blocks for a file to fulfil write request.
+   Maps all unmapped but prepared pages from the list.
+   Updates metadata with newly allocated blocknumbers as needed */
+int reiserfs_allocate_blocks_for_region(
+				struct inode *inode, /* Inode we work with */
+				loff_t pos, /* Writing position */
+				int num_pages, /* number of pages write going
+						  to touch */
+				int write_bytes, /* amount of bytes to write */
+				struct page **prepared_pages, /* array of
+							         prepared pages
+							       */
+				int blocks_to_allocate /* Amount of blocks we
+							  need to allocate to
+							  fit the data into file
+							 */
+				)
+{
+    struct cpu_key key; // cpu key of item that we are going to deal with
+    struct item_head *ih; // pointer to item head that we are going to deal with
+    struct buffer_head *bh; // Buffer head that contains items that we are going to deal with
+    struct reiserfs_transaction_handle th; // transaction handle for transaction we are going to create.
+    __u32 * item; // pointer to item we are going to deal with
+    INITIALIZE_PATH(path); // path to item, that we are going to deal with.
+    b_blocknr_t allocated_blocks[blocks_to_allocate]; // Pointer to a place where allocated blocknumbers would be stored. Right now statically allocated, later that will change.
+    reiserfs_blocknr_hint_t hint; // hint structure for block allocator.
+    size_t res; // return value of various functions that we call.
+    int curr_block; // current block used to keep track of unmapped blocks.
+    int i; // loop counter
+    int itempos; // position in item
+    unsigned int from = (pos & (PAGE_CACHE_SIZE - 1)); // writing position in
+						       // first page
+    unsigned int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1; /* last modified byte offset in last page */
+    __u64 hole_size ; // amount of blocks for a file hole, if it needed to be created.
+    int modifying_this_item = 0; // Flag for items traversal code to keep track
+				 // of the fact that we already prepared
+				 // current block for journal
+
+
+    RFALSE(!blocks_to_allocate, "green-9004: tried to allocate zero blocks?");
+
+    /* First we compose a key to point at the writing position, we want to do
+       that outside of any locking region. */
+    make_cpu_key (&key, inode, pos+1, TYPE_ANY, 3/*key length*/);
+
+    /* If we came here, it means we absolutely need to open a transaction,
+       since we need to allocate some blocks */
+    reiserfs_write_lock(inode->i_sb); // Journaling stuff and we need that.
+    journal_begin(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1); // Wish I know if this number enough
+    reiserfs_update_inode_transaction(inode) ;
+
+    /* Look for the in-tree position of our write, need path for block allocator */
+    res = search_for_position_by_key(inode->i_sb, &key, &path);
+    if ( res == IO_ERROR ) {
+	res = -EIO;
+	goto error_exit;
+    }
+   
+    /* Allocate blocks */
+    /* First fill in "hint" structure for block allocator */
+    hint.th = &th; // transaction handle.
+    hint.path = &path; // Path, so that block allocator can determine packing locality or whatever it needs to determine.
+    hint.inode = inode; // Inode is needed by block allocator too.
+    hint.search_start = 0; // We have no hint on where to search free blocks for block allocator.
+    hint.key = key.on_disk_key; // on disk key of file.
+    hint.block = inode->i_blocks>>(inode->i_sb->s_blocksize_bits-9); // Number of disk blocks this file occupies already.
+    hint.formatted_node = 0; // We are allocating blocks for unformatted node.
+    hint.preallocate = 0; // We do not do any preallocation for now.
+
+    /* Call block allocator to allocate blocks */
+    res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate);
+    if ( res != CARRY_ON ) {
+	if ( res == NO_DISK_SPACE ) {
+	    /* We flush the transaction in case of no space. This way some
+	       blocks might become free */
+	    SB_JOURNAL(inode->i_sb)->j_must_wait = 1;
+	    restart_transaction(&th, inode, &path);
+
+	    /* We might have scheduled, so search again */
+	    res = search_for_position_by_key(inode->i_sb, &key, &path);
+	    if ( res == IO_ERROR ) {
+		res = -EIO;
+		goto error_exit;
+	    }
+
+	    /* update changed info for hint structure. */
+	    res = reiserfs_allocate_blocknrs(&hint, allocated_blocks, blocks_to_allocate, blocks_to_allocate);
+	    if ( res != CARRY_ON ) {
+		res = -ENOSPC; 
+		pathrelse(&path);
+		goto error_exit;
+	    }
+	} else {
+	    res = -ENOSPC;
+	    pathrelse(&path);
+	    goto error_exit;
+	}
+    }
+
+#ifdef __BIG_ENDIAN
+        // Too bad, I have not found any way to convert a given region from
+        // cpu format to little endian format
+    {
+        int i;
+        for ( i = 0; i < blocks_to_allocate ; i++)
+            allocated_blocks[i]=cpu_to_le32(allocated_blocks[i]);
+    }
+#endif
+
+    /* Blocks allocating well might have scheduled and tree might have changed,
+       let's search the tree again */
+    /* find where in the tree our write should go */
+    res = search_for_position_by_key(inode->i_sb, &key, &path);
+    if ( res == IO_ERROR ) {
+	res = -EIO;
+	goto error_exit_free_blocks;
+    }
+
+    bh = get_last_bh( &path ); // Get a bufferhead for last element in path.
+    ih = get_ih( &path );      // Get a pointer to last item head in path.
+    item = get_item( &path );  // Get a pointer to last item in path
+
+    /* Let's see what we have found */
+    if ( res != POSITION_FOUND ) { /* position not found, this means that we
+				      might need to append file with holes
+				      first */
+	// Since we are writing past the file's end, we need to find out if
+	// there is a hole that needs to be inserted before our writing
+	// position, and how many blocks it is going to cover (we need to
+	//  populate pointers to file blocks representing the hole with zeros)
+
+	hole_size = (pos + 1 - (le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key))+op_bytes_number(ih, inode->i_sb->s_blocksize))) >> inode->i_sb->s_blocksize_bits;
+
+	if ( hole_size > 0 ) {
+	    int to_paste = min_t(__u64, hole_size, MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE ); // How much data to insert first time.
+	    /* area filled with zeroes, to supply as list of zero blocknumbers
+	       We allocate it outside of loop just in case loop would spin for
+	       several iterations. */
+	    char *zeros = kmalloc(to_paste*UNFM_P_SIZE, GFP_ATOMIC); // We cannot insert more than MAX_ITEM_LEN bytes anyway.
+	    if ( !zeros ) {
+		res = -ENOMEM;
+		goto error_exit_free_blocks;
+	    }
+	    memset ( zeros, 0, to_paste*UNFM_P_SIZE);
+	    do {
+		to_paste = min_t(__u64, hole_size, MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE );
+		if ( is_indirect_le_ih(ih) ) {
+		    /* Ok, there is existing indirect item already. Need to append it */
+		    /* Calculate position past inserted item */
+		    make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
+		    res = reiserfs_paste_into_item( &th, &path, &key, (char *)zeros, UNFM_P_SIZE*to_paste);
+		    if ( res ) {
+			kfree(zeros);
+			goto error_exit_free_blocks;
+		    }
+		} else if ( is_statdata_le_ih(ih) ) {
+		    /* No existing item, create it */
+		    /* item head for new item */
+		    struct item_head ins_ih;
+
+		    /* create a key for our new item */
+		    make_cpu_key( &key, inode, 1, TYPE_INDIRECT, 3);
+
+		    /* Create new item head for our new item */
+		    make_le_item_head (&ins_ih, &key, key.version, 1,
+				       TYPE_INDIRECT, to_paste*UNFM_P_SIZE,
+				       0 /* free space */);
+
+		    /* Find where such item should live in the tree */
+		    res = search_item (inode->i_sb, &key, &path);
+		    if ( res != ITEM_NOT_FOUND ) {
+			/* item should not exist, otherwise we have error */
+			if ( res != -ENOSPC ) {
+			    reiserfs_warning ("green-9008: search_by_key (%K) returned %d\n",
+					       &key, res);
+			}
+			res = -EIO;
+		        kfree(zeros);
+			goto error_exit_free_blocks;
+		    }
+		    res = reiserfs_insert_item( &th, &path, &key, &ins_ih, (char *)zeros);
+		} else {
+		    reiserfs_panic(inode->i_sb, "green-9011: Unexpected key type %K\n", &key);
+		}
+		if ( res ) {
+		    kfree(zeros);
+		    goto error_exit_free_blocks;
+		}
+		/* Now we want to check if transaction is too full, and if it is
+		   we restart it. This will also free the path. */
+		if (journal_transaction_should_end(&th, th.t_blocks_allocated))
+		    restart_transaction(&th, inode, &path);
+
+		/* Well, need to recalculate path and stuff */
+		set_cpu_key_k_offset( &key, cpu_key_k_offset(&key) + (to_paste << inode->i_blkbits));
+		res = search_for_position_by_key(inode->i_sb, &key, &path);
+		if ( res == IO_ERROR ) {
+		    res = -EIO;
+		    kfree(zeros);
+		    goto error_exit_free_blocks;
+		}
+		bh=get_last_bh(&path);
+		ih=get_ih(&path);
+		item = get_item(&path);
+		hole_size -= to_paste;
+	    } while ( hole_size );
+	    kfree(zeros);
+	}
+    }
+
+    // Go through existing indirect items first
+    // replace all zeroes with blocknumbers from list
+    // Note that if no corresponding item was found, by previous search,
+    // it means there are no existing in-tree representation for file area
+    // we are going to overwrite, so there is nothing to scan through for holes.
+    for ( curr_block = 0, itempos = path.pos_in_item ; curr_block < blocks_to_allocate && res == POSITION_FOUND ; ) {
+
+	if ( itempos >= ih_item_len(ih)/UNFM_P_SIZE ) {
+	    /* We run out of data in this indirect item, let's look for another
+	       one. */
+	    /* First if we are already modifying current item, log it */
+	    if ( modifying_this_item ) {
+		journal_mark_dirty (&th, inode->i_sb, bh);
+		modifying_this_item = 0;
+	    }
+	    /* Then set the key to look for a new indirect item (offset of old
+	       item is added to old item length */
+	    set_cpu_key_k_offset( &key, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize));
+	    /* Search ofor position of new key in the tree. */
+	    res = search_for_position_by_key(inode->i_sb, &key, &path);
+	    if ( res == IO_ERROR) {
+		res = -EIO;
+		goto error_exit_free_blocks;
+	    }
+	    bh=get_last_bh(&path);
+	    ih=get_ih(&path);
+	    item = get_item(&path);
+	    itempos = path.pos_in_item;
+	    continue; // loop to check all kinds of conditions and so on.
+	}
+	/* Ok, we have correct position in item now, so let's see if it is
+	   representing file hole (blocknumber is zero) and fill it if needed */
+	if ( !item[itempos] ) {
+	    /* Ok, a hole. Now we need to check if we already prepared this
+	       block to be journaled */
+	    while ( !modifying_this_item ) { // loop until succeed
+		/* Well, this item is not journaled yet, so we must prepare
+		   it for journal first, before we can change it */
+		struct item_head tmp_ih; // We copy item head of found item,
+					 // here to detect if fs changed under
+					 // us while we were preparing for
+					 // journal.
+		int fs_gen; // We store fs generation here to find if someone
+			    // changes fs under our feet
+
+		copy_item_head (&tmp_ih, ih); // Remember itemhead
+		fs_gen = get_generation (inode->i_sb); // remember fs generation
+		reiserfs_prepare_for_journal(inode->i_sb, bh, 1); // Prepare a buffer within which indirect item is stored for changing.
+		if (fs_changed (fs_gen, inode->i_sb) && item_moved (&tmp_ih, &path)) {
+		    // Sigh, fs was changed under us, we need to look for new
+		    // location of item we are working with
+
+		    /* unmark prepaerd area as journaled and search for it's
+		       new position */
+		    reiserfs_restore_prepared_buffer(inode->i_sb, bh);
+		    res = search_for_position_by_key(inode->i_sb, &key, &path);
+		    if ( res == IO_ERROR) {
+			res = -EIO;
+			goto error_exit_free_blocks;
+		    }
+		    bh=get_last_bh(&path);
+		    ih=get_ih(&path);
+		    item = get_item(&path);
+		    // Itempos is still the same
+		    continue;
+		}
+		modifying_this_item = 1;
+	    }
+	    item[itempos] = allocated_blocks[curr_block]; // Assign new block
+	    curr_block++;
+	}
+	itempos++;
+    }
+
+    if ( modifying_this_item ) { // We need to log last-accessed block, if it
+				 // was modified, but not logged yet.
+	journal_mark_dirty (&th, inode->i_sb, bh);
+    }
+
+    if ( curr_block < blocks_to_allocate ) {
+	// Oh, well need to append to indirect item, or to create indirect item
+	// if there weren't any
+	if ( is_indirect_le_ih(ih) ) {
+	    // Existing indirect item - append. First calculate key for append
+	    // position. We do not need to recalculate path as it should
+	    // already point to correct place.
+	    make_cpu_key( &key, inode, le_key_k_offset( get_inode_item_key_version(inode), &(ih->ih_key)) + op_bytes_number(ih, inode->i_sb->s_blocksize), TYPE_INDIRECT, 3);
+	    res = reiserfs_paste_into_item( &th, &path, &key, (char *)(allocated_blocks+curr_block), UNFM_P_SIZE*(blocks_to_allocate-curr_block));
+	    if ( res ) {
+		goto error_exit_free_blocks;
+	    }
+	} else if (is_statdata_le_ih(ih) ) {
+	    // Last found item was statdata. That means we need to create indirect item.
+	    struct item_head ins_ih; /* itemhead for new item */
+
+	    /* create a key for our new item */
+	    make_cpu_key( &key, inode, 1, TYPE_INDIRECT, 3); // Position one,
+							    // because that's
+							    // where first
+							    // indirect item
+							    // begins
+	    /* Create new item head for our new item */
+	    make_le_item_head (&ins_ih, &key, key.version, 1, TYPE_INDIRECT,
+			       (blocks_to_allocate-curr_block)*UNFM_P_SIZE,
+			       0 /* free space */);
+	    /* Find where such item should live in the tree */
+	    res = search_item (inode->i_sb, &key, &path);
+	    if ( res != ITEM_NOT_FOUND ) {
+		/* Well, if we have found such item already, or some error
+		   occured, we need to warn user and return error */
+		if ( res != -ENOSPC ) {
+		    reiserfs_warning ("green-9009: search_by_key (%K) returned %d\n",
+			              &key, res);
+		}
+		res = -EIO;
+		goto error_exit_free_blocks;
+	    }
+	    /* Insert item into the tree with the data as its body */
+	    res = reiserfs_insert_item( &th, &path, &key, &ins_ih, (char *)(allocated_blocks+curr_block));
+	} else {
+	    reiserfs_panic(inode->i_sb, "green-9010: unexpected item type for key %K\n",&key);
+	}
+    }
+
+    /* Now the final thing, if we have grew the file, we must update it's size*/
+    if ( pos + write_bytes > inode->i_size) {
+	inode->i_size = pos + write_bytes; // Set new size
+    }
+
+    /* Amount of on-disk blocks used by file have changed, update it */
+    inode->i_blocks += blocks_to_allocate << (inode->i_blkbits - 9);
+    reiserfs_update_sd(&th, inode); // And update on-disk metadata
+    // finish all journal stuff now, We are not going to play with metadata
+    // anymore.
+    pathrelse(&path);
+    journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1);
+    reiserfs_write_unlock(inode->i_sb);
+
+    // go through all the pages/buffers and map the buffers to newly allocated
+    // blocks (so that system knows where to write these pages later).
+    curr_block = 0;
+    for ( i = 0; i < num_pages ; i++ ) {
+	struct page *page=prepared_pages[i]; //current page
+	struct buffer_head *head = page_buffers(page);// first buffer for a page
+	int block_start, block_end; // in-page offsets for buffers.
+
+	if (!page_buffers(page))
+	    reiserfs_panic(inode->i_sb, "green-9005: No buffers for prepared page???");
+
+	/* For each buffer in page */
+	for(bh = head, block_start = 0; bh != head || !block_start;
+	    block_start=block_end, bh = bh->b_this_page) {
+	    if (!bh)
+		reiserfs_panic(inode->i_sb, "green-9006: Allocated but absent buffer for a page?");
+	    block_end = block_start+inode->i_sb->s_blocksize;
+	    if (i == 0 && block_end <= from )
+		/* if this buffer is before requested data to map, skip it */
+		continue;
+	    if (i == num_pages - 1 && block_start >= to)
+		/* If this buffer is after requested data to map, abort
+		   processing of current page */
+		break;
+
+	    if ( !buffer_mapped(bh) ) { // Ok, unmapped buffer, need to map it
+		map_bh( bh, inode->i_sb, le32_to_cpu(allocated_blocks[curr_block]));
+		curr_block++;
+	    }
+	}
+    }
+
+    RFALSE( curr_block > blocks_to_allocate, "green-9007: Used too many blocks? weird");
+
+    return 0;
+
+// Need to deal with transaction here.
+error_exit_free_blocks:
+    pathrelse(&path);
+    // free blocks
+    for( i = 0; i < blocks_to_allocate; i++ )
+	reiserfs_free_block( &th, le32_to_cpu(allocated_blocks[i]));
+
+error_exit:
+    journal_end(&th, inode->i_sb, JOURNAL_PER_BALANCE_CNT * 3 + 1);
+    reiserfs_write_unlock(inode->i_sb);
+
+    return res;
+}
+
+/* Unlock pages prepared by reiserfs_prepare_file_region_for_write */
+void reiserfs_unprepare_pages(struct page **prepared_pages, /* list of locked pages */
+			      int num_pages /* amount of pages */) {
+    int i; // loop counter
+
+    for (i=0; i < num_pages ; i++) {
+	struct page *page = prepared_pages[i];
+
+	try_to_free_buffers(page);
+	kunmap(page);
+	unlock_page(page);
+	page_cache_release(page);
+    }
+}
+
+/* This function will copy data from userspace to specified pages within
+   supplied byte range */
+int reiserfs_copy_from_user_to_file_region(
+				loff_t pos, /* In-file position */
+				int num_pages, /* Number of pages affected */
+				int write_bytes, /* Amount of bytes to write */
+				struct page **prepared_pages, /* pointer to 
+								 array to
+								 prepared pages
+								*/
+				const char *buf /* Pointer to user-supplied
+						   data*/
+				)
+{
+    long page_fault=0; // status of copy_from_user.
+    int i; // loop counter.
+    int offset; // offset in page
+
+    for ( i = 0, offset = (pos & (PAGE_CACHE_SIZE-1)); i < num_pages ; i++,offset=0) {
+	int count = min_t(int,PAGE_CACHE_SIZE-offset,write_bytes); // How much of bytes to write to this page
+	struct page *page=prepared_pages[i]; // Current page we process.
+
+	fault_in_pages_readable( buf, count);
+
+	/* Copy data from userspace to the current page */
+	kmap(page);
+	page_fault = __copy_from_user(page_address(page)+offset, buf, count); // Copy the data.
+	/* Flush processor's dcache for this page */
+	flush_dcache_page(page);
+	kunmap(page);
+	buf+=count;
+	write_bytes-=count;
+
+	if (page_fault)
+	    break; // Was there a fault? abort.
+    }
+
+    return page_fault?-EFAULT:0;
+}
+
+
+
+/* Submit pages for write. This was separated from actual file copying
+   because we might want to allocate block numbers in-between.
+   This function assumes that caller will adjust file size to correct value. */
+int reiserfs_submit_file_region_for_write(
+				loff_t pos, /* Writing position offset */
+				int num_pages, /* Number of pages to write */
+				int write_bytes, /* number of bytes to write */
+				struct page **prepared_pages /* list of pages */
+				)
+{
+    int status; // return status of block_commit_write.
+    int retval = 0; // Return value we are going to return.
+    int i; // loop counter
+    int offset; // Writing offset in page.
+
+    for ( i = 0, offset = (pos & (PAGE_CACHE_SIZE-1)); i < num_pages ; i++,offset=0) {
+	int count = min_t(int,PAGE_CACHE_SIZE-offset,write_bytes); // How much of bytes to write to this page
+	struct page *page=prepared_pages[i]; // Current page we process.
+
+	status = block_commit_write(page, offset, offset+count);
+	if ( status )
+	    retval = status; // To not overcomplicate matters We are going to
+			     // submit all the pages even if there was error.
+			     // we only remember error status to report it on
+			     // exit.
+	write_bytes-=count;
+	SetPageReferenced(page);
+	unlock_page(page); // We unlock the page as it was locked by earlier call
+			  // to grab_cache_page
+	page_cache_release(page);
+    }
+    return retval;
+}
+
+/* Look if passed writing region is going to touch file's tail
+   (if it is present). And if it is, convert the tail to unformatted node */
+int reiserfs_check_for_tail_and_convert( struct inode *inode, /* inode to deal with */
+					 loff_t pos, /* Writing position */
+					 int write_bytes /* amount of bytes to write */
+				        )
+{
+    INITIALIZE_PATH(path); // needed for search_for_position
+    struct cpu_key key; // Key that would represent last touched writing byte.
+    struct item_head *ih; // item header of found block;
+    int res; // Return value of various functions we call.
+    int cont_expand_offset; // We will put offset for generic_cont_expand here
+			    // This can be int just because tails are created
+			    // only for small files.
+ 
+/* this embodies a dependency on a particular tail policy */
+    if ( inode->i_size >= inode->i_sb->s_blocksize*4 ) {
+	/* such a big files do not have tails, so we won't bother ourselves
+	   to look for tails, simply return */
+	return 0;
+    }
+
+    reiserfs_write_lock(inode->i_sb);
+    /* find the item containing the last byte to be written, or if
+     * writing past the end of the file then the last item of the
+     * file (and then we check its type). */
+    make_cpu_key (&key, inode, pos+write_bytes+1, TYPE_ANY, 3/*key length*/);
+    res = search_for_position_by_key(inode->i_sb, &key, &path);
+    if ( res == IO_ERROR ) {
+        reiserfs_write_unlock(inode->i_sb);
+	return -EIO;
+    }
+    ih = get_ih(&path);
+    res = 0;
+    if ( is_direct_le_ih(ih) ) {
+	/* Ok, closest item is file tail (tails are stored in "direct"
+	 * items), so we need to unpack it. */
+	/* To not overcomplicate matters, we just call generic_cont_expand
+	   which will in turn call other stuff and finally will boil down to
+	    reiserfs_get_block() that would do necessary conversion. */
+	cont_expand_offset = le_key_k_offset(get_inode_item_key_version(inode), &(ih->ih_key));
+	pathrelse(&path);
+	res = generic_cont_expand( inode, cont_expand_offset);
+    } else
+	pathrelse(&path);
+
+    reiserfs_write_unlock(inode->i_sb);
+    return res;
+}
+
+/* This function locks pages starting from @pos for @inode.
+   @num_pages pages are locked and stored in
+   @prepared_pages array. Also buffers are allocated for these pages.
+   First and last page of the region is read if it is overwritten only
+   partially. If last page did not exist before write (file hole or file
+   append), it is zeroed, then. 
+   Returns number of unallocated blocks that should be allocated to cover
+   new file data.*/
+int reiserfs_prepare_file_region_for_write(
+				struct inode *inode /* Inode of the file */,
+				loff_t pos, /* position in the file */
+				int num_pages, /* number of pages to
+					          prepare */
+				int write_bytes, /* Amount of bytes to be
+						    overwritten from
+						    @pos */
+				struct page **prepared_pages /* pointer to array
+							       where to store
+							       prepared pages */
+					   )
+{
+    int res=0; // Return values of different functions we call.
+    unsigned long index = pos >> PAGE_CACHE_SHIFT; // Offset in file in pages.
+    int from = (pos & (PAGE_CACHE_SIZE - 1)); // Writing offset in first page
+    int to = ((pos + write_bytes - 1) & (PAGE_CACHE_SIZE - 1)) + 1;
+					 /* offset of last modified byte in last
+				            page */
+    struct address_space *mapping = inode->i_mapping; // Pages are mapped here.
+    int i; // Simple counter
+    int blocks = 0; /* Return value (blocks that should be allocated) */
+    struct buffer_head *bh, *head; // Current bufferhead and first bufferhead
+				   // of a page.
+    unsigned block_start, block_end; // Starting and ending offsets of current
+				     // buffer in the page.
+    struct buffer_head *wait[2], **wait_bh=wait; // Buffers for page, if
+						 // Page appeared to be not up
+						 // to date. Note how we have
+						 // at most 2 buffers, this is
+						 // because we at most may
+						 // partially overwrite two
+						 // buffers for one page. One at                                                 // the beginning of write area
+						 // and one at the end.
+						 // Everything inthe middle gets                                                 // overwritten totally.
+
+    struct cpu_key key; // cpu key of item that we are going to deal with
+    struct item_head *ih = NULL; // pointer to item head that we are going to deal with
+    struct buffer_head *itembuf=NULL; // Buffer head that contains items that we are going to deal with
+    INITIALIZE_PATH(path); // path to item, that we are going to deal with.
+    __u32 * item=0; // pointer to item we are going to deal with
+
+
+    if ( num_pages < 1 ) {
+	reiserfs_warning("green-9001: reiserfs_prepare_file_region_for_write called with zero number of pages to process\n");
+	return -EFAULT;
+    }
+
+    /* We have 2 loops for pages. In first loop we grab and lock the pages, so
+       that nobody would touch these until we release the pages. Then
+       we'd start to deal with mapping buffers to blocks. */
+    for ( i = 0; i < num_pages; i++) {
+	prepared_pages[i] = grab_cache_page(mapping, index + i); // locks the page
+	if ( !prepared_pages[i]) {
+	    res = -ENOMEM;
+	    goto failed_page_grabbing;
+	}
+	if (!page_has_buffers(prepared_pages[i]))
+	    create_empty_buffers(prepared_pages[i], inode->i_sb->s_blocksize, 0);
+    }
+
+    /* Let's count amount of blocks for a case where all the blocks
+       overwritten are new (we will substract already allocated blocks later)*/
+    if ( num_pages > 2 )
+	/* These are full-overwritten pages so we count all the blocks in
+	   these pages are counted as needed to be allocated */
+	blocks = (num_pages - 2) << (PAGE_CACHE_SHIFT - inode->i_blkbits);
+
+    /* count blocks needed for first page (possibly partially written) */
+    blocks += ((PAGE_CACHE_SIZE - from) >> inode->i_blkbits) +
+	   !!(from & (inode->i_sb->s_blocksize-1)); /* roundup */
+
+    /* Now we account for last page. If last page == first page (we
+       overwrite only one page), we substract all the blocks past the
+       last writing position in a page out of already calculated number
+       of blocks */
+    blocks += ((num_pages > 1) << (PAGE_CACHE_SHIFT-inode->i_blkbits)) -
+	   ((PAGE_CACHE_SIZE - to) >> inode->i_blkbits);
+	   /* Note how we do not roundup here since partial blocks still
+		   should be allocated */
+
+    /* Now if all the write area lies past the file end, no point in
+       maping blocks, since there is none, so we just zero out remaining
+       parts of first and last pages in write area (if needed) */
+    if ( (pos & ~(PAGE_CACHE_SIZE - 1)) > inode->i_size ) {
+	if ( from != 0 ) {/* First page needs to be partially zeroed */
+	    char *kaddr = kmap_atomic(prepared_pages[0], KM_USER0);
+	    memset(kaddr, 0, from);
+	    kunmap_atomic( kaddr, KM_USER0);
+	}
+	if ( to != PAGE_CACHE_SIZE ) { /* Last page needs to be partially zeroed */
+	    char *kaddr = kmap_atomic(prepared_pages[num_pages-1], KM_USER0);
+	    memset(kaddr+to, 0, PAGE_CACHE_SIZE - to);
+	    kunmap_atomic( kaddr, KM_USER0);
+	}
+
+	/* Since all blocks are new - use already calculated value */
+	return blocks;
+    }
+
+    /* Well, since we write somewhere into the middle of a file, there is
+       possibility we are writing over some already allocated blocks, so
+       let's map these blocks and substract number of such blocks out of blocks
+       we need to allocate (calculated above) */
+    /* Mask write position to start on blocksize, we do it out of the
+       loop for performance reasons */
+    pos &= ~(inode->i_sb->s_blocksize - 1);
+    /* Set cpu key to the starting position in a file (on left block boundary)*/
+    make_cpu_key (&key, inode, 1 + ((pos) & ~(inode->i_sb->s_blocksize - 1)), TYPE_ANY, 3/*key length*/);
+
+    reiserfs_write_lock(inode->i_sb); // We need that for at least search_by_key()
+    for ( i = 0; i < num_pages ; i++ ) { 
+	int item_pos=-1; /* Position in indirect item */
+
+	head = page_buffers(prepared_pages[i]);
+	/* For each buffer in the page */
+	for(bh = head, block_start = 0; bh != head || !block_start;
+	    block_start=block_end, bh = bh->b_this_page) {
+		if (!bh)
+		    reiserfs_panic(inode->i_sb, "green-9002: Allocated but absent buffer for a page?");
+		/* Find where this buffer ends */
+		block_end = block_start+inode->i_sb->s_blocksize;
+		if (i == 0 && block_end <= from )
+		    /* if this buffer is before requested data to map, skip it*/
+		    continue;
+
+		if (i == num_pages - 1 && block_start >= to) {
+		    /* If this buffer is after requested data to map, abort
+		       processing of current page */
+		    break;
+		}
+
+		if ( buffer_mapped(bh) && bh->b_blocknr !=0 ) {
+		    /* This is optimisation for a case where buffer is mapped
+		       and have blocknumber assigned. In case significant amount
+		       of such buffers are present, we may avoid some amount
+		       of search_by_key calls.
+		       Probably it would be possible to move parts of this code
+		       out of BKL, but I afraid that would overcomplicate code
+		       without any noticeable benefit.
+		    */
+		    item_pos++;
+		    /* Update the key */
+		    set_cpu_key_k_offset( &key, cpu_key_k_offset(&key) + inode->i_sb->s_blocksize);
+		    blocks--; // Decrease the amount of blocks that need to be
+			      // allocated
+		    continue; // Go to the next buffer
+		}
+
+		if ( !itembuf || /* if first iteration */
+		     item_pos >= ih_item_len(ih)/UNFM_P_SIZE)
+					     { /* or if we progressed past the
+						  current unformatted_item */
+			/* Try to find next item */
+			res = search_for_position_by_key(inode->i_sb, &key, &path);
+			/* Abort if no more items */
+			if ( res != POSITION_FOUND )
+			    break;
+
+			/* Update information about current indirect item */
+			itembuf = get_last_bh( &path );
+			ih = get_ih( &path );
+			item = get_item( &path );
+			item_pos = path.pos_in_item;
+
+			RFALSE( !is_indirect_le_ih (ih), "green-9003: indirect item expected");
+		}
+
+		/* See if there is some block associated with the file
+		   at that position, map the buffer to this block */
+		if ( get_block_num(item,item_pos) ) {
+		    map_bh(bh, inode->i_sb, get_block_num(item,item_pos));
+		    blocks--; // Decrease the amount of blocks that need to be
+			      // allocated
+		}
+		item_pos++;
+		/* Update the key */
+		set_cpu_key_k_offset( &key, cpu_key_k_offset(&key) + inode->i_sb->s_blocksize);
+	}
+    }
+    pathrelse(&path); // Free the path
+    reiserfs_write_unlock(inode->i_sb);
+
+	/* Now zero out unmappend buffers for the first and last pages of
+	   write area or issue read requests if page is mapped. */
+	/* First page, see if it is not uptodate */
+	if ( !PageUptodate(prepared_pages[0]) ) {
+	    head = page_buffers(prepared_pages[0]);
+
+	    /* For each buffer in page */
+	    for(bh = head, block_start = 0; bh != head || !block_start;
+		block_start=block_end, bh = bh->b_this_page) {
+
+		if (!bh)
+		    reiserfs_panic(inode->i_sb, "green-9002: Allocated but absent buffer for a page?");
+		/* Find where this buffer ends */
+		block_end = block_start+inode->i_sb->s_blocksize;
+		if ( block_end <= from )
+		    /* if this buffer is before requested data to map, skip it*/
+		    continue;
+		if ( block_start < from ) { /* Aha, our partial buffer */
+		    if ( buffer_mapped(bh) ) { /* If it is mapped, we need to
+						  issue READ request for it to
+						  not loose data */
+			ll_rw_block(READ, 1, &bh);
+			*wait_bh++=bh;
+		    } else { /* Not mapped, zero it */
+			char *kaddr = kmap_atomic(prepared_pages[0], KM_USER0);
+			memset(kaddr+block_start, 0, from-block_start);
+			kunmap_atomic( kaddr, KM_USER0);
+			set_buffer_uptodate(bh);
+		    }
+		}
+	    }
+	}
+
+	/* Last page, see if it is not uptodate, or if the last page is past the end of the file. */
+	if ( !PageUptodate(prepared_pages[num_pages-1]) || 
+	    ((pos+write_bytes)>>PAGE_CACHE_SHIFT) > (inode->i_size>>PAGE_CACHE_SHIFT) ) {
+	    head = page_buffers(prepared_pages[num_pages-1]);
+
+	    /* for each buffer in page */
+	    for(bh = head, block_start = 0; bh != head || !block_start;
+		block_start=block_end, bh = bh->b_this_page) {
+
+		if (!bh)
+		    reiserfs_panic(inode->i_sb, "green-9002: Allocated but absent buffer for a page?");
+		/* Find where this buffer ends */
+		block_end = block_start+inode->i_sb->s_blocksize;
+		if ( block_start >= to )
+		    /* if this buffer is after requested data to map, skip it*/
+		    break;
+		if ( block_end > to ) { /* Aha, our partial buffer */
+		    if ( buffer_mapped(bh) ) { /* If it is mapped, we need to
+						  issue READ request for it to
+						  not loose data */
+			ll_rw_block(READ, 1, &bh);
+			*wait_bh++=bh;
+		    } else { /* Not mapped, zero it */
+			char *kaddr = kmap_atomic(prepared_pages[num_pages-1], KM_USER0);
+			memset(kaddr+to, 0, block_end-to);
+			kunmap_atomic( kaddr, KM_USER0);
+			set_buffer_uptodate(bh);
+		    }
+		}
+	    }
+	}
+
+    /* Wait for read requests we made to happen, if necessary */
+    while(wait_bh > wait) {
+	wait_on_buffer(*--wait_bh);
+	if (!buffer_uptodate(*wait_bh)) {
+	    res = -EIO;
+	    goto failed_read;
+	}
+    }
+
+    return blocks;
+failed_page_grabbing:
+    num_pages = i;
+failed_read:
+    reiserfs_unprepare_pages(prepared_pages, num_pages);
+    return res;
+}
+
+/* Write @count bytes at position @ppos in a file indicated by @file
+   from the buffer @buf.  
+
+   generic_file_write() is only appropriate for filesystems that are not seeking to optimize performance and want
+   something simple that works.  It is not for serious use by general purpose filesystems, excepting the one that it was
+   written for (ext2/3).  This is for several reasons:
+
+   * It has no understanding of any filesystem specific optimizations.
+
+   * It enters the filesystem repeatedly for each page that is written.
+
+   * It depends on reiserfs_get_block() function which if implemented by reiserfs performs costly search_by_key
+   * operation for each page it is supplied with. By contrast reiserfs_file_write() feeds as much as possible at a time
+   * to reiserfs which allows for fewer tree traversals.
+
+   * Each indirect pointer insertion takes a lot of cpu, because it involves memory moves inside of blocks.
+
+   * Asking the block allocation code for blocks one at a time is slightly less efficient.
+
+   All of these reasons for not using only generic file write were understood back when reiserfs was first miscoded to
+   use it, but we were in a hurry to make code freeze, and so it couldn't be revised then.  This new code should make
+   things right finally.
+
+   Future Features: providing search_by_key with hints.
+
+*/
+ssize_t reiserfs_file_write( struct file *file, /* the file we are going to write into */
+                             const char *buf, /*  pointer to user supplied data
+(in userspace) */
+                             size_t count, /* amount of bytes to write */
+                             loff_t *ppos /* pointer to position in file that we start writing at. Should be updated to
+                                           * new current position before returning. */ )
+{
+    size_t already_written = 0; // Number of bytes already written to the file.
+    loff_t pos; // Current position in the file.
+    size_t res; // return value of various functions that we call.
+    struct inode *inode = file->f_dentry->d_inode; // Inode of the file that we are writing to.
+    struct page * prepared_pages[REISERFS_WRITE_PAGES_AT_A_TIME];
+				/* To simplify coding at this time, we store
+				   locked pages in array for now */
+    if ( count <= PAGE_CACHE_SIZE || file->f_flags & O_DIRECT)
+        return generic_file_write(file, buf, count, ppos);
+
+    if ( unlikely((ssize_t) count < 0 ))
+        return -EINVAL;
+
+    if (unlikely(!access_ok(VERIFY_READ, buf, count)))
+        return -EFAULT;
+
+    down(&inode->i_sem); // locks the entire file for just us
+
+    pos = *ppos;
+
+    /* Check if we can write to specified region of file, file
+       is not overly big and this kind of stuff. Adjust pos and
+       count, if needed */
+    res = generic_write_checks(inode, file, &pos, &count, 0);
+    if (res)
+	goto out;
+
+    if ( count == 0 )
+	goto out;
+
+    remove_suid(file->f_dentry);
+    inode_update_time(inode, 1); /* Both mtime and ctime */
+
+    // Ok, we are done with all the checks.
+
+    // Now we should start real work
+
+    /* If we are going to write past the file's packed tail or if we are going
+       to overwrite part of the tail, we need that tail to be converted into
+       unformatted node */
+    res = reiserfs_check_for_tail_and_convert( inode, pos, count);
+    if (res)
+	goto out;
+
+    while ( count > 0) {
+	/* This is the main loop in which we running until some error occures
+	   or until we write all of the data. */
+	int num_pages;/* amount of pages we are going to write this iteration */
+	int write_bytes; /* amount of bytes to write during this iteration */
+	int blocks_to_allocate; /* how much blocks we need to allocate for
+				   this iteration */
+        
+        /*  (pos & (PAGE_CACHE_SIZE-1)) is an idiom for offset into a page of pos*/
+	num_pages = !!((pos+count) & (PAGE_CACHE_SIZE - 1)) + /* round up partial
+							  pages */
+		    ((count + (pos & (PAGE_CACHE_SIZE-1))) >> PAGE_CACHE_SHIFT); 
+						/* convert size to amount of
+						   pages */
+	reiserfs_write_lock(inode->i_sb);
+	if ( num_pages > REISERFS_WRITE_PAGES_AT_A_TIME 
+		|| num_pages > reiserfs_can_fit_pages(inode->i_sb) ) {
+	    /* If we were asked to write more data than we want to or if there
+	       is not that much space, then we shorten amount of data to write
+	       for this iteration. */
+	    num_pages = min_t(int, REISERFS_WRITE_PAGES_AT_A_TIME, reiserfs_can_fit_pages(inode->i_sb));
+	    /* Also we should not forget to set size in bytes accordingly */
+	    write_bytes = (num_pages << PAGE_CACHE_SHIFT) - 
+			    (pos & (PAGE_CACHE_SIZE-1));
+					 /* If position is not on the
+					    start of the page, we need
+					    to substract the offset
+					    within page */
+	} else
+	    write_bytes = count;
+
+	/* reserve the blocks to be allocated later, so that later on
+	   we still have the space to write the blocks to */
+	reiserfs_claim_blocks_to_be_allocated(inode->i_sb, num_pages << (PAGE_CACHE_SHIFT - inode->i_blkbits));
+	reiserfs_write_unlock(inode->i_sb);
+
+	if ( !num_pages ) { /* If we do not have enough space even for */
+	    res = -ENOSPC;  /* single page, return -ENOSPC */
+	    if ( pos > (inode->i_size & (inode->i_sb->s_blocksize-1)))
+		break; // In case we are writing past the file end, break.
+	    // Otherwise we are possibly overwriting the file, so
+	    // let's set write size to be equal or less than blocksize.
+	    // This way we get it correctly for file holes.
+	    // But overwriting files on absolutelly full volumes would not
+	    // be very efficient. Well, people are not supposed to fill
+	    // 100% of disk space anyway.
+	    write_bytes = min_t(int, count, inode->i_sb->s_blocksize - (pos & (inode->i_sb->s_blocksize - 1)));
+	    num_pages = 1;
+	}
+
+	/* Prepare for writing into the region, read in all the
+	   partially overwritten pages, if needed. And lock the pages,
+	   so that nobody else can access these until we are done.
+	   We get number of actual blocks needed as a result.*/
+	blocks_to_allocate = reiserfs_prepare_file_region_for_write(inode, pos, num_pages, write_bytes, prepared_pages);
+	if ( blocks_to_allocate < 0 ) {
+	    res = blocks_to_allocate;
+	    reiserfs_release_claimed_blocks(inode->i_sb, num_pages << (PAGE_CACHE_SHIFT - inode->i_blkbits));
+	    break;
+	}
+
+	/* First we correct our estimate of how many blocks we need */
+	reiserfs_release_claimed_blocks(inode->i_sb, (num_pages << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits)) - blocks_to_allocate );
+
+	if ( blocks_to_allocate > 0) {/*We only allocate blocks if we need to*/
+	    /* Fill in all the possible holes and append the file if needed */
+	    res = reiserfs_allocate_blocks_for_region(inode, pos, num_pages, write_bytes, prepared_pages, blocks_to_allocate);
+	} else if ( pos + write_bytes > inode->i_size ) {
+	    /* File might have grown even though no new blocks were added */
+	    inode->i_size = pos + write_bytes;
+	    inode->i_sb->s_op->dirty_inode(inode);
+	}
+
+	/* well, we have allocated the blocks, so it is time to free
+	   the reservation we made earlier. */
+	reiserfs_release_claimed_blocks(inode->i_sb, blocks_to_allocate);
+	if ( res ) {
+	    reiserfs_unprepare_pages(prepared_pages, num_pages);
+	    break;
+	}
+
+/* NOTE that allocating blocks and filling blocks can be done in reverse order
+   and probably we would do that just to get rid of garbage in files after a
+   crash */
+
+	/* Copy data from user-supplied buffer to file's pages */
+	res = reiserfs_copy_from_user_to_file_region(pos, num_pages, write_bytes, prepared_pages, buf);
+	if ( res ) {
+	    reiserfs_unprepare_pages(prepared_pages, num_pages);
+	    break;
+	}
+
+	/* Send the pages to disk and unlock them. */
+	res = reiserfs_submit_file_region_for_write(pos, num_pages, write_bytes, prepared_pages);
+	if ( res )
+	    break;
+
+	already_written += write_bytes;
+	buf += write_bytes;
+	*ppos = pos += write_bytes;
+	count -= write_bytes;
+    }
+
+    if ((file->f_flags & O_SYNC) || IS_SYNC(inode))
+	res = generic_osync_inode(inode, OSYNC_METADATA|OSYNC_DATA);
+
+    up(&inode->i_sem);
+    return (already_written != 0)?already_written:res;
+
+out:
+    up(&inode->i_sem); // unlock the file on exit.
+    return res;
+}
+
 struct file_operations reiserfs_file_operations = {
     .read	= generic_file_read,
-    .write	= generic_file_write,
+    .write	= reiserfs_file_write,
     .ioctl	= reiserfs_ioctl,
     .mmap	= generic_file_mmap,
     .release	= reiserfs_file_release,
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c	Sat Apr 19 23:22:23 2003
+++ b/fs/reiserfs/inode.c	Sat May 17 14:09:36 2003
@@ -14,6 +14,8 @@
 #include <linux/mpage.h>
 #include <linux/writeback.h>
 
+extern int reiserfs_default_io_size; /* default io size devuned in super.c */
+
 /* args for the create parameter of reiserfs_get_block */
 #define GET_BLOCK_NO_CREATE 0 /* don't create new blocks or convert tails */
 #define GET_BLOCK_CREATE 1    /* add anything you need to find block */
@@ -766,7 +768,11 @@
 	       pointer to 'block'-th block use block, which is already
 	       allocated */
 	    struct cpu_key tmp_key;
-	    struct unfm_nodeinfo un = {0, 0};
+	    unp_t unf_single=0; // We use this in case we need to allocate only
+				// one block which is a fastpath
+	    unp_t *un;
+	    __u64 max_to_insert=MAX_ITEM_LEN(inode->i_sb->s_blocksize)/UNFM_P_SIZE;
+	    __u64 blocks_needed;
 
 	    RFALSE( pos_in_item != ih_item_len(ih) / UNFM_P_SIZE,
 		    "vs-804: invalid position for append");
@@ -775,30 +781,58 @@
 			  le_key_k_offset (version, &(ih->ih_key)) + op_bytes_number (ih, inode->i_sb->s_blocksize),
 			  //pos_in_item * inode->i_sb->s_blocksize,
 			  TYPE_INDIRECT, 3);// key type is unimportant
-		  
-	    if (cpu_key_k_offset (&tmp_key) == cpu_key_k_offset (&key)) {
+
+	    blocks_needed = 1 + ((cpu_key_k_offset (&key) - cpu_key_k_offset (&tmp_key)) >> inode->i_sb->s_blocksize_bits);
+	    RFALSE( blocks_needed < 0, "green-805: invalid offset");
+
+	    if ( blocks_needed == 1 ) {
+		un = &unf_single;
+	    } else {
+		un=kmalloc( min(blocks_needed,max_to_insert)*UNFM_P_SIZE,
+			    GFP_ATOMIC); // We need to avoid scheduling.
+		if ( !un) {
+		    un = &unf_single;
+		    blocks_needed = 1;
+		    max_to_insert = 0;
+		} else
+		    memset(un, 0, UNFM_P_SIZE * min(blocks_needed,max_to_insert));
+	    }
+	    if ( blocks_needed <= max_to_insert) {
 		/* we are going to add target block to the file. Use allocated
 		   block for that */
-		un.unfm_nodenum = cpu_to_le32 (allocated_block_nr);
+		un[blocks_needed-1] = cpu_to_le32 (allocated_block_nr);
 		set_block_dev_mapped (bh_result, allocated_block_nr, inode);
 		set_buffer_new(bh_result);
 		done = 1;
 	    } else {
 		/* paste hole to the indirect item */
+		/* If kmalloc failed, max_to_insert becomes zero and it means we
+		   only have space for one block */
+		blocks_needed=max_to_insert?max_to_insert:1;
 	    }
-	    retval = reiserfs_paste_into_item (&th, &path, &tmp_key, (char *)&un, UNFM_P_SIZE);
+	    retval = reiserfs_paste_into_item (&th, &path, &tmp_key, (char *)un, UNFM_P_SIZE * blocks_needed);
+
+	    if (blocks_needed != 1)
+		kfree(un);
+
 	    if (retval) {
 		reiserfs_free_block (&th, allocated_block_nr);
 		goto failure;
 	    }
-	    if (un.unfm_nodenum)
+	    if (done) {
 		inode->i_blocks += inode->i_sb->s_blocksize / 512;
+	    } else {
+		/* We need to mark new file size in case this function will be
+		   interrupted/aborted later on. And we may do this only for
+		   holes. */
+		inode->i_size += inode->i_sb->s_blocksize * blocks_needed;
+	    }
 	    //mark_tail_converted (inode);
 	}
-		
+
 	if (done == 1)
 	    break;
-	 
+
 	/* this loop could log more blocks than we had originally asked
 	** for.  So, we have to allow the transaction to end if it is
 	** too big or too full.  Update the inode so things are 
@@ -876,7 +910,7 @@
 
 
     copy_key (INODE_PKEY (inode), &(ih->ih_key));
-    inode->i_blksize = PAGE_SIZE;
+    inode->i_blksize = reiserfs_default_io_size;
 
     INIT_LIST_HEAD(&(REISERFS_I(inode)->i_prealloc_list ));
     REISERFS_I(inode)->i_flags = 0;
@@ -1566,7 +1600,7 @@
     }
     // these do not go to on-disk stat data
     inode->i_ino = le32_to_cpu (ih.ih_key.k_objectid);
-    inode->i_blksize = PAGE_SIZE;
+    inode->i_blksize = reiserfs_default_io_size;
   
     // store in in-core inode the key of stat data and version all
     // object items will have (directory items will have old offset
diff -Nru a/fs/reiserfs/prints.c b/fs/reiserfs/prints.c
--- a/fs/reiserfs/prints.c	Sat Mar 22 22:14:13 2003
+++ b/fs/reiserfs/prints.c	Sat May 17 14:08:16 2003
@@ -164,7 +164,7 @@
 
   *skip = 0;
   
-  while ((k = strstr (k, "%")) != NULL)
+  while ((k = strchr (k, '%')) != NULL)
   {
     if (k[1] == 'k' || k[1] == 'K' || k[1] == 'h' || k[1] == 't' ||
 	      k[1] == 'z' || k[1] == 'b' || k[1] == 'y' || k[1] == 'a' ) {
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
--- a/fs/reiserfs/super.c	Tue Feb 25 09:45:25 2003
+++ b/fs/reiserfs/super.c	Sat May 17 14:09:36 2003
@@ -532,6 +532,11 @@
     {NULL, 0}
 };
 
+int reiserfs_default_io_size = 128 * 1024; /* Default recommended I/O size is 128k.
+					      There might be broken applications that are
+					      confused by this. Use nolargeio mount option
+					      to get usual i/o size = PAGE_SIZE.
+					    */
 
 /* proceed only one option from a list *cur - string containing of mount options
    opts - array of options which are accepted
@@ -657,6 +662,7 @@
 		{"block-allocator", 'a', balloc, -1}, 
 		{"resize", 'r', 0, -1},
 		{"jdev", 'j', 0, -1},
+		{"nolargeio", 'w', 0, -1},
 		{NULL, 0, 0, -1}
     };
 	
@@ -688,6 +694,10 @@
 	    }
 	}
 
+	if ( c == 'w' ) {
+		reiserfs_default_io_size = PAGE_SIZE;
+	}
+
 	if (c == 'j') {
 	    if (arg && *arg && jdev_name) {
 		*jdev_name = arg;
@@ -1318,6 +1328,7 @@
     reiserfs_proc_register( s, "oidmap", reiserfs_oidmap_in_proc );
     reiserfs_proc_register( s, "journal", reiserfs_journal_in_proc );
     init_waitqueue_head (&(sbi->s_wait));
+    sbi->bitmap_lock = SPIN_LOCK_UNLOCKED;
 
     return (0);
 
diff -Nru a/fs/reiserfs/tail_conversion.c b/fs/reiserfs/tail_conversion.c
--- a/fs/reiserfs/tail_conversion.c	Sat Sep  7 16:22:00 2002
+++ b/fs/reiserfs/tail_conversion.c	Sat May 17 14:09:35 2003
@@ -30,7 +30,7 @@
                                 key of unfm pointer to be pasted */
     int	n_blk_size,
       n_retval;	  /* returned value for reiserfs_insert_item and clones */
-    struct unfm_nodeinfo unfm_ptr;  /* Handle on an unformatted node
+    unp_t unfm_ptr;  /* Handle on an unformatted node
 				       that will be inserted in the
 				       tree. */
 
@@ -59,8 +59,7 @@
     
     p_le_ih = PATH_PITEM_HEAD (path);
 
-    unfm_ptr.unfm_nodenum = cpu_to_le32 (unbh->b_blocknr);
-    unfm_ptr.unfm_freespace = 0; // ???
+    unfm_ptr = cpu_to_le32 (unbh->b_blocknr);
     
     if ( is_statdata_le_ih (p_le_ih) )  {
 	/* Insert new indirect item. */
diff -Nru a/fs/select.c b/fs/select.c
--- a/fs/select.c	Wed Apr  9 06:42:36 2003
+++ b/fs/select.c	Wed May  7 21:21:13 2003
@@ -176,7 +176,7 @@
 {
 	struct poll_wqueues table;
 	poll_table *wait;
-	int retval, i, off;
+	int retval, i;
 	long __timeout = *timeout;
 
  	spin_lock(&current->files->file_lock);
@@ -193,38 +193,58 @@
 		wait = NULL;
 	retval = 0;
 	for (;;) {
+		unsigned long *rinp, *routp, *rexp, *inp, *outp, *exp;
+
 		set_current_state(TASK_INTERRUPTIBLE);
-		for (i = 0 ; i < n; i++) {
-			unsigned long bit = BIT(i);
-			unsigned long mask;
-			struct file *file;
 
-			off = i / __NFDBITS;
-			if (!(bit & BITS(fds, off)))
+		inp = fds->in; outp = fds->out; exp = fds->ex;
+		rinp = fds->res_in; routp = fds->res_out; rexp = fds->res_ex;
+
+		for (i = 0; i < n; ++rinp, ++routp, ++rexp) {
+			unsigned long in, out, ex, all_bits, bit = 1, mask, j;
+			unsigned long res_in = 0, res_out = 0, res_ex = 0;
+			struct file_operations *f_op = NULL;
+			struct file *file = NULL;
+
+			in = *inp++; out = *outp++; ex = *exp++;
+			all_bits = in | out | ex;
+			if (all_bits == 0) {
+				i += __NFDBITS;
 				continue;
-			file = fget(i);
-			mask = POLLNVAL;
-			if (file) {
-				mask = DEFAULT_POLLMASK;
-				if (file->f_op && file->f_op->poll)
-					mask = file->f_op->poll(file, wait);
-				fput(file);
 			}
-			if ((mask & POLLIN_SET) && ISSET(bit, __IN(fds,off))) {
-				SET(bit, __RES_IN(fds,off));
-				retval++;
-				wait = NULL;
-			}
-			if ((mask & POLLOUT_SET) && ISSET(bit, __OUT(fds,off))) {
-				SET(bit, __RES_OUT(fds,off));
-				retval++;
-				wait = NULL;
-			}
-			if ((mask & POLLEX_SET) && ISSET(bit, __EX(fds,off))) {
-				SET(bit, __RES_EX(fds,off));
-				retval++;
-				wait = NULL;
+
+			for (j = 0; j < __NFDBITS; ++j, ++i, bit <<= 1) {
+				if (i >= n)
+					break;
+				if (!(bit & all_bits))
+					continue;
+				file = fget(i);
+				if (file) {
+					f_op = file->f_op;
+					mask = DEFAULT_POLLMASK;
+					if (f_op && f_op->poll)
+						mask = (*f_op->poll)(file, retval ? NULL : wait);
+					fput(file);
+					if ((mask & POLLIN_SET) && (in & bit)) {
+						res_in |= bit;
+						retval++;
+					}
+					if ((mask & POLLOUT_SET) && (out & bit)) {
+						res_out |= bit;
+						retval++;
+					}
+					if ((mask & POLLEX_SET) && (ex & bit)) {
+						res_ex |= bit;
+						retval++;
+					}
+				}
 			}
+			if (res_in)
+				*rinp = res_in;
+			if (res_out)
+				*routp = res_out;
+			if (res_ex)
+				*rexp = res_ex;
 		}
 		wait = NULL;
 		if (retval || !__timeout || signal_pending(current))
diff -Nru a/fs/seq_file.c b/fs/seq_file.c
--- a/fs/seq_file.c	Thu Apr 10 10:23:30 2003
+++ b/fs/seq_file.c	Mon May 19 09:25:35 2003
@@ -297,6 +297,37 @@
 	return -1;
 }
 
+int seq_path(struct seq_file *m,
+		struct vfsmount *mnt, struct dentry *dentry,
+		char *esc)
+{
+	if (m->count < m->size) {
+		char *s = m->buf + m->count;
+		char *p = d_path(dentry, mnt, s, m->size - m->count);
+		if (!IS_ERR(p)) {
+			while (s <= p) {
+				char c = *p++;
+				if (!c) {
+					p = m->buf + m->count;
+					m->count = s - m->buf;
+					return s - p;
+				} else if (!strchr(esc, c)) {
+					*s++ = c;
+				} else if (s + 4 > p) {
+					break;
+				} else {
+					*s++ = '\\';
+					*s++ = '0' + ((c & 0300) >> 6);
+					*s++ = '0' + ((c & 070) >> 3);
+					*s++ = '0' + (c & 07);
+				}
+			}
+		}
+	}
+	m->count = m->size;
+	return -1;
+}
+
 static void *single_start(struct seq_file *p, loff_t *pos)
 {
 	return NULL + (*pos == 0);
@@ -338,3 +369,13 @@
 	kfree(op);
 	return res;
 }
+
+int seq_release_private(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq = file->private_data;
+
+	kfree(seq->private);
+	seq->private = NULL;
+	return seq_release(inode, file);
+}
+
diff -Nru a/fs/stat.c b/fs/stat.c
--- a/fs/stat.c	Wed Apr  9 22:13:11 2003
+++ b/fs/stat.c	Sun May  4 22:49:54 2003
@@ -244,7 +244,7 @@
 		if (inode->i_op && inode->i_op->readlink) {
 			error = security_inode_readlink(nd.dentry);
 			if (!error) {
-				UPDATE_ATIME(inode);
+				update_atime(inode);
 				error = inode->i_op->readlink(nd.dentry, buf, bufsiz);
 			}
 		}
diff -Nru a/fs/super.c b/fs/super.c
--- a/fs/super.c	Thu Apr 10 10:23:49 2003
+++ b/fs/super.c	Mon May 12 21:23:22 2003
@@ -31,6 +31,7 @@
 #include <linux/mount.h>
 #include <linux/security.h>
 #include <linux/vfs.h>
+#include <linux/writeback.h>		/* for the emergency remount stuff */
 #include <asm/uaccess.h>
 
 
@@ -431,6 +432,18 @@
 	return err;
 }
 
+static void mark_files_ro(struct super_block *sb)
+{
+	struct file *f;
+
+	file_list_lock();
+	list_for_each_entry(f, &sb->s_files, f_list) {
+		if (S_ISREG(f->f_dentry->d_inode->i_mode) && file_count(f))
+			f->f_mode &= ~FMODE_WRITE;
+	}
+	file_list_unlock();
+}
+
 /**
  *	do_remount_sb	-	asks filesystem to change mount options.
  *	@sb:	superblock in question
@@ -439,21 +452,25 @@
  *
  *	Alters the mount options of a mounted file system.
  */
-int do_remount_sb(struct super_block *sb, int flags, void *data)
+int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
 {
 	int retval;
 	
 	if (!(flags & MS_RDONLY) && bdev_read_only(sb->s_bdev))
 		return -EACCES;
-		/*flags |= MS_RDONLY;*/
 	if (flags & MS_RDONLY)
 		acct_auto_close(sb);
 	shrink_dcache_sb(sb);
 	fsync_super(sb);
+
 	/* If we are remounting RDONLY, make sure there are no rw files open */
-	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY))
-		if (!fs_may_remount_ro(sb))
+	if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) {
+		if (force)
+			mark_files_ro(sb);
+		else if (!fs_may_remount_ro(sb))
 			return -EBUSY;
+	}
+
 	if (sb->s_op->remount_fs) {
 		lock_super(sb);
 		retval = sb->s_op->remount_fs(sb, &flags, data);
@@ -465,6 +482,29 @@
 	return 0;
 }
 
+static void do_emergency_remount(unsigned long foo)
+{
+	struct super_block *sb;
+
+	spin_lock(&sb_lock);
+	list_for_each_entry(sb, &super_blocks, s_list) {
+		sb->s_count++;
+		spin_unlock(&sb_lock);
+		down_read(&sb->s_umount);
+		if (sb->s_root && sb->s_bdev && !(sb->s_flags & MS_RDONLY))
+			do_remount_sb(sb, MS_RDONLY, NULL, 1);
+		drop_super(sb);
+		spin_lock(&sb_lock);
+	}
+	spin_unlock(&sb_lock);
+	printk("Emergency Remount complete\n");
+}
+
+void emergency_remount(void)
+{
+	pdflush_operation(do_emergency_remount, 0);
+}
+
 /*
  * Unnamed block devices are dummy devices used by virtual
  * filesystems which don't use real block-devices.  -- jrs
@@ -618,7 +658,7 @@
 		}
 		s->s_flags |= MS_ACTIVE;
 	}
-	do_remount_sb(s, flags, data);
+	do_remount_sb(s, flags, data, 0);
 	return s;
 }
 
diff -Nru a/fs/sysfs/bin.c b/fs/sysfs/bin.c
--- a/fs/sysfs/bin.c	Tue Apr  1 23:09:06 2003
+++ b/fs/sysfs/bin.c	Wed Apr 16 14:11:21 2003
@@ -2,170 +2,118 @@
  * bin.c - binary file operations for sysfs.
  */
 
+#include <linux/errno.h>
 #include <linux/fs.h>
-#include <linux/module.h>
 #include <linux/kobject.h>
+#include <linux/module.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 
 #include "sysfs.h"
 
-static struct file_operations bin_fops;
-
-static int fill_read(struct file * file, struct sysfs_bin_buffer * buffer)
+static int
+fill_read(struct dentry *dentry, char *buffer, loff_t off, size_t count)
 {
-	struct bin_attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct bin_attribute * attr = dentry->d_fsdata;
+	struct kobject * kobj = dentry->d_parent->d_fsdata;
 
-	if (!buffer->data)
-		attr->read(kobj,buffer);
-	return buffer->size ? 0 : -ENOENT;
-}
-
-static int flush_read(struct file * file, char * userbuf, 
-		      struct sysfs_bin_buffer * buffer)
-{
-	return copy_to_user(userbuf,buffer->data + buffer->offset,buffer->count) ? 
-		-EFAULT : 0;
+	return attr->read(kobj, buffer, off, count);
 }
 
 static ssize_t
 read(struct file * file, char * userbuf, size_t count, loff_t * off)
 {
-	struct sysfs_bin_buffer * buffer = file->private_data;
+	char *buffer = file->private_data;
+	struct dentry *dentry = file->f_dentry;
+	int size = dentry->d_inode->i_size;
+	loff_t offs = *off;
 	int ret;
 
-	ret = fill_read(file,buffer);
-	if (ret) 
-		goto Done;
+	if (offs > size)
+		return 0;
+	if (offs + count > size)
+		count = size - offs;
 
-	buffer->offset = *off;
+	ret = fill_read(dentry, buffer, offs, count);
+	if (ret < 0) 
+		goto Done;
+	count = ret;
 
-	if (count > (buffer->size - *off))
-		count = buffer->size - *off;
+	ret = -EFAULT;
+	if (copy_to_user(userbuf, buffer + offs, count) != 0)
+		goto Done;
 
-	buffer->count = count;
+	*off = offs + count;
+	ret = count;
 
-	ret = flush_read(file,userbuf,buffer);
-	if (!ret) {
-		*off += count;
-		ret = count;
-	}
  Done:
-	if (buffer && buffer->data) {
-		kfree(buffer->data);
-		buffer->data = NULL;
-	}
 	return ret;
 }
 
-int alloc_buf_data(struct sysfs_bin_buffer * buffer)
-{
-	buffer->data = kmalloc(buffer->count,GFP_KERNEL);
-	if (buffer->data) {
-		memset(buffer->data,0,buffer->count);
-		return 0;
-	} else
-		return -ENOMEM;
-}
-
-static int fill_write(struct file * file, const char * userbuf, 
-		      struct sysfs_bin_buffer * buffer)
-{
-	return copy_from_user(buffer->data,userbuf,buffer->count) ?
-		-EFAULT : 0;
-}
-
-static int flush_write(struct file * file, const char * userbuf, 
-		       struct sysfs_bin_buffer * buffer)
+static int
+flush_write(struct dentry *dentry, char *buffer, loff_t offset, size_t count)
 {
-	struct bin_attribute * attr = file->f_dentry->d_fsdata;
-	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
+	struct bin_attribute *attr = dentry->d_fsdata;
+	struct kobject *kobj = dentry->d_parent->d_fsdata;
 
-	return attr->write(kobj,buffer);
+	return attr->write(kobj, buffer, offset, count);
 }
 
 static ssize_t write(struct file * file, const char * userbuf,
 		     size_t count, loff_t * off)
 {
-	struct sysfs_bin_buffer * buffer = file->private_data;
+	char *buffer = file->private_data;
+	struct dentry *dentry = file->f_dentry;
+	int size = dentry->d_inode->i_size;
+	loff_t offs = *off;
 	int ret;
 
-	if (count > PAGE_SIZE)
-		count = PAGE_SIZE;
-	buffer->count = count;
-
-	ret = alloc_buf_data(buffer);
-	if (ret)
-		goto Done;
+	if (offs > size)
+		return 0;
+	if (offs + count > size)
+		count = size - offs;
 
-	ret = fill_write(file,userbuf,buffer);
-	if (ret)
+	ret = -EFAULT;
+	if (copy_from_user(buffer + offs, userbuf, count))
 		goto Done;
 
-	ret = flush_write(file,userbuf,buffer);
-	if (ret > 0)
-		*off += count;
+	count = flush_write(dentry, buffer, offs, count);
+	if (count > 0)
+		*off = offs + count;
+	ret = 0;
  Done:
-	if (buffer->data) {
-		kfree(buffer->data);
-		buffer->data = NULL;
-	}
 	return ret;
 }
 
-static int check_perm(struct inode * inode, struct file * file)
+static int open(struct inode * inode, struct file * file)
 {
 	struct kobject * kobj = kobject_get(file->f_dentry->d_parent->d_fsdata);
 	struct bin_attribute * attr = file->f_dentry->d_fsdata;
-	struct sysfs_bin_buffer * buffer;
-	int error = 0;
+	int error = -EINVAL;
 
 	if (!kobj || !attr)
-		goto Einval;
+		goto Done;
 
-	/* File needs write support.
-	 * The inode's perms must say it's ok, 
-	 * and we must have a store method.
-	 */
-	if (file->f_mode & FMODE_WRITE) {
-		if (!(inode->i_mode & S_IWUGO) || !attr->write)
-			goto Eaccess;
-	}
-
-	/* File needs read support.
-	 * The inode's perms must say it's ok, and we there
-	 * must be a show method for it.
-	 */
-	if (file->f_mode & FMODE_READ) {
-		if (!(inode->i_mode & S_IRUGO) || !attr->read)
-			goto Eaccess;
-	}
-
-	buffer = kmalloc(sizeof(struct sysfs_bin_buffer),GFP_KERNEL);
-	if (buffer) {
-		memset(buffer,0,sizeof(struct sysfs_bin_buffer));
-		file->private_data = buffer;
-	} else
-		error = -ENOMEM;
-	goto Done;
-
- Einval:
-	error = -EINVAL;
-	goto Done;
- Eaccess:
 	error = -EACCES;
+	if ((file->f_mode & FMODE_WRITE) && !attr->write)
+		goto Done;
+	if ((file->f_mode & FMODE_READ) && !attr->read)
+		goto Done;
+
+	error = -ENOMEM;
+	file->private_data = kmalloc(attr->size, GFP_KERNEL);
+	if (!file->private_data)
+		goto Done;
+
+	error = 0;
+
  Done:
 	if (error && kobj)
 		kobject_put(kobj);
 	return error;
 }
 
-static int open(struct inode * inode, struct file * file)
-{
-	return check_perm(inode,file);
-}
-
 static int release(struct inode * inode, struct file * file)
 {
 	struct kobject * kobj = file->f_dentry->d_parent->d_fsdata;
@@ -173,8 +121,7 @@
 
 	if (kobj) 
 		kobject_put(kobj);
-	if (buffer)
-		kfree(buffer);
+	kfree(buffer);
 	return 0;
 }
 
diff -Nru a/fs/sysv/dir.c b/fs/sysv/dir.c
--- a/fs/sysv/dir.c	Mon Oct  7 13:50:42 2002
+++ b/fs/sysv/dir.c	Sun May  4 22:49:54 2003
@@ -116,7 +116,7 @@
 
 done:
 	filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset;
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 	unlock_kernel();
 	return 0;
 }
diff -Nru a/fs/udf/dir.c b/fs/udf/dir.c
--- a/fs/udf/dir.c	Tue Feb 25 10:47:06 2003
+++ b/fs/udf/dir.c	Sun May  4 22:49:54 2003
@@ -98,7 +98,7 @@
 	}
 
 	result = do_udf_readdir(dir, filp, filldir, dirent);
-	UPDATE_ATIME(dir);
+	update_atime(dir);
 	unlock_kernel();
  	return result;
 }
diff -Nru a/fs/ufs/dir.c b/fs/ufs/dir.c
--- a/fs/ufs/dir.c	Wed Feb  5 08:27:03 2003
+++ b/fs/ufs/dir.c	Sun May  4 22:49:54 2003
@@ -166,7 +166,7 @@
 		offset = 0;
 		brelse (bh);
 	}
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 	unlock_kernel();
 	return 0;
 }
diff -Nru a/fs/xattr.c b/fs/xattr.c
--- a/fs/xattr.c	Tue Feb 25 08:21:08 2003
+++ b/fs/xattr.c	Tue May  6 07:02:55 2003
@@ -79,15 +79,16 @@
 
 	error = -EOPNOTSUPP;
 	if (d->d_inode->i_op && d->d_inode->i_op->setxattr) {
+		down(&d->d_inode->i_sem);
 		error = security_inode_setxattr(d, kname, kvalue, size, flags);
 		if (error)
 			goto out;
-		down(&d->d_inode->i_sem);
 		error = d->d_inode->i_op->setxattr(d, kname, kvalue, size, flags);
+		if (!error)
+			security_inode_post_setxattr(d, kname, kvalue, size, flags);
+out:
 		up(&d->d_inode->i_sem);
 	}
-
-out:
 	xattr_free(kvalue, size);
 	return error;
 }
diff -Nru a/fs/xfs/Makefile b/fs/xfs/Makefile
--- a/fs/xfs/Makefile	Fri May  2 12:36:00 2003
+++ b/fs/xfs/Makefile	Mon May 19 11:56:12 2003
@@ -132,7 +132,6 @@
 # Objects in support/
 xfs-y				+= $(addprefix support/, \
 				   debug.o \
-				   kmem.o \
 				   ktrace.o \
 				   move.o \
 				   mrlock.o \
diff -Nru a/fs/xfs/linux/xfs_globals.c b/fs/xfs/linux/xfs_globals.c
--- a/fs/xfs/linux/xfs_globals.c	Fri May  2 13:01:25 2003
+++ b/fs/xfs/linux/xfs_globals.c	Mon May 19 11:29:41 2003
@@ -48,7 +48,7 @@
  * Tunable XFS parameters.  xfs_params is required even when CONFIG_SYSCTL=n,
  * other XFS code uses these values.
  */
-xfs_param_t xfs_params = { 0, 1, 0, 0, 0, 3 };
+xfs_param_t xfs_params = { 0, 1, 0, 0, 0, 3, 30 * HZ };
 
 /*
  * Global system credential structure.
diff -Nru a/fs/xfs/linux/xfs_iops.c b/fs/xfs/linux/xfs_iops.c
--- a/fs/xfs/linux/xfs_iops.c	Fri May  2 13:01:25 2003
+++ b/fs/xfs/linux/xfs_iops.c	Mon May 19 11:29:41 2003
@@ -152,8 +152,6 @@
 			ip->i_rdev = to_kdev_t(rdev);
 		validate_fields(dir);
 		d_instantiate(dentry, ip);
-		mark_inode_dirty_sync(ip);
-		mark_inode_dirty_sync(dir);
 	}
 
 	if (!error && have_default_acl) {
@@ -240,7 +238,6 @@
 		VN_HOLD(vp);
 		validate_fields(ip);
 		d_instantiate(dentry, ip);
-		mark_inode_dirty_sync(ip);
 	}
 	return -error;
 }
@@ -261,8 +258,6 @@
 	if (!error) {
 		validate_fields(dir);	/* For size only */
 		validate_fields(inode);
-		mark_inode_dirty_sync(inode);
-		mark_inode_dirty_sync(dir);
 	}
 
 	return -error;
@@ -296,8 +291,6 @@
 		d_instantiate(dentry, ip);
 		validate_fields(dir);
 		validate_fields(ip); /* size needs update */
-		mark_inode_dirty_sync(ip);
-		mark_inode_dirty_sync(dir);
 	}
 	return -error;
 }
@@ -315,8 +308,6 @@
 	if (!error) {
 		validate_fields(inode);
 		validate_fields(dir);
-		mark_inode_dirty_sync(inode);
-		mark_inode_dirty_sync(dir);
 	}
 	return -error;
 }
@@ -346,7 +337,6 @@
 	validate_fields(odir);
 	if (ndir != odir)
 		validate_fields(ndir);
-	mark_inode_dirty(ndir);
 	return 0;
 }
 
@@ -520,7 +510,6 @@
 
 	if (!error) {
 		vn_revalidate(vp);
-		mark_inode_dirty_sync(inode);
 	}
 	return error;
 }
diff -Nru a/fs/xfs/linux/xfs_lrw.c b/fs/xfs/linux/xfs_lrw.c
--- a/fs/xfs/linux/xfs_lrw.c	Fri May  2 13:01:25 2003
+++ b/fs/xfs/linux/xfs_lrw.c	Mon May 19 12:07:04 2003
@@ -887,29 +887,23 @@
 	return (xfs_bioerror_relse(bp));
 }
 
-
-void
-XFS_bflush(xfs_buftarg_t *target)
-{
-	pagebuf_delwri_flush(target, PBDF_WAIT, NULL);
-}
-
 /*
- * If the underlying (log or data) device is readonly, there are some
+ * If the underlying (data/log/rt) device is readonly, there are some
  * operations that cannot proceed.
  */
 int
-xfs_dev_is_read_only(xfs_mount_t *mp, char *message)
+xfs_dev_is_read_only(
+	xfs_mount_t		*mp,
+	char			*message)
 {
-	if (bdev_read_only(mp->m_ddev_targp->pbr_bdev) ||
-	    bdev_read_only(mp->m_logdev_targp->pbr_bdev) ||
-	   (mp->m_rtdev_targp && bdev_read_only(mp->m_rtdev_targp->pbr_bdev))) {
+	if (xfs_readonly_buftarg(mp->m_ddev_targp) ||
+	    xfs_readonly_buftarg(mp->m_logdev_targp) ||
+	    (mp->m_rtdev_targp && xfs_readonly_buftarg(mp->m_rtdev_targp))) {
 		cmn_err(CE_NOTE,
 			"XFS: %s required on read-only device.", message);
 		cmn_err(CE_NOTE,
 			"XFS: write access unavailable, cannot proceed.");
 		return EROFS;
 	}
-
 	return 0;
 }
diff -Nru a/fs/xfs/linux/xfs_super.c b/fs/xfs/linux/xfs_super.c
--- a/fs/xfs/linux/xfs_super.c	Fri May  2 13:01:25 2003
+++ b/fs/xfs/linux/xfs_super.c	Mon May 19 12:07:04 2003
@@ -217,13 +217,27 @@
 }
 
 void
-xfs_free_buftarg(
+xfs_flush_buftarg(
 	xfs_buftarg_t		*btp)
 {
 	pagebuf_delwri_flush(btp, PBDF_WAIT, NULL);
+}
+
+void
+xfs_free_buftarg(
+	xfs_buftarg_t		*btp)
+{
+	xfs_flush_buftarg(btp);
 	kmem_free(btp, sizeof(*btp));
 }
 
+int
+xfs_readonly_buftarg(
+	xfs_buftarg_t		*btp)
+{
+	return bdev_read_only(btp->pbr_bdev);
+}
+
 void
 xfs_relse_buftarg(
 	xfs_buftarg_t		*btp)
@@ -331,9 +345,10 @@
 }
 
 /*
- * We do not actually write the inode here, just mark the
- * super block dirty so that sync_supers calls us and
- * forces the flush.
+ * Attempt to flush the inode, this will actually fail
+ * if the inode is pinned, but we dirty the inode again
+ * at the point when it is unpinned after a log write,
+ * since this is when the inode itself becomes flushable. 
  */
 STATIC void
 linvfs_write_inode(
@@ -348,8 +363,6 @@
 		if (sync)
 			flags |= FLUSH_SYNC;
 		VOP_IFLUSH(vp, flags, error);
-		if (error == EAGAIN)
-			inode->i_sb->s_dirt = 1;
 	}
 }
 
@@ -369,6 +382,61 @@
 	}
 }
 
+
+#define SYNCD_FLAGS	(SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR)
+
+STATIC int
+syncd(void *arg)
+{
+	vfs_t			*vfsp = (vfs_t *) arg;
+	int			error;
+
+	daemonize("xfs_syncd");
+
+	vfsp->vfs_sync_task = current;
+	wmb();
+	wake_up(&vfsp->vfs_wait_sync_task);
+
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(xfs_params.sync_interval);
+		if (vfsp->vfs_flag & VFS_UMOUNT)
+			break;
+		if (vfsp->vfs_flag & VFS_RDONLY)
+			continue;
+		VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error);
+	}
+
+	vfsp->vfs_sync_task = NULL;
+	wmb();
+	wake_up(&vfsp->vfs_wait_sync_task);
+
+	return 0;
+}
+
+STATIC int
+linvfs_start_syncd(vfs_t *vfsp)
+{
+	int pid;
+
+	pid = kernel_thread(syncd, (void *) vfsp,
+			CLONE_VM | CLONE_FS | CLONE_FILES);
+	if (pid < 0)
+		return pid;
+	wait_event(vfsp->vfs_wait_sync_task, vfsp->vfs_sync_task);
+	return 0;
+}
+
+STATIC void
+linvfs_stop_syncd(vfs_t *vfsp)
+{
+	vfsp->vfs_flag |= VFS_UMOUNT;
+	wmb();
+
+	wake_up_process(vfsp->vfs_sync_task);
+	wait_event(vfsp->vfs_wait_sync_task, !vfsp->vfs_sync_task);
+}
+
 STATIC void
 linvfs_put_super(
 	struct super_block	*sb)
@@ -376,8 +444,9 @@
 	vfs_t			*vfsp = LINVFS_GET_VFS(sb);
 	int			error;
 
+	linvfs_stop_syncd(vfsp);
 	VFS_SYNC(vfsp, SYNC_ATTR|SYNC_DELWRI, NULL, error);
-	if (error == 0)
+	if (!error)
 		VFS_UNMOUNT(vfsp, 0, NULL, error);
 	if (error) {
 		printk("XFS unmount got error %d\n", error);
@@ -395,10 +464,13 @@
 	vfs_t			*vfsp = LINVFS_GET_VFS(sb);
 	int			error;
 
-	sb->s_dirt = 0;
-	if (sb->s_flags & MS_RDONLY)
+	if (sb->s_flags & MS_RDONLY) {
+		sb->s_dirt = 0; /* paranoia */
 		return;
-	VFS_SYNC(vfsp, SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR, NULL, error);
+	}
+	/* Push the log and superblock a little */
+	VFS_SYNC(vfsp, SYNC_FSDATA, NULL, error);
+	sb->s_dirt = 0;
 }
 
 STATIC int
@@ -424,12 +496,8 @@
 	int			error;
 
 	VFS_PARSEARGS(vfsp, options, args, 1, error);
-	if (error)
-		goto out;
-
-	VFS_MNTUPDATE(vfsp, flags, args, error);
-
-out:
+	if (!error)
+		VFS_MNTUPDATE(vfsp, flags, args, error);
 	kmem_free(args, sizeof(*args));
 	return error;
 }
@@ -438,11 +506,10 @@
 linvfs_freeze_fs(
 	struct super_block	*sb)
 {
-	vfs_t			*vfsp;
+	vfs_t			*vfsp = LINVFS_GET_VFS(sb);
 	vnode_t			*vp;
 	int			error;
 
-	vfsp = LINVFS_GET_VFS(sb);
 	if (sb->s_flags & MS_RDONLY)
 		return;
 	VFS_ROOT(vfsp, &vp, error);
@@ -454,11 +521,10 @@
 linvfs_unfreeze_fs(
 	struct super_block	*sb)
 {
-	vfs_t			*vfsp;
+	vfs_t			*vfsp = LINVFS_GET_VFS(sb);
 	vnode_t			*vp;
 	int			error;
 
-	vfsp = LINVFS_GET_VFS(sb);
 	VFS_ROOT(vfsp, &vp, error);
 	VOP_IOCTL(vp, LINVFS_GET_IP(vp), NULL, XFS_IOC_THAW, 0, error);
 	VN_RELE(vp);
@@ -652,7 +718,8 @@
 		goto fail_vnrele;
 	if (is_bad_inode(sb->s_root->d_inode))
 		goto fail_vnrele;
-
+	if (linvfs_start_syncd(vfsp))
+		goto fail_vnrele;
 	vn_trace_exit(rootvp, __FUNCTION__, (inst_t *)__return_address);
 
 	kmem_free(args, sizeof(*args));
diff -Nru a/fs/xfs/linux/xfs_super.h b/fs/xfs/linux/xfs_super.h
--- a/fs/xfs/linux/xfs_super.h	Fri May  2 12:51:20 2003
+++ b/fs/xfs/linux/xfs_super.h	Mon May 19 12:07:04 2003
@@ -101,7 +101,8 @@
 extern struct pb_target *xfs_alloc_buftarg(struct block_device *);
 extern void xfs_relse_buftarg(struct pb_target *);
 extern void xfs_free_buftarg(struct pb_target *);
-
+extern void xfs_flush_buftarg(struct pb_target *);
+extern int xfs_readonly_buftarg(struct pb_target *);
 extern void xfs_setsize_buftarg(struct pb_target *, unsigned int, unsigned int);
 extern unsigned int xfs_getsize_buftarg(struct pb_target *);
 
diff -Nru a/fs/xfs/linux/xfs_syncd.c b/fs/xfs/linux/xfs_syncd.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/fs/xfs/linux/xfs_syncd.c	Mon May 19 11:41:59 2003
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it would be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * Further, this software is distributed without any warranty that it is
+ * free of the rightful claim of any third person regarding infringement
+ * or the like.  Any license provided herein, whether implied or
+ * otherwise, applies only to this software file.  Patent licenses, if
+ * any, provided herein do not apply to combinations of this program with
+ * other software, or any other product whatsoever.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ *
+ * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
+ * Mountain View, CA  94043, or:
+ *
+ * http://www.sgi.com
+ *
+ * For further information regarding this notice, see:
+ *
+ * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
+ */
+
+#include <xfs.h>
+
+#define SYNCD_FLAGS	(SYNC_FSDATA|SYNC_BDFLUSH|SYNC_ATTR)
+
+int syncd(void *arg)
+{
+	vfs_t			*vfsp = (vfs_t *) arg;
+	int			error;
+
+	daemonize("xfs_syncd");
+
+	vfsp->vfs_sync_task = current;
+	wmb();
+	wake_up(&vfsp->vfs_wait_sync_task);
+
+	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(xfs_params.sync_interval);
+		if (vfsp->vfs_flag & VFS_UMOUNT)
+			break;
+		if (vfsp->vfs_flag & VFS_RDONLY);
+			continue;
+		VFS_SYNC(vfsp, SYNCD_FLAGS, NULL, error);
+	}
+
+	vfsp->vfs_sync_task = NULL;
+	wmb();
+	wake_up(&vfsp->vfs_wait_sync_task);
+
+	return 0;
+}
+
+int
+linvfs_start_syncd(vfs_t *vfsp)
+{
+	int pid;
+
+	pid = kernel_thread(syncd, (void *) vfsp,
+			CLONE_VM | CLONE_FS | CLONE_FILES);
+	if (pid < 0)
+		return pid;
+	wait_event(vfsp->vfs_wait_sync_task, vfsp->vfs_sync_task);
+	return 0;
+}
+
+void
+linvfs_stop_syncd(vfs_t *vfsp)
+{
+	vfsp->vfs_flag |= VFS_UMOUNT;
+	wmb();
+
+	wake_up_process(vfsp->vfs_sync_task);
+	wait_event(vfsp->vfs_wait_sync_task, !vfsp->vfs_sync_task);
+}
diff -Nru a/fs/xfs/linux/xfs_sysctl.c b/fs/xfs/linux/xfs_sysctl.c
--- a/fs/xfs/linux/xfs_sysctl.c	Fri May  2 13:01:25 2003
+++ b/fs/xfs/linux/xfs_sysctl.c	Mon May 19 11:29:41 2003
@@ -36,8 +36,8 @@
 #include <linux/proc_fs.h>
 
 
-STATIC ulong xfs_min[XFS_PARAM] = { 0, 0, 0, 0, 0,   0 };
-STATIC ulong xfs_max[XFS_PARAM] = { 1, 1, 1, 1, 127, 3 };
+STATIC ulong xfs_min[XFS_PARAM] = { 0, 0, 0, 0, 0,   0, HZ };
+STATIC ulong xfs_max[XFS_PARAM] = { 1, 1, 1, 1, 127, 3, HZ * 60 };
 
 static struct ctl_table_header *xfs_table_header;
 
@@ -91,6 +91,10 @@
 	{XFS_ERRLEVEL, "error_level", &xfs_params.error_level,
 	sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
 	&sysctl_intvec, NULL, &xfs_min[5], &xfs_max[5]},
+
+	{XFS_SYNC_INTERVAL, "sync_interval", &xfs_params.sync_interval,
+	sizeof(ulong), 0644, NULL, &proc_doulongvec_minmax,
+	&sysctl_intvec, NULL, &xfs_min[6], &xfs_max[6]},
 
 	{0}
 };
diff -Nru a/fs/xfs/linux/xfs_sysctl.h b/fs/xfs/linux/xfs_sysctl.h
--- a/fs/xfs/linux/xfs_sysctl.h	Fri May  2 12:36:00 2003
+++ b/fs/xfs/linux/xfs_sysctl.h	Mon May 19 11:29:41 2003
@@ -49,6 +49,7 @@
 	ulong	symlink_mode;	/* Symlink creat mode affected by umask. */
 	ulong	panic_mask;	/* bitmask to specify panics on errors.  */
 	ulong	error_level;	/* Degree of reporting for internal probs*/
+	ulong	sync_interval;	/* time between sync calls		 */
 } xfs_param_t;
 
 /*
@@ -73,6 +74,7 @@
 	XFS_SYMLINK_MODE = 4,
 	XFS_PANIC_MASK = 5,
 	XFS_ERRLEVEL = 6,
+	XFS_SYNC_INTERVAL = 7,
 };
 
 extern xfs_param_t	xfs_params;
diff -Nru a/fs/xfs/linux/xfs_vfs.c b/fs/xfs/linux/xfs_vfs.c
--- a/fs/xfs/linux/xfs_vfs.c	Fri May  2 13:01:25 2003
+++ b/fs/xfs/linux/xfs_vfs.c	Mon May 19 11:42:00 2003
@@ -238,6 +238,7 @@
 
 	vfsp = kmem_zalloc(sizeof(vfs_t), KM_SLEEP);
 	bhv_head_init(VFS_BHVHEAD(vfsp), "vfs");
+	init_waitqueue_head(&vfsp->vfs_wait_sync_task);
 	return vfsp;
 }
 
diff -Nru a/fs/xfs/linux/xfs_vfs.h b/fs/xfs/linux/xfs_vfs.h
--- a/fs/xfs/linux/xfs_vfs.h	Fri May  2 12:51:20 2003
+++ b/fs/xfs/linux/xfs_vfs.h	Mon May 19 11:42:00 2003
@@ -48,6 +48,8 @@
 	fsid_t			*vfs_altfsid;	/* An ID fixed for life of FS */
 	bhv_head_t		vfs_bh;		/* head of vfs behavior chain */
 	struct super_block	*vfs_super;	/* Linux superblock structure */
+	struct task_struct	*vfs_sync_task;
+	wait_queue_head_t	vfs_wait_sync_task;
 } vfs_t;
 
 #define vfs_fbhv		vfs_bh.bh_first	/* 1st on vfs behavior chain */
@@ -78,7 +80,8 @@
 #define VFS_RDONLY		0x0001	/* read-only vfs */
 #define VFS_GRPID		0x0002	/* group-ID assigned from directory */
 #define VFS_DMI			0x0004	/* filesystem has the DMI enabled */
-#define VFS_END			0x0004	/* max flag */
+#define VFS_UMOUNT		0x0008	/* unmount in progress */
+#define VFS_END			0x0008	/* max flag */
 
 #define SYNC_ATTR		0x0001	/* sync attributes */
 #define SYNC_CLOSE		0x0002	/* close file system down */
@@ -86,6 +89,7 @@
 #define SYNC_WAIT		0x0008	/* wait for i/o to complete */
 #define SYNC_FSDATA		0x0020	/* flush fs data (e.g. superblocks) */
 #define SYNC_BDFLUSH		0x0010	/* BDFLUSH is calling -- don't block */
+
 
 typedef int	(*vfs_mount_t)(bhv_desc_t *,
 				struct xfs_mount_args *, struct cred *);
diff -Nru a/fs/xfs/linux/xfs_vnode.h b/fs/xfs/linux/xfs_vnode.h
--- a/fs/xfs/linux/xfs_vnode.h	Fri May  2 12:36:00 2003
+++ b/fs/xfs/linux/xfs_vnode.h	Mon May 19 11:29:41 2003
@@ -562,8 +562,7 @@
 	(!list_empty(&(LINVFS_GET_IP(vp)->i_mapping->i_mmap_shared))))
 #define VN_CACHED(vp)	(LINVFS_GET_IP(vp)->i_mapping->nrpages)
 #define VN_DIRTY(vp)	(!list_empty(&(LINVFS_GET_IP(vp)->i_mapping->dirty_pages)))
-#define VMODIFY(vp)	{ VN_FLAGSET(vp, VMODIFIED); \
-			mark_inode_dirty(LINVFS_GET_IP(vp)); }
+#define VMODIFY(vp)	VN_FLAGSET(vp, VMODIFIED)
 #define VUNMODIFY(vp)	VN_FLAGCLR(vp, VMODIFIED)
 
 /*
diff -Nru a/fs/xfs/pagebuf/page_buf.c b/fs/xfs/pagebuf/page_buf.c
--- a/fs/xfs/pagebuf/page_buf.c	Fri May  2 12:53:58 2003
+++ b/fs/xfs/pagebuf/page_buf.c	Mon May 19 12:00:43 2003
@@ -68,7 +68,7 @@
 #define BN_ALIGN_MASK	((1 << (PAGE_CACHE_SHIFT - BBSHIFT)) - 1)
 
 #ifndef GFP_READAHEAD
-#define GFP_READAHEAD	__GFP_NOWARN
+#define GFP_READAHEAD	(__GFP_NOWARN|__GFP_NORETRY)
 #endif
 
 /*
@@ -76,11 +76,11 @@
  */
 
 #ifdef PAGEBUF_TRACE
-static	spinlock_t		pb_trace_lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t		pb_trace_lock = SPIN_LOCK_UNLOCKED;
 struct pagebuf_trace_buf	pb_trace;
 EXPORT_SYMBOL(pb_trace);
 EXPORT_SYMBOL(pb_trace_func);
-#define CIRC_INC(i)     (((i) + 1) & (PB_TRACE_BUFSIZE - 1))
+#define CIRC_INC(i)	(((i) + 1) & (PB_TRACE_BUFSIZE - 1))
 
 void
 pb_trace_func(
@@ -181,7 +181,7 @@
 	 * dev_t is 16 bits, loff_t is always 64 bits
 	 */
 	base ^= dev;
-	for (bit = hval = 0; base != 0 && bit < sizeof(base) * 8; bit += NBITS) {
+	for (bit = hval = 0; base && bit < sizeof(base) * 8; bit += NBITS) {
 		hval ^= (int)base & (NHASH-1);
 		base >>= NBITS;
 	}
@@ -189,18 +189,18 @@
 }
 
 /*
- * Mapping of multi-page buffers into contingous virtual space
+ * Mapping of multi-page buffers into contiguous virtual space
  */
 
 STATIC void *pagebuf_mapout_locked(page_buf_t *);
 
-STATIC  spinlock_t              as_lock = SPIN_LOCK_UNLOCKED;
 typedef struct a_list {
-	void	*vm_addr;
+	void		*vm_addr;
 	struct a_list	*next;
 } a_list_t;
-STATIC  a_list_t	*as_free_head;
-STATIC  int		as_list_len;
+STATIC a_list_t		*as_free_head;
+STATIC int		as_list_len;
+STATIC spinlock_t	as_lock = SPIN_LOCK_UNLOCKED;
 
 
 /*
@@ -1897,13 +1897,6 @@
 }
 #endif  /* CONFIG_PROC_FS */
 
-STATIC void
-pagebuf_shaker(void)
-{
-	pagebuf_daemon_wakeup(1);
-}
-
-
 /*
  *	Initialization and Termination
  */
@@ -1943,7 +1936,6 @@
 #endif
 
 	pagebuf_daemon_start();
-	kmem_shake_register(pagebuf_shaker);
 	return 0;
 }
 
@@ -1959,7 +1951,6 @@
 	pagebuf_daemon_stop();
 
 	kmem_cache_destroy(pagebuf_cache);
-	kmem_shake_deregister(pagebuf_shaker);
 
 	unregister_sysctl_table(pagebuf_table_header);
 #ifdef  CONFIG_PROC_FS
diff -Nru a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
--- a/fs/xfs/quota/xfs_qm.c	Fri May  2 13:01:25 2003
+++ b/fs/xfs/quota/xfs_qm.c	Mon May 19 11:56:12 2003
@@ -88,7 +88,7 @@
 STATIC int	xfs_qm_quotacheck(xfs_mount_t *);
 
 STATIC int	xfs_qm_init_quotainos(xfs_mount_t *);
-STATIC void	xfs_qm_shake(void);
+STATIC int	xfs_qm_shake(int, unsigned int);
 
 #ifdef DEBUG
 extern mutex_t	qcheck_lock;
@@ -112,6 +112,8 @@
 #define XQM_LIST_PRINT(l, NXT, title) do { } while (0)
 #endif
 
+struct shrinker *xfs_qm_shrinker;
+
 /*
  * Initialize the XQM structure.
  * Note that there is not one quota manager per file system.
@@ -161,7 +163,7 @@
 	} else
 		xqm->qm_dqzone = qm_dqzone;
 
-	kmem_shake_register(xfs_qm_shake);
+	xfs_qm_shrinker = set_shrinker(DEFAULT_SEEKS, xfs_qm_shake);
 
 	/*
 	 * The t_dqinfo portion of transactions.
@@ -193,7 +195,8 @@
 
 	ASSERT(xqm != NULL);
 	ASSERT(xqm->qm_nrefs == 0);
-	kmem_shake_deregister(xfs_qm_shake);
+
+	remove_shrinker(xfs_qm_shrinker);
 	hsize = xqm->qm_dqhashmask + 1;
 	for (i = 0; i < hsize; i++) {
 		xfs_qm_list_destroy(&(xqm->qm_usr_dqhtable[i]));
@@ -2088,7 +2091,7 @@
 			xfs_dqunlock(dqp);
 			xfs_qm_freelist_unlock(xfs_Gqm);
 			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-				return (nreclaimed != howmany);
+				goto out;
 			XQM_STATS_INC(xqmstats.xs_qm_dqwants);
 			goto tryagain;
 		}
@@ -2163,7 +2166,7 @@
 			XFS_DQ_HASH_UNLOCK(hash);
 			xfs_qm_freelist_unlock(xfs_Gqm);
 			if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
-				return (nreclaimed != howmany);
+				goto out;
 			goto tryagain;
 		}
 		xfs_dqtrace_entry(dqp, "DQSHAKE: UNLINKING");
@@ -2188,7 +2191,8 @@
 		dqp = nextdqp;
 	}
 	xfs_qm_freelist_unlock(xfs_Gqm);
-	return (nreclaimed != howmany);
+ out:
+	return nreclaimed;
 }
 
 
@@ -2197,13 +2201,15 @@
  * running low.
  */
 /* ARGSUSED */
-STATIC void
-xfs_qm_shake(void)
+STATIC int
+xfs_qm_shake(int nr_to_scan, unsigned int gfp_mask)
 {
 	int	ndqused, nfree, n;
 
+	if (!(gfp_mask & __GFP_WAIT))
+		return 0;
 	if (!xfs_Gqm)
-		return;
+		return 0;
 
 	nfree = xfs_Gqm->qm_dqfreelist.qh_nelems; /* free dquots */
 	/* incore dquots in all f/s's */
@@ -2212,12 +2218,12 @@
 	ASSERT(ndqused >= 0);
 
 	if (nfree <= ndqused && nfree < ndquot)
-		return;
+		return 0;
 
 	ndqused *= xfs_Gqm->qm_dqfree_ratio;	/* target # of free dquots */
 	n = nfree - ndqused - ndquot;		/* # over target */
 
-	(void) xfs_qm_shake_freelist(MAX(nfree, n));
+	return xfs_qm_shake_freelist(MAX(nfree, n));
 }
 
 
diff -Nru a/fs/xfs/support/kmem.h b/fs/xfs/support/kmem.h
--- a/fs/xfs/support/kmem.h	Fri May  2 12:36:01 2003
+++ b/fs/xfs/support/kmem.h	Mon May 19 11:56:12 2003
@@ -32,31 +32,118 @@
 #ifndef __XFS_SUPPORT_KMEM_H__
 #define __XFS_SUPPORT_KMEM_H__
 
+#include <linux/mm.h>
+#include <linux/highmem.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 
 /*
- * memory management routines
+ * Cutoff point to use vmalloc instead of kmalloc.
  */
-#define KM_SLEEP	0x0001
-#define KM_NOSLEEP	0x0002
-#define KM_NOFS		0x0004
+#define MAX_SLAB_SIZE	0x10000
 
+/*
+ * XFS uses slightly different names for these due to the
+ * IRIX heritage.
+ */
 #define	kmem_zone	kmem_cache_s
 #define kmem_zone_t	kmem_cache_t
 
-extern kmem_zone_t  *kmem_zone_init(int, char *);
-extern void	    *kmem_zone_zalloc(kmem_zone_t *, int);
-extern void	    *kmem_zone_alloc(kmem_zone_t *, int);
-extern void         kmem_zone_free(kmem_zone_t *, void *);
-
-extern void	    *kmem_alloc(size_t, int);
-extern void	    *kmem_realloc(void *, size_t, size_t, int);
-extern void	    *kmem_zalloc(size_t, int);
-extern void         kmem_free(void *, size_t);
+#define KM_SLEEP	0x0001
+#define KM_NOSLEEP	0x0002
+#define KM_NOFS		0x0004
 
-typedef void	    (*kmem_shake_func_t)(void);
 
-extern void	    kmem_shake_register(kmem_shake_func_t);
-extern void	    kmem_shake_deregister(kmem_shake_func_t);
+/*
+ * XXX get rid of the unconditional  __GFP_NOFAIL by adding
+ * a KM_FAIL flag and using it where we're allowed to fail.
+ */
+static __inline unsigned int
+flag_convert(int flags)
+{
+#if DEBUG
+	if (unlikely(flags & ~(KM_SLEEP|KM_NOSLEEP|KM_NOFS))) {
+		printk(KERN_WARNING
+		    "XFS: memory allocation with wrong flags (%x)\n", flags);
+		BUG();
+	}
+#endif
+
+	if (flags & KM_NOSLEEP)
+		return GFP_ATOMIC;
+	/* If we're in a transaction, FS activity is not ok */
+	else if ((current->flags & PF_FSTRANS) || (flags & KM_NOFS))
+		return GFP_NOFS | __GFP_NOFAIL;
+	return GFP_KERNEL | __GFP_NOFAIL;
+}
+
+static __inline void *
+kmem_alloc(size_t size, int flags)
+{
+	if (unlikely(MAX_SLAB_SIZE < size))
+		/* Avoid doing filesystem sensitive stuff to get this */
+		return __vmalloc(size, flag_convert(flags), PAGE_KERNEL);
+	return kmalloc(size, flag_convert(flags));
+}
+
+static __inline void *
+kmem_zalloc(size_t size, int flags)
+{
+	void *ptr = kmem_alloc(size, flags);
+	if (likely(ptr != NULL))
+		memset(ptr, 0, size);
+	return ptr;
+}
+
+static __inline void
+kmem_free(void *ptr, size_t size)
+{
+	if (unlikely((unsigned long)ptr < VMALLOC_START ||
+		     (unsigned long)ptr >= VMALLOC_END))
+		kfree(ptr);
+	else
+		vfree(ptr);
+}
+
+static __inline void *
+kmem_realloc(void *ptr, size_t newsize, size_t oldsize, int flags)
+{
+	void *new = kmem_alloc(newsize, flags);
+
+	if (likely(ptr != NULL)) {
+		if (likely(new != NULL))
+			memcpy(new, ptr, min(oldsize, newsize));
+		kmem_free(ptr, oldsize);
+	}
+
+	return new;
+}
+
+static __inline kmem_zone_t *
+kmem_zone_init(int size, char *zone_name)
+{
+	return kmem_cache_create(zone_name, size, 0, 0, NULL, NULL);
+}
+
+static __inline void *
+kmem_zone_alloc(kmem_zone_t *zone, int flags)
+{
+	return kmem_cache_alloc(zone, flag_convert(flags));
+}
+
+static __inline void *
+kmem_zone_zalloc(kmem_zone_t *zone, int flags)
+{
+	void *ptr = kmem_zone_alloc(zone, flags);
+	if (likely(ptr != NULL))
+		memset(ptr, 0, kmem_cache_size(zone));
+	return ptr;
+}
+
+static __inline void
+kmem_zone_free(kmem_zone_t *zone, void *ptr)
+{
+	kmem_cache_free(zone, ptr);
+}
 
 #endif /* __XFS_SUPPORT_KMEM_H__ */
diff -Nru a/fs/xfs/xfs_ag.h b/fs/xfs/xfs_ag.h
--- a/fs/xfs/xfs_ag.h	Fri May  2 12:36:08 2003
+++ b/fs/xfs/xfs_ag.h	Mon May 19 12:04:58 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -185,9 +185,8 @@
 #endif
 #define XFS_AGFL_SIZE(mp)	((mp)->m_sb.sb_sectsize / sizeof(xfs_agblock_t))
 
-/* -- nathans TODO ... use of BBSIZE here - should be sector size -- */
 typedef struct xfs_agfl {
-	xfs_agblock_t	agfl_bno[BBSIZE/sizeof(xfs_agblock_t)];
+	xfs_agblock_t	agfl_bno[1];	/* actually XFS_AGFL_SIZE(mp) */
 } xfs_agfl_t;
 
 /*
diff -Nru a/fs/xfs/xfs_buf.h b/fs/xfs/xfs_buf.h
--- a/fs/xfs/xfs_buf.h	Wed Mar 26 10:25:07 2003
+++ b/fs/xfs/xfs_buf.h	Mon May 19 12:07:04 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -283,7 +283,6 @@
 	return error;
 }
 
-
 #define XFS_bdwrite(pb)		     \
 	    pagebuf_iostart(pb, PBF_DELWRI | PBF_ASYNC)
 
@@ -307,15 +306,15 @@
  * of its metadata.
  */
 
-extern void XFS_bflush(xfs_buftarg_t *);
-#define xfs_binval(buftarg) XFS_bflush(buftarg)
+#define xfs_binval(buftarg)	xfs_flush_buftarg(buftarg)
+
+#define XFS_bflush(buftarg)	xfs_flush_buftarg(buftarg)
 
 #define xfs_incore_relse(buftarg,delwri_only,wait)	\
 	xfs_relse_buftarg(buftarg)
 
 #define xfs_baread(target, rablkno, ralen)  \
-	pagebuf_readahead((target), (rablkno), \
-			  (ralen), PBF_DONT_BLOCK)
+	pagebuf_readahead((target), (rablkno), (ralen), PBF_DONT_BLOCK)
 
 #define XFS_getrbuf(sleep,mp)	\
 	pagebuf_get_empty((mp)->m_ddev_targp)
diff -Nru a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c
--- a/fs/xfs/xfs_iget.c	Fri May  2 13:01:27 2003
+++ b/fs/xfs/xfs_iget.c	Mon May 19 11:29:41 2003
@@ -252,6 +252,11 @@
 			if (newnode) {
 				xfs_iocore_inode_reinit(ip);
 			}
+
+			XFS_MOUNT_ILOCK(mp);
+			list_del_init(&ip->i_reclaim);
+			XFS_MOUNT_IUNLOCK(mp);
+
 			vn_trace_exit(vp, "xfs_iget.found",
 						(inst_t *)__return_address);
 			goto return_ip;
@@ -467,8 +472,10 @@
 			}
 
 			bdp = vn_bhv_lookup(VN_BHV_HEAD(vp), &xfs_vnodeops);
-			if (bdp == NULL)
+			if (bdp == NULL) {
+				XFS_STATS_INC(xfsstats.xs_ig_dup);
 				goto inode_allocate;
+			}
 			ip = XFS_BHVTOI(bdp);
 			if (lock_flags != 0)
 				xfs_ilock(ip, lock_flags);
@@ -719,6 +726,9 @@
 			mp->m_inodes = iq;
 		}
 	}
+
+	/* Deal with the deleted inodes list */
+	list_del_init(&ip->i_reclaim);
 
 	mp->m_ireclaims++;
 	XFS_MOUNT_IUNLOCK(mp);
diff -Nru a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
--- a/fs/xfs/xfs_inode.c	Fri May  2 13:01:27 2003
+++ b/fs/xfs/xfs_inode.c	Mon May 19 11:48:20 2003
@@ -656,7 +656,9 @@
 	int		nex;
 	int		real_size;
 	int		size;
+#if ARCH_CONVERT != ARCH_NOCONVERT
 	int		i;
+#endif
 
 	ifp = XFS_IFORK_PTR(ip, whichfork);
 	nex = XFS_DFORK_NEXTENTS_ARCH(dip, whichfork, ARCH_CONVERT);
@@ -976,6 +978,8 @@
 			XFS_IFORK_DSIZE(ip) / (uint)sizeof(xfs_bmbt_rec_t);
 	}
 
+	INIT_LIST_HEAD(&ip->i_reclaim);
+
 	/*
 	 * The inode format changed when we moved the link count and
 	 * made it 32 bits long.  If this is an old format inode,
@@ -2625,6 +2629,15 @@
 	ASSERT(atomic_read(&ip->i_pincount) > 0);
 
 	if (atomic_dec_and_test(&ip->i_pincount)) {
+		vnode_t	*vp = XFS_ITOV_NULL(ip);
+
+		/* make sync come back and flush this inode */
+		if (vp) {
+			struct inode	*inode = LINVFS_GET_IP(vp);
+
+			mark_inode_dirty_sync(inode);
+		}
+
 		wake_up(&ip->i_ipin_wait);
 	}
 }
@@ -3640,6 +3653,8 @@
 	 */
 	SYNCHRONIZE();
 	ip->i_update_core = 1;
+	if (!(inode->i_state & I_LOCK))
+		mark_inode_dirty(inode);
 }
 
 #ifdef XFS_ILOCK_TRACE
diff -Nru a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h
--- a/fs/xfs/xfs_inode.h	Fri May  2 12:36:11 2003
+++ b/fs/xfs/xfs_inode.h	Mon May 19 11:29:41 2003
@@ -243,6 +243,7 @@
 	struct xfs_inode	*i_mprev;	/* ptr to prev inode */
 	struct xfs_inode	**i_prevp;	/* ptr to prev i_next */
 	struct xfs_mount	*i_mount;	/* fs mount struct ptr */
+	struct list_head	i_reclaim;	/* reclaim list */
 	struct bhv_desc		i_bhv_desc;	/* inode behavior descriptor*/
 	struct xfs_dquot	*i_udquot;	/* user dquot */
 	struct xfs_dquot	*i_gdquot;	/* group dquot */
@@ -477,7 +478,7 @@
 void		xfs_ifunlock(xfs_inode_t *);
 void		xfs_ireclaim(xfs_inode_t *);
 int		xfs_finish_reclaim(xfs_inode_t *, int, int);
-int		xfs_finish_reclaim_all(struct xfs_mount *);
+int		xfs_finish_reclaim_all(struct xfs_mount *, int);
 
 /*
  * xfs_inode.c prototypes.
diff -Nru a/fs/xfs/xfs_log.c b/fs/xfs/xfs_log.c
--- a/fs/xfs/xfs_log.c	Fri May  2 13:01:27 2003
+++ b/fs/xfs/xfs_log.c	Mon May 19 12:20:40 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -414,19 +414,6 @@
 }
 
 /*
- * Initialize log manager data.  This routine is intended to be called when
- * a system boots up.  It is not a per filesystem initialization.
- *
- * As you can see, we currently do nothing.
- */
-int
-xfs_log_init(void)
-{
-	return( 0 );
-}
-
-
-/*
  *  1. Reserve an amount of on-disk log space and return a ticket corresponding
  *	to the reservation.
  *  2. Potentially, push buffers at tail of log to disk.
@@ -497,8 +484,6 @@
 	      xfs_daddr_t	blk_offset,
 	      int		num_bblks)
 {
-	xlog_t *log;
-
 	if (!(mp->m_flags & XFS_MOUNT_NORECOVERY))
 		cmn_err(CE_NOTE, "XFS mounting filesystem %s", mp->m_fsname);
 	else {
@@ -508,7 +493,7 @@
 		ASSERT(XFS_MTOVFS(mp)->vfs_flag & VFS_RDONLY);
 	}
 
-	mp->m_log = log = xlog_alloc_log(mp, log_dev, blk_offset, num_bblks);
+	mp->m_log = xlog_alloc_log(mp, log_dev, blk_offset, num_bblks);
 
 #if defined(DEBUG) || defined(XLOG_NOLOG)
 	if (! xlog_debug) {
@@ -528,19 +513,19 @@
 		if (readonly)
 			vfsp->vfs_flag &= ~VFS_RDONLY;
 
-		error = xlog_recover(log, readonly);
+		error = xlog_recover(mp->m_log, readonly);
 
 		if (readonly)
 			vfsp->vfs_flag |= VFS_RDONLY;
 		if (error) {
 			cmn_err(CE_WARN, "XFS: log mount/recovery failed");
-			xlog_unalloc_log(log);
+			xlog_unalloc_log(mp->m_log);
 			return error;
 		}
 	}
 
 	/* Normal transactions can now occur */
-	log->l_flags &= ~XLOG_ACTIVE_RECOVERY;
+	mp->m_log->l_flags &= ~XLOG_ACTIVE_RECOVERY;
 
 	/* End mounting message in xfs_log_mount_finish */
 	return 0;
@@ -1191,28 +1176,39 @@
 	int			i;
 	int			iclogsize;
 
-	log = (void *)kmem_zalloc(sizeof(xlog_t), KM_SLEEP);
+	log = (xlog_t *)kmem_zalloc(sizeof(xlog_t), KM_SLEEP);
 
 	log->l_mp	   = mp;
 	log->l_dev	   = log_dev;
 	log->l_logsize     = BBTOB(num_bblks);
 	log->l_logBBstart  = blk_offset;
 	log->l_logBBsize   = num_bblks;
-	log->l_roundoff	   = 0;
 	log->l_covered_state = XLOG_STATE_COVER_IDLE;
 	log->l_flags	   |= XLOG_ACTIVE_RECOVERY;
 
 	log->l_prev_block  = -1;
 	ASSIGN_ANY_LSN(log->l_tail_lsn, 1, 0, ARCH_NOCONVERT);
-	/* log->l_tail_lsn    = 0x100000000LL; cycle = 1; current block = 0 */
+	/* log->l_tail_lsn = 0x100000000LL; cycle = 1; current block = 0 */
 	log->l_last_sync_lsn = log->l_tail_lsn;
 	log->l_curr_cycle  = 1;	    /* 0 is bad since this is initial value */
-	log->l_curr_block  = 0;		/* filled in by xlog_recover */
-	log->l_grant_reserve_bytes = 0;
 	log->l_grant_reserve_cycle = 1;
-	log->l_grant_write_bytes = 0;
 	log->l_grant_write_cycle = 1;
-	log->l_quotaoffs_flag = 0;      /* XFS_LI_QUOTAOFF logitems */
+
+	if (XFS_SB_VERSION_HASLOGV2(&mp->m_sb)) {
+		if (mp->m_sb.sb_logsunit <= 1) {
+			log->l_stripemask = 1;
+		} else {
+			log->l_stripemask = 1 <<
+				xfs_highbit32(mp->m_sb.sb_logsunit >> BBSHIFT);
+		}
+	}
+	if (XFS_SB_VERSION_HASSECTOR(&mp->m_sb)) {
+		log->l_sectbb_log = mp->m_sb.sb_logsectlog - BBSHIFT;
+		ASSERT(log->l_sectbb_log <= mp->m_sectbb_log);
+		ASSERT(XFS_SB_VERSION_HASLOGV2(&mp->m_sb));
+		ASSERT(mp->m_sb.sb_logsectlog >= BBSHIFT);
+	}
+	log->l_sectbb_mask = (1 << log->l_sectbb_log) - 1;
 
 	xlog_get_iclog_buffer_size(mp, log);
 
@@ -2811,10 +2807,9 @@
 
 	/* Round up to next log-sunit */
 	if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
-		if (log->l_curr_block & (log->l_mp->m_lstripemask - 1)) {
-			roundup = log->l_mp->m_lstripemask -
-				(log->l_curr_block &
-				 (log->l_mp->m_lstripemask - 1));
+		if (log->l_curr_block & (log->l_stripemask - 1)) {
+			roundup = log->l_stripemask -
+				(log->l_curr_block & (log->l_stripemask - 1));
 		} else {
 			roundup = 0;
 		}
@@ -3293,15 +3288,17 @@
 {
     xfs_buf_t	*bp;
     uint	cycle_no;
+    xfs_caddr_t ptr;
     xfs_daddr_t	i;
 
     if (BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT) < 10) {
 	cycle_no = CYCLE_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT);
-	bp = xlog_get_bp(1, log->l_mp);
+	bp = xlog_get_bp(log, 1);
 	ASSERT(bp);
 	for (i = 0; i < BLOCK_LSN(iclog->ic_header.h_lsn, ARCH_CONVERT); i++) {
 	    xlog_bread(log, i, 1, bp);
-	    if (GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT) != cycle_no)
+	    ptr = xlog_align(log, i, 1, bp);
+	    if (GET_CYCLE(ptr, ARCH_CONVERT) != cycle_no)
 		xlog_warn("XFS: xlog_verify_disk_cycle_no: bad cycle no");
 	}
 	xlog_put_bp(bp);
diff -Nru a/fs/xfs/xfs_log.h b/fs/xfs/xfs_log.h
--- a/fs/xfs/xfs_log.h	Fri May  2 12:36:11 2003
+++ b/fs/xfs/xfs_log.h	Mon May 19 12:20:40 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -153,7 +153,6 @@
 int	  xfs_log_force(struct xfs_mount *mp,
 			xfs_lsn_t	 lsn,
 			uint		 flags);
-int	  xfs_log_init(void);
 int	  xfs_log_mount(struct xfs_mount *mp,
 			dev_t		 log_dev,
 			xfs_daddr_t		 start_block,
diff -Nru a/fs/xfs/xfs_log_priv.h b/fs/xfs/xfs_log_priv.h
--- a/fs/xfs/xfs_log_priv.h	Fri May  2 12:36:11 2003
+++ b/fs/xfs/xfs_log_priv.h	Mon May 19 12:20:40 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -73,6 +73,9 @@
 
 #define XLOG_HEADER_SIZE	512
 
+#define XLOG_REC_SHIFT(log) \
+	BTOBB(1 << (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? \
+	 XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT))
 #define XLOG_TOTAL_REC_SHIFT(log) \
 	BTOBB(XLOG_MAX_ICLOGS << (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? \
 	 XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT))
@@ -202,9 +205,9 @@
 #define LOG_LOCK(log)		mutex_spinlock(&(log)->l_icloglock)
 #define LOG_UNLOCK(log, s)	mutex_spinunlock(&(log)->l_icloglock, s)
 
-#define xlog_panic(s)		{cmn_err(CE_PANIC, s); }
-#define xlog_exit(s)		{cmn_err(CE_PANIC, s); }
-#define xlog_warn(s)		{cmn_err(CE_WARN, s); }
+#define xlog_panic(args...)	cmn_err(CE_PANIC, ## args)
+#define xlog_exit(args...)	cmn_err(CE_PANIC, ## args)
+#define xlog_warn(args...)	cmn_err(CE_WARN, ## args)
 
 /*
  * In core log state
@@ -403,6 +406,7 @@
 	uint	  xh_cycle;	/* write cycle of log			: 4 */
 	uint	  xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /*	: 256 */
 } xlog_rec_ext_header_t;
+
 #ifdef __KERNEL__
 /*
  * - A log record header is 512 bytes.  There is plenty of room to grow the
@@ -441,12 +445,10 @@
 	char			*ic_datap;	/* pointer to iclog data */
 } xlog_iclog_fields_t;
 
-typedef struct xlog_in_core2 {
-	union {
-		xlog_rec_header_t hic_header;
-		xlog_rec_ext_header_t hic_xheader;
-		char		  hic_sector[XLOG_HEADER_SIZE];
-	} ic_h;
+typedef union xlog_in_core2 {
+	xlog_rec_header_t	hic_header;
+	xlog_rec_ext_header_t	hic_xheader;
+	char			hic_sector[XLOG_HEADER_SIZE];
 } xlog_in_core_2_t;
 
 typedef struct xlog_in_core {
@@ -473,7 +475,7 @@
 #define	ic_bwritecnt	hic_fields.ic_bwritecnt
 #define	ic_state	hic_fields.ic_state
 #define ic_datap	hic_fields.ic_datap
-#define ic_header	hic_data->ic_h.hic_header
+#define ic_header	hic_data->hic_header
 
 /*
  * The reservation head lsn is not made up of a cycle number and block number.
@@ -530,8 +532,11 @@
     uint		l_flags;
     uint		l_quotaoffs_flag;/* XFS_DQ_*, if QUOTAOFFs found */
     struct xfs_buf_cancel **l_buf_cancel_table;
+    int			l_stripemask;	/* log stripe mask */
     int			l_iclog_hsize;  /* size of iclog header */
     int			l_iclog_heads;  /* number of iclog header sectors */
+    uint		l_sectbb_log;   /* log2 of sector size in bbs */
+    uint		l_sectbb_mask;  /* sector size in bbs alignment mask */
 } xlog_t;
 
 
@@ -546,10 +551,12 @@
 extern int	 xlog_recover(xlog_t *log, int readonly);
 extern int	 xlog_recover_finish(xlog_t *log, int mfsi_flags);
 extern void	 xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog);
-extern struct xfs_buf *xlog_get_bp(int,xfs_mount_t *);
-extern void	 xlog_put_bp(struct xfs_buf *);
-extern int	 xlog_bread(xlog_t *, xfs_daddr_t blkno, int bblks, struct xfs_buf *bp);
 extern void	 xlog_recover_process_iunlinks(xlog_t *log);
+
+extern struct xfs_buf *xlog_get_bp(xlog_t *, int);
+extern void	 xlog_put_bp(struct xfs_buf *);
+extern int	 xlog_bread(xlog_t *, xfs_daddr_t, int, struct xfs_buf *);
+extern xfs_caddr_t xlog_align(xlog_t *, xfs_daddr_t, int, struct xfs_buf *);
 
 #define XLOG_TRACE_GRAB_FLUSH  1
 #define XLOG_TRACE_REL_FLUSH   2
diff -Nru a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c
--- a/fs/xfs/xfs_log_recover.c	Fri May  2 13:01:27 2003
+++ b/fs/xfs/xfs_log_recover.c	Mon May 19 12:18:11 2003
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000-2002 Silicon Graphics, Inc.  All Rights Reserved.
+ * Copyright (c) 2000-2003 Silicon Graphics, Inc.  All Rights Reserved.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
@@ -65,53 +65,68 @@
 #include "xfs_quota.h"
 #include "xfs_rw.h"
 
-STATIC int	xlog_find_zeroed(struct log *log, xfs_daddr_t *blk_no);
-
-STATIC int	xlog_clear_stale_blocks(xlog_t	*log, xfs_lsn_t tail_lsn);
+STATIC int	xlog_find_zeroed(xlog_t *, xfs_daddr_t *);
+STATIC int	xlog_clear_stale_blocks(xlog_t *, xfs_lsn_t);
 STATIC void	xlog_recover_insert_item_backq(xlog_recover_item_t **q,
 					       xlog_recover_item_t *item);
-
 #if defined(DEBUG)
-STATIC void	xlog_recover_check_summary(xlog_t *log);
-STATIC void	xlog_recover_check_ail(xfs_mount_t *mp, xfs_log_item_t *lip,
-				       int gen);
+STATIC void	xlog_recover_check_summary(xlog_t *);
+STATIC void	xlog_recover_check_ail(xfs_mount_t *, xfs_log_item_t *, int);
 #else
 #define	xlog_recover_check_summary(log)
 #define	xlog_recover_check_ail(mp, lip, gen)
-#endif /* DEBUG */
+#endif
 
 
+/*
+ * Sector aligned buffer routines for buffer create/read/write/access
+ */
+
+#define XLOG_SECTOR_ROUNDUP_BBCOUNT(log, bbs)	\
+	( ((log)->l_sectbb_mask && (bbs & (log)->l_sectbb_mask)) ? \
+	((bbs + (log)->l_sectbb_mask + 1) & ~(log)->l_sectbb_mask) : (bbs) )
+#define XLOG_SECTOR_ROUNDDOWN_BLKNO(log, bno)	((bno) & ~(log)->l_sectbb_mask)
+
 xfs_buf_t *
-xlog_get_bp(int num_bblks, xfs_mount_t *mp)
+xlog_get_bp(
+	xlog_t		*log,
+	int		num_bblks)
 {
-	xfs_buf_t   *bp;
-
 	ASSERT(num_bblks > 0);
 
-	bp = XFS_ngetrbuf(BBTOB(num_bblks),mp);
-	return bp;
-}	/* xlog_get_bp */
-
+	if (log->l_sectbb_log) {
+		if (num_bblks > 1)
+			num_bblks += XLOG_SECTOR_ROUNDUP_BBCOUNT(log, 1);
+		num_bblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, num_bblks);
+	}
+	return XFS_ngetrbuf(BBTOB(num_bblks), log->l_mp);
+}
 
 void
-xlog_put_bp(xfs_buf_t *bp)
+xlog_put_bp(
+	xfs_buf_t	*bp)
 {
 	XFS_nfreerbuf(bp);
-}	/* xlog_put_bp */
+}
 
 
 /*
  * nbblks should be uint, but oh well.  Just want to catch that 32-bit length.
  */
 int
-xlog_bread(xlog_t	*log,
-	   xfs_daddr_t	blk_no,
-	   int		nbblks,
-	   xfs_buf_t	*bp)
+xlog_bread(
+	xlog_t		*log,
+	xfs_daddr_t	blk_no,
+	int		nbblks,
+	xfs_buf_t	*bp)
 {
-	int error;
+	int		error;
+
+	if (log->l_sectbb_log) {
+		blk_no = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, blk_no);
+		nbblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, nbblks);
+	}
 
-	ASSERT(log);
 	ASSERT(nbblks > 0);
 	ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp));
 	ASSERT(bp);
@@ -123,14 +138,11 @@
 	XFS_BUF_SET_TARGET(bp, log->l_mp->m_logdev_targp);
 
 	xfsbdstrat(log->l_mp, bp);
-	if ((error = xfs_iowait(bp))) {
+	if ((error = xfs_iowait(bp)))
 		xfs_ioerror_alert("xlog_bread", log->l_mp,
 				  bp, XFS_BUF_ADDR(bp));
-		return (error);
-	}
 	return error;
-}	/* xlog_bread */
-
+}
 
 /*
  * Write out the buffer at the given block for the given number of blocks.
@@ -139,12 +151,17 @@
  */
 int
 xlog_bwrite(
-	xlog_t	*log,
-	int	blk_no,
-	int	nbblks,
+	xlog_t		*log,
+	xfs_daddr_t	blk_no,
+	int		nbblks,
 	xfs_buf_t	*bp)
 {
-	int	error;
+	int		error;
+
+	if (log->l_sectbb_log) {
+		blk_no = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, blk_no);
+		nbblks = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, nbblks);
+	}
 
 	ASSERT(nbblks > 0);
 	ASSERT(BBTOB(nbblks) <= XFS_BUF_SIZE(bp));
@@ -160,94 +177,109 @@
 	if ((error = xfs_bwrite(log->l_mp, bp)))
 		xfs_ioerror_alert("xlog_bwrite", log->l_mp,
 				  bp, XFS_BUF_ADDR(bp));
+	return error;
+}
 
-	return (error);
-}	/* xlog_bwrite */
+xfs_caddr_t
+xlog_align(
+	xlog_t		*log,
+	xfs_daddr_t	blk_no,
+	int		nbblks,
+	xfs_buf_t	*bp)
+{
+	xfs_caddr_t	ptr;
+
+	if (!log->l_sectbb_log)
+		return XFS_BUF_PTR(bp);
+
+	ptr = XFS_BUF_PTR(bp) + BBTOB((int)blk_no & log->l_sectbb_mask);
+	ASSERT(XFS_BUF_SIZE(bp) >=
+		BBTOB(nbblks + (blk_no & log->l_sectbb_mask)));
+	return ptr;
+}
 
 #ifdef DEBUG
 /*
- * check log record header for recovery
+ * dump debug superblock and log record information
  */
-static void
-xlog_header_check_dump(xfs_mount_t *mp, xlog_rec_header_t *head)
+STATIC void
+xlog_header_check_dump(
+	xfs_mount_t		*mp,
+	xlog_rec_header_t	*head)
 {
-    int b;
+	int			b;
 
-    printk("%s:  SB : uuid = ", __FUNCTION__);
-    for (b=0;b<16;b++) printk("%02x",((unsigned char *)&mp->m_sb.sb_uuid)[b]);
-    printk(", fmt = %d\n",XLOG_FMT);
-    printk("    log : uuid = ");
-    for (b=0;b<16;b++) printk("%02x",((unsigned char *)&head->h_fs_uuid)[b]);
-    printk(", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT));
+	printk("%s:  SB : uuid = ", __FUNCTION__);
+	for (b = 0; b < 16; b++)
+		printk("%02x",((unsigned char *)&mp->m_sb.sb_uuid)[b]);
+	printk(", fmt = %d\n", XLOG_FMT);
+	printk("    log : uuid = ");
+	for (b = 0; b < 16; b++)
+		printk("%02x",((unsigned char *)&head->h_fs_uuid)[b]);
+	printk(", fmt = %d\n", INT_GET(head->h_fmt, ARCH_CONVERT));
 }
+#else
+#define xlog_header_check_dump(mp, head)
 #endif
 
 /*
  * check log record header for recovery
  */
-
 STATIC int
-xlog_header_check_recover(xfs_mount_t *mp, xlog_rec_header_t *head)
+xlog_header_check_recover(
+	xfs_mount_t		*mp,
+	xlog_rec_header_t	*head)
 {
-    ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
-
-    /*
-     * IRIX doesn't write the h_fmt field and leaves it zeroed
-     * (XLOG_FMT_UNKNOWN). This stops us from trying to recover
-     * a dirty log created in IRIX.
-     */
-
-    if (unlikely(INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT)) {
-	xlog_warn("XFS: dirty log written in incompatible format - can't recover");
-#ifdef DEBUG
-	xlog_header_check_dump(mp, head);
-#endif
-	XFS_ERROR_REPORT("xlog_header_check_recover(1)",
-			 XFS_ERRLEVEL_HIGH, mp);
-	return XFS_ERROR(EFSCORRUPTED);
-    } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
-	xlog_warn("XFS: dirty log entry has mismatched uuid - can't recover");
-#ifdef DEBUG
-	xlog_header_check_dump(mp, head);
-#endif
-	XFS_ERROR_REPORT("xlog_header_check_recover(2)",
-			 XFS_ERRLEVEL_HIGH, mp);
-	return XFS_ERROR(EFSCORRUPTED);
-    }
+	ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
 
-    return 0;
+	/*
+	 * IRIX doesn't write the h_fmt field and leaves it zeroed
+	 * (XLOG_FMT_UNKNOWN). This stops us from trying to recover
+	 * a dirty log created in IRIX.
+	 */
+	if (unlikely(INT_GET(head->h_fmt, ARCH_CONVERT) != XLOG_FMT)) {
+		xlog_warn(
+	"XFS: dirty log written in incompatible format - can't recover");
+		xlog_header_check_dump(mp, head);
+		XFS_ERROR_REPORT("xlog_header_check_recover(1)",
+				 XFS_ERRLEVEL_HIGH, mp);
+		return XFS_ERROR(EFSCORRUPTED);
+	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+		xlog_warn(
+	"XFS: dirty log entry has mismatched uuid - can't recover");
+		xlog_header_check_dump(mp, head);
+		XFS_ERROR_REPORT("xlog_header_check_recover(2)",
+				 XFS_ERRLEVEL_HIGH, mp);
+		return XFS_ERROR(EFSCORRUPTED);
+	}
+	return 0;
 }
 
 /*
  * read the head block of the log and check the header
  */
-
 STATIC int
-xlog_header_check_mount(xfs_mount_t *mp, xlog_rec_header_t *head)
+xlog_header_check_mount(
+	xfs_mount_t		*mp,
+	xlog_rec_header_t	*head)
 {
-    ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
-
-    if (uuid_is_nil(&head->h_fs_uuid)) {
-
-	/*
-	 * IRIX doesn't write the h_fs_uuid or h_fmt fields. If
-	 * h_fs_uuid is nil, we assume this log was last mounted
-	 * by IRIX and continue.
-	 */
-
-	xlog_warn("XFS: nil uuid in log - IRIX style log");
+	ASSERT(INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
 
-    } else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
-	xlog_warn("XFS: log has mismatched uuid - can't recover");
-#ifdef DEBUG
-	xlog_header_check_dump(mp, head);
-#endif
-	XFS_ERROR_REPORT("xlog_header_check_mount",
-			 XFS_ERRLEVEL_HIGH, mp);
-	return XFS_ERROR(EFSCORRUPTED);
-    }
-
-    return 0;
+	if (uuid_is_nil(&head->h_fs_uuid)) {
+		/*
+		 * IRIX doesn't write the h_fs_uuid or h_fmt fields. If
+		 * h_fs_uuid is nil, we assume this log was last mounted
+		 * by IRIX and continue.
+		 */
+		xlog_warn("XFS: nil uuid in log - IRIX style log");
+	} else if (unlikely(!uuid_equal(&mp->m_sb.sb_uuid, &head->h_fs_uuid))) {
+		xlog_warn("XFS: log has mismatched uuid - can't recover");
+		xlog_header_check_dump(mp, head);
+		XFS_ERROR_REPORT("xlog_header_check_mount",
+				 XFS_ERRLEVEL_HIGH, mp);
+		return XFS_ERROR(EFSCORRUPTED);
+	}
+	return 0;
 }
 
 STATIC void
@@ -255,6 +287,7 @@
 	struct xfs_buf	*bp)
 {
 	xfs_mount_t	*mp;
+
 	ASSERT(XFS_BUF_FSPRIVATE(bp, void *));
 
 	if (XFS_BUF_GETERROR(bp)) {
@@ -279,12 +312,14 @@
  * necessarily be perfect.
  */
 int
-xlog_find_cycle_start(xlog_t		*log,
-		      xfs_buf_t		*bp,
-		      xfs_daddr_t	first_blk,
-		      xfs_daddr_t	*last_blk,
-		      uint		cycle)
+xlog_find_cycle_start(
+	xlog_t		*log,
+	xfs_buf_t	*bp,
+	xfs_daddr_t	first_blk,
+	xfs_daddr_t	*last_blk,
+	uint		cycle)
 {
+	xfs_caddr_t	offset;
 	xfs_daddr_t	mid_blk;
 	uint		mid_cycle;
 	int		error;
@@ -293,7 +328,8 @@
 	while (mid_blk != first_blk && mid_blk != *last_blk) {
 		if ((error = xlog_bread(log, mid_blk, 1, bp)))
 			return error;
-		mid_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
+		offset = xlog_align(log, mid_blk, 1, bp);
+		mid_cycle = GET_CYCLE(offset, ARCH_CONVERT);
 		if (mid_cycle == cycle) {
 			*last_blk = mid_blk;
 			/* last_half_cycle == mid_cycle */
@@ -307,8 +343,7 @@
 	       (mid_blk == *last_blk && mid_blk-1 == first_blk));
 
 	return 0;
-}	/* xlog_find_cycle_start */
-
+}
 
 /*
  * Check that the range of blocks does not contain the cycle number
@@ -320,27 +355,27 @@
  * Set blkno to -1 if we encounter no errors.  This is an invalid block number
  * since we don't ever expect logs to get this large.
  */
-
 STATIC int
-xlog_find_verify_cycle( xlog_t		*log,
-			xfs_daddr_t	start_blk,
-			int		nbblks,
-			uint		stop_on_cycle_no,
-			xfs_daddr_t	*new_blk)
+xlog_find_verify_cycle(
+	xlog_t		*log,
+	xfs_daddr_t	start_blk,
+	int		nbblks,
+	uint		stop_on_cycle_no,
+	xfs_daddr_t	*new_blk)
 {
-	xfs_daddr_t		i, j;
-	uint			cycle;
-	xfs_buf_t		*bp;
-	char                    *buf        = NULL;
-	int			error       = 0;
-	xfs_daddr_t		bufblks;
+	xfs_daddr_t	i, j;
+	uint		cycle;
+	xfs_buf_t	*bp;
+	xfs_daddr_t	bufblks;
+	xfs_caddr_t	buf = NULL;
+	int		error = 0;
 
 	bufblks = 1 << ffs(nbblks);
 
-	while (!(bp = xlog_get_bp(bufblks, log->l_mp))) {
+	while (!(bp = xlog_get_bp(log, bufblks))) {
 		/* can't get enough memory to do everything in one big buffer */
 		bufblks >>= 1;
-		if (!bufblks)
+		if (bufblks <= log->l_sectbb_log)
 			return ENOMEM;
 	}
 
@@ -352,7 +387,7 @@
 		if ((error = xlog_bread(log, i, bcount, bp)))
 			goto out;
 
-		buf = XFS_BUF_PTR(bp);
+		buf = xlog_align(log, i, bcount, bp);
 		for (j = 0; j < bcount; j++) {
 			cycle = GET_CYCLE(buf, ARCH_CONVERT);
 			if (cycle == stop_on_cycle_no) {
@@ -368,10 +403,8 @@
 
 out:
 	xlog_put_bp(bp);
-
 	return error;
-}	/* xlog_find_verify_cycle */
-
+}
 
 /*
  * Potentially backup over partial log record write.
@@ -385,98 +418,103 @@
  * extra_bblks is the number of blocks potentially verified on a previous
  * call to this routine.
  */
-
 STATIC int
-xlog_find_verify_log_record(xlog_t	*log,
-			    xfs_daddr_t	start_blk,
-			    xfs_daddr_t	*last_blk,
-			    int		extra_bblks)
-{
-    xfs_daddr_t         i;
-    xfs_buf_t		*bp;
-    char                *buf        = NULL;
-    xlog_rec_header_t	*head       = NULL;
-    int			error       = 0;
-    int                 smallmem    = 0;
-    int                 num_blks    = *last_blk - start_blk;
-    int			xhdrs;
-
-    ASSERT(start_blk != 0 || *last_blk != start_blk);
-
-    if (!(bp = xlog_get_bp(num_blks, log->l_mp))) {
-	if (!(bp = xlog_get_bp(1, log->l_mp)))
-	    return ENOMEM;
-	smallmem = 1;
-	buf = XFS_BUF_PTR(bp);
-    } else {
-	if ((error = xlog_bread(log, start_blk, num_blks, bp)))
-	    goto out;
-	buf = XFS_BUF_PTR(bp) + ((num_blks - 1) << BBSHIFT);
-    }
-
-    for (i = (*last_blk) - 1; i >= 0; i--) {
-	if (i < start_blk) {
-	    /* legal log record not found */
-	    xlog_warn("XFS: Log inconsistent (didn't find previous header)");
-	    ASSERT(0);
-	    error = XFS_ERROR(EIO);
-	    goto out;
+xlog_find_verify_log_record(
+	xlog_t			*log,
+	xfs_daddr_t		start_blk,
+	xfs_daddr_t		*last_blk,
+	int			extra_bblks)
+{
+	xfs_daddr_t		i;
+	xfs_buf_t		*bp;
+	xfs_caddr_t		offset = NULL;
+	xlog_rec_header_t	*head = NULL;
+	int			error = 0;
+	int			smallmem = 0;
+	int			num_blks = *last_blk - start_blk;
+	int			xhdrs;
+
+	ASSERT(start_blk != 0 || *last_blk != start_blk);
+
+	if (!(bp = xlog_get_bp(log, num_blks))) {
+		if (!(bp = xlog_get_bp(log, 1)))
+			return ENOMEM;
+		smallmem = 1;
+	} else {
+		if ((error = xlog_bread(log, start_blk, num_blks, bp)))
+			goto out;
+		offset = xlog_align(log, start_blk, num_blks, bp);
+		offset += ((num_blks - 1) << BBSHIFT);
 	}
 
-	if (smallmem && (error = xlog_bread(log, i, 1, bp)))
-	    goto out;
-	head = (xlog_rec_header_t*)buf;
-
-	if (INT_GET(head->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM)
-	    break;
-
-	if (!smallmem)
-	    buf -= BBSIZE;
-    }
-
-    /*
-     * We hit the beginning of the physical log & still no header.  Return
-     * to caller.  If caller can handle a return of -1, then this routine
-     * will be called again for the end of the physical log.
-     */
-    if (i == -1) {
-	error = -1;
-	goto out;
-    }
-
-    /* we have the final block of the good log (the first block
-     * of the log record _before_ the head. So we check the uuid.
-     */
-
-    if ((error = xlog_header_check_mount(log->l_mp, head)))
-	goto out;
-
-    /*
-     * We may have found a log record header before we expected one.
-     * last_blk will be the 1st block # with a given cycle #.  We may end
-     * up reading an entire log record.  In this case, we don't want to
-     * reset last_blk.  Only when last_blk points in the middle of a log
-     * record do we update last_blk.
-     */
-    if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
-	uint	h_size = INT_GET(head->h_size, ARCH_CONVERT);
-
-	xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE;
-	if (h_size % XLOG_HEADER_CYCLE_SIZE)
-		xhdrs++;
-    } else {
-	xhdrs = 1;
-    }
-
-    if (*last_blk - i + extra_bblks
-		!= BTOBB(INT_GET(head->h_len, ARCH_CONVERT))+xhdrs)
-	    *last_blk = i;
+	for (i = (*last_blk) - 1; i >= 0; i--) {
+		if (i < start_blk) {
+			/* legal log record not found */
+			xlog_warn(
+		"XFS: Log inconsistent (didn't find previous header)");
+			ASSERT(0);
+			error = XFS_ERROR(EIO);
+			goto out;
+		}
 
-out:
-    xlog_put_bp(bp);
+		if (smallmem) {
+			if ((error = xlog_bread(log, i, 1, bp)))
+				goto out;
+			offset = xlog_align(log, i, 1, bp);
+		}
+
+		head = (xlog_rec_header_t *)offset;
+
+		if (XLOG_HEADER_MAGIC_NUM ==
+		    INT_GET(head->h_magicno, ARCH_CONVERT))
+			break;
+
+		if (!smallmem)
+			offset -= BBSIZE;
+	}
+
+	/*
+	 * We hit the beginning of the physical log & still no header.  Return
+	 * to caller.  If caller can handle a return of -1, then this routine
+	 * will be called again for the end of the physical log.
+	 */
+	if (i == -1) {
+		error = -1;
+		goto out;
+	}
+
+	/*
+	 * We have the final block of the good log (the first block
+	 * of the log record _before_ the head. So we check the uuid.
+	 */
+	if ((error = xlog_header_check_mount(log->l_mp, head)))
+		goto out;
 
-    return error;
-}	/* xlog_find_verify_log_record */
+	/*
+	 * We may have found a log record header before we expected one.
+	 * last_blk will be the 1st block # with a given cycle #.  We may end
+	 * up reading an entire log record.  In this case, we don't want to
+	 * reset last_blk.  Only when last_blk points in the middle of a log
+	 * record do we update last_blk.
+	 */
+	if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+		uint	h_size = INT_GET(head->h_size, ARCH_CONVERT);
+
+		xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE;
+		if (h_size % XLOG_HEADER_CYCLE_SIZE)
+			xhdrs++;
+	} else {
+		xhdrs = 1;
+	}
+
+	if (*last_blk - i + extra_bblks
+			!= BTOBB(INT_GET(head->h_len, ARCH_CONVERT)) + xhdrs)
+		*last_blk = i;
+
+out:
+	xlog_put_bp(bp);
+	return error;
+}
 
 /*
  * Head is defined to be the point of the log where the next log write
@@ -489,252 +527,257 @@
  * last_blk contains the block number of the first block with a given
  * cycle number.
  *
- * Also called from xfs_log_print.c
- *
  * Return: zero if normal, non-zero if error.
  */
 int
-xlog_find_head(xlog_t  *log,
-	       xfs_daddr_t *return_head_blk)
+xlog_find_head(
+	xlog_t 		*log,
+	xfs_daddr_t	*return_head_blk)
 {
-    xfs_buf_t   *bp;
-    xfs_daddr_t new_blk, first_blk, start_blk, last_blk, head_blk;
-    int     num_scan_bblks;
-    uint    first_half_cycle, last_half_cycle;
-    uint    stop_on_cycle;
-    int     error, log_bbnum = log->l_logBBsize;
-
-    /* Is the end of the log device zeroed? */
-    if ((error = xlog_find_zeroed(log, &first_blk)) == -1) {
-	*return_head_blk = first_blk;
-
-	/* is the whole lot zeroed? */
-	if (!first_blk) {
-	    /* Linux XFS shouldn't generate totally zeroed logs -
-	     * mkfs etc write a dummy unmount record to a fresh
-	     * log so we can store the uuid in there
-	     */
-	    xlog_warn("XFS: totally zeroed log");
-	}
+	xfs_buf_t	*bp;
+	xfs_caddr_t	offset;
+	xfs_daddr_t	new_blk, first_blk, start_blk, last_blk, head_blk;
+	int		num_scan_bblks;
+	uint		first_half_cycle, last_half_cycle;
+	uint		stop_on_cycle;
+	int		error, log_bbnum = log->l_logBBsize;
+
+	/* Is the end of the log device zeroed? */
+	if ((error = xlog_find_zeroed(log, &first_blk)) == -1) {
+		*return_head_blk = first_blk;
+
+		/* Is the whole lot zeroed? */
+		if (!first_blk) {
+			/* Linux XFS shouldn't generate totally zeroed logs -
+			 * mkfs etc write a dummy unmount record to a fresh
+			 * log so we can store the uuid in there
+			 */
+			xlog_warn("XFS: totally zeroed log");
+		}
 
-	return 0;
-    } else if (error) {
-	xlog_warn("XFS: empty log check failed");
-	return error;
-    }
+		return 0;
+	} else if (error) {
+		xlog_warn("XFS: empty log check failed");
+		return error;
+	}
 
-    first_blk = 0;				/* get cycle # of 1st block */
-    bp = xlog_get_bp(1,log->l_mp);
-    if (!bp)
-	return ENOMEM;
-    if ((error = xlog_bread(log, 0, 1, bp)))
-	goto bp_err;
-    first_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
-
-    last_blk = head_blk = log_bbnum-1;		/* get cycle # of last block */
-    if ((error = xlog_bread(log, last_blk, 1, bp)))
-	goto bp_err;
-    last_half_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
-    ASSERT(last_half_cycle != 0);
-
-    /*
-     * If the 1st half cycle number is equal to the last half cycle number,
-     * then the entire log is stamped with the same cycle number.  In this
-     * case, head_blk can't be set to zero (which makes sense).  The below
-     * math doesn't work out properly with head_blk equal to zero.  Instead,
-     * we set it to log_bbnum which is an illegal block number, but this
-     * value makes the math correct.  If head_blk doesn't changed through
-     * all the tests below, *head_blk is set to zero at the very end rather
-     * than log_bbnum.  In a sense, log_bbnum and zero are the same block
-     * in a circular file.
-     */
-    if (first_half_cycle == last_half_cycle) {
-	/*
-	 * In this case we believe that the entire log should have cycle
-	 * number last_half_cycle.  We need to scan backwards from the
-	 * end verifying that there are no holes still containing
-	 * last_half_cycle - 1.  If we find such a hole, then the start
-	 * of that hole will be the new head.  The simple case looks like
-	 *        x | x ... | x - 1 | x
-	 * Another case that fits this picture would be
-	 *        x | x + 1 | x ... | x
-	 * In this case the head really is somwhere at the end of the
-	 * log, as one of the latest writes at the beginning was incomplete.
-	 * One more case is
-	 *        x | x + 1 | x ... | x - 1 | x
-	 * This is really the combination of the above two cases, and the
-	 * head has to end up at the start of the x-1 hole at the end of
-	 * the log.
-	 *
-	 * In the 256k log case, we will read from the beginning to the
-	 * end of the log and search for cycle numbers equal to x-1.  We
-	 * don't worry about the x+1 blocks that we encounter, because
-	 * we know that they cannot be the head since the log started with
-	 * x.
-	 */
-	head_blk = log_bbnum;
-	stop_on_cycle = last_half_cycle - 1;
-    } else {
-	/*
-	 * In this case we want to find the first block with cycle number
-	 * matching last_half_cycle.  We expect the log to be some
-	 * variation on
-	 *        x + 1 ... | x ...
-	 * The first block with cycle number x (last_half_cycle) will be
-	 * where the new head belongs.  First we do a binary search for
-	 * the first occurrence of last_half_cycle.  The binary search
-	 * may not be totally accurate, so then we scan back from there
-	 * looking for occurrences of last_half_cycle before us.  If
-	 * that backwards scan wraps around the beginning of the log,
-	 * then we look for occurrences of last_half_cycle - 1 at the
-	 * end of the log.  The cases we're looking for look like
-	 *        x + 1 ... | x | x + 1 | x ...
-	 *                               ^ binary search stopped here
-	 * or
-	 *        x + 1 ... | x ... | x - 1 | x
-	 *        <---------> less than scan distance
-	 */
-	stop_on_cycle = last_half_cycle;
-	if ((error = xlog_find_cycle_start(log, bp, first_blk,
-					  &head_blk, last_half_cycle)))
-	    goto bp_err;
-    }
+	first_blk = 0;			/* get cycle # of 1st block */
+	bp = xlog_get_bp(log, 1);
+	if (!bp)
+		return ENOMEM;
+	if ((error = xlog_bread(log, 0, 1, bp)))
+		goto bp_err;
+	offset = xlog_align(log, 0, 1, bp);
+	first_half_cycle = GET_CYCLE(offset, ARCH_CONVERT);
 
-    /*
-     * Now validate the answer.  Scan back some number of maximum possible
-     * blocks and make sure each one has the expected cycle number.  The
-     * maximum is determined by the total possible amount of buffering
-     * in the in-core log.  The following number can be made tighter if
-     * we actually look at the block size of the filesystem.
-     */
-    num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log);
-    if (head_blk >= num_scan_bblks) {
-	/*
-	 * We are guaranteed that the entire check can be performed
-	 * in one buffer.
-	 */
-	start_blk = head_blk - num_scan_bblks;
-	if ((error = xlog_find_verify_cycle(log, start_blk, num_scan_bblks,
-					 stop_on_cycle, &new_blk)))
-	    goto bp_err;
-	if (new_blk != -1)
-	    head_blk = new_blk;
-    } else {			/* need to read 2 parts of log */
-	/*
-	 * We are going to scan backwards in the log in two parts.  First
-	 * we scan the physical end of the log.  In this part of the log,
-	 * we are looking for blocks with cycle number last_half_cycle - 1.
-	 * If we find one, then we know that the log starts there, as we've
-	 * found a hole that didn't get written in going around the end
-	 * of the physical log.  The simple case for this is
-	 *        x + 1 ... | x ... | x - 1 | x
-	 *        <---------> less than scan distance
-	 * If all of the blocks at the end of the log have cycle number
-	 * last_half_cycle, then we check the blocks at the start of the
-	 * log looking for occurrences of last_half_cycle.  If we find one,
-	 * then our current estimate for the location of the first
-	 * occurrence of last_half_cycle is wrong and we move back to the
-	 * hole we've found.  This case looks like
-	 *        x + 1 ... | x | x + 1 | x ...
-	 *                               ^ binary search stopped here
-	 * Another case we need to handle that only occurs in 256k logs is
-	 *        x + 1 ... | x ... | x+1 | x ...
-	 *                   ^ binary search stops here
-	 * In a 256k log, the scan at the end of the log will see the x+1
-	 * blocks.  We need to skip past those since that is certainly not
-	 * the head of the log.  By searching for last_half_cycle-1 we
-	 * accomplish that.
-	 */
-	start_blk = log_bbnum - num_scan_bblks + head_blk;
-	ASSERT(head_blk <= INT_MAX && (xfs_daddr_t) num_scan_bblks-head_blk >= 0);
-	if ((error = xlog_find_verify_cycle(log, start_blk,
-			num_scan_bblks-(int)head_blk, (stop_on_cycle - 1),
-			&new_blk)))
+	last_blk = head_blk = log_bbnum - 1;	/* get cycle # of last block */
+	if ((error = xlog_bread(log, last_blk, 1, bp)))
 		goto bp_err;
-	if (new_blk != -1) {
-	    head_blk = new_blk;
-	    goto bad_blk;
+	offset = xlog_align(log, last_blk, 1, bp);
+	last_half_cycle = GET_CYCLE(offset, ARCH_CONVERT);
+	ASSERT(last_half_cycle != 0);
+
+	/*
+	 * If the 1st half cycle number is equal to the last half cycle number,
+	 * then the entire log is stamped with the same cycle number.  In this
+	 * case, head_blk can't be set to zero (which makes sense).  The below
+	 * math doesn't work out properly with head_blk equal to zero.  Instead,
+	 * we set it to log_bbnum which is an illegal block number, but this
+	 * value makes the math correct.  If head_blk doesn't changed through
+	 * all the tests below, *head_blk is set to zero at the very end rather
+	 * than log_bbnum.  In a sense, log_bbnum and zero are the same block
+	 * in a circular file.
+	 */
+	if (first_half_cycle == last_half_cycle) {
+		/*
+		 * In this case we believe that the entire log should have
+		 * cycle number last_half_cycle.  We need to scan backwards
+		 * from the end verifying that there are no holes still
+		 * containing last_half_cycle - 1.  If we find such a hole,
+		 * then the start of that hole will be the new head.  The
+		 * simple case looks like
+		 *        x | x ... | x - 1 | x
+		 * Another case that fits this picture would be
+		 *        x | x + 1 | x ... | x
+		 * In this case the head really is somwhere at the end of the
+		 * log, as one of the latest writes at the beginning was
+		 * incomplete.
+		 * One more case is
+		 *        x | x + 1 | x ... | x - 1 | x
+		 * This is really the combination of the above two cases, and
+		 * the head has to end up at the start of the x-1 hole at the
+		 * end of the log.
+		 *
+		 * In the 256k log case, we will read from the beginning to the
+		 * end of the log and search for cycle numbers equal to x-1.
+		 * We don't worry about the x+1 blocks that we encounter,
+		 * because we know that they cannot be the head since the log
+		 * started with x.
+		 */
+		head_blk = log_bbnum;
+		stop_on_cycle = last_half_cycle - 1;
+	} else {
+		/*
+		 * In this case we want to find the first block with cycle
+		 * number matching last_half_cycle.  We expect the log to be
+		 * some variation on
+		 *        x + 1 ... | x ...
+		 * The first block with cycle number x (last_half_cycle) will
+		 * be where the new head belongs.  First we do a binary search
+		 * for the first occurrence of last_half_cycle.  The binary
+		 * search may not be totally accurate, so then we scan back
+		 * from there looking for occurrences of last_half_cycle before
+		 * us.  If that backwards scan wraps around the beginning of
+		 * the log, then we look for occurrences of last_half_cycle - 1
+		 * at the end of the log.  The cases we're looking for look
+		 * like
+		 *        x + 1 ... | x | x + 1 | x ...
+		 *                               ^ binary search stopped here
+		 * or
+		 *        x + 1 ... | x ... | x - 1 | x
+		 *        <---------> less than scan distance
+		 */
+		stop_on_cycle = last_half_cycle;
+		if ((error = xlog_find_cycle_start(log, bp, first_blk,
+						&head_blk, last_half_cycle)))
+			goto bp_err;
 	}
 
 	/*
-	 * Scan beginning of log now.  The last part of the physical log
-	 * is good.  This scan needs to verify that it doesn't find the
-	 * last_half_cycle.
+	 * Now validate the answer.  Scan back some number of maximum possible
+	 * blocks and make sure each one has the expected cycle number.  The
+	 * maximum is determined by the total possible amount of buffering
+	 * in the in-core log.  The following number can be made tighter if
+	 * we actually look at the block size of the filesystem.
 	 */
-	start_blk = 0;
-	ASSERT(head_blk <= INT_MAX);
-	if ((error = xlog_find_verify_cycle(log, start_blk, (int) head_blk,
-					 stop_on_cycle, &new_blk)))
-	    goto bp_err;
-	if (new_blk != -1)
-	    head_blk = new_blk;
-    }
-
-bad_blk:
-    /*
-     * Now we need to make sure head_blk is not pointing to a block in
-     * the middle of a log record.
-     */
-    num_scan_bblks = BTOBB(XLOG_MAX_RECORD_BSIZE);
-    if (head_blk >= num_scan_bblks) {
-	start_blk = head_blk - num_scan_bblks;  /* don't read head_blk */
-
-	/* start ptr at last block ptr before head_blk */
-	if ((error = xlog_find_verify_log_record(log,
-						 start_blk,
-						 &head_blk,
-						 0)) == -1) {
-	    error = XFS_ERROR(EIO);
-	    goto bp_err;
-	} else if (error)
-	    goto bp_err;
-    } else {
-	start_blk = 0;
-	ASSERT(head_blk <= INT_MAX);
-	if ((error = xlog_find_verify_log_record(log,
-						 start_blk,
-						 &head_blk,
-						 0)) == -1) {
-	    /* We hit the beginning of the log during our search */
-	    start_blk = log_bbnum - num_scan_bblks + head_blk;
-	    new_blk = log_bbnum;
-	    ASSERT(start_blk <= INT_MAX && (xfs_daddr_t) log_bbnum-start_blk >= 0);
-	    ASSERT(head_blk <= INT_MAX);
-	    if ((error = xlog_find_verify_log_record(log,
-						     start_blk,
-						     &new_blk,
-						     (int)head_blk)) == -1) {
-		error = XFS_ERROR(EIO);
-		goto bp_err;
-	    } else if (error)
-		goto bp_err;
-	    if (new_blk != log_bbnum)
-		head_blk = new_blk;
-	} else if (error)
-	    goto bp_err;
-    }
+	num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log);
+	if (head_blk >= num_scan_bblks) {
+		/*
+		 * We are guaranteed that the entire check can be performed
+		 * in one buffer.
+		 */
+		start_blk = head_blk - num_scan_bblks;
+		if ((error = xlog_find_verify_cycle(log,
+						start_blk, num_scan_bblks,
+						stop_on_cycle, &new_blk)))
+			goto bp_err;
+		if (new_blk != -1)
+			head_blk = new_blk;
+	} else {		/* need to read 2 parts of log */
+		/*
+		 * We are going to scan backwards in the log in two parts.
+		 * First we scan the physical end of the log.  In this part
+		 * of the log, we are looking for blocks with cycle number
+		 * last_half_cycle - 1.
+		 * If we find one, then we know that the log starts there, as
+		 * we've found a hole that didn't get written in going around
+		 * the end of the physical log.  The simple case for this is
+		 *        x + 1 ... | x ... | x - 1 | x
+		 *        <---------> less than scan distance
+		 * If all of the blocks at the end of the log have cycle number
+		 * last_half_cycle, then we check the blocks at the start of
+		 * the log looking for occurrences of last_half_cycle.  If we
+		 * find one, then our current estimate for the location of the
+		 * first occurrence of last_half_cycle is wrong and we move
+		 * back to the hole we've found.  This case looks like
+		 *        x + 1 ... | x | x + 1 | x ...
+		 *                               ^ binary search stopped here
+		 * Another case we need to handle that only occurs in 256k
+		 * logs is
+		 *        x + 1 ... | x ... | x+1 | x ...
+		 *                   ^ binary search stops here
+		 * In a 256k log, the scan at the end of the log will see the
+		 * x + 1 blocks.  We need to skip past those since that is
+		 * certainly not the head of the log.  By searching for
+		 * last_half_cycle-1 we accomplish that.
+		 */
+		start_blk = log_bbnum - num_scan_bblks + head_blk;
+		ASSERT(head_blk <= INT_MAX &&
+			(xfs_daddr_t) num_scan_bblks - head_blk >= 0);
+		if ((error = xlog_find_verify_cycle(log, start_blk,
+					num_scan_bblks - (int)head_blk,
+					(stop_on_cycle - 1), &new_blk)))
+			goto bp_err;
+		if (new_blk != -1) {
+			head_blk = new_blk;
+			goto bad_blk;
+		}
+
+		/*
+		 * Scan beginning of log now.  The last part of the physical
+		 * log is good.  This scan needs to verify that it doesn't find
+		 * the last_half_cycle.
+		 */
+		start_blk = 0;
+		ASSERT(head_blk <= INT_MAX);
+		if ((error = xlog_find_verify_cycle(log,
+					start_blk, (int)head_blk,
+					stop_on_cycle, &new_blk)))
+			goto bp_err;
+		if (new_blk != -1)
+			head_blk = new_blk;
+	}
+
+ bad_blk:
+	/*
+	 * Now we need to make sure head_blk is not pointing to a block in
+	 * the middle of a log record.
+	 */
+	num_scan_bblks = XLOG_REC_SHIFT(log);
+	if (head_blk >= num_scan_bblks) {
+		start_blk = head_blk - num_scan_bblks; /* don't read head_blk */
+
+		/* start ptr at last block ptr before head_blk */
+		if ((error = xlog_find_verify_log_record(log, start_blk,
+							&head_blk, 0)) == -1) {
+			error = XFS_ERROR(EIO);
+			goto bp_err;
+		} else if (error)
+			goto bp_err;
+	} else {
+		start_blk = 0;
+		ASSERT(head_blk <= INT_MAX);
+		if ((error = xlog_find_verify_log_record(log, start_blk,
+							&head_blk, 0)) == -1) {
+			/* We hit the beginning of the log during our search */
+			start_blk = log_bbnum - num_scan_bblks + head_blk;
+			new_blk = log_bbnum;
+			ASSERT(start_blk <= INT_MAX &&
+				(xfs_daddr_t) log_bbnum-start_blk >= 0);
+			ASSERT(head_blk <= INT_MAX);
+			if ((error = xlog_find_verify_log_record(log,
+							start_blk, &new_blk,
+							(int)head_blk)) == -1) {
+				error = XFS_ERROR(EIO);
+				goto bp_err;
+			} else if (error)
+				goto bp_err;
+			if (new_blk != log_bbnum)
+				head_blk = new_blk;
+		} else if (error)
+			goto bp_err;
+	}
 
-    xlog_put_bp(bp);
-    if (head_blk == log_bbnum)
-	    *return_head_blk = 0;
-    else
-	    *return_head_blk = head_blk;
-    /*
-     * When returning here, we have a good block number.  Bad block
-     * means that during a previous crash, we didn't have a clean break
-     * from cycle number N to cycle number N-1.  In this case, we need
-     * to find the first block with cycle number N-1.
-     */
-    return 0;
+	xlog_put_bp(bp);
+	if (head_blk == log_bbnum)
+		*return_head_blk = 0;
+	else
+		*return_head_blk = head_blk;
+	/*
+	 * When returning here, we have a good block number.  Bad block
+	 * means that during a previous crash, we didn't have a clean break
+	 * from cycle number N to cycle number N-1.  In this case, we need
+	 * to find the first block with cycle number N-1.
+	 */
+	return 0;
 
-bp_err:
+ bp_err:
 	xlog_put_bp(bp);
 
 	if (error)
 	    xlog_warn("XFS: failed to find log head");
-
 	return error;
-}	/* xlog_find_head */
+}
 
 /*
  * Find the sync block number or the tail of the log.
@@ -753,13 +796,15 @@
  * available.
  */
 int
-xlog_find_tail(xlog_t		*log,
-	       xfs_daddr_t	*head_blk,
-	       xfs_daddr_t	*tail_blk,
-	       int		readonly)
+xlog_find_tail(
+	xlog_t			*log,
+	xfs_daddr_t		*head_blk,
+	xfs_daddr_t		*tail_blk,
+	int			readonly)
 {
 	xlog_rec_header_t	*rhead;
 	xlog_op_header_t	*op_head;
+	xfs_caddr_t		offset = NULL;
 	xfs_buf_t		*bp;
 	int			error, i, found;
 	xfs_daddr_t		umount_data_blk;
@@ -775,13 +820,14 @@
 	if ((error = xlog_find_head(log, head_blk)))
 		return error;
 
-	bp = xlog_get_bp(1,log->l_mp);
+	bp = xlog_get_bp(log, 1);
 	if (!bp)
 		return ENOMEM;
 	if (*head_blk == 0) {				/* special case */
 		if ((error = xlog_bread(log, 0, 1, bp)))
 			goto bread_err;
-		if (GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT) == 0) {
+		offset = xlog_align(log, 0, 1, bp);
+		if (GET_CYCLE(offset, ARCH_CONVERT) == 0) {
 			*tail_blk = 0;
 			/* leave all other log inited values alone */
 			goto exit;
@@ -795,8 +841,9 @@
 	for (i = (int)(*head_blk) - 1; i >= 0; i--) {
 		if ((error = xlog_bread(log, i, 1, bp)))
 			goto bread_err;
+		offset = xlog_align(log, i, 1, bp);
 		if (XLOG_HEADER_MAGIC_NUM ==
-		    INT_GET(*(uint *)(XFS_BUF_PTR(bp)), ARCH_CONVERT)) {
+		    INT_GET(*(uint *)offset, ARCH_CONVERT)) {
 			found = 1;
 			break;
 		}
@@ -811,8 +858,9 @@
 		for (i = log->l_logBBsize - 1; i >= (int)(*head_blk); i--) {
 			if ((error = xlog_bread(log, i, 1, bp)))
 				goto bread_err;
+			offset = xlog_align(log, i, 1, bp);
 			if (XLOG_HEADER_MAGIC_NUM ==
-			    INT_GET(*(uint*)(XFS_BUF_PTR(bp)), ARCH_CONVERT)) {
+			    INT_GET(*(uint*)offset, ARCH_CONVERT)) {
 				found = 2;
 				break;
 			}
@@ -825,7 +873,7 @@
 	}
 
 	/* find blk_no of tail of log */
-	rhead = (xlog_rec_header_t *)XFS_BUF_PTR(bp);
+	rhead = (xlog_rec_header_t *)offset;
 	*tail_blk = BLOCK_LSN(rhead->h_tail_lsn, ARCH_CONVERT);
 
 	/*
@@ -885,7 +933,8 @@
 		if ((error = xlog_bread(log, umount_data_blk, 1, bp))) {
 			goto bread_err;
 		}
-		op_head = (xlog_op_header_t *)XFS_BUF_PTR(bp);
+		offset = xlog_align(log, umount_data_blk, 1, bp);
+		op_head = (xlog_op_header_t *)offset;
 		if (op_head->oh_flags & XLOG_UNMOUNT_TRANS) {
 			/*
 			 * Set tail and last sync so that newly written
@@ -900,7 +949,6 @@
 		}
 	}
 
-#ifdef __KERNEL__
 	/*
 	 * Make sure that there are no blocks in front of the head
 	 * with the same cycle number as the head.  This can happen
@@ -920,11 +968,9 @@
 	 * But... if the -device- itself is readonly, just skip this.
 	 * We can't recover this device anyway, so it won't matter.
 	 */
-
-	if (!bdev_read_only(log->l_mp->m_logdev_targp->pbr_bdev)) {
+	if (!xfs_readonly_buftarg(log->l_mp->m_logdev_targp)) {
 		error = xlog_clear_stale_blocks(log, tail_lsn);
 	}
-#endif
 
 bread_err:
 exit:
@@ -932,10 +978,8 @@
 
 	if (error)
 		xlog_warn("XFS: failed to locate log tail");
-
 	return error;
-}	/* xlog_find_tail */
-
+}
 
 /*
  * Is the log zeroed at all?
@@ -954,22 +998,25 @@
  *	>0 => error has occurred
  */
 int
-xlog_find_zeroed(struct log	*log,
-		 xfs_daddr_t	*blk_no)
+xlog_find_zeroed(
+	xlog_t		*log,
+	xfs_daddr_t	*blk_no)
 {
 	xfs_buf_t	*bp;
+	xfs_caddr_t	offset;
 	uint	        first_cycle, last_cycle;
 	xfs_daddr_t	new_blk, last_blk, start_blk;
 	xfs_daddr_t     num_scan_bblks;
 	int	        error, log_bbnum = log->l_logBBsize;
 
 	/* check totally zeroed log */
-	bp = xlog_get_bp(1,log->l_mp);
+	bp = xlog_get_bp(log, 1);
 	if (!bp)
 		return ENOMEM;
 	if ((error = xlog_bread(log, 0, 1, bp)))
 		goto bp_err;
-	first_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
+	offset = xlog_align(log, 0, 1, bp);
+	first_cycle = GET_CYCLE(offset, ARCH_CONVERT);
 	if (first_cycle == 0) {		/* completely zeroed log */
 		*blk_no = 0;
 		xlog_put_bp(bp);
@@ -979,7 +1026,8 @@
 	/* check partially zeroed log */
 	if ((error = xlog_bread(log, log_bbnum-1, 1, bp)))
 		goto bp_err;
-	last_cycle = GET_CYCLE(XFS_BUF_PTR(bp), ARCH_CONVERT);
+	offset = xlog_align(log, log_bbnum-1, 1, bp);
+	last_cycle = GET_CYCLE(offset, ARCH_CONVERT);
 	if (last_cycle != 0) {		/* log completely written to */
 		xlog_put_bp(bp);
 		return 0;
@@ -1040,67 +1088,106 @@
 	if (error)
 		return error;
 	return -1;
-}	/* xlog_find_zeroed */
+}
 
 /*
- * This is simply a subroutine used by xlog_clear_stale_blocks() below
+ * These are simple subroutines used by xlog_clear_stale_blocks() below
  * to initialize a buffer full of empty log record headers and write
  * them into the log.
  */
+STATIC void
+xlog_add_record(
+	xlog_t			*log,
+	xfs_caddr_t		buf,
+	int			cycle,
+	int			block,
+	int			tail_cycle,
+	int			tail_block)
+{
+	xlog_rec_header_t	*recp = (xlog_rec_header_t *)buf;
+
+	memset(buf, 0, BBSIZE);
+	INT_SET(recp->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
+	INT_SET(recp->h_cycle, ARCH_CONVERT, cycle);
+	INT_SET(recp->h_version, ARCH_CONVERT,
+			XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1);
+	ASSIGN_ANY_LSN(recp->h_lsn, cycle, block, ARCH_CONVERT);
+	ASSIGN_ANY_LSN(recp->h_tail_lsn, tail_cycle, tail_block, ARCH_CONVERT);
+	INT_SET(recp->h_fmt, ARCH_CONVERT, XLOG_FMT);
+	memcpy(&recp->h_fs_uuid, &log->l_mp->m_sb.sb_uuid, sizeof(uuid_t));
+}
+
 STATIC int
 xlog_write_log_records(
-	xlog_t	*log,
-	int	cycle,
-	int	start_block,
-	int	blocks,
-	int	tail_cycle,
-	int	tail_block)
-{
-	xlog_rec_header_t	*recp;
-	int			i, j;
-	int			end_block = start_block + blocks;
-	int			error       = 0;
-	xfs_buf_t		*bp;
-	char		        *buf;
-	int			bufblks;
+	xlog_t		*log,
+	int		cycle,
+	int		start_block,
+	int		blocks,
+	int		tail_cycle,
+	int		tail_block)
+{
+	xfs_caddr_t	offset;
+	xfs_buf_t	*bp;
+	int		balign, ealign;
+	int		sectbb = XLOG_SECTOR_ROUNDUP_BBCOUNT(log, 1);
+	int		end_block = start_block + blocks;
+	int		bufblks;
+	int		error = 0;
+	int		i, j = 0;
 
 	bufblks = 1 << ffs(blocks);
-	while (!(bp = xlog_get_bp(bufblks, log->l_mp))) {
+	while (!(bp = xlog_get_bp(log, bufblks))) {
 		bufblks >>= 1;
-		if (!bufblks)
+		if (bufblks <= log->l_sectbb_log)
 			return ENOMEM;
 	}
 
-	buf = XFS_BUF_PTR(bp);
-	recp = (xlog_rec_header_t*)buf;
-
-	memset(buf, 0, BBSIZE);
-	INT_SET(recp->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
-	INT_SET(recp->h_cycle, ARCH_CONVERT, cycle);
-	INT_SET(recp->h_version, ARCH_CONVERT,
-			XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? 2 : 1);
-	ASSIGN_ANY_LSN(recp->h_tail_lsn, tail_cycle, tail_block, ARCH_CONVERT);
+	/* We may need to do a read at the start to fill in part of
+	 * the buffer in the starting sector not covered by the first
+	 * write below.
+	 */
+	balign = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, start_block);
+	if (balign != start_block) {
+		if ((error = xlog_bread(log, start_block, 1, bp))) {
+			xlog_put_bp(bp);
+			return error;
+		}
+		j = start_block - balign;
+	}
 
 	for (i = start_block; i < end_block; i += bufblks) {
-		int bcount = min(bufblks, end_block - start_block);
-		/* with plenty of memory, we duplicate the block
-		 * right through the buffer and modify each entry
-		 */
-		ASSIGN_ANY_LSN(recp->h_lsn, cycle, i, ARCH_CONVERT);
-		for (j = 1; j < bcount; j++) {
-			buf += BBSIZE;
-			recp = (xlog_rec_header_t*)buf;
-			memcpy(buf, XFS_BUF_PTR(bp), BBSIZE);
-			ASSIGN_ANY_LSN(recp->h_lsn, cycle, i+j, ARCH_CONVERT);
-		}
-		/* then write the whole lot out at once */
-		error = xlog_bwrite(log, start_block, bcount, bp);
-		start_block += bcount;
-		buf = XFS_BUF_PTR(bp);
-		recp = (xlog_rec_header_t*)buf;
+		int		bcount, endcount;
+
+		bcount = min(bufblks, end_block - start_block);
+		endcount = bcount - j;
+
+		/* We may need to do a read at the end to fill in part of
+		 * the buffer in the final sector not covered by the write.
+		 * If this is the same sector as the above read, skip it.
+		 */
+		ealign = XLOG_SECTOR_ROUNDDOWN_BLKNO(log, end_block);
+		if (j == 0 && (start_block + endcount > ealign)) {
+			offset = XFS_BUF_PTR(bp);
+			balign = BBTOB(ealign - start_block);
+			XFS_BUF_SET_PTR(bp, offset + balign, BBTOB(sectbb));
+			if ((error = xlog_bread(log, ealign, sectbb, bp)))
+				break;
+			XFS_BUF_SET_PTR(bp, offset, bufblks);
+		}
+
+		offset = xlog_align(log, start_block, endcount, bp);
+		for (; j < endcount; j++) {
+			xlog_add_record(log, offset, cycle, i+j,
+					tail_cycle, tail_block);
+			offset += BBSIZE;
+		}
+		error = xlog_bwrite(log, start_block, endcount, bp);
+		if (error)
+			break;
+		start_block += endcount;
+		j = 0;
 	}
 	xlog_put_bp(bp);
-
 	return error;
 }
 
@@ -1244,10 +1331,11 @@
  */
 
 STATIC xlog_recover_t *
-xlog_recover_find_tid(xlog_recover_t *q,
-		      xlog_tid_t     tid)
+xlog_recover_find_tid(
+	xlog_recover_t		*q,
+	xlog_tid_t		tid)
 {
-	xlog_recover_t *p = q;
+	xlog_recover_t		*p = q;
 
 	while (p != NULL) {
 		if (p->r_log_tid == tid)
@@ -1255,42 +1343,43 @@
 		p = p->r_next;
 	}
 	return p;
-}	/* xlog_recover_find_tid */
-
+}
 
 STATIC void
-xlog_recover_put_hashq(xlog_recover_t **q,
-		       xlog_recover_t *trans)
+xlog_recover_put_hashq(
+	xlog_recover_t		**q,
+	xlog_recover_t		*trans)
 {
 	trans->r_next = *q;
 	*q = trans;
-}	/* xlog_recover_put_hashq */
-
+}
 
 STATIC void
-xlog_recover_add_item(xlog_recover_item_t **itemq)
+xlog_recover_add_item(
+	xlog_recover_item_t	**itemq)
 {
-	xlog_recover_item_t *item;
+	xlog_recover_item_t	*item;
 
 	item = kmem_zalloc(sizeof(xlog_recover_item_t), 0);
 	xlog_recover_insert_item_backq(itemq, item);
-}	/* xlog_recover_add_item */
-
+}
 
 STATIC int
-xlog_recover_add_to_cont_trans(xlog_recover_t	*trans,
-			       xfs_caddr_t		dp,
-			       int		len)
+xlog_recover_add_to_cont_trans(
+	xlog_recover_t		*trans,
+	xfs_caddr_t		dp,
+	int			len)
 {
 	xlog_recover_item_t	*item;
-	xfs_caddr_t			ptr, old_ptr;
+	xfs_caddr_t		ptr, old_ptr;
 	int			old_len;
 
 	item = trans->r_itemq;
 	if (item == 0) {
 		/* finish copying rest of trans header */
 		xlog_recover_add_item(&trans->r_itemq);
-		ptr = (xfs_caddr_t)&trans->r_theader+sizeof(xfs_trans_header_t)-len;
+		ptr = (xfs_caddr_t) &trans->r_theader +
+				sizeof(xfs_trans_header_t) - len;
 		memcpy(ptr, dp, len); /* d, s, l */
 		return 0;
 	}
@@ -1304,10 +1393,10 @@
 	item->ri_buf[item->ri_cnt-1].i_len += len;
 	item->ri_buf[item->ri_cnt-1].i_addr = ptr;
 	return 0;
-}	/* xlog_recover_add_to_cont_trans */
-
+}
 
-/* The next region to add is the start of a new region.  It could be
+/*
+ * The next region to add is the start of a new region.  It could be
  * a whole region or it could be the first part of a new region.  Because
  * of this, the assumption here is that the type and size fields of all
  * format structures fit into the first 32 bits of the structure.
@@ -1320,13 +1409,14 @@
  * will appear in the current log item.
  */
 STATIC int
-xlog_recover_add_to_trans(xlog_recover_t	*trans,
-			  xfs_caddr_t		dp,
-			  int			len)
-{
-	xfs_inode_log_format_t	 *in_f;			/* any will do */
-	xlog_recover_item_t	 *item;
-	xfs_caddr_t		 ptr;
+xlog_recover_add_to_trans(
+	xlog_recover_t		*trans,
+	xfs_caddr_t		dp,
+	int			len)
+{
+	xfs_inode_log_format_t	*in_f;			/* any will do */
+	xlog_recover_item_t	*item;
+	xfs_caddr_t		ptr;
 
 	if (!len)
 		return 0;
@@ -1339,7 +1429,7 @@
 		return 0;
 	}
 
-	ptr = kmem_alloc(len, 0);
+	ptr = kmem_alloc(len, KM_SLEEP);
 	memcpy(ptr, dp, len);
 	in_f = (xfs_inode_log_format_t *)ptr;
 
@@ -1362,29 +1452,29 @@
 	item->ri_buf[item->ri_cnt].i_len  = len;
 	item->ri_cnt++;
 	return 0;
-}	/* xlog_recover_add_to_trans */
-
+}
 
 STATIC void
-xlog_recover_new_tid(xlog_recover_t	**q,
-		     xlog_tid_t		tid,
-		     xfs_lsn_t		lsn)
+xlog_recover_new_tid(
+	xlog_recover_t		**q,
+	xlog_tid_t		tid,
+	xfs_lsn_t		lsn)
 {
-	xlog_recover_t	*trans;
+	xlog_recover_t		*trans;
 
-	trans = kmem_zalloc(sizeof(xlog_recover_t), 0);
+	trans = kmem_zalloc(sizeof(xlog_recover_t), KM_SLEEP);
 	trans->r_log_tid   = tid;
 	trans->r_lsn	   = lsn;
 	xlog_recover_put_hashq(q, trans);
-}	/* xlog_recover_new_tid */
-
+}
 
 STATIC int
-xlog_recover_unlink_tid(xlog_recover_t	**q,
-			xlog_recover_t	*trans)
+xlog_recover_unlink_tid(
+	xlog_recover_t		**q,
+	xlog_recover_t		*trans)
 {
-	xlog_recover_t	*tp;
-	int		found = 0;
+	xlog_recover_t		*tp;
+	int			found = 0;
 
 	ASSERT(trans != 0);
 	if (trans == *q) {
@@ -1407,11 +1497,12 @@
 		tp->r_next = tp->r_next->r_next;
 	}
 	return 0;
-}	/* xlog_recover_unlink_tid */
+}
 
 STATIC void
-xlog_recover_insert_item_backq(xlog_recover_item_t **q,
-			       xlog_recover_item_t *item)
+xlog_recover_insert_item_backq(
+	xlog_recover_item_t	**q,
+	xlog_recover_item_t	*item)
 {
 	if (*q == 0) {
 		item->ri_prev = item->ri_next = item;
@@ -1422,55 +1513,53 @@
 		(*q)->ri_prev		= item;
 		item->ri_prev->ri_next	= item;
 	}
-}	/* xlog_recover_insert_item_backq */
+}
 
 STATIC void
-xlog_recover_insert_item_frontq(xlog_recover_item_t **q,
-				xlog_recover_item_t *item)
+xlog_recover_insert_item_frontq(
+	xlog_recover_item_t	**q,
+	xlog_recover_item_t	*item)
 {
 	xlog_recover_insert_item_backq(q, item);
 	*q = item;
-}	/* xlog_recover_insert_item_frontq */
+}
 
 STATIC int
-xlog_recover_reorder_trans(xlog_t	  *log,
-			   xlog_recover_t *trans)
+xlog_recover_reorder_trans(
+	xlog_t			*log,
+	xlog_recover_t		*trans)
 {
-    xlog_recover_item_t *first_item, *itemq, *itemq_next;
+	xlog_recover_item_t	*first_item, *itemq, *itemq_next;
 
-    first_item = itemq = trans->r_itemq;
-    trans->r_itemq = NULL;
-    do {
-	itemq_next = itemq->ri_next;
-	switch (ITEM_TYPE(itemq)) {
-	    case XFS_LI_BUF:
-	    case XFS_LI_6_1_BUF:
-	    case XFS_LI_5_3_BUF: {
-		xlog_recover_insert_item_frontq(&trans->r_itemq, itemq);
-		break;
-	    }
-	    case XFS_LI_INODE:
-	    case XFS_LI_6_1_INODE:
-	    case XFS_LI_5_3_INODE:
-	    case XFS_LI_DQUOT:
-	    case XFS_LI_QUOTAOFF:
-	    case XFS_LI_EFD:
-	    case XFS_LI_EFI: {
-		xlog_recover_insert_item_backq(&trans->r_itemq, itemq);
-		break;
-	    }
-	    default: {
-		xlog_warn(
+	first_item = itemq = trans->r_itemq;
+	trans->r_itemq = NULL;
+	do {
+		itemq_next = itemq->ri_next;
+		switch (ITEM_TYPE(itemq)) {
+		case XFS_LI_BUF:
+		case XFS_LI_6_1_BUF:
+		case XFS_LI_5_3_BUF:
+			xlog_recover_insert_item_frontq(&trans->r_itemq, itemq);
+			break;
+		case XFS_LI_INODE:
+		case XFS_LI_6_1_INODE:
+		case XFS_LI_5_3_INODE:
+		case XFS_LI_DQUOT:
+		case XFS_LI_QUOTAOFF:
+		case XFS_LI_EFD:
+		case XFS_LI_EFI:
+			xlog_recover_insert_item_backq(&trans->r_itemq, itemq);
+			break;
+		default:
+			xlog_warn(
 	"XFS: xlog_recover_reorder_trans: unrecognized type of log operation");
-		ASSERT(0);
-		return XFS_ERROR(EIO);
-	    }
-	}
-	itemq = itemq_next;
-    } while (first_item != itemq);
-    return 0;
-}	/* xlog_recover_reorder_trans */
-
+			ASSERT(0);
+			return XFS_ERROR(EIO);
+		}
+		itemq = itemq_next;
+	} while (first_item != itemq);
+	return 0;
+}
 
 /*
  * Build up the table of buf cancel records so that we don't replay
@@ -1485,17 +1574,18 @@
  * record during the second pass.
  */
 STATIC void
-xlog_recover_do_buffer_pass1(xlog_t			*log,
-			     xfs_buf_log_format_t	*buf_f)
+xlog_recover_do_buffer_pass1(
+	xlog_t			*log,
+	xfs_buf_log_format_t	*buf_f)
 {
 	xfs_buf_cancel_t	*bcp;
 	xfs_buf_cancel_t	*nextp;
 	xfs_buf_cancel_t	*prevp;
 	xfs_buf_cancel_t	**bucket;
 	xfs_buf_log_format_v1_t	*obuf_f;
-	xfs_daddr_t		blkno=0;
-	uint			len=0;
-	ushort			flags=0;
+	xfs_daddr_t		blkno = 0;
+	uint			len = 0;
+	ushort			flags = 0;
 
 	switch (buf_f->blf_type) {
 	case XFS_LI_BUF:
@@ -1515,9 +1605,8 @@
 	/*
 	 * If this isn't a cancel buffer item, then just return.
 	 */
-	if (!(flags & XFS_BLI_CANCEL)) {
+	if (!(flags & XFS_BLI_CANCEL))
 		return;
-	}
 
 	/*
 	 * Insert an xfs_buf_cancel record into the hash table of
@@ -1531,8 +1620,8 @@
 	 * the bucket.
 	 */
 	if (*bucket == NULL) {
-		bcp = (xfs_buf_cancel_t*)kmem_alloc(sizeof(xfs_buf_cancel_t),
-						    KM_SLEEP);
+		bcp = (xfs_buf_cancel_t *)kmem_alloc(sizeof(xfs_buf_cancel_t),
+						     KM_SLEEP);
 		bcp->bc_blkno = blkno;
 		bcp->bc_len = len;
 		bcp->bc_refcount = 1;
@@ -1557,8 +1646,8 @@
 		nextp = nextp->bc_next;
 	}
 	ASSERT(prevp != NULL);
-	bcp = (xfs_buf_cancel_t*)kmem_alloc(sizeof(xfs_buf_cancel_t),
-					    KM_SLEEP);
+	bcp = (xfs_buf_cancel_t *)kmem_alloc(sizeof(xfs_buf_cancel_t),
+					     KM_SLEEP);
 	bcp->bc_blkno = blkno;
 	bcp->bc_len = len;
 	bcp->bc_refcount = 1;
@@ -1580,17 +1669,17 @@
  * made at that point.
  */
 STATIC int
-xlog_recover_do_buffer_pass2(xlog_t			*log,
-			     xfs_buf_log_format_t	*buf_f)
+xlog_recover_do_buffer_pass2(
+	xlog_t			*log,
+	xfs_buf_log_format_t	*buf_f)
 {
 	xfs_buf_cancel_t	*bcp;
 	xfs_buf_cancel_t	*prevp;
 	xfs_buf_cancel_t	**bucket;
 	xfs_buf_log_format_v1_t	*obuf_f;
-	xfs_daddr_t		blkno=0;
-	ushort			flags=0;
-	uint			len=0;
-
+	xfs_daddr_t		blkno = 0;
+	ushort			flags = 0;
+	uint			len = 0;
 
 	switch (buf_f->blf_type) {
 	case XFS_LI_BUF:
@@ -1667,7 +1756,6 @@
 	return 0;
 }
 
-
 /*
  * Perform recovery for a buffer full of inodes.  In these buffers,
  * the only data which should be recovered is that which corresponds
@@ -1682,10 +1770,11 @@
  * sent to xlog_recover_do_reg_buffer() below during recovery.
  */
 STATIC int
-xlog_recover_do_inode_buffer(xfs_mount_t		*mp,
-			     xlog_recover_item_t	*item,
-			     xfs_buf_t			*bp,
-			     xfs_buf_log_format_t	*buf_f)
+xlog_recover_do_inode_buffer(
+	xfs_mount_t		*mp,
+	xlog_recover_item_t	*item,
+	xfs_buf_t		*bp,
+	xfs_buf_log_format_t	*buf_f)
 {
 	int			i;
 	int			item_index;
@@ -1698,8 +1787,8 @@
 	xfs_agino_t		*logged_nextp;
 	xfs_agino_t		*buffer_nextp;
 	xfs_buf_log_format_v1_t	*obuf_f;
-	unsigned int		*data_map=NULL;
-	unsigned int		map_size=0;
+	unsigned int		*data_map = NULL;
+	unsigned int		map_size = 0;
 
 	switch (buf_f->blf_type) {
 	case XFS_LI_BUF:
@@ -1790,7 +1879,7 @@
 	}
 
 	return 0;
-}	/* xlog_recover_do_inode_buffer */
+}
 
 /*
  * Perform a 'normal' buffer recovery.  Each logged region of the
@@ -1800,17 +1889,18 @@
  */
 /*ARGSUSED*/
 STATIC void
-xlog_recover_do_reg_buffer(xfs_mount_t		*mp,
-			   xlog_recover_item_t	*item,
-			   xfs_buf_t		*bp,
-			   xfs_buf_log_format_t	*buf_f)
+xlog_recover_do_reg_buffer(
+	xfs_mount_t		*mp,
+	xlog_recover_item_t	*item,
+	xfs_buf_t		*bp,
+	xfs_buf_log_format_t	*buf_f)
 {
 	int			i;
 	int			bit;
 	int			nbits;
 	xfs_buf_log_format_v1_t	*obuf_f;
-	unsigned int		*data_map=NULL;
-	unsigned int		map_size=0;
+	unsigned int		*data_map = NULL;
+	unsigned int		map_size = 0;
 	int                     error;
 
 	switch (buf_f->blf_type) {
@@ -1860,7 +1950,7 @@
 
 	/* Shouldn't be any more regions */
 	ASSERT(i == item->ri_total);
-}	/* xlog_recover_do_reg_buffer */
+}
 
 /*
  * Do some primitive error checking on ondisk dquot data structures.
@@ -1991,7 +2081,7 @@
 	xfs_buf_t		*bp,
 	xfs_buf_log_format_t	*buf_f)
 {
-	uint type;
+	uint			type;
 
 	/*
 	 * Filesystems are required to send in quota flags at mount time.
@@ -2038,9 +2128,10 @@
  * for more details on the implementation of the table of cancel records.
  */
 STATIC int
-xlog_recover_do_buffer_trans(xlog_t		 *log,
-			     xlog_recover_item_t *item,
-			     int		 pass)
+xlog_recover_do_buffer_trans(
+	xlog_t			*log,
+	xlog_recover_item_t	*item,
+	int			pass)
 {
 	xfs_buf_log_format_t	*buf_f;
 	xfs_buf_log_format_v1_t	*obuf_f;
@@ -2075,19 +2166,19 @@
 		}
 	}
 	switch (buf_f->blf_type) {
-	      case XFS_LI_BUF:
+	case XFS_LI_BUF:
 		blkno = buf_f->blf_blkno;
 		len = buf_f->blf_len;
 		flags = buf_f->blf_flags;
 		break;
-	      case XFS_LI_6_1_BUF:
-	      case XFS_LI_5_3_BUF:
+	case XFS_LI_6_1_BUF:
+	case XFS_LI_5_3_BUF:
 		obuf_f = (xfs_buf_log_format_v1_t*)buf_f;
 		blkno = obuf_f->blf_blkno;
 		len = obuf_f->blf_len;
 		flags = obuf_f->blf_flags;
 		break;
-	      default:
+	default:
 		xfs_fs_cmn_err(CE_ALERT, log->l_mp,
 			"xfs_log_recover: unknown buffer type 0x%x, dev 0x%x",
 			buf_f->blf_type, log->l_dev);
@@ -2152,12 +2243,13 @@
 	}
 
 	return (error);
-}	/* xlog_recover_do_buffer_trans */
+}
 
 STATIC int
-xlog_recover_do_inode_trans(xlog_t		*log,
-			    xlog_recover_item_t *item,
-			    int			pass)
+xlog_recover_do_inode_trans(
+	xlog_t			*log,
+	xlog_recover_item_t	*item,
+	int			pass)
 {
 	xfs_inode_log_format_t	*in_f;
 	xfs_mount_t		*mp;
@@ -2377,7 +2469,6 @@
 		}
 	}
 
-
 write_inode_buffer:
 	if (ITEM_TYPE(item) == XFS_LI_INODE) {
 		ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL ||
@@ -2391,8 +2482,7 @@
 	}
 
 	return (error);
-}	/* xlog_recover_do_inode_trans */
-
+}
 
 /*
  * Recover QUOTAOFF records. We simply make a note of it in the xlog_t
@@ -2400,11 +2490,12 @@
  * of that type.
  */
 STATIC int
-xlog_recover_do_quotaoff_trans(xlog_t			*log,
-			       xlog_recover_item_t	*item,
-			       int			pass)
+xlog_recover_do_quotaoff_trans(
+	xlog_t			*log,
+	xlog_recover_item_t	*item,
+	int			pass)
 {
-	xfs_qoff_logformat_t *qoff_f;
+	xfs_qoff_logformat_t	*qoff_f;
 
 	if (pass == XLOG_RECOVER_PASS2) {
 		return (0);
@@ -2425,14 +2516,14 @@
 	return (0);
 }
 
-
 /*
  * Recover a dquot record
  */
 STATIC int
-xlog_recover_do_dquot_trans(xlog_t		*log,
-			    xlog_recover_item_t *item,
-			    int			pass)
+xlog_recover_do_dquot_trans(
+	xlog_t			*log,
+	xlog_recover_item_t	*item,
+	int			pass)
 {
 	xfs_mount_t		*mp;
 	xfs_buf_t		*bp;
@@ -2516,7 +2607,7 @@
 	xfs_bdwrite(mp, bp);
 
 	return (0);
-}	/* xlog_recover_do_dquot_trans */
+}
 
 /*
  * This routine is called to create an in-core extent free intent
@@ -2526,10 +2617,11 @@
  * LSN.
  */
 STATIC void
-xlog_recover_do_efi_trans(xlog_t		*log,
-			  xlog_recover_item_t	*item,
-			  xfs_lsn_t		lsn,
-			  int			pass)
+xlog_recover_do_efi_trans(
+	xlog_t			*log,
+	xlog_recover_item_t	*item,
+	xfs_lsn_t		lsn,
+	int			pass)
 {
 	xfs_mount_t		*mp;
 	xfs_efi_log_item_t	*efip;
@@ -2558,7 +2650,7 @@
 	 * xfs_trans_update_ail() drops the AIL lock.
 	 */
 	xfs_trans_update_ail(mp, (xfs_log_item_t *)efip, lsn, s);
-}	/* xlog_recover_do_efi_trans */
+}
 
 
 /*
@@ -2570,13 +2662,14 @@
  * AIL and free it.
  */
 STATIC void
-xlog_recover_do_efd_trans(xlog_t		*log,
-			  xlog_recover_item_t	*item,
-			  int			pass)
+xlog_recover_do_efd_trans(
+	xlog_t			*log,
+	xlog_recover_item_t	*item,
+	int			pass)
 {
 	xfs_mount_t		*mp;
 	xfs_efd_log_format_t	*efd_formatp;
-	xfs_efi_log_item_t	*efip=NULL;
+	xfs_efi_log_item_t	*efip = NULL;
 	xfs_log_item_t		*lip;
 	int			gen;
 	int			nexts;
@@ -2629,9 +2722,9 @@
 				  ((nexts - 1) * sizeof(xfs_extent_t)));
 		} else {
 			kmem_zone_free(xfs_efi_zone, efip);
+		}
 	}
-	}
-}	/* xlog_recover_do_efd_trans */
+}
 
 /*
  * Perform the transaction
@@ -2640,12 +2733,13 @@
  * EFIs and EFDs get queued up by adding entries into the AIL for them.
  */
 STATIC int
-xlog_recover_do_trans(xlog_t	     *log,
-		      xlog_recover_t *trans,
-		      int	     pass)
+xlog_recover_do_trans(
+	xlog_t			*log,
+	xlog_recover_t		*trans,
+	int			pass)
 {
-	int		    error = 0;
-	xlog_recover_item_t *item, *first_item;
+	int			error = 0;
+	xlog_recover_item_t	*item, *first_item;
 
 	if ((error = xlog_recover_reorder_trans(log, trans)))
 		return error;
@@ -2695,8 +2789,7 @@
 	} while (first_item != item);
 
 	return error;
-}	/* xlog_recover_do_trans */
-
+}
 
 /*
  * Free up any resources allocated by the transaction
@@ -2704,10 +2797,11 @@
  * Remember that EFIs, EFDs, and IUNLINKs are handled later.
  */
 STATIC void
-xlog_recover_free_trans(xlog_recover_t      *trans)
+xlog_recover_free_trans(
+	xlog_recover_t		*trans)
 {
-	xlog_recover_item_t *first_item, *item, *free_item;
-	int i;
+	xlog_recover_item_t	*first_item, *item, *free_item;
+	int			i;
 
 	item = first_item = trans->r_itemq;
 	do {
@@ -2725,16 +2819,16 @@
 	} while (first_item != item);
 	/* Free the transaction recover structure */
 	kmem_free(trans, sizeof(xlog_recover_t));
-}	/* xlog_recover_free_trans */
-
+}
 
 STATIC int
-xlog_recover_commit_trans(xlog_t	 *log,
-			  xlog_recover_t **q,
-			  xlog_recover_t *trans,
-			  int		 pass)
+xlog_recover_commit_trans(
+	xlog_t			*log,
+	xlog_recover_t		**q,
+	xlog_recover_t		*trans,
+	int			pass)
 {
-	int error;
+	int			error;
 
 	if ((error = xlog_recover_unlink_tid(q, trans)))
 		return error;
@@ -2742,18 +2836,16 @@
 		return error;
 	xlog_recover_free_trans(trans);			/* no error */
 	return 0;
-}	/* xlog_recover_commit_trans */
-
+}
 
-/*ARGSUSED*/
 STATIC int
-xlog_recover_unmount_trans(xlog_recover_t *trans)
+xlog_recover_unmount_trans(
+	xlog_recover_t		*trans)
 {
 	/* Do nothing now */
 	xlog_warn("XFS: xlog_recover_unmount_trans: Unmount LR");
-	return( 0 );
-}	/* xlog_recover_unmount_trans */
-
+	return 0;
+}
 
 /*
  * There are two valid states of the r_state field.  0 indicates that the
@@ -2765,97 +2857,101 @@
  * NOTE: skip LRs with 0 data length.
  */
 STATIC int
-xlog_recover_process_data(xlog_t	    *log,
-			  xlog_recover_t    *rhash[],
-			  xlog_rec_header_t *rhead,
-			  xfs_caddr_t	    dp,
-			  int		    pass)
-{
-    xfs_caddr_t		lp	   = dp+INT_GET(rhead->h_len, ARCH_CONVERT);
-    int			num_logops = INT_GET(rhead->h_num_logops, ARCH_CONVERT);
-    xlog_op_header_t	*ohead;
-    xlog_recover_t	*trans;
-    xlog_tid_t		tid;
-    int			error;
-    unsigned long	hash;
-    uint		flags;
-
-    /* check the log format matches our own - else we can't recover */
-    if (xlog_header_check_recover(log->l_mp, rhead))
-	    return (XFS_ERROR(EIO));
-
-    while ((dp < lp) && num_logops) {
-	ASSERT(dp + sizeof(xlog_op_header_t) <= lp);
-	ohead = (xlog_op_header_t *)dp;
-	dp += sizeof(xlog_op_header_t);
-	if (ohead->oh_clientid != XFS_TRANSACTION &&
-	    ohead->oh_clientid != XFS_LOG) {
-	    xlog_warn("XFS: xlog_recover_process_data: bad clientid");
-	    ASSERT(0);
-	    return (XFS_ERROR(EIO));
-	}
-	tid = INT_GET(ohead->oh_tid, ARCH_CONVERT);
-	hash = XLOG_RHASH(tid);
-	trans = xlog_recover_find_tid(rhash[hash], tid);
-	if (trans == NULL) {			   /* not found; add new tid */
-	    if (ohead->oh_flags & XLOG_START_TRANS)
-		xlog_recover_new_tid(&rhash[hash], tid, INT_GET(rhead->h_lsn, ARCH_CONVERT));
-	} else {
-	    ASSERT(dp+INT_GET(ohead->oh_len, ARCH_CONVERT) <= lp);
-	    flags = ohead->oh_flags & ~XLOG_END_TRANS;
-	    if (flags & XLOG_WAS_CONT_TRANS)
-		flags &= ~XLOG_CONTINUE_TRANS;
-	    switch (flags) {
-		case XLOG_COMMIT_TRANS: {
-		    error = xlog_recover_commit_trans(log, &rhash[hash],
-						      trans, pass);
-		    break;
-		}
-		case XLOG_UNMOUNT_TRANS: {
-		    error = xlog_recover_unmount_trans(trans);
-		    break;
-		}
-		case XLOG_WAS_CONT_TRANS: {
-		    error = xlog_recover_add_to_cont_trans(trans, dp,
-				  INT_GET(ohead->oh_len, ARCH_CONVERT));
-		    break;
-		}
-		case XLOG_START_TRANS : {
-		    xlog_warn("XFS: xlog_recover_process_data: bad transaction");
-		    ASSERT(0);
-		    error = XFS_ERROR(EIO);
-		    break;
-		}
-		case 0:
-		case XLOG_CONTINUE_TRANS: {
-		    error = xlog_recover_add_to_trans(trans, dp,
-				   INT_GET(ohead->oh_len, ARCH_CONVERT));
-		    break;
+xlog_recover_process_data(
+	xlog_t			*log,
+	xlog_recover_t		*rhash[],
+	xlog_rec_header_t	*rhead,
+	xfs_caddr_t		dp,
+	int			pass)
+{
+	xfs_caddr_t		lp;
+	int			num_logops;
+	xlog_op_header_t	*ohead;
+	xlog_recover_t		*trans;
+	xlog_tid_t		tid;
+	int			error;
+	unsigned long		hash;
+	uint			flags;
+
+	lp = dp + INT_GET(rhead->h_len, ARCH_CONVERT);
+	num_logops = INT_GET(rhead->h_num_logops, ARCH_CONVERT);
+
+	/* check the log format matches our own - else we can't recover */
+	if (xlog_header_check_recover(log->l_mp, rhead))
+		return (XFS_ERROR(EIO));
+
+	while ((dp < lp) && num_logops) {
+		ASSERT(dp + sizeof(xlog_op_header_t) <= lp);
+		ohead = (xlog_op_header_t *)dp;
+		dp += sizeof(xlog_op_header_t);
+		if (ohead->oh_clientid != XFS_TRANSACTION &&
+		    ohead->oh_clientid != XFS_LOG) {
+			xlog_warn(
+		"XFS: xlog_recover_process_data: bad clientid");
+			ASSERT(0);
+			return (XFS_ERROR(EIO));
 		}
-		default: {
-		    xlog_warn("XFS: xlog_recover_process_data: bad flag");
-		    ASSERT(0);
-		    error = XFS_ERROR(EIO);
-		    break;
+		tid = INT_GET(ohead->oh_tid, ARCH_CONVERT);
+		hash = XLOG_RHASH(tid);
+		trans = xlog_recover_find_tid(rhash[hash], tid);
+		if (trans == NULL) {		   /* not found; add new tid */
+			if (ohead->oh_flags & XLOG_START_TRANS)
+				xlog_recover_new_tid(&rhash[hash], tid,
+					INT_GET(rhead->h_lsn, ARCH_CONVERT));
+		} else {
+			ASSERT(dp+INT_GET(ohead->oh_len, ARCH_CONVERT) <= lp);
+			flags = ohead->oh_flags & ~XLOG_END_TRANS;
+			if (flags & XLOG_WAS_CONT_TRANS)
+				flags &= ~XLOG_CONTINUE_TRANS;
+			switch (flags) {
+			case XLOG_COMMIT_TRANS:
+				error = xlog_recover_commit_trans(log,
+						&rhash[hash], trans, pass);
+				break;
+			case XLOG_UNMOUNT_TRANS:
+				error = xlog_recover_unmount_trans(trans);
+				break;
+			case XLOG_WAS_CONT_TRANS:
+				error = xlog_recover_add_to_cont_trans(trans,
+						dp, INT_GET(ohead->oh_len,
+							ARCH_CONVERT));
+				break;
+			case XLOG_START_TRANS:
+				xlog_warn(
+			"XFS: xlog_recover_process_data: bad transaction");
+				ASSERT(0);
+				error = XFS_ERROR(EIO);
+				break;
+			case 0:
+			case XLOG_CONTINUE_TRANS:
+				error = xlog_recover_add_to_trans(trans,
+						dp, INT_GET(ohead->oh_len,
+							ARCH_CONVERT));
+				break;
+			default:
+				xlog_warn(
+			"XFS: xlog_recover_process_data: bad flag");
+				ASSERT(0);
+				error = XFS_ERROR(EIO);
+				break;
+			}
+			if (error)
+				return error;
 		}
-	    } /* switch */
-	    if (error)
-		return error;
-	} /* if */
-	dp += INT_GET(ohead->oh_len, ARCH_CONVERT);
-	num_logops--;
-    }
-    return( 0 );
-}	/* xlog_recover_process_data */
-
+		dp += INT_GET(ohead->oh_len, ARCH_CONVERT);
+		num_logops--;
+	}
+	return 0;
+}
 
 /*
  * Process an extent free intent item that was recovered from
  * the log.  We need to free the extents that it describes.
  */
 STATIC void
-xlog_recover_process_efi(xfs_mount_t		*mp,
-			 xfs_efi_log_item_t	*efip)
+xlog_recover_process_efi(
+	xfs_mount_t		*mp,
+	xfs_efi_log_item_t	*efip)
 {
 	xfs_efd_log_item_t	*efdp;
 	xfs_trans_t		*tp;
@@ -2900,8 +2996,7 @@
 
 	efip->efi_flags |= XFS_EFI_RECOVERED;
 	xfs_trans_commit(tp, 0, NULL);
-}	/* xlog_recover_process_efi */
-
+}
 
 /*
  * Verify that once we've encountered something other than an EFI
@@ -2909,13 +3004,13 @@
  */
 #if defined(DEBUG)
 STATIC void
-xlog_recover_check_ail(xfs_mount_t	*mp,
-		       xfs_log_item_t	*lip,
-		       int		gen)
+xlog_recover_check_ail(
+	xfs_mount_t		*mp,
+	xfs_log_item_t		*lip,
+	int			gen)
 {
-	int	orig_gen;
+	int			orig_gen = gen;
 
-	orig_gen = gen;
 	do {
 		ASSERT(lip->li_type != XFS_LI_EFI);
 		lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
@@ -2930,7 +3025,6 @@
 }
 #endif	/* DEBUG */
 
-
 /*
  * When this is called, all of the EFIs which did not have
  * corresponding EFDs should be in the AIL.  What we do now
@@ -2950,7 +3044,8 @@
  * we see something other than an EFI in the AIL.
  */
 STATIC void
-xlog_recover_process_efis(xlog_t	*log)
+xlog_recover_process_efis(
+	xlog_t			*log)
 {
 	xfs_log_item_t		*lip;
 	xfs_efi_log_item_t	*efip;
@@ -2986,8 +3081,7 @@
 		lip = xfs_trans_next_ail(mp, lip, &gen, NULL);
 	}
 	AIL_UNLOCK(mp, s);
-}	/* xlog_recover_process_efis */
-
+}
 
 /*
  * This routine performs a transaction to null out a bad inode pointer
@@ -3030,8 +3124,7 @@
 			  (offset + sizeof(xfs_agino_t) - 1));
 
 	(void) xfs_trans_commit(tp, 0, NULL);
-}	/* xlog_recover_clear_agi_bucket */
-
+}
 
 /*
  * xlog_iunlink_recover
@@ -3046,7 +3139,8 @@
  * atomic.
  */
 void
-xlog_recover_process_iunlinks(xlog_t	*log)
+xlog_recover_process_iunlinks(
+	xlog_t		*log)
 {
 	xfs_mount_t	*mp;
 	xfs_agnumber_t	agno;
@@ -3188,40 +3282,47 @@
 	}
 
 	mp->m_dmevmask = mp_dmevmask;
+}
 
-}	/* xlog_recover_process_iunlinks */
-
-
-/*
- * Stamp cycle number in every block
- *
- * This routine is also called in xfs_log.c
- */
-/*ARGSUSED*/
-void
-xlog_pack_data(xlog_t *log, xlog_in_core_t *iclog)
-{
-	int	i, j, k;
-	int	size = iclog->ic_offset + iclog->ic_roundoff;
-	xfs_caddr_t dp;
-	union ich {
-		xlog_rec_ext_header_t	hic_xheader;
-		char			hic_sector[XLOG_HEADER_SIZE];
-	} *xhdr;
-	uint	cycle_lsn;
 
 #ifdef DEBUG
-	uint	*up;
-	uint	chksum = 0;
+STATIC void
+xlog_pack_data_checksum(
+	xlog_t		*log,
+	xlog_in_core_t	*iclog,
+	int		size)
+{
+	int		i;
+	uint		*up;
+	uint		chksum = 0;
 
 	up = (uint *)iclog->ic_datap;
 	/* divide length by 4 to get # words */
-	for (i=0; i<size >> 2; i++) {
+	for (i = 0; i < (size >> 2); i++) {
 		chksum ^= INT_GET(*up, ARCH_CONVERT);
 		up++;
 	}
 	INT_SET(iclog->ic_header.h_chksum, ARCH_CONVERT, chksum);
-#endif /* DEBUG */
+}
+#else
+#define xlog_pack_data_checksum(log, iclog, size)
+#endif
+
+/*
+ * Stamp cycle number in every block
+ */
+void
+xlog_pack_data(
+	xlog_t			*log,
+	xlog_in_core_t		*iclog)
+{
+	int			i, j, k;
+	int			size = iclog->ic_offset + iclog->ic_roundoff;
+	uint			cycle_lsn;
+	xfs_caddr_t		dp;
+	xlog_in_core_2_t	*xhdr;
+
+	xlog_pack_data_checksum(log, iclog, size);
 
 	cycle_lsn = CYCLE_LSN_NOCONV(iclog->ic_header.h_lsn, ARCH_CONVERT);
 
@@ -3234,7 +3335,7 @@
 	}
 
 	if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
-		xhdr = (union ich*)&iclog->ic_header;
+		xhdr = (xlog_in_core_2_t *)&iclog->ic_header;
 		for ( ; i < BTOBB(size); i++) {
 			j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
 			k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
@@ -3247,45 +3348,18 @@
 			xhdr[i].hic_xheader.xh_cycle = cycle_lsn;
 		}
 	}
-
-}	/* xlog_pack_data */
-
-
-/*ARGSUSED*/
-STATIC void
-xlog_unpack_data(xlog_rec_header_t *rhead,
-		 xfs_caddr_t	   dp,
-		 xlog_t		   *log)
-{
-	int i, j, k;
-	union ich {
-		xlog_rec_header_t	hic_header;
-		xlog_rec_ext_header_t	hic_xheader;
-		char			hic_sector[XLOG_HEADER_SIZE];
-	} *xhdr;
+}
 
 #if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
-	uint *up = (uint *)dp;
-	uint chksum = 0;
-#endif
-
-	for (i=0; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)) &&
-		  i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) {
-		*(uint *)dp = *(uint *)&rhead->h_cycle_data[i];
-		dp += BBSIZE;
-	}
-
-	if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
-		xhdr = (union ich*)rhead;
-		for ( ; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) {
-			j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
-			k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
-			*(uint *)dp = xhdr[j].hic_xheader.xh_cycle_data[k];
-			dp += BBSIZE;
-		}
-	}
+STATIC void
+xlog_unpack_data_checksum(
+	xlog_rec_header_t	*rhead,
+	xfs_caddr_t		dp,
+	xlog_t			*log)
+{
+	uint			*up = (uint *)dp;
+	uint			chksum = 0;
 
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
 	/* divide length by 4 to get # words */
 	for (i=0; i < INT_GET(rhead->h_len, ARCH_CONVERT) >> 2; i++) {
 		chksum ^= INT_GET(*up, ARCH_CONVERT);
@@ -3306,9 +3380,38 @@
 		    log->l_flags |= XLOG_CHKSUM_MISMATCH;
 	    }
 	}
-#endif /* DEBUG && XFS_LOUD_RECOVERY */
-}	/* xlog_unpack_data */
+}
+#else
+#define xlog_unpack_data_checksum(rhead, dp, log)
+#endif
+
+STATIC void
+xlog_unpack_data(
+	xlog_rec_header_t	*rhead,
+	xfs_caddr_t		dp,
+	xlog_t			*log)
+{
+	int			i, j, k;
+	xlog_in_core_2_t	*xhdr;
+
+	for (i = 0; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)) &&
+		  i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) {
+		*(uint *)dp = *(uint *)&rhead->h_cycle_data[i];
+		dp += BBSIZE;
+	}
+
+	if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+		xhdr = (xlog_in_core_2_t *)rhead;
+		for ( ; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) {
+			j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
+			k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
+			*(uint *)dp = xhdr[j].hic_xheader.xh_cycle_data[k];
+			dp += BBSIZE;
+		}
+	}
 
+	xlog_unpack_data_checksum(rhead, dp, log);
+}
 
 /*
  * Read the log from tail to head and process the log records found.
@@ -3319,223 +3422,294 @@
  * here.
  */
 STATIC int
-xlog_do_recovery_pass(xlog_t	*log,
-		      xfs_daddr_t	head_blk,
-		      xfs_daddr_t	tail_blk,
-		      int	pass)
-{
-    xlog_rec_header_t	*rhead;
-    xfs_daddr_t		blk_no;
-    xfs_caddr_t		bufaddr;
-    xfs_buf_t		*hbp, *dbp;
-    int			error, h_size;
-    int			bblks, split_bblks;
-    int			hblks, split_hblks, wrapped_hblks;
-    xlog_recover_t	*rhash[XLOG_RHASH_SIZE];
-
-    error = 0;
-
-
-    /*
-     * Read the header of the tail block and get the iclog buffer size from
-     * h_size.  Use this to tell how many sectors make up the log header.
-     */
-    if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
-	/*
-	 * When using variable length iclogs, read first sector of iclog
-	 * header and extract the header size from it.  Get a new hbp that
-	 * is the correct size.
+xlog_do_recovery_pass(
+	xlog_t			*log,
+	xfs_daddr_t		head_blk,
+	xfs_daddr_t		tail_blk,
+	int			pass)
+{
+	xlog_rec_header_t	*rhead;
+	xfs_daddr_t		blk_no;
+	xfs_caddr_t		bufaddr, offset;
+	xfs_buf_t		*hbp, *dbp;
+	int			error = 0, h_size;
+	int			bblks, split_bblks;
+	int			hblks, split_hblks, wrapped_hblks;
+	xlog_recover_t		*rhash[XLOG_RHASH_SIZE];
+
+	/*
+	 * Read the header of the tail block and get the iclog buffer size from
+	 * h_size.  Use this to tell how many sectors make up the log header.
 	 */
-	hbp = xlog_get_bp(1, log->l_mp);
-	if (!hbp)
-	    return ENOMEM;
-	if ((error = xlog_bread(log, tail_blk, 1, hbp)))
-	    goto bread_err1;
-	rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp);
-	ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) ==
+	if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+		/*
+		 * When using variable length iclogs, read first sector of
+		 * iclog header and extract the header size from it.  Get a
+		 * new hbp that is the correct size.
+		 */
+		hbp = xlog_get_bp(log, 1);
+		if (!hbp)
+			return ENOMEM;
+		if ((error = xlog_bread(log, tail_blk, 1, hbp)))
+			goto bread_err1;
+		offset = xlog_align(log, tail_blk, 1, hbp);
+		rhead = (xlog_rec_header_t *)offset;
+		ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) ==
 						XLOG_HEADER_MAGIC_NUM);
-	if ((INT_GET(rhead->h_version, ARCH_CONVERT) & (~XLOG_VERSION_OKBITS)) != 0) {
-	    xlog_warn("XFS: xlog_do_recovery_pass: unrecognised log version number.");
-	    error = XFS_ERROR(EIO);
-	    goto bread_err1;
-	}
-	h_size = INT_GET(rhead->h_size, ARCH_CONVERT);
+		if ((INT_GET(rhead->h_version, ARCH_CONVERT) &
+				(~XLOG_VERSION_OKBITS)) != 0) {
+			xlog_warn(
+	"XFS: xlog_do_recovery_pass: unrecognised log version number.");
+			error = XFS_ERROR(EIO);
+			goto bread_err1;
+		}
+		h_size = INT_GET(rhead->h_size, ARCH_CONVERT);
 
-	if ((INT_GET(rhead->h_version, ARCH_CONVERT) & XLOG_VERSION_2) &&
-	    (h_size > XLOG_HEADER_CYCLE_SIZE)) {
-	    hblks = h_size / XLOG_HEADER_CYCLE_SIZE;
-	    if (h_size % XLOG_HEADER_CYCLE_SIZE)
-		hblks++;
-	    xlog_put_bp(hbp);
-	    hbp = xlog_get_bp(hblks, log->l_mp);
+		if ((INT_GET(rhead->h_version, ARCH_CONVERT)
+				& XLOG_VERSION_2) &&
+		    (h_size > XLOG_HEADER_CYCLE_SIZE)) {
+			hblks = h_size / XLOG_HEADER_CYCLE_SIZE;
+			if (h_size % XLOG_HEADER_CYCLE_SIZE)
+				hblks++;
+			xlog_put_bp(hbp);
+			hbp = xlog_get_bp(log, hblks);
+		} else {
+			hblks = 1;
+		}
 	} else {
-	    hblks=1;
+		ASSERT(log->l_sectbb_log == 0);
+		hblks = 1;
+		hbp = xlog_get_bp(log, 1);
+		h_size = XLOG_BIG_RECORD_BSIZE;
 	}
-    } else {
-	hblks=1;
-	hbp = xlog_get_bp(1, log->l_mp);
-	h_size = XLOG_BIG_RECORD_BSIZE;
-    }
-
-    if (!hbp)
-	return ENOMEM;
-    dbp = xlog_get_bp(BTOBB(h_size),log->l_mp);
-    if (!dbp) {
-	xlog_put_bp(hbp);
-	return ENOMEM;
-    }
-
-    memset(rhash, 0, sizeof(rhash));
-    if (tail_blk <= head_blk) {
-	for (blk_no = tail_blk; blk_no < head_blk; ) {
-	    if ((error = xlog_bread(log, blk_no, hblks, hbp)))
-		goto bread_err2;
-	    rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp);
-	    ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
-	    ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX));
-	    bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));	/* blocks in data section */
-
-	    if (unlikely((INT_GET(rhead->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) ||
-		(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) > INT_MAX)) ||
-		(bblks <= 0) ||
-		(blk_no > log->l_logBBsize))) {
-		    XFS_ERROR_REPORT("xlog_do_recovery_pass(1)",
-				     XFS_ERRLEVEL_LOW, log->l_mp);
-		    error = EFSCORRUPTED;
-		    goto bread_err2;
-	    }
 
-	    if ((INT_GET(rhead->h_version, ARCH_CONVERT) & (~XLOG_VERSION_OKBITS)) != 0) {
-		xlog_warn("XFS: xlog_do_recovery_pass: unrecognised log version number.");
-		error = XFS_ERROR(EIO);
-		goto bread_err2;
-	    }
-	    bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));	/* blocks in data section */
-	    if (bblks > 0) {
-		if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp)))
-		    goto bread_err2;
-		xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log);
-		if ((error = xlog_recover_process_data(log, rhash,
-						      rhead, XFS_BUF_PTR(dbp),
-						      pass)))
-			goto bread_err2;
-	    }
-	    blk_no += (bblks+hblks);
+	if (!hbp)
+		return ENOMEM;
+	dbp = xlog_get_bp(log, BTOBB(h_size));
+	if (!dbp) {
+		xlog_put_bp(hbp);
+		return ENOMEM;
 	}
-    } else {
-	/*
-	 * Perform recovery around the end of the physical log.  When the head
-	 * is not on the same cycle number as the tail, we can't do a sequential
-	 * recovery as above.
-	 */
-	blk_no = tail_blk;
-	while (blk_no < log->l_logBBsize) {
-	    /*
-	     * Check for header wrapping around physical end-of-log
-	     */
-	    wrapped_hblks = 0;
-	    if (blk_no+hblks <= log->l_logBBsize) {
-		/* Read header in one read */
-		if ((error = xlog_bread(log, blk_no, hblks, hbp)))
-		    goto bread_err2;
-	    } else {
-		/* This log record is split across physical end of log */
-		split_hblks = 0;
-		if (blk_no != log->l_logBBsize) {
-		    /* some data is before physical end of log */
-		    ASSERT(blk_no <= INT_MAX);
-		    split_hblks = log->l_logBBsize - (int)blk_no;
-		    ASSERT(split_hblks > 0);
-		    if ((error = xlog_bread(log, blk_no, split_hblks, hbp)))
-			goto bread_err2;
-		}
-		bufaddr = XFS_BUF_PTR(hbp);
-		XFS_BUF_SET_PTR(hbp, bufaddr + BBTOB(split_hblks),
-			BBTOB(hblks - split_hblks));
-		wrapped_hblks = hblks - split_hblks;
-		if ((error = xlog_bread(log, 0, wrapped_hblks, hbp)))
-		    goto bread_err2;
-		XFS_BUF_SET_PTR(hbp, bufaddr, hblks);
-	    }
-	    rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp);
-	    ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
-	    ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX));
-	    bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
-
-	    /* LR body must have data or it wouldn't have been written */
-	    ASSERT(bblks > 0);
-	    blk_no += hblks;			/* successfully read header */
-
-	    if (unlikely((INT_GET(rhead->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) ||
-		(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) > INT_MAX)) ||
-		(bblks <= 0))) {
-		    XFS_ERROR_REPORT("xlog_do_recovery_pass(2)",
-				     XFS_ERRLEVEL_LOW, log->l_mp);
-		    error = EFSCORRUPTED;
-		    goto bread_err2;
-	    }
 
-	    /* Read in data for log record */
-	    if (blk_no+bblks <= log->l_logBBsize) {
-		if ((error = xlog_bread(log, blk_no, bblks, dbp)))
-		    goto bread_err2;
-	    } else {
-		/* This log record is split across physical end of log */
-		split_bblks = 0;
-		if (blk_no != log->l_logBBsize) {
-
-		    /* some data is before physical end of log */
-		    ASSERT(blk_no <= INT_MAX);
-		    split_bblks = log->l_logBBsize - (int)blk_no;
-		    ASSERT(split_bblks > 0);
-		    if ((error = xlog_bread(log, blk_no, split_bblks, dbp)))
-			goto bread_err2;
-		}
-		bufaddr = XFS_BUF_PTR(dbp);
-		XFS_BUF_SET_PTR(dbp, bufaddr + BBTOB(split_bblks),
-			BBTOB(bblks - split_bblks));
-		if ((error = xlog_bread(log, wrapped_hblks,
-					bblks - split_bblks, dbp)))
-		    goto bread_err2;
-		XFS_BUF_SET_PTR(dbp, bufaddr, XLOG_BIG_RECORD_BSIZE);
-	    }
-	    xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log);
-	    if ((error = xlog_recover_process_data(log, rhash,
-						  rhead, XFS_BUF_PTR(dbp),
-						  pass)))
-		goto bread_err2;
-	    blk_no += bblks;
-	}
-
-	ASSERT(blk_no >= log->l_logBBsize);
-	blk_no -= log->l_logBBsize;
-
-	/* read first part of physical log */
-	while (blk_no < head_blk) {
-	    if ((error = xlog_bread(log, blk_no, hblks, hbp)))
-		goto bread_err2;
-	    rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp);
-	    ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
-	    ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX));
-	    bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
-	    ASSERT(bblks > 0);
-	    if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp)))
-		goto bread_err2;
-	    xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log);
-	    if ((error = xlog_recover_process_data(log, rhash,
-						  rhead, XFS_BUF_PTR(dbp),
-						  pass)))
-		goto bread_err2;
-	    blk_no += (bblks+hblks);
-	}
-    }
-
-bread_err2:
-    xlog_put_bp(dbp);
-bread_err1:
-    xlog_put_bp(hbp);
+	memset(rhash, 0, sizeof(rhash));
+	if (tail_blk <= head_blk) {
+		for (blk_no = tail_blk; blk_no < head_blk; ) {
+			if ((error = xlog_bread(log, blk_no, hblks, hbp)))
+				goto bread_err2;
+			offset = xlog_align(log, blk_no, hblks, hbp);
+			rhead = (xlog_rec_header_t *)offset;
+			ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) ==
+				XLOG_HEADER_MAGIC_NUM);
+			ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <=
+				INT_MAX));
+			/* blocks in data section */
+			bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
+
+			if (unlikely(
+			    (INT_GET(rhead->h_magicno, ARCH_CONVERT) !=
+					XLOG_HEADER_MAGIC_NUM) ||
+			    (BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) >
+					INT_MAX)) ||
+			    (bblks <= 0) ||
+			    (blk_no > log->l_logBBsize))) {
+				XFS_ERROR_REPORT("xlog_do_recovery_pass(1)",
+						XFS_ERRLEVEL_LOW, log->l_mp);
+				error = EFSCORRUPTED;
+				goto bread_err2;
+			}
+
+			if ((INT_GET(rhead->h_version, ARCH_CONVERT) &
+					(~XLOG_VERSION_OKBITS)) != 0) {
+				xlog_warn(
+		"XFS: xlog_do_recovery_pass: unrecognised log version number.");
+				error = XFS_ERROR(EIO);
+				goto bread_err2;
+			}
+			/* blocks in data section */
+			bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
+			if (bblks > 0) {
+				if ((error = xlog_bread(log, blk_no + hblks,
+							bblks, dbp)))
+					goto bread_err2;
+				offset = xlog_align(log, blk_no + hblks,
+							bblks, dbp);
+				xlog_unpack_data(rhead, offset, log);
+				if ((error = xlog_recover_process_data(log,
+						rhash, rhead, offset, pass)))
+					goto bread_err2;
+			}
+			blk_no += (bblks+hblks);
+		}
+	} else {
+		/*
+		 * Perform recovery around the end of the physical log.
+		 * When the head is not on the same cycle number as the tail,
+		 * we can't do a sequential recovery as above.
+		 */
+		blk_no = tail_blk;
+		while (blk_no < log->l_logBBsize) {
+			/*
+			 * Check for header wrapping around physical end-of-log
+			 */
+			wrapped_hblks = 0;
+			if (blk_no+hblks <= log->l_logBBsize) {
+				/* Read header in one read */
+				if ((error = xlog_bread(log, blk_no,
+							hblks, hbp)))
+					goto bread_err2;
+				offset = xlog_align(log, blk_no, hblks, hbp);
+			} else {
+				/* This LR is split across physical log end */
+				offset = NULL;
+				split_hblks = 0;
+				if (blk_no != log->l_logBBsize) {
+					/* some data before physical log end */
+					ASSERT(blk_no <= INT_MAX);
+					split_hblks = log->l_logBBsize - (int)blk_no;
+					ASSERT(split_hblks > 0);
+					if ((error = xlog_bread(log, blk_no,
+							split_hblks, hbp)))
+						goto bread_err2;
+					offset = xlog_align(log, blk_no,
+							split_hblks, hbp);
+				}
+				/*
+				 * Note: this black magic still works with
+				 * large sector sizes (non-512) only because:
+				 * - we increased the buffer size originally
+				 *   by 1 sector giving us enough extra space
+				 *   for the second read;
+				 * - the log start is guaranteed to be sector
+				 *   aligned;
+				 * - we read the log end (LR header start)
+				 *   _first_, then the log start (LR header end)
+				 *   - order is important.
+				 */
+				bufaddr = XFS_BUF_PTR(hbp);
+				XFS_BUF_SET_PTR(hbp,
+						bufaddr + BBTOB(split_hblks),
+						BBTOB(hblks - split_hblks));
+				wrapped_hblks = hblks - split_hblks;
+				if ((error = xlog_bread(log, 0,
+							wrapped_hblks, hbp)))
+					goto bread_err2;
+				XFS_BUF_SET_PTR(hbp, bufaddr, hblks);
+				if (!offset)
+					offset = xlog_align(log, 0,
+							wrapped_hblks, hbp);
+			}
+			rhead = (xlog_rec_header_t *)offset;
+			ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) ==
+				XLOG_HEADER_MAGIC_NUM);
+			ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <=
+				INT_MAX));
+			bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
+
+			/* LR body must have data or it wouldn't have been
+			 * written */
+			ASSERT(bblks > 0);
+			blk_no += hblks;	/* successfully read header */
+
+			if (unlikely(
+			    (INT_GET(rhead->h_magicno, ARCH_CONVERT) !=
+					XLOG_HEADER_MAGIC_NUM) ||
+			    (BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) >
+					INT_MAX)) ||
+			    (bblks <= 0))) {
+				XFS_ERROR_REPORT("xlog_do_recovery_pass(2)",
+					     XFS_ERRLEVEL_LOW, log->l_mp);
+				error = EFSCORRUPTED;
+				goto bread_err2;
+			}
+
+			/* Read in data for log record */
+			if (blk_no+bblks <= log->l_logBBsize) {
+				if ((error = xlog_bread(log, blk_no,
+							bblks, dbp)))
+					goto bread_err2;
+				offset = xlog_align(log, blk_no, bblks, dbp);
+			} else {
+				/* This log record is split across the
+				 * physical end of log */
+				offset = NULL;
+				split_bblks = 0;
+				if (blk_no != log->l_logBBsize) {
+					/* some data is before the physical
+					 * end of log */
+					ASSERT(!wrapped_hblks);
+					ASSERT(blk_no <= INT_MAX);
+					split_bblks =
+						log->l_logBBsize - (int)blk_no;
+					ASSERT(split_bblks > 0);
+					if ((error = xlog_bread(log, blk_no,
+							split_bblks, dbp)))
+						goto bread_err2;
+					offset = xlog_align(log, blk_no,
+							split_bblks, dbp);
+				}
+				/*
+				 * Note: this black magic still works with
+				 * large sector sizes (non-512) only because:
+				 * - we increased the buffer size originally
+				 *   by 1 sector giving us enough extra space
+				 *   for the second read;
+				 * - the log start is guaranteed to be sector
+				 *   aligned;
+				 * - we read the log end (LR header start)
+				 *   _first_, then the log start (LR header end)
+				 *   - order is important.
+				 */
+				bufaddr = XFS_BUF_PTR(dbp);
+				XFS_BUF_SET_PTR(dbp,
+						bufaddr + BBTOB(split_bblks),
+						BBTOB(bblks - split_bblks));
+				if ((error = xlog_bread(log, wrapped_hblks,
+						bblks - split_bblks, dbp)))
+					goto bread_err2;
+				XFS_BUF_SET_PTR(dbp, bufaddr,
+						XLOG_BIG_RECORD_BSIZE);
+				if (!offset)
+					offset = xlog_align(log, wrapped_hblks,
+						bblks - split_bblks, dbp);
+			}
+			xlog_unpack_data(rhead, offset, log);
+			if ((error = xlog_recover_process_data(log, rhash,
+						  rhead, offset, pass)))
+				goto bread_err2;
+			blk_no += bblks;
+		}
+
+		ASSERT(blk_no >= log->l_logBBsize);
+		blk_no -= log->l_logBBsize;
+
+		/* read first part of physical log */
+		while (blk_no < head_blk) {
+			if ((error = xlog_bread(log, blk_no, hblks, hbp)))
+				goto bread_err2;
+			offset = xlog_align(log, blk_no, hblks, hbp);
+			rhead = (xlog_rec_header_t *)offset;
+			ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) ==
+				XLOG_HEADER_MAGIC_NUM);
+			ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <=
+				INT_MAX));
+			bblks = (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
+			ASSERT(bblks > 0);
+			if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp)))
+				goto bread_err2;
+			offset = xlog_align(log, blk_no+hblks, bblks, dbp);
+			xlog_unpack_data(rhead, offset, log);
+			if ((error = xlog_recover_process_data(log, rhash,
+							  rhead, offset, pass)))
+				goto bread_err2;
+			blk_no += (bblks+hblks);
+		}
+	}
 
-    return error;
+ bread_err2:
+	xlog_put_bp(dbp);
+ bread_err1:
+	xlog_put_bp(hbp);
+	return error;
 }
 
 /*
@@ -3552,9 +3726,10 @@
  * the log recovery has been completed.
  */
 STATIC int
-xlog_do_log_recovery(xlog_t	*log,
-		     xfs_daddr_t	head_blk,
-		     xfs_daddr_t	tail_blk)
+xlog_do_log_recovery(
+	xlog_t		*log,
+	xfs_daddr_t	head_blk,
+	xfs_daddr_t	tail_blk)
 {
 	int		error;
 #ifdef DEBUG
@@ -3599,9 +3774,10 @@
  * Do the actual recovery
  */
 STATIC int
-xlog_do_recover(xlog_t	*log,
-		xfs_daddr_t head_blk,
-		xfs_daddr_t tail_blk)
+xlog_do_recover(
+	xlog_t		*log,
+	xfs_daddr_t	head_blk,
+	xfs_daddr_t	tail_blk)
 {
 	int		error;
 	xfs_buf_t	*bp;
@@ -3663,7 +3839,7 @@
 	/* Normal transactions can now occur */
 	log->l_flags &= ~XLOG_ACTIVE_RECOVERY;
 	return 0;
-}	/* xlog_do_recover */
+}
 
 /*
  * Perform recovery and re-initialize some log variables in xlog_find_tail.
@@ -3671,22 +3847,18 @@
  * Return error or zero.
  */
 int
-xlog_recover(xlog_t *log, int readonly)
+xlog_recover(
+	xlog_t		*log,
+	int		readonly)
 {
-	xfs_daddr_t head_blk, tail_blk;
-	int	error;
+	xfs_daddr_t	head_blk, tail_blk;
+	int		error;
 
 	/* find the tail of the log */
-
 	if ((error = xlog_find_tail(log, &head_blk, &tail_blk, readonly)))
 		return error;
 
 	if (tail_blk != head_blk) {
-#ifndef __KERNEL__
-		extern xfs_daddr_t HEAD_BLK, TAIL_BLK;
-		head_blk = HEAD_BLK;
-		tail_blk = TAIL_BLK;
-#endif
 		/* There used to be a comment here:
 		 *
 		 * disallow recovery on read-only mounts.  note -- mount
@@ -3698,36 +3870,21 @@
 		 * under the vfs layer, so we can get away with it unless
 		 * the device itself is read-only, in which case we fail.
 		 */
-#ifdef __KERNEL__
 		if ((error = xfs_dev_is_read_only(log->l_mp,
 						"recovery required"))) {
 			return error;
 		}
-#else
-		if (readonly) {
-			return ENOSPC;
-		}
-#endif
 
-#ifdef __KERNEL__
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
 		cmn_err(CE_NOTE,
 			"Starting XFS recovery on filesystem: %s (dev: %d/%d)",
 			log->l_mp->m_fsname, MAJOR(log->l_dev),
 			MINOR(log->l_dev));
-#else
-		cmn_err(CE_NOTE,
-			"!Starting XFS recovery on filesystem: %s (dev: %d/%d)",
-			log->l_mp->m_fsname, MAJOR(log->l_dev),
-			MINOR(log->l_dev));
-#endif
-#endif
+
 		error = xlog_do_recover(log, head_blk, tail_blk);
 		log->l_flags |= XLOG_RECOVERY_NEEDED;
 	}
 	return error;
-}	/* xlog_recover */
-
+}
 
 /*
  * In the first part of recovery we replay inodes and buffers and build
@@ -3739,7 +3896,9 @@
  * in the real-time portion of the file system.
  */
 int
-xlog_recover_finish(xlog_t *log, int mfsi_flags)
+xlog_recover_finish(
+	xlog_t		*log,
+	int		mfsi_flags)
 {
 	/*
 	 * Now we're ready to do the transactions needed for the
@@ -3761,23 +3920,16 @@
 			      (XFS_LOG_FORCE | XFS_LOG_SYNC));
 
 		if ( (mfsi_flags & XFS_MFSI_NOUNLINK) == 0 ) {
-
 			xlog_recover_process_iunlinks(log);
 		}
 
 		xlog_recover_check_summary(log);
 
-#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
 		cmn_err(CE_NOTE,
 			"Ending XFS recovery on filesystem: %s (dev: %d/%d)",
 			log->l_mp->m_fsname, MAJOR(log->l_dev),
 			MINOR(log->l_dev));
-#else
-		cmn_err(CE_NOTE,
-			"!Ending XFS recovery on filesystem: %s (dev: %d/%d)",
-			log->l_mp->m_fsname, MAJOR(log->l_dev),
-			MINOR(log->l_dev));
-#endif
+
 		log->l_flags &= ~XLOG_RECOVERY_NEEDED;
 	} else {
 		cmn_err(CE_DEBUG,
@@ -3785,7 +3937,7 @@
 			log->l_mp->m_fsname);
 	}
 	return 0;
-}	/* xlog_recover_finish */
+}
 
 
 #if defined(DEBUG)
@@ -3794,7 +3946,8 @@
  * are consistent with the superblock counters.
  */
 void
-xlog_recover_check_summary(xlog_t	*log)
+xlog_recover_check_summary(
+	xlog_t		*log)
 {
 	xfs_mount_t	*mp;
 	xfs_agf_t	*agfp;
diff -Nru a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c
--- a/fs/xfs/xfs_mount.c	Fri May  2 13:01:28 2003
+++ b/fs/xfs/xfs_mount.c	Mon May 19 12:11:14 2003
@@ -467,7 +467,11 @@
 
 	bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR,
 				BTOBB(sector_size), extra_flags);
-	ASSERT(bp);
+	if (!bp || XFS_BUF_ISERROR(bp)) {
+		cmn_err(CE_WARN, "XFS: SB read failed");
+		error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM;
+		goto fail;
+	}
 	ASSERT(XFS_BUF_ISBUSY(bp));
 	ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
 
@@ -482,9 +486,7 @@
 	error = xfs_mount_validate_sb(mp, &(mp->m_sb));
 	if (error) {
 		cmn_err(CE_WARN, "XFS: SB validate failed");
-		XFS_BUF_UNMANAGE(bp);
-		xfs_buf_relse(bp);
-		return error;
+		goto fail;
 	}
 
 	/*
@@ -494,9 +496,8 @@
 		cmn_err(CE_WARN,
 			"XFS: device supports only %u byte sectors (not %u)",
 			sector_size, mp->m_sb.sb_sectsize);
-		XFS_BUF_UNMANAGE(bp);
-		xfs_buf_relse(bp);
-		return XFS_ERROR(ENOSYS);
+		error = ENOSYS;
+		goto fail;
 	}
 
 	/*
@@ -509,7 +510,11 @@
 		sector_size = mp->m_sb.sb_sectsize;
 		bp = xfs_buf_read_flags(mp->m_ddev_targp, XFS_SB_DADDR,
 					BTOBB(sector_size), extra_flags);
-		ASSERT(bp);
+		if (!bp || XFS_BUF_ISERROR(bp)) {
+			cmn_err(CE_WARN, "XFS: SB re-read failed");
+			error = bp ? XFS_BUF_GETERROR(bp) : ENOMEM;
+			goto fail;
+		}
 		ASSERT(XFS_BUF_ISBUSY(bp));
 		ASSERT(XFS_BUF_VALUSEMA(bp) <= 0);
 	}
@@ -518,6 +523,13 @@
 	xfs_buf_relse(bp);
 	ASSERT(XFS_BUF_VALUSEMA(bp) > 0);
 	return 0;
+
+ fail:
+	if (bp) {
+		XFS_BUF_UNMANAGE(bp);
+		xfs_buf_relse(bp);
+	}
+	return error;
 }
 
 
@@ -546,16 +558,7 @@
 	mp->m_blockmask = sbp->sb_blocksize - 1;
 	mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
 	mp->m_blockwmask = mp->m_blockwsize - 1;
-
-
-	if (XFS_SB_VERSION_HASLOGV2(sbp)) {
-		if (sbp->sb_logsunit <= 1) {
-			mp->m_lstripemask = 1;
-		} else {
-			mp->m_lstripemask =
-				1 << xfs_highbit32(sbp->sb_logsunit >> BBSHIFT);
-		}
-	}
+	INIT_LIST_HEAD(&mp->m_del_inodes);
 
 	/*
 	 * Setup for attributes, in case they get created.
@@ -601,7 +604,6 @@
 					sbp->sb_inopblock);
 	mp->m_ialloc_blks = mp->m_ialloc_inos >> sbp->sb_inopblog;
 }
-
 /*
  * xfs_mountfs
  *
diff -Nru a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h
--- a/fs/xfs/xfs_mount.h	Fri May  2 12:36:12 2003
+++ b/fs/xfs/xfs_mount.h	Mon May 19 12:11:14 2003
@@ -68,6 +68,7 @@
 	((xfs_agblock_t)(XFS_BB_TO_FSBT(mp, d) % (mp)->m_sb.sb_agblocks))
 #else
 struct cred;
+struct log;
 struct vfs;
 struct vnode;
 struct xfs_mount_args;
@@ -296,13 +297,14 @@
 	int			m_ihsize;	/* size of next field */
 	struct xfs_ihash	*m_ihash;	/* fs private inode hash table*/
 	struct xfs_inode	*m_inodes;	/* active inode list */
+	struct list_head	m_del_inodes;	/* inodes to reclaim */
 	mutex_t			m_ilock;	/* inode list mutex */
 	uint			m_ireclaims;	/* count of calls to reclaim*/
 	uint			m_readio_log;	/* min read size log bytes */
 	uint			m_readio_blocks; /* min read size blocks */
 	uint			m_writeio_log;	/* min write size log bytes */
 	uint			m_writeio_blocks; /* min write size blocks */
-	void			*m_log;		/* log specific stuff */
+	struct log		*m_log;		/* log specific stuff */
 	int			m_logbufs;	/* number of log buffers */
 	int			m_logbsize;	/* size of each log buffer */
 	uint			m_rsumlevels;	/* rt summary levels */
@@ -357,7 +359,6 @@
 #endif
 	int			m_dalign;	/* stripe unit */
 	int			m_swidth;	/* stripe width */
-	int			m_lstripemask;	/* log stripe mask */
 	int			m_sinoalign;	/* stripe unit inode alignmnt */
 	int			m_attr_magicpct;/* 37% of the blocksize */
 	int			m_dir_magicpct;	/* 37% of the dir blocksize */
diff -Nru a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c
--- a/fs/xfs/xfs_vfsops.c	Fri May  2 13:01:28 2003
+++ b/fs/xfs/xfs_vfsops.c	Mon May 19 11:29:42 2003
@@ -620,7 +620,7 @@
 
 	if (*flags & MS_RDONLY) {
 		pagebuf_delwri_flush(mp->m_ddev_targp, 0, NULL);
-		xfs_finish_reclaim_all(mp);
+		xfs_finish_reclaim_all(mp, 0);
 
 		do {
 			VFS_SYNC(vfsp, SYNC_ATTR|SYNC_WAIT, NULL, error);
@@ -849,19 +849,14 @@
  * xfs sync routine for internal use
  *
  * This routine supports all of the flags defined for the generic VFS_SYNC
- * interface as explained above under xys_sync.  In the interests of not
+ * interface as explained above under xfs_sync.  In the interests of not
  * changing interfaces within the 6.5 family, additional internallly-
  * required functions are specified within a separate xflags parameter,
  * only available by calling this routine.
  *
- * xflags:
- *	XFS_XSYNC_RELOC - Sync for relocation.  Don't try to get behavior
- *                        locks as this will cause you to hang.  Not all
- *                        combinations of flags are necessarily supported
- *                        when this is specified.
  */
-int
-xfs_syncsub(
+STATIC int
+xfs_sync_inodes(
 	xfs_mount_t	*mp,
 	int		flags,
 	int             xflags,
@@ -877,12 +872,10 @@
 	uint64_t	fflag;
 	uint		lock_flags;
 	uint		base_lock_flags;
-	uint		log_flags;
 	boolean_t	mount_locked;
 	boolean_t	vnode_refed;
 	int		preempt;
 	xfs_dinode_t	*dip;
-	xfs_buf_log_item_t	*bip;
 	xfs_iptr_t	*ipointer;
 #ifdef DEBUG
 	boolean_t	ipointer_in = B_FALSE;
@@ -961,16 +954,6 @@
 		base_lock_flags |= XFS_IOLOCK_SHARED;
 	}
 
-	/*
-	 * Sync out the log.  This ensures that the log is periodically
-	 * flushed even if there is not enough activity to fill it up.
-	 */
-	if (flags & SYNC_WAIT) {
-		xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC);
-	} else {
-		xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
-	}
-
 	XFS_MOUNT_ILOCK(mp);
 
 	ip = mp->m_inodes;
@@ -1016,27 +999,23 @@
 				ip = ip->i_mnext;
 				continue;
 			}
-			if ((ip->i_update_core == 0) &&
-			    ((ip->i_itemp == NULL) ||
-			    !(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL))) {
-				if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
-					ip = ip->i_mnext;
-				} else if ((xfs_ipincount(ip) == 0) &&
+			if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0) {
+				ip = ip->i_mnext;
+			} else if ((xfs_ipincount(ip) == 0) &&
 				    xfs_iflock_nowait(ip)) {
-					IPOINTER_INSERT(ip, mp);
+				IPOINTER_INSERT(ip, mp);
 
-					xfs_finish_reclaim(ip, 1,
-						XFS_IFLUSH_DELWRI_ELSE_SYNC);
+				xfs_finish_reclaim(ip, 1,
+						XFS_IFLUSH_DELWRI_ELSE_ASYNC);
 
-					XFS_MOUNT_ILOCK(mp);
-					mount_locked = B_TRUE;
-					IPOINTER_REMOVE(ip, mp);
-				} else {
-					xfs_iunlock(ip, XFS_ILOCK_EXCL);
-					ip = ip->i_mnext;
-				}
-				continue;
+				XFS_MOUNT_ILOCK(mp);
+				mount_locked = B_TRUE;
+				IPOINTER_REMOVE(ip, mp);
+			} else {
+				xfs_iunlock(ip, XFS_ILOCK_EXCL);
+				ip = ip->i_mnext;
 			}
+			continue;
 		}
 
 		if (XFS_FORCED_SHUTDOWN(mp) && !(flags & SYNC_CLOSE)) {
@@ -1148,21 +1127,9 @@
 			xfs_iunlock(ip, XFS_ILOCK_SHARED);
 
 			if (XFS_FORCED_SHUTDOWN(mp)) {
-				if (xflags & XFS_XSYNC_RELOC) {
-					fs_tosspages(XFS_ITOBHV(ip), 0, -1,
-						     FI_REMAPF);
-				}
-				else {
-					VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF);
-				}
+				VOP_TOSS_PAGES(vp, 0, -1, FI_REMAPF);
 			} else {
-				if (xflags & XFS_XSYNC_RELOC) {
-					fs_flushinval_pages(XFS_ITOBHV(ip),
-							    0, -1, FI_REMAPF);
-				}
-				else {
-					VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_REMAPF);
-				}
+				VOP_FLUSHINVAL_PAGES(vp, 0, -1, FI_REMAPF);
 			}
 
 			xfs_ilock(ip, XFS_ILOCK_SHARED);
@@ -1418,16 +1385,55 @@
 
 	ASSERT(ipointer_in == B_FALSE);
 
+	kmem_free(ipointer, sizeof(xfs_iptr_t));
+	return XFS_ERROR(last_error);
+}
+
+/*
+ * xfs sync routine for internal use
+ *
+ * This routine supports all of the flags defined for the generic VFS_SYNC
+ * interface as explained above under xfs_sync.  In the interests of not
+ * changing interfaces within the 6.5 family, additional internallly-
+ * required functions are specified within a separate xflags parameter,
+ * only available by calling this routine.
+ *
+ */
+int
+xfs_syncsub(
+	xfs_mount_t	*mp,
+	int		flags,
+	int             xflags,
+	int             *bypassed)
+{
+	int		error = 0;
+	int		last_error = 0;
+	uint		log_flags = XFS_LOG_FORCE;
+	xfs_buf_t	*bp;
+	xfs_buf_log_item_t	*bip;
+
+	/*
+	 * Sync out the log.  This ensures that the log is periodically
+	 * flushed even if there is not enough activity to fill it up.
+	 */
+	if (flags & SYNC_WAIT)
+		log_flags |= XFS_LOG_SYNC;
+
+	xfs_log_force(mp, (xfs_lsn_t)0, log_flags);
+
+	if (flags & (SYNC_ATTR|SYNC_DELWRI)) {
+		if (flags & SYNC_BDFLUSH)
+			xfs_finish_reclaim_all(mp, 1);
+		else
+			error = xfs_sync_inodes(mp, flags, xflags, bypassed);
+	}
+
 	/*
 	 * Flushing out dirty data above probably generated more
 	 * log activity, so if this isn't vfs_sync() then flush
-	 * the log again.  If SYNC_WAIT is set then do it synchronously.
+	 * the log again.
 	 */
-	if (!(flags & SYNC_BDFLUSH)) {
-		log_flags = XFS_LOG_FORCE;
-		if (flags & SYNC_WAIT) {
-			log_flags |= XFS_LOG_SYNC;
-		}
+	if (flags & SYNC_DELWRI) {
 		xfs_log_force(mp, (xfs_lsn_t)0, log_flags);
 	}
 
@@ -1463,11 +1469,10 @@
 			 * that point so it can become pinned in between
 			 * there and here.
 			 */
-			if (XFS_BUF_ISPINNED(bp)) {
-				xfs_log_force(mp, (xfs_lsn_t)0,
-					      XFS_LOG_FORCE);
-			}
-			XFS_BUF_BFLAGS(bp) |= fflag;
+			if (XFS_BUF_ISPINNED(bp))
+				xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
+			if (!(flags & SYNC_WAIT))
+				XFS_BUF_BFLAGS(bp) |= XFS_B_ASYNC;
 			error = xfs_bwrite(mp, bp);
 		}
 		if (error) {
@@ -1478,9 +1483,9 @@
 	/*
 	 * Now check to see if the log needs a "dummy" transaction.
 	 */
-
 	if (xfs_log_need_covered(mp)) {
 		xfs_trans_t *tp;
+		xfs_inode_t *ip;
 
 		/*
 		 * Put a dummy transaction in the log to tell
@@ -1491,7 +1496,6 @@
 				XFS_ICHANGE_LOG_RES(mp),
 				0, 0, 0)))  {
 			xfs_trans_cancel(tp, 0);
-			kmem_free(ipointer, sizeof(xfs_iptr_t));
 			return error;
 		}
 
@@ -1503,6 +1507,7 @@
 		xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 		error = xfs_trans_commit(tp, 0, NULL);
 		xfs_iunlock(ip, XFS_ILOCK_EXCL);
+		xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE);
 	}
 
 	/*
@@ -1516,7 +1521,6 @@
 		}
 	}
 
-	kmem_free(ipointer, sizeof(xfs_iptr_t));
 	return XFS_ERROR(last_error);
 }
 
diff -Nru a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
--- a/fs/xfs/xfs_vnodeops.c	Fri May  2 13:01:28 2003
+++ b/fs/xfs/xfs_vnodeops.c	Mon May 19 11:31:47 2003
@@ -658,7 +658,7 @@
 		if (vap->va_size > ip->i_d.di_size) {
 			code = xfs_igrow_start(ip, vap->va_size, credp);
 			xfs_iunlock(ip, XFS_ILOCK_EXCL);
-		} else if (vap->va_size < ip->i_d.di_size) {
+		} else if (vap->va_size <= ip->i_d.di_size) {
 			xfs_iunlock(ip, XFS_ILOCK_EXCL);
 			xfs_itruncate_start(ip, XFS_ITRUNC_DEFINITE,
 					    (xfs_fsize_t)vap->va_size);
@@ -701,7 +701,7 @@
 		if (vap->va_size > ip->i_d.di_size) {
 			xfs_igrow_finish(tp, ip, vap->va_size,
 			    !(flags & ATTR_DMI));
-		} else if ((vap->va_size < ip->i_d.di_size) ||
+		} else if ((vap->va_size <= ip->i_d.di_size) ||
 			   ((vap->va_size == 0) && ip->i_d.di_nextents)) {
 			/*
 			 * signal a sync transaction unless
@@ -3786,27 +3786,30 @@
 					flush_flags = XFS_IFLUSH_SYNC;
 				else
 #endif
-					flush_flags = XFS_IFLUSH_DELWRI;
+				flush_flags = XFS_IFLUSH_DELWRI_ELSE_ASYNC;
 
 				xfs_ifunlock(ip);
 				xfs_iunlock(ip, XFS_ILOCK_SHARED);
 				error = xfs_itobp(mp, NULL, ip, &dip, &bp, 0);
 				if (error)
-					goto eagain;
+					return error;
 				xfs_buf_relse(bp);
 
 				if (xfs_ilock_nowait(ip, XFS_ILOCK_SHARED) == 0)
-					goto eagain;
+					return EAGAIN;
+
+				if (xfs_ipincount(ip) ||
+				    !xfs_iflock_nowait(ip)) {
+					xfs_iunlock(ip, XFS_ILOCK_SHARED);
+					return EAGAIN;
+				}
 
-				if ((xfs_ipincount(ip) == 0) &&
-				     xfs_iflock_nowait(ip))
-					error = xfs_iflush(ip, flush_flags);
+				error = xfs_iflush(ip, flush_flags);
 			} else {
 				error = EAGAIN;
 			}
 			xfs_iunlock(ip, XFS_ILOCK_SHARED);
 		} else {
-eagain:
 			error = EAGAIN;
 		}
 	}
@@ -3934,6 +3937,8 @@
 		/* Protect sync from us */
 		XFS_MOUNT_ILOCK(mp);
 		vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip));
+		list_add_tail(&ip->i_reclaim, &mp->m_del_inodes);
+
 		XFS_MOUNT_IUNLOCK(mp);
 	}
 	return 0;
@@ -4010,40 +4015,33 @@
 }
 
 int
-xfs_finish_reclaim_all(xfs_mount_t *mp)
+xfs_finish_reclaim_all(xfs_mount_t *mp, int noblock)
 {
 	int		purged;
+	struct list_head	*curr, *next;
 	xfs_inode_t	*ip;
-	vnode_t		*vp;
 	int		done = 0;
 
 	while (!done) {
 		purged = 0;
 		XFS_MOUNT_ILOCK(mp);
-		ip = mp->m_inodes;
-		if (ip == NULL) {
+		list_for_each_safe(curr, next, &mp->m_del_inodes) {
+			ip = list_entry(curr, xfs_inode_t, i_reclaim);
+			if (noblock) {
+				if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0)
+					continue;
+				if (xfs_ipincount(ip) ||
+				    !xfs_iflock_nowait(ip)) {
+					xfs_iunlock(ip, XFS_ILOCK_EXCL);
+					continue;
+				}
+			}
+			XFS_MOUNT_IUNLOCK(mp);
+			xfs_finish_reclaim(ip, noblock,
+				XFS_IFLUSH_DELWRI_ELSE_ASYNC);
+			purged = 1;
 			break;
 		}
-		do {
-			/* Make sure we skip markers inserted by sync */
-			if (ip->i_mount == NULL) {
-				ip = ip->i_mnext;
-				continue;
-			}
-
-			/*
-			 * It's up to our caller to purge the root
-			 * and quota vnodes later.
-			 */
-			vp = XFS_ITOV_NULL(ip);
-
-			if (!vp) {
-				XFS_MOUNT_IUNLOCK(mp);
-				xfs_finish_reclaim(ip, 0, XFS_IFLUSH_ASYNC);
-				purged = 1;
-				break;
-			}
-		} while (ip != mp->m_inodes);
 
 		done = !purged;
 	}
diff -Nru a/fs/xfs/xfsidbg.c b/fs/xfs/xfsidbg.c
--- a/fs/xfs/xfsidbg.c	Fri May  2 13:01:28 2003
+++ b/fs/xfs/xfsidbg.c	Mon May 19 12:11:14 2003
@@ -4269,8 +4269,10 @@
 	kdb_printf("iclog_bak: 0x%p  iclog_size: 0x%x (%d)  num iclogs: %d\n",
 		log->l_iclog_bak, log->l_iclog_size, log->l_iclog_size,
 		log->l_iclog_bufs);
-	kdb_printf("l_iclog_hsize %d l_iclog_heads %d\n",
-		log->l_iclog_hsize, log->l_iclog_heads);
+	kdb_printf("l_stripemask %d l_iclog_hsize %d l_iclog_heads %d\n",
+		log->l_stripemask, log->l_iclog_hsize, log->l_iclog_heads);
+	kdb_printf("l_sectbb_log %u l_sectbb_mask %u\n",
+		log->l_sectbb_log, log->l_sectbb_mask);
 	kdb_printf("&grant_lock: 0x%p  resHeadQ: 0x%p  wrHeadQ: 0x%p\n",
 		&log->l_grant_lock, log->l_reserve_headq, log->l_write_headq);
 	kdb_printf("GResCycle: %d  GResBytes: %d  GWrCycle: %d  GWrBytes: %d\n",
@@ -4712,7 +4714,6 @@
 		(xfs_dfiloff_t)mp->m_dirfreeblk);
 	kdb_printf("chsize %d chash 0x%p\n",
 		mp->m_chsize, mp->m_chash);
-	kdb_printf("m_lstripemask %d\n", mp->m_lstripemask);
 	kdb_printf("m_frozen %d m_active_trans %d\n",
 		mp->m_frozen, mp->m_active_trans.counter);
 	if (mp->m_fsname != NULL)
diff -Nru a/include/asm-alpha/elf.h b/include/asm-alpha/elf.h
--- a/include/asm-alpha/elf.h	Mon Mar 17 21:31:50 2003
+++ b/include/asm-alpha/elf.h	Mon May 12 07:06:45 2003
@@ -2,6 +2,49 @@
 #define __ASM_ALPHA_ELF_H
 
 /*
+ * Alpha ELF relocation types
+ */
+#define R_ALPHA_NONE            0       /* No reloc */
+#define R_ALPHA_REFLONG         1       /* Direct 32 bit */
+#define R_ALPHA_REFQUAD         2       /* Direct 64 bit */
+#define R_ALPHA_GPREL32         3       /* GP relative 32 bit */
+#define R_ALPHA_LITERAL         4       /* GP relative 16 bit w/optimization */
+#define R_ALPHA_LITUSE          5       /* Optimization hint for LITERAL */
+#define R_ALPHA_GPDISP          6       /* Add displacement to GP */
+#define R_ALPHA_BRADDR          7       /* PC+4 relative 23 bit shifted */
+#define R_ALPHA_HINT            8       /* PC+4 relative 16 bit shifted */
+#define R_ALPHA_SREL16          9       /* PC relative 16 bit */
+#define R_ALPHA_SREL32          10      /* PC relative 32 bit */
+#define R_ALPHA_SREL64          11      /* PC relative 64 bit */
+#define R_ALPHA_GPRELHIGH       17      /* GP relative 32 bit, high 16 bits */
+#define R_ALPHA_GPRELLOW        18      /* GP relative 32 bit, low 16 bits */
+#define R_ALPHA_GPREL16         19      /* GP relative 16 bit */
+#define R_ALPHA_COPY            24      /* Copy symbol at runtime */
+#define R_ALPHA_GLOB_DAT        25      /* Create GOT entry */
+#define R_ALPHA_JMP_SLOT        26      /* Create PLT entry */
+#define R_ALPHA_RELATIVE        27      /* Adjust by program base */
+#define R_ALPHA_BRSGP		28
+#define R_ALPHA_TLSGD           29
+#define R_ALPHA_TLS_LDM         30
+#define R_ALPHA_DTPMOD64        31
+#define R_ALPHA_GOTDTPREL       32
+#define R_ALPHA_DTPREL64        33
+#define R_ALPHA_DTPRELHI        34
+#define R_ALPHA_DTPRELLO        35
+#define R_ALPHA_DTPREL16        36
+#define R_ALPHA_GOTTPREL        37
+#define R_ALPHA_TPREL64         38
+#define R_ALPHA_TPRELHI         39
+#define R_ALPHA_TPRELLO         40
+#define R_ALPHA_TPREL16         41
+
+#define SHF_ALPHA_GPREL		0x10000000
+
+/* Legal values for e_flags field of Elf64_Ehdr.  */
+
+#define EF_ALPHA_32BIT		1	/* All addresses are below 2GB */
+
+/*
  * ELF register definitions..
  */
 
diff -Nru a/include/asm-alpha/hardirq.h b/include/asm-alpha/hardirq.h
--- a/include/asm-alpha/hardirq.h	Thu Aug 15 04:12:53 2002
+++ b/include/asm-alpha/hardirq.h	Mon May 12 18:59:24 2003
@@ -79,7 +79,7 @@
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 #define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-alpha/kmap_types.h b/include/asm-alpha/kmap_types.h
--- a/include/asm-alpha/kmap_types.h	Sun Feb  2 23:34:59 2003
+++ b/include/asm-alpha/kmap_types.h	Mon May 12 18:59:23 2003
@@ -5,7 +5,7 @@
 
 #include <linux/config.h>
 
-#if CONFIG_DEBUG_HIGHMEM
+#ifdef CONFIG_DEBUG_HIGHMEM
 # define D(n) __KM_FENCE_##n ,
 #else
 # define D(n)
diff -Nru a/include/asm-alpha/spinlock.h b/include/asm-alpha/spinlock.h
--- a/include/asm-alpha/spinlock.h	Sun Sep 22 01:01:47 2002
+++ b/include/asm-alpha/spinlock.h	Mon May 12 18:59:24 2003
@@ -16,7 +16,7 @@
 
 typedef struct {
 	volatile unsigned int lock /*__attribute__((aligned(32))) */;
-#if CONFIG_DEBUG_SPINLOCK
+#ifdef CONFIG_DEBUG_SPINLOCK
 	int on_cpu;
 	int line_no;
 	void *previous;
@@ -25,7 +25,7 @@
 #endif
 } spinlock_t;
 
-#if CONFIG_DEBUG_SPINLOCK
+#ifdef CONFIG_DEBUG_SPINLOCK
 #define SPIN_LOCK_UNLOCKED (spinlock_t) {0, -1, 0, 0, 0, 0}
 #define spin_lock_init(x)						\
 	((x)->lock = 0, (x)->on_cpu = -1, (x)->previous = 0, (x)->task = 0)
@@ -37,7 +37,7 @@
 #define spin_is_locked(x)	((x)->lock != 0)
 #define spin_unlock_wait(x)	({ do { barrier(); } while ((x)->lock); })
 
-#if CONFIG_DEBUG_SPINLOCK
+#ifdef CONFIG_DEBUG_SPINLOCK
 extern void _raw_spin_unlock(spinlock_t * lock);
 extern void debug_spin_lock(spinlock_t * lock, const char *, int);
 extern int debug_spin_trylock(spinlock_t * lock, const char *, int);
@@ -102,7 +102,7 @@
 #define rwlock_init(x)	do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *)(x) != 0)
 
-#if CONFIG_DEBUG_RWLOCK
+#ifdef CONFIG_DEBUG_RWLOCK
 extern void _raw_write_lock(rwlock_t * lock);
 extern void _raw_read_lock(rwlock_t * lock);
 #else
diff -Nru a/include/asm-arm/arch-anakin/time.h b/include/asm-arm/arch-anakin/time.h
--- a/include/asm-arm/arch-anakin/time.h	Thu Mar  6 05:40:54 2003
+++ b/include/asm-arm/arch-anakin/time.h	Tue May 13 08:20:49 2003
@@ -14,10 +14,11 @@
 #ifndef __ASM_ARCH_TIME_H
 #define __ASM_ARCH_TIME_H
 
-static void
+static irqreturn_t
 anakin_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_timer(regs);
+	return IRQ_HANDLED;
 }
 
 void __init time_init(void)
diff -Nru a/include/asm-arm/arch-arc/time.h b/include/asm-arm/arch-arc/time.h
--- a/include/asm-arm/arch-arc/time.h	Mon Feb 25 11:43:22 2002
+++ b/include/asm-arm/arch-arc/time.h	Tue May 13 08:20:49 2003
@@ -14,11 +14,13 @@
  */
 extern void ioctime_init(void);
 
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_timer(regs);
 	do_set_rtc();
 	do_profile(regs);
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-cl7500/time.h b/include/asm-arm/arch-cl7500/time.h
--- a/include/asm-arm/arch-cl7500/time.h	Mon Feb 25 11:43:22 2002
+++ b/include/asm-arm/arch-cl7500/time.h	Tue May 13 08:20:50 2003
@@ -11,7 +11,8 @@
 
 extern void ioctime_init(void);
 
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_timer(regs);
 	do_set_rtc();
@@ -26,6 +27,7 @@
 			*((volatile unsigned int *)LED_ADDRESS) = state;
 		}
 	}
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-clps711x/time.h b/include/asm-arm/arch-clps711x/time.h
--- a/include/asm-arm/arch-clps711x/time.h	Mon Feb 25 11:43:22 2002
+++ b/include/asm-arm/arch-clps711x/time.h	Tue May 13 08:20:50 2003
@@ -25,11 +25,13 @@
 /*
  * IRQ handler for the timer
  */
-static void p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+p720t_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_leds();
 	do_timer(regs);
 	do_profile(regs);
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-ebsa110/time.h b/include/asm-arm/arch-ebsa110/time.h
--- a/include/asm-arm/arch-ebsa110/time.h	Sun Jan 26 16:09:40 2003
+++ b/include/asm-arm/arch-ebsa110/time.h	Tue May 13 08:20:50 2003
@@ -74,7 +74,8 @@
 	return offset;
 }
 
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	u32 count;
 
@@ -91,6 +92,8 @@
 	do_leds();
 	do_timer(regs);
 	do_profile(regs);
+
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-ebsa285/time.h b/include/asm-arm/arch-ebsa285/time.h
--- a/include/asm-arm/arch-ebsa285/time.h	Mon Dec 30 04:29:15 2002
+++ b/include/asm-arm/arch-ebsa285/time.h	Tue May 13 08:20:50 2003
@@ -69,7 +69,8 @@
 	return count;
 }
 
-static void isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+isa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	if (machine_is_netwinder())
 		do_leds();
@@ -77,6 +78,8 @@
 	do_timer(regs);
 	do_set_rtc();
 	do_profile(regs);
+
+	return IRQ_HANDLED;
 }
 
 static unsigned long __init get_isa_cmos_time(void)
@@ -186,7 +189,8 @@
 	return ((tick_nsec / 1000) * value) / LATCH;
 }
 
-static void timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	*CSR_TIMER1_CLR = 0;
 
@@ -195,6 +199,8 @@
 	do_timer(regs);
 	do_set_rtc();
 	do_profile(regs);
+
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-epxa10db/time.h b/include/asm-arm/arch-epxa10db/time.h
--- a/include/asm-arm/arch-epxa10db/time.h	Mon Feb 25 11:43:23 2002
+++ b/include/asm-arm/arch-epxa10db/time.h	Tue May 13 08:20:50 2003
@@ -27,7 +27,8 @@
 /*
  * IRQ handler for the timer
  */
-static void excalibur_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+excalibur_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 
 	// ...clear the interrupt
@@ -36,6 +37,8 @@
 	do_leds();
 	do_timer(regs);
 	do_profile(regs);
+
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-integrator/time.h b/include/asm-arm/arch-integrator/time.h
--- a/include/asm-arm/arch-integrator/time.h	Tue May  7 12:04:43 2002
+++ b/include/asm-arm/arch-integrator/time.h	Tue May 13 08:20:50 2003
@@ -98,7 +98,8 @@
 /*
  * IRQ handler for the timer
  */
-static void integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+integrator_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	volatile TimerStruct_t *timer1 = (volatile TimerStruct_t *)TIMER1_VA_BASE;
 
@@ -108,6 +109,8 @@
 	do_leds();
 	do_timer(regs);
 	do_profile(regs);
+
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-l7200/time.h b/include/asm-arm/arch-l7200/time.h
--- a/include/asm-arm/arch-l7200/time.h	Mon Feb 25 11:43:23 2002
+++ b/include/asm-arm/arch-l7200/time.h	Tue May 13 08:20:51 2003
@@ -42,11 +42,14 @@
 /*
  * Handler for RTC timer interrupt
  */
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_timer(regs);
 	do_profile(regs);
 	RTC_RTCC = 0;				/* Clear interrupt */
+
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-nexuspci/time.h b/include/asm-arm/arch-nexuspci/time.h
--- a/include/asm-arm/arch-nexuspci/time.h	Mon Feb 25 11:43:23 2002
+++ b/include/asm-arm/arch-nexuspci/time.h	Tue May 13 08:20:52 2003
@@ -14,7 +14,8 @@
  * 2 of the License, or (at your option) any later version.
  */
 
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	static int count = 25;
 	unsigned char stat = __raw_readb(DUART_BASE + 0x14);
@@ -40,7 +41,9 @@
 	__raw_readb(DUART_BASE + 0x14);
 	__raw_readb(DUART_BASE + 0x14);
 
-	do_timer(regs);	
+	do_timer(regs);
+
+	return IRQ_HANDLED;
 }
 
 void __init time_init(void)
diff -Nru a/include/asm-arm/arch-pxa/irqs.h b/include/asm-arm/arch-pxa/irqs.h
--- a/include/asm-arm/arch-pxa/irqs.h	Mon Feb 17 14:47:55 2003
+++ b/include/asm-arm/arch-pxa/irqs.h	Tue Apr 22 05:39:47 2003
@@ -10,9 +10,10 @@
  * published by the Free Software Foundation.
  */
 
-#define PXA_IRQ_SKIP	8	/* The first 8 IRQs are reserved */
+#define PXA_IRQ_SKIP	7	/* The first 7 IRQs are not yet used */
 #define PXA_IRQ(x)		((x) - PXA_IRQ_SKIP)
 
+#define IRQ_HWUART	PXA_IRQ(7)	/* HWUART Transmit/Receive/Error */
 #define	IRQ_GPIO0	PXA_IRQ(8)	/* GPIO0 Edge Detect */
 #define	IRQ_GPIO1	PXA_IRQ(9)	/* GPIO1 Edge Detect */
 #define	IRQ_GPIO_2_80	PXA_IRQ(10)	/* GPIO[2-80] Edge Detect */
@@ -20,6 +21,8 @@
 #define	IRQ_PMU		PXA_IRQ(12)	/* Performance Monitoring Unit */
 #define	IRQ_I2S		PXA_IRQ(13)	/* I2S Interrupt */
 #define	IRQ_AC97	PXA_IRQ(14)	/* AC97 Interrupt */
+#define IRQ_ASSP	PXA_IRQ(15)	/* Audio SSP Service Request */
+#define IRQ_NSSP	PXA_IRQ(16)	/* Network SSP Service Request */
 #define	IRQ_LCD		PXA_IRQ(17)	/* LCD Controller Service Request */
 #define	IRQ_I2C		PXA_IRQ(18)	/* I2C Service Request */
 #define	IRQ_ICP		PXA_IRQ(19)	/* ICP Transmit/Receive/Error */
diff -Nru a/include/asm-arm/arch-pxa/time.h b/include/asm-arm/arch-pxa/time.h
--- a/include/asm-arm/arch-pxa/time.h	Tue Mar 18 13:59:49 2003
+++ b/include/asm-arm/arch-pxa/time.h	Tue May 13 08:20:52 2003
@@ -47,7 +47,8 @@
 	return usec;
 }
 
-static void pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+pxa_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	int next_match;
 
@@ -66,6 +67,8 @@
 		OSSR = OSSR_M0;  /* Clear match on timer 0 */
 		next_match = (OSMR0 += LATCH);
 	} while( (signed long)(next_match - OSCR) <= 0 );
+
+	return IRQ_HANDLED;
 }
 
 void __init time_init(void)
diff -Nru a/include/asm-arm/arch-rpc/time.h b/include/asm-arm/arch-rpc/time.h
--- a/include/asm-arm/arch-rpc/time.h	Mon Feb 25 11:43:23 2002
+++ b/include/asm-arm/arch-rpc/time.h	Tue May 13 08:20:52 2003
@@ -14,11 +14,14 @@
  */
 extern void ioctime_init(void);
 
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_timer(regs);
 	do_set_rtc();
 	do_profile(regs);
+
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-sa1100/time.h b/include/asm-arm/arch-sa1100/time.h
--- a/include/asm-arm/arch-sa1100/time.h	Thu Mar  6 05:40:54 2003
+++ b/include/asm-arm/arch-sa1100/time.h	Tue May 13 08:20:53 2003
@@ -72,7 +72,8 @@
  * lost_ticks (updated in do_timer()) and the match reg value, so we
  * can use do_gettimeofday() from interrupt handlers.
  */
-static void sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+sa1100_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	unsigned int next_match;
 
@@ -85,6 +86,8 @@
 	} while ((signed long)(next_match - OSCR) <= 0);
 
 	do_profile(regs);
+
+	return IRQ_HANDLED;
 }
 
 void __init time_init(void)
diff -Nru a/include/asm-arm/arch-shark/time.h b/include/asm-arm/arch-shark/time.h
--- a/include/asm-arm/arch-shark/time.h	Thu Mar  6 05:40:55 2003
+++ b/include/asm-arm/arch-shark/time.h	Tue May 13 08:20:53 2003
@@ -13,11 +13,14 @@
 #define IRQ_TIMER 0
 #define HZ_TIME ((1193180 + HZ/2) / HZ)
 
-static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
 	do_leds();
 	do_timer(regs);
 	do_profile(regs);
+
+	return IRQ_HANDLED;
 }
 
 /*
diff -Nru a/include/asm-arm/arch-tbox/time.h b/include/asm-arm/arch-tbox/time.h
--- a/include/asm-arm/arch-tbox/time.h	Mon Feb 25 11:43:24 2002
+++ b/include/asm-arm/arch-tbox/time.h	Tue May 13 08:20:53 2003
@@ -20,13 +20,16 @@
 
 #define update_rtc()
 
-static void timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+static irqreturn_t
+timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 {
 	/* Clear irq */
 	__raw_writel(1, FPGA1CONT + 0xc); 
 	__raw_writel(0, FPGA1CONT + 0xc);
 
 	do_timer(regs);
+
+	return IRQ_HANDLED;
 }
 
 void __init time_init(void)
diff -Nru a/include/asm-arm/bitops.h b/include/asm-arm/bitops.h
--- a/include/asm-arm/bitops.h	Sat Apr 12 15:37:38 2003
+++ b/include/asm-arm/bitops.h	Tue May 13 09:11:10 2003
@@ -173,7 +173,7 @@
  */
 static inline int __test_bit(int nr, const unsigned long * p)
 {
-	return p[nr >> 5] & (1UL << (nr & 31));
+	return (p[nr >> 5] >> (nr & 31)) & 1UL;
 }
 
 /*
@@ -277,6 +277,8 @@
 
 #endif
 
+#if __LINUX_ARM_ARCH__ < 5
+
 /*
  * ffz = Find First Zero in word. Undefined if no zero exists,
  * so code should check against ~0UL first..
@@ -325,6 +327,23 @@
  */
 
 #define ffs(x) generic_ffs(x)
+
+#else
+
+/*
+ * On ARMv5 and above those functions can be implemented around
+ * the clz instruction for much better code efficiency.
+ */
+
+extern __inline__ int generic_fls(int x);
+#define fls(x) \
+	( __builtin_constant_p(x) ? generic_fls(x) : \
+	  ({ int __r; asm("clz%?\t%0, %1" : "=r"(__r) : "r"(x)); 32-__r; }) )
+#define ffs(x) ({ unsigned long __t = (x); fls(__t & -__t); })
+#define __ffs(x) (ffs(x) - 1)
+#define ffz(x) __ffs( ~(x) )
+
+#endif
 
 /*
  * Find first bit set in a 168-bit bitmap, where the first
diff -Nru a/include/asm-arm/bugs.h b/include/asm-arm/bugs.h
--- a/include/asm-arm/bugs.h	Sun Apr 27 16:55:21 2003
+++ b/include/asm-arm/bugs.h	Tue Apr 29 07:00:53 2003
@@ -10,8 +10,6 @@
 #ifndef __ASM_BUGS_H
 #define __ASM_BUGS_H
 
-#include <asm/proc-fns.h>
-
 #define check_bugs() do { } while (0)
 
 #endif
diff -Nru a/include/asm-arm/elf.h b/include/asm-arm/elf.h
--- a/include/asm-arm/elf.h	Mon Apr 28 15:05:52 2003
+++ b/include/asm-arm/elf.h	Mon May 12 06:59:47 2003
@@ -16,6 +16,10 @@
 #define EM_ARM	40
 #define EF_ARM_APCS26 0x08
 
+#define R_ARM_NONE	0
+#define R_ARM_PC24	1
+#define R_ARM_ABS32	2
+
 #define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
 typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 
diff -Nru a/include/asm-arm/mach/arch.h b/include/asm-arm/mach/arch.h
--- a/include/asm-arm/mach/arch.h	Tue Mar 18 15:19:45 2003
+++ b/include/asm-arm/mach/arch.h	Tue May 13 11:52:45 2003
@@ -54,39 +54,37 @@
 #define MACHINE_START(_type,_name)		\
 const struct machine_desc __mach_desc_##_type	\
  __attribute__((__section__(".arch.info"))) = {	\
-	nr:		MACH_TYPE_##_type,	\
-	name:		_name,
+	.nr		= MACH_TYPE_##_type,	\
+	.name		= _name,
 
 #define MAINTAINER(n)
 
 #define BOOT_MEM(_pram,_pio,_vio)		\
-	phys_ram:	_pram,	                \
-	phys_io:	_pio,  	                \
-	io_pg_offst:	((_vio)>>18)&0xfffc,
+	.phys_ram	= _pram,		\
+	.phys_io	= _pio,			\
+	.io_pg_offst	= ((_vio)>>18)&0xfffc,
 
 #define BOOT_PARAMS(_params)			\
-	param_offset:	_params,
+	.param_offset	= _params,
 
 #define VIDEO(_start,_end)			\
-	video_start:	_start,			\
-	video_end:	_end,
+	.video_start	= _start,		\
+	.video_end	= _end,
 
 #define DISABLE_PARPORT(_n)			\
-	reserve_lp##_n:	1,
-
-#define BROKEN_HLT /* unused */
+	.reserve_lp##_n	= 1,
 
 #define SOFT_REBOOT				\
-	soft_reboot:	1,
+	.soft_reboot	= 1,
 
 #define FIXUP(_func)				\
-	fixup:		_func,
+	.fixup		= _func,
 
 #define MAPIO(_func)				\
-	map_io:		_func,
+	.map_io		= _func,
 
 #define INITIRQ(_func)				\
-	init_irq:	_func,
+	.init_irq	= _func,
 
 #define MACHINE_END				\
 };
diff -Nru a/include/asm-arm/mach/dma.h b/include/asm-arm/mach/dma.h
--- a/include/asm-arm/mach/dma.h	Tue Mar 18 15:19:45 2003
+++ b/include/asm-arm/mach/dma.h	Sat May 17 14:23:29 2003
@@ -41,6 +41,7 @@
 	unsigned int	dma_base;	/* Controller base address	*/
 	int		dma_irq;	/* Controller IRQ		*/
 	struct scatterlist cur_sg;	/* Current controller buffer	*/
+	unsigned int	state;
 
 	struct dma_ops	*d_ops;
 };
diff -Nru a/include/asm-arm/processor.h b/include/asm-arm/processor.h
--- a/include/asm-arm/processor.h	Mon Mar 10 10:20:30 2003
+++ b/include/asm-arm/processor.h	Tue May 13 08:53:45 2003
@@ -74,6 +74,29 @@
  */
 extern int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags);
 
+/*
+ * Prefetching support - only ARMv5.
+ */
+#if __LINUX_ARM_ARCH__ >= 5
+
+#define ARCH_HAS_PREFETCH
+#define prefetch(ptr)				\
+	({					\
+		__asm__ __volatile__(		\
+		"pld\t%0"			\
+		:				\
+		: "o" (*(char *)(ptr))		\
+		: "cc");			\
+	})
+
+#define ARCH_HAS_PREFETCHW
+#define prefetchw(ptr)	prefetch(ptr)
+
+#define ARCH_HAS_SPINLOCK_PREFETCH
+#define spin_lock_prefetch(x) do { } while (0)
+
+#endif
+
 #endif
 
 #endif /* __ASM_ARM_PROCESSOR_H */
diff -Nru a/include/asm-arm/traps.h b/include/asm-arm/traps.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-arm/traps.h	Tue May 13 10:56:54 2003
@@ -0,0 +1,18 @@
+#ifndef _ASMARM_TRAP_H
+#define _ASMARM_TRAP_H
+
+#include <linux/list.h>
+
+struct undef_hook {
+	struct list_head node;
+	u32 instr_mask;
+	u32 instr_val;
+	u32 cpsr_mask;
+	u32 cpsr_val;
+	int (*fn)(struct pt_regs *regs, unsigned int instr);
+};
+
+void register_undef_hook(struct undef_hook *hook);
+void unregister_undef_hook(struct undef_hook *hook);
+
+#endif
diff -Nru a/include/asm-generic/rmap.h b/include/asm-generic/rmap.h
--- a/include/asm-generic/rmap.h	Fri Feb  7 00:20:35 2003
+++ b/include/asm-generic/rmap.h	Mon May 12 14:35:19 2003
@@ -61,7 +61,7 @@
 	return page->index + low_bits;
 }
 
-#if CONFIG_HIGHPTE
+#ifdef CONFIG_HIGHPTE
 static inline pte_addr_t ptep_to_paddr(pte_t *ptep)
 {
 	pte_addr_t paddr;
diff -Nru a/include/asm-h8300/hardirq.h b/include/asm-h8300/hardirq.h
--- a/include/asm-h8300/hardirq.h	Thu Apr 17 12:31:21 2003
+++ b/include/asm-h8300/hardirq.h	Mon May 12 18:59:24 2003
@@ -74,13 +74,13 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
 #endif
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-i386/apicdef.h b/include/asm-i386/apicdef.h
--- a/include/asm-i386/apicdef.h	Mon Feb  3 23:46:57 2003
+++ b/include/asm-i386/apicdef.h	Sun May  4 23:38:34 2003
@@ -11,13 +11,6 @@
 #define		APIC_DEFAULT_PHYS_BASE	0xfee00000
  
 #define		APIC_ID		0x20
-#ifdef CONFIG_X86_SUMMIT
- #define		APIC_ID_MASK		(0xFF<<24)
- #define		GET_APIC_ID(x)		(((x)>>24)&0xFF)
-#else
- #define		APIC_ID_MASK		(0x0F<<24)
- #define		GET_APIC_ID(x)		(((x)>>24)&0x0F)
-#endif
 #define		APIC_LVR	0x30
 #define			APIC_LVR_MASK		0xFF00FF
 #define			GET_APIC_VERSION(x)	((x)&0xFF)
diff -Nru a/include/asm-i386/edd.h b/include/asm-i386/edd.h
--- a/include/asm-i386/edd.h	Tue Jan 21 20:08:02 2003
+++ b/include/asm-i386/edd.h	Wed May  7 21:53:24 2003
@@ -141,7 +141,7 @@
 			u32 array_number;
 			u32 reserved1;
 			u64 reserved2;
-		} __attribute((packed)) raid;
+		} __attribute__ ((packed)) raid;
 		struct {
 			u8 device;
 			u8 reserved1;
diff -Nru a/include/asm-i386/elf.h b/include/asm-i386/elf.h
--- a/include/asm-i386/elf.h	Thu Apr 24 16:24:32 2003
+++ b/include/asm-i386/elf.h	Mon May 12 07:00:17 2003
@@ -12,6 +12,19 @@
 
 #include <linux/utsname.h>
 
+#define R_386_NONE	0
+#define R_386_32	1
+#define R_386_PC32	2
+#define R_386_GOT32	3
+#define R_386_PLT32	4
+#define R_386_COPY	5
+#define R_386_GLOB_DAT	6
+#define R_386_JMP_SLOT	7
+#define R_386_RELATIVE	8
+#define R_386_GOTOFF	9
+#define R_386_GOTPC	10
+#define R_386_NUM	11
+
 typedef unsigned long elf_greg_t;
 
 #define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
diff -Nru a/include/asm-i386/fixmap.h b/include/asm-i386/fixmap.h
--- a/include/asm-i386/fixmap.h	Mon Feb 10 06:04:32 2003
+++ b/include/asm-i386/fixmap.h	Sun May  4 23:38:34 2003
@@ -60,7 +60,7 @@
 #ifdef CONFIG_X86_F00F_BUG
 	FIX_F00F_IDT,	/* Virtual mapping for IDT */
 #endif
-#ifdef CONFIG_X86_SUMMIT
+#ifdef CONFIG_X86_CYCLONE_TIMER
 	FIX_CYCLONE_TIMER, /*cyclone timer register*/
 #endif 
 #ifdef CONFIG_HIGHMEM
diff -Nru a/include/asm-i386/genapic.h b/include/asm-i386/genapic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/genapic.h	Sat May 17 14:09:29 2003
@@ -0,0 +1,108 @@
+#ifndef _ASM_GENAPIC_H
+#define _ASM_GENAPIC_H 1
+
+/* 
+ * Generic APIC driver interface.
+ *  
+ * An straight forward mapping of the APIC related parts of the 
+ * x86 subarchitecture interface to a dynamic object.
+ *	
+ * This is used by the "generic" x86 subarchitecture. 
+ *
+ * Copyright 2003 Andi Kleen, SuSE Labs.
+ */
+
+struct mpc_config_translation;
+struct mpc_config_bus;
+struct mp_config_table;
+struct mpc_config_processor;
+
+struct genapic { 
+	char *name; 
+	int (*probe)(void); 
+
+	int (*apic_id_registered)(void);
+	unsigned long (*target_cpus)(void); 
+	int int_delivery_mode;
+	int int_dest_mode; 
+	int apic_broadcast_id; 
+	int esr_disable;
+	unsigned long (*check_apicid_used)(unsigned long bitmap, int apicid); 
+	unsigned long (*check_apicid_present)(int apicid); 
+	int no_balance_irq;
+	void (*init_apic_ldr)(void);
+	unsigned long (*ioapic_phys_id_map)(unsigned long map); 
+
+	void (*clustered_apic_check)(void);
+	int (*multi_timer_check)(int apic, int irq);
+	int (*apicid_to_node)(int logical_apicid); 
+	int (*cpu_to_logical_apicid)(int cpu);
+	int (*cpu_present_to_apicid)(int mps_cpu);
+	unsigned long (*apicid_to_cpu_present)(int phys_apicid); 
+	int (*mpc_apic_id)(struct mpc_config_processor *m, 
+			   struct mpc_config_translation *t); 
+	void (*setup_portio_remap)(void); 
+	int (*check_phys_apicid_present)(int boot_cpu_physical_apicid);
+
+	/* mpparse */
+	void (*mpc_oem_bus_info)(struct mpc_config_bus *, char *, 
+				 struct mpc_config_translation *);
+	void (*mpc_oem_pci_bus)(struct mpc_config_bus *, 
+				struct mpc_config_translation *); 
+
+	/* When one of the next two hooks returns 1 the genapic
+	   is switched to this. Essentially they are additional probe 
+	   functions. */
+	int (*mps_oem_check)(struct mp_config_table *mpc, char *oem, 
+			      char *productid);
+	int (*acpi_madt_oem_check)(char *oem_id, char *oem_table_id);
+
+	unsigned (*get_apic_id)(unsigned long x);
+	unsigned long apic_id_mask; 
+	unsigned int (*cpu_mask_to_apicid)(unsigned long cpumask);
+	
+	/* ipi */
+	void (*send_IPI_mask)(int mask, int vector);
+	void (*send_IPI_allbutself)(int vector);
+	void (*send_IPI_all)(int vector);
+}; 
+
+#define APICFUNC(x) .x = x
+
+#define APIC_INIT(aname, aprobe) { \
+	.name = aname, \
+	.probe = aprobe, \
+	.int_delivery_mode = INT_DELIVERY_MODE, \
+	.int_dest_mode = INT_DEST_MODE, \
+	.apic_broadcast_id = APIC_BROADCAST_ID, \
+	.no_balance_irq = NO_BALANCE_IRQ, \
+	APICFUNC(apic_id_registered), \
+	APICFUNC(target_cpus), \
+	APICFUNC(check_apicid_used), \
+	APICFUNC(check_apicid_present), \
+	APICFUNC(init_apic_ldr), \
+	APICFUNC(ioapic_phys_id_map), \
+	APICFUNC(clustered_apic_check), \
+	APICFUNC(multi_timer_check), \
+	APICFUNC(apicid_to_node), \
+	APICFUNC(cpu_to_logical_apicid), \
+	APICFUNC(cpu_present_to_apicid), \
+	APICFUNC(apicid_to_cpu_present), \
+	APICFUNC(mpc_apic_id), \
+	APICFUNC(setup_portio_remap), \
+	APICFUNC(check_phys_apicid_present), \
+	APICFUNC(mpc_oem_bus_info), \
+	APICFUNC(mpc_oem_pci_bus), \
+	APICFUNC(mps_oem_check), \
+	APICFUNC(get_apic_id), \
+	.apic_id_mask = APIC_ID_MASK, \
+	APICFUNC(cpu_mask_to_apicid), \
+	APICFUNC(acpi_madt_oem_check), \
+	APICFUNC(send_IPI_mask), \
+	APICFUNC(send_IPI_allbutself), \
+	APICFUNC(send_IPI_all), \
+	}
+
+extern struct genapic *genapic;
+
+#endif
diff -Nru a/include/asm-i386/i387.h b/include/asm-i386/i387.h
--- a/include/asm-i386/i387.h	Tue Apr  8 21:33:40 2003
+++ b/include/asm-i386/i387.h	Fri May  9 14:22:55 2003
@@ -87,15 +87,15 @@
 /*
  * ptrace request handers...
  */
-extern int get_fpregs( struct user_i387_struct *buf,
+extern int get_fpregs( struct user_i387_struct __user *buf,
 		       struct task_struct *tsk );
 extern int set_fpregs( struct task_struct *tsk,
-		       struct user_i387_struct *buf );
+		       struct user_i387_struct __user *buf );
 
-extern int get_fpxregs( struct user_fxsr_struct *buf,
+extern int get_fpxregs( struct user_fxsr_struct __user *buf,
 			struct task_struct *tsk );
 extern int set_fpxregs( struct task_struct *tsk,
-			struct user_fxsr_struct *buf );
+			struct user_fxsr_struct __user *buf );
 
 /*
  * FPU state for core dumps...
diff -Nru a/include/asm-i386/ipc.h b/include/asm-i386/ipc.h
--- a/include/asm-i386/ipc.h	Sat Dec 14 09:40:48 2002
+++ b/include/asm-i386/ipc.h	Fri May  9 14:23:37 2003
@@ -7,7 +7,7 @@
  * See arch/i386/kernel/sys_i386.c for ugly details..
  */
 struct ipc_kludge {
-	struct msgbuf *msgp;
+	struct msgbuf __user *msgp;
 	long msgtyp;
 };
 
diff -Nru a/include/asm-i386/kmap_types.h b/include/asm-i386/kmap_types.h
--- a/include/asm-i386/kmap_types.h	Sun Feb  2 23:34:59 2003
+++ b/include/asm-i386/kmap_types.h	Wed May  7 21:17:51 2003
@@ -3,7 +3,7 @@
 
 #include <linux/config.h>
 
-#if CONFIG_DEBUG_HIGHMEM
+#ifdef CONFIG_DEBUG_HIGHMEM
 # define D(n) __KM_FENCE_##n ,
 #else
 # define D(n)
diff -Nru a/include/asm-i386/mach-bigsmp/mach_apic.h b/include/asm-i386/mach-bigsmp/mach_apic.h
--- a/include/asm-i386/mach-bigsmp/mach_apic.h	Mon Mar 10 12:08:08 2003
+++ b/include/asm-i386/mach-bigsmp/mach_apic.h	Sat May 17 14:09:28 2003
@@ -15,23 +15,43 @@
 
 static inline int apic_id_registered(void)
 {
-	        return (1);
+	return (1);
 }
 
 #define APIC_DFR_VALUE	(APIC_DFR_CLUSTER)
-#define TARGET_CPUS	((cpu_online_map < 0xf)?cpu_online_map:0xf)
+static inline unsigned long target_cpus(void)
+{ 
+	return ((cpu_online_map < 0xf)?cpu_online_map:0xf);
+}
+#define TARGET_CPUS	(target_cpus())
 
 #define INT_DELIVERY_MODE dest_LowestPrio
 #define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
 
 #define APIC_BROADCAST_ID     (0x0f)
-#define check_apicid_used(bitmap, apicid) (0)
-#define check_apicid_present(bit) (phys_cpu_present_map & (1 << bit))
+static inline unsigned long check_apicid_used(unsigned long bitmap, int apicid) 
+{ 
+	return 0;
+} 
+static inline unsigned long check_apicid_present(int bit) 
+{
+	return (phys_cpu_present_map & (1 << bit));
+}
+
+#define apicid_cluster(apicid) (apicid & 0xF0)
+
+static inline unsigned get_apic_id(unsigned long x) 
+{ 
+	return (((x)>>24)&0x0F);
+} 
+
+#define		GET_APIC_ID(x)	get_apic_id(x)
 
 static inline unsigned long calculate_ldr(unsigned long old)
 {
 	unsigned long id;
-	id = xapic_phys_to_log_apicid(hard_smp_processor_id());
+	id = xapic_phys_to_log_apicid(
+			GET_APIC_LOGICAL_ID(*(unsigned long *)(APIC_BASE+APIC_LDR)));
 	return ((old & ~APIC_LDR_MASK) | SET_APIC_LOGICAL_ID(id));
 }
 
@@ -113,6 +133,41 @@
 static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
 {
 	return (1);
+}
+
+#define		APIC_ID_MASK		(0x0F<<24)
+
+static inline unsigned int cpu_mask_to_apicid (unsigned long cpumask)
+{
+	int num_bits_set;
+	int cpus_found = 0;
+	int cpu;
+	int apicid;	
+
+	num_bits_set = hweight32(cpumask); 
+	/* Return id to all */
+	if (num_bits_set == 32)
+		return (int) 0xFF;
+	/* 
+	 * The cpus in the mask must all be on the apic cluster.  If are not 
+	 * on the same apicid cluster return default value of TARGET_CPUS. 
+	 */
+	cpu = ffs(cpumask)-1;
+	apicid = cpu_to_logical_apicid(cpu);
+	while (cpus_found < num_bits_set) {
+		if (cpumask & (1 << cpu)) {
+			int new_apicid = cpu_to_logical_apicid(cpu);
+			if (apicid_cluster(apicid) != 
+					apicid_cluster(new_apicid)){
+				printk ("%s: Not a valid mask!\n",__FUNCTION__);
+				return TARGET_CPUS;
+			}
+			apicid = apicid | new_apicid;
+			cpus_found++;
+		}
+		cpu++;
+	}
+	return apicid;
 }
 
 #endif /* __ASM_MACH_APIC_H */
diff -Nru a/include/asm-i386/mach-bigsmp/mach_ipi.h b/include/asm-i386/mach-bigsmp/mach_ipi.h
--- a/include/asm-i386/mach-bigsmp/mach_ipi.h	Wed Jan  1 19:21:13 2003
+++ b/include/asm-i386/mach-bigsmp/mach_ipi.h	Sun May  4 23:38:34 2003
@@ -1,7 +1,7 @@
 #ifndef __ASM_MACH_IPI_H
 #define __ASM_MACH_IPI_H
 
-static inline void send_IPI_mask_sequence(int mask, int vector);
+inline void send_IPI_mask_sequence(int mask, int vector);
 
 static inline void send_IPI_mask(int mask, int vector)
 {
diff -Nru a/include/asm-i386/mach-default/mach_apic.h b/include/asm-i386/mach-default/mach_apic.h
--- a/include/asm-i386/mach-default/mach_apic.h	Mon Mar 10 12:08:08 2003
+++ b/include/asm-i386/mach-default/mach_apic.h	Mon May 12 21:23:20 2003
@@ -3,11 +3,15 @@
 
 #define APIC_DFR_VALUE	(APIC_DFR_FLAT)
 
+static inline unsigned long target_cpus(void)
+{ 
 #ifdef CONFIG_SMP
- #define TARGET_CPUS (cpu_online_map)
+	return cpu_online_map;
 #else
- #define TARGET_CPUS 0x01
+	return 1; 
 #endif
+} 
+#define TARGET_CPUS (target_cpus())
 
 #define NO_BALANCE_IRQ (0)
 #define esr_disable (0)
@@ -16,13 +20,15 @@
 #define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
 
 #define APIC_BROADCAST_ID      0x0F
-#define check_apicid_used(bitmap, apicid) (bitmap & (1 << apicid))
-#define check_apicid_present(bit) (phys_cpu_present_map & (1 << bit))
 
-static inline int apic_id_registered(void)
+static inline unsigned long check_apicid_used(unsigned long bitmap, int apicid) 
+{ 
+	return (bitmap & (1UL << apicid)); 
+} 
+
+static inline unsigned long check_apicid_present(int bit) 
 {
-	return (test_bit(GET_APIC_ID(apic_read(APIC_ID)), 
-						&phys_cpu_present_map));
+	return (phys_cpu_present_map & (1UL << bit));
 }
 
 /*
@@ -42,7 +48,7 @@
 	apic_write_around(APIC_LDR, val);
 }
 
-static inline ulong ioapic_phys_id_map(ulong phys_map)
+static inline unsigned long ioapic_phys_id_map(unsigned long phys_map)
 {
 	return phys_map;
 }
@@ -97,6 +103,26 @@
 static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
 {
 	return test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map);
+}
+
+#define		APIC_ID_MASK		(0xF<<24)
+
+static inline unsigned get_apic_id(unsigned long x) 
+{ 
+	return (((x)>>24)&0xF);
+} 
+
+#define		GET_APIC_ID(x)	get_apic_id(x)
+
+static inline int apic_id_registered(void)
+{
+	return (test_bit(GET_APIC_ID(apic_read(APIC_ID)), 
+						&phys_cpu_present_map));
+}
+
+static inline unsigned int cpu_mask_to_apicid (unsigned long cpumask)
+{
+	return cpumask;
 }
 
 #endif /* __ASM_MACH_APIC_H */
diff -Nru a/include/asm-i386/mach-default/mach_ipi.h b/include/asm-i386/mach-default/mach_ipi.h
--- a/include/asm-i386/mach-default/mach_ipi.h	Sun Dec 22 04:11:09 2002
+++ b/include/asm-i386/mach-default/mach_ipi.h	Sun May  4 23:38:34 2003
@@ -1,8 +1,8 @@
 #ifndef __ASM_MACH_IPI_H
 #define __ASM_MACH_IPI_H
 
-static inline void send_IPI_mask_bitmask(int mask, int vector);
-static inline void __send_IPI_shortcut(unsigned int shortcut, int vector);
+inline void send_IPI_mask_bitmask(int mask, int vector);
+inline void __send_IPI_shortcut(unsigned int shortcut, int vector);
 
 static inline void send_IPI_mask(int mask, int vector)
 {
diff -Nru a/include/asm-i386/mach-default/mach_mpparse.h b/include/asm-i386/mach-default/mach_mpparse.h
--- a/include/asm-i386/mach-default/mach_mpparse.h	Fri Feb 14 17:59:39 2003
+++ b/include/asm-i386/mach-default/mach_mpparse.h	Sun May  4 23:38:34 2003
@@ -12,14 +12,16 @@
 {
 }
 
-static inline void mps_oem_check(struct mp_config_table *mpc, char *oem, 
+static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, 
 		char *productid)
 {
+	return 0;
 }
 
 /* Hook from generic ACPI tables.c */
-static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
+	return 0;
 }
 
 
diff -Nru a/include/asm-i386/mach-generic/mach_apic.h b/include/asm-i386/mach-generic/mach_apic.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/mach-generic/mach_apic.h	Sat May 17 14:09:29 2003
@@ -0,0 +1,31 @@
+#ifndef __ASM_MACH_APIC_H
+#define __ASM_MACH_APIC_H
+
+#include <asm/genapic.h>
+
+#define esr_disable (genapic->esr_disable)
+#define NO_BALANCE_IRQ (genapic->no_balance_irq)
+#define APIC_BROADCAST_ID (genapic->apic_broadcast_id)
+#define INT_DELIVERY_MODE (genapic->int_delivery_mode)
+#define INT_DEST_MODE (genapic->int_dest_mode)
+#define TARGET_CPUS	  (genapic->target_cpus())
+#define apic_id_registered (genapic->apic_id_registered)
+#define apic_id_registered (genapic->apic_id_registered)
+#define init_apic_ldr (genapic->init_apic_ldr)
+#define ioapic_phys_id_map (genapic->ioapic_phys_id_map)
+#define clustered_apic_check (genapic->clustered_apic_check) 
+#define multi_timer_check (genapic->multi_timer_check)
+#define apicid_to_node (genapic->apicid_to_node)
+#define cpu_to_logical_apicid (genapic->cpu_to_logical_apicid) 
+#define cpu_present_to_apicid (genapic->cpu_present_to_apicid)
+#define apicid_to_cpu_present (genapic->apicid_to_cpu_present)
+#define mpc_apic_id (genapic->mpc_apic_id) 
+#define setup_portio_remap (genapic->setup_portio_remap)
+#define check_apicid_present (genapic->check_apicid_present)
+#define check_phys_apicid_present (genapic->check_phys_apicid_present)
+#define check_apicid_used (genapic->check_apicid_used)
+#define GET_APIC_ID (genapic->get_apic_id)
+#define APIC_ID_MASK (genapic->apic_id_mask)
+#define cpu_mask_to_apicid (genapic->cpu_mask_to_apicid)
+
+#endif /* __ASM_MACH_APIC_H */
diff -Nru a/include/asm-i386/mach-generic/mach_ipi.h b/include/asm-i386/mach-generic/mach_ipi.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/mach-generic/mach_ipi.h	Sun May  4 23:38:34 2003
@@ -0,0 +1,10 @@
+#ifndef _MACH_IPI_H
+#define _MACH_IPI_H 1
+
+#include <asm/genapic.h>
+
+#define send_IPI_mask (genapic->send_IPI_mask)
+#define send_IPI_allbutself (genapic->send_IPI_allbutself)
+#define send_IPI_all (genapic->send_IPI_all)
+
+#endif
diff -Nru a/include/asm-i386/mach-generic/mach_mpparse.h b/include/asm-i386/mach-generic/mach_mpparse.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-i386/mach-generic/mach_mpparse.h	Sun May  4 23:38:34 2003
@@ -0,0 +1,12 @@
+#ifndef _MACH_MPPARSE_H
+#define _MACH_MPPARSE_H 1
+
+#include <asm/genapic.h>
+
+#define mpc_oem_bus_info (genapic->mpc_oem_bus_info)
+#define mpc_oem_pci_bus (genapic->mpc_oem_pci_bus)
+
+int mps_oem_check(struct mp_config_table *mpc, char *oem, char *productid); 
+int acpi_madt_oem_check(char *oem_id, char *oem_table_id); 
+
+#endif
diff -Nru a/include/asm-i386/mach-numaq/mach_apic.h b/include/asm-i386/mach-numaq/mach_apic.h
--- a/include/asm-i386/mach-numaq/mach_apic.h	Fri Feb 28 15:03:59 2003
+++ b/include/asm-i386/mach-numaq/mach_apic.h	Mon May 12 21:23:20 2003
@@ -1,6 +1,9 @@
 #ifndef __ASM_MACH_APIC_H
 #define __ASM_MACH_APIC_H
 
+#include <asm/io.h>
+#include <linux/mmzone.h>
+
 #define APIC_DFR_VALUE	(APIC_DFR_CLUSTER)
 
 #define TARGET_CPUS (0xf)
@@ -14,6 +17,7 @@
 #define APIC_BROADCAST_ID      0x0F
 #define check_apicid_used(bitmap, apicid) ((bitmap) & (1 << (apicid)))
 #define check_apicid_present(bit) (phys_cpu_present_map & (1 << bit))
+#define apicid_cluster(apicid) (apicid & 0xF0)
 
 static inline int apic_id_registered(void)
 {
@@ -101,6 +105,48 @@
 static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
 {
 	return (1);
+}
+
+#define APIC_ID_MASK (0xF<<24)
+
+static inline unsigned get_apic_id(unsigned long x)
+{
+	        return (((x)>>24)&0x0F);
+}
+
+#define         GET_APIC_ID(x)  get_apic_id(x)
+
+static inline unsigned int cpu_mask_to_apicid (unsigned long cpumask)
+{
+	int num_bits_set;
+	int cpus_found = 0;
+	int cpu;
+	int apicid;	
+
+	num_bits_set = hweight32(cpumask); 
+	/* Return id to all */
+	if (num_bits_set == 32)
+		return (int) 0xFF;
+	/* 
+	 * The cpus in the mask must all be on the apic cluster.  If are not 
+	 * on the same apicid cluster return default value of TARGET_CPUS. 
+	 */
+	cpu = ffs(cpumask)-1;
+	apicid = cpu_to_logical_apicid(cpu);
+	while (cpus_found < num_bits_set) {
+		if (cpumask & (1 << cpu)) {
+			int new_apicid = cpu_to_logical_apicid(cpu);
+			if (apicid_cluster(apicid) != 
+					apicid_cluster(new_apicid)){
+				printk ("%s: Not a valid mask!\n",__FUNCTION__);
+				return TARGET_CPUS;
+			}
+			apicid = apicid | new_apicid;
+			cpus_found++;
+		}
+		cpu++;
+	}
+	return apicid;
 }
 
 #endif /* __ASM_MACH_APIC_H */
diff -Nru a/include/asm-i386/mach-summit/mach_apic.h b/include/asm-i386/mach-summit/mach_apic.h
--- a/include/asm-i386/mach-summit/mach_apic.h	Mon Mar 10 12:08:08 2003
+++ b/include/asm-i386/mach-summit/mach_apic.h	Sat May 17 14:09:28 2003
@@ -1,7 +1,13 @@
 #ifndef __ASM_MACH_APIC_H
 #define __ASM_MACH_APIC_H
 
+#include <linux/config.h>
+
+#ifdef CONFIG_X86_GENERICARCH
+#define x86_summit 1	/* must be an constant expressiona for generic arch */
+#else
 extern int x86_summit;
+#endif
 
 #define esr_disable (x86_summit ? 1 : 0)
 #define NO_BALANCE_IRQ (0)
@@ -9,29 +15,53 @@
 #define XAPIC_DEST_CPUS_MASK    0x0Fu
 #define XAPIC_DEST_CLUSTER_MASK 0xF0u
 
-#define xapic_phys_to_log_apicid(phys_apic) ( (1ul << ((phys_apic) & 0x3)) |\
-		((phys_apic) & XAPIC_DEST_CLUSTER_MASK) )
+static inline unsigned long xapic_phys_to_log_apicid(int phys_apic) 
+{
+	return ( (1ul << ((phys_apic) & 0x3)) |
+		 ((phys_apic) & XAPIC_DEST_CLUSTER_MASK) );
+}
 
 #define APIC_DFR_VALUE	(x86_summit ? APIC_DFR_CLUSTER : APIC_DFR_FLAT)
-#define TARGET_CPUS	(x86_summit ? XAPIC_DEST_CPUS_MASK : cpu_online_map)
+
+static inline unsigned long target_cpus(void)
+{
+	return (x86_summit ? XAPIC_DEST_CPUS_MASK : cpu_online_map);
+} 
+#define TARGET_CPUS	(target_cpus())
 
 #define INT_DELIVERY_MODE (x86_summit ? dest_Fixed : dest_LowestPrio)
 #define INT_DEST_MODE 1     /* logical delivery broadcast to all procs */
 
-#define APIC_BROADCAST_ID     (x86_summit ? 0xFF : 0x0F)
-#define check_apicid_used(bitmap, apicid) (x86_summit ? 0 : (bitmap & (1 << apicid)))
+#define APIC_BROADCAST_ID     (0x0F)
+static inline unsigned long check_apicid_used(unsigned long bitmap, int apicid) 
+{
+	return (x86_summit ? 0 : (bitmap & (1 << apicid)));
+} 
 
 /* we don't use the phys_cpu_present_map to indicate apicid presence */
-#define check_apicid_present(bit) (x86_summit ? 1 : (phys_cpu_present_map & (1 << bit))) 
+static inline unsigned long check_apicid_present(int bit) 
+{
+	return (x86_summit ? 1 : (phys_cpu_present_map & (1 << bit)));
+}
+
+#define apicid_cluster(apicid) (apicid & 0xF0)
 
 extern u8 bios_cpu_apicid[];
 
+static inline unsigned get_apic_id(unsigned long x) 
+{ 
+	return (((x)>>24)&0xFF);
+} 
+
+#define		GET_APIC_ID(x)	get_apic_id(x)
+
 static inline void init_apic_ldr(void)
 {
 	unsigned long val, id;
 
 	if (x86_summit)
-		id = xapic_phys_to_log_apicid(hard_smp_processor_id());
+		id = xapic_phys_to_log_apicid(
+			GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID)));
 	else
 		id = 1UL << smp_processor_id();
 	apic_write_around(APIC_DFR, APIC_DFR_VALUE);
@@ -111,6 +141,41 @@
 		return (1);
 	else
 		return test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map);
+}
+
+#define		APIC_ID_MASK		(0xFF<<24)
+
+static inline unsigned int cpu_mask_to_apicid (unsigned long cpumask)
+{
+	int num_bits_set;
+	int cpus_found = 0;
+	int cpu;
+	int apicid;	
+
+	num_bits_set = hweight32(cpumask); 
+	/* Return id to all */
+	if (num_bits_set == 32)
+		return (int) 0xFF;
+	/* 
+	 * The cpus in the mask must all be on the apic cluster.  If are not 
+	 * on the same apicid cluster return default value of TARGET_CPUS. 
+	 */
+	cpu = ffs(cpumask)-1;
+	apicid = cpu_to_logical_apicid(cpu);
+	while (cpus_found < num_bits_set) {
+		if (cpumask & (1 << cpu)) {
+			int new_apicid = cpu_to_logical_apicid(cpu);
+			if (apicid_cluster(apicid) != 
+					apicid_cluster(new_apicid)){
+				printk ("%s: Not a valid mask!\n",__FUNCTION__);
+				return TARGET_CPUS;
+			}
+			apicid = apicid | new_apicid;
+			cpus_found++;
+		}
+		cpu++;
+	}
+	return apicid;
 }
 
 #endif /* __ASM_MACH_APIC_H */
diff -Nru a/include/asm-i386/mach-summit/mach_ipi.h b/include/asm-i386/mach-summit/mach_ipi.h
--- a/include/asm-i386/mach-summit/mach_ipi.h	Sun Dec 22 04:11:34 2002
+++ b/include/asm-i386/mach-summit/mach_ipi.h	Sun May  4 23:38:34 2003
@@ -1,7 +1,7 @@
 #ifndef __ASM_MACH_IPI_H
 #define __ASM_MACH_IPI_H
 
-static inline void send_IPI_mask_sequence(int mask, int vector);
+inline void send_IPI_mask_sequence(int mask, int vector);
 
 static inline void send_IPI_mask(int mask, int vector)
 {
diff -Nru a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-i386/mach-summit/mach_mpparse.h
--- a/include/asm-i386/mach-summit/mach_mpparse.h	Thu Apr 17 12:32:30 2003
+++ b/include/asm-i386/mach-summit/mach_mpparse.h	Sun May  4 23:38:34 2003
@@ -14,26 +14,34 @@
 {
 }
 
-static inline void mps_oem_check(struct mp_config_table *mpc, char *oem, 
+static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, 
 		char *productid)
 {
 	if (!strncmp(oem, "IBM ENSW", 8) && 
 			(!strncmp(productid, "VIGIL SMP", 9) 
 			 || !strncmp(productid, "EXA", 3)
 			 || !strncmp(productid, "RUTHLESS SMP", 12))){
+#ifndef CONFIG_X86_GENERICARCH
 		x86_summit = 1;
+#endif
 		use_cyclone = 1; /*enable cyclone-timer*/
+		return 1;
 	}
+	return 0;
 }
 
 /* Hook from generic ACPI tables.c */
-static inline void acpi_madt_oem_check(char *oem_id, char *oem_table_id)
+static inline int acpi_madt_oem_check(char *oem_id, char *oem_table_id)
 {
 	if (!strncmp(oem_id, "IBM", 3) &&
 	    (!strncmp(oem_table_id, "SERVIGIL", 8)
 	     || !strncmp(oem_table_id, "EXA", 3))){
+#ifndef CONFIG_X86_GENERICARCH
 		x86_summit = 1;
+#endif
 		use_cyclone = 1; /*enable cyclone-timer*/
+		return 1;
 	}
+	return 0;
 }
 #endif /* __ASM_MACH_MPPARSE_H */
diff -Nru a/include/asm-i386/mach-visws/mach_apic.h b/include/asm-i386/mach-visws/mach_apic.h
--- a/include/asm-i386/mach-visws/mach_apic.h	Tue Feb 18 18:58:55 2003
+++ b/include/asm-i386/mach-visws/mach_apic.h	Wed May 14 23:44:07 2003
@@ -19,6 +19,14 @@
 #define check_apicid_used(bitmap, apicid) (bitmap & (1 << apicid))
 #define check_apicid_present(bit) (phys_cpu_present_map & (1 << bit))
 
+#define         APIC_ID_MASK            (0xF<<24)
+
+static inline unsigned get_apic_id(unsigned long x)
+{
+	        return (((x)>>24)&0xF);
+}
+#define         GET_APIC_ID(x)  get_apic_id(x)
+
 static inline int apic_id_registered(void)
 {
 	return (test_bit(GET_APIC_ID(apic_read(APIC_ID)), 
@@ -77,4 +85,8 @@
 	return test_bit(boot_cpu_physical_apicid, &phys_cpu_present_map);
 }
 
+static inline unsigned int cpu_mask_to_apicid (unsigned long cpumask)
+{
+	return cpumask;
+}
 #endif /* __ASM_MACH_APIC_H */
diff -Nru a/include/asm-i386/mmu_context.h b/include/asm-i386/mmu_context.h
--- a/include/asm-i386/mmu_context.h	Fri Feb 21 05:32:36 2003
+++ b/include/asm-i386/mmu_context.h	Sat May 17 14:09:52 2003
@@ -45,8 +45,8 @@
 #ifdef CONFIG_SMP
 	else {
 		cpu_tlbstate[cpu].state = TLBSTATE_OK;
-		if (cpu_tlbstate[cpu].active_mm != next)
-			BUG();
+		BUG_ON(cpu_tlbstate[cpu].active_mm != next);
+
 		if (!test_and_set_bit(cpu, &next->cpu_vm_mask)) {
 			/* We were in lazy tlb mode and leave_mm disabled 
 			 * tlb flush IPI delivery. We must reload %cr3.
diff -Nru a/include/asm-i386/mmzone.h b/include/asm-i386/mmzone.h
--- a/include/asm-i386/mmzone.h	Tue Mar  4 23:41:55 2003
+++ b/include/asm-i386/mmzone.h	Sun May  4 23:38:34 2003
@@ -120,7 +120,7 @@
 
 #ifdef CONFIG_X86_NUMAQ
 #include <asm/numaq.h>
-#elif CONFIG_X86_SUMMIT
+#elif CONFIG_NUMA	/* summit or generic arch */
 #include <asm/srat.h>
 #elif CONFIG_X86_PC
 #define get_memcfg_numa get_memcfg_numa_flat
diff -Nru a/include/asm-i386/mpspec.h b/include/asm-i386/mpspec.h
--- a/include/asm-i386/mpspec.h	Tue Jan 14 03:02:28 2003
+++ b/include/asm-i386/mpspec.h	Sun May  4 23:38:34 2003
@@ -16,7 +16,7 @@
 /*
  * a maximum of 16 APICs with the current APIC ID architecture.
  */
-#if defined(CONFIG_X86_NUMAQ) || defined (CONFIG_X86_SUMMIT)
+#if defined(CONFIG_X86_NUMAQ) || defined (CONFIG_X86_SUMMIT) || defined(CONFIG_X86_GENERICARCH)
 #define MAX_APICS 256
 #else
 #define MAX_APICS 16
diff -Nru a/include/asm-i386/numnodes.h b/include/asm-i386/numnodes.h
--- a/include/asm-i386/numnodes.h	Mon Feb 24 23:13:14 2003
+++ b/include/asm-i386/numnodes.h	Sun May  4 23:38:34 2003
@@ -5,7 +5,7 @@
 
 #ifdef CONFIG_X86_NUMAQ
 #include <asm/numaq.h>
-#elif CONFIG_X86_SUMMIT
+#elif CONFIG_NUMA
 #include <asm/srat.h>
 #else
 #define MAX_NUMNODES	1
diff -Nru a/include/asm-i386/processor.h b/include/asm-i386/processor.h
--- a/include/asm-i386/processor.h	Wed Apr 30 15:48:26 2003
+++ b/include/asm-i386/processor.h	Fri May  9 14:24:03 2003
@@ -400,7 +400,7 @@
 /* floating point info */
 	union i387_union	i387;
 /* virtual 86 mode info */
-	struct vm86_struct	* vm86_info;
+	struct vm86_struct __user * vm86_info;
 	unsigned long		screen_bitmap;
 	unsigned long		v86flags, v86mask, saved_esp0;
 	unsigned int		saved_fs, saved_gs;
@@ -536,7 +536,7 @@
 #define ASM_NOP6 K8_NOP6
 #define ASM_NOP7 K8_NOP7
 #define ASM_NOP8 K8_NOP8
-#elif CONFIG_MK7
+#elif defined(CONFIG_MK7)
 #define ASM_NOP1 K7_NOP1
 #define ASM_NOP2 K7_NOP2
 #define ASM_NOP3 K7_NOP3
diff -Nru a/include/asm-i386/smp.h b/include/asm-i386/smp.h
--- a/include/asm-i386/smp.h	Mon Jan 13 16:42:37 2003
+++ b/include/asm-i386/smp.h	Sun May  4 23:38:34 2003
@@ -87,11 +87,17 @@
 	return -1;
 }
 #ifdef CONFIG_X86_LOCAL_APIC
-static __inline int hard_smp_processor_id(void)
+
+#ifdef APIC_DEFINITION
+extern int hard_smp_processor_id(void);
+#else
+#include <mach_apic.h>
+static inline int hard_smp_processor_id(void)
 {
 	/* we don't want to mark this access volatile - bad code generation */
 	return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
 }
+#endif
 
 static __inline int logical_smp_processor_id(void)
 {
diff -Nru a/include/asm-i386/spinlock.h b/include/asm-i386/spinlock.h
--- a/include/asm-i386/spinlock.h	Sat Oct 19 14:18:27 2002
+++ b/include/asm-i386/spinlock.h	Sat May 17 14:09:52 2003
@@ -5,6 +5,7 @@
 #include <asm/rwlock.h>
 #include <asm/page.h>
 #include <linux/config.h>
+#include <linux/compiler.h>
 
 extern int printk(const char * fmt, ...)
 	__attribute__ ((format (printf, 1, 2)));
@@ -70,10 +71,8 @@
 static inline void _raw_spin_unlock(spinlock_t *lock)
 {
 #ifdef CONFIG_DEBUG_SPINLOCK
-	if (lock->magic != SPINLOCK_MAGIC)
-		BUG();
-	if (!spin_is_locked(lock))
-		BUG();
+	BUG_ON(lock->magic != SPINLOCK_MAGIC);
+	BUG_ON(!spin_is_locked(lock));
 #endif
 	__asm__ __volatile__(
 		spin_unlock_string
@@ -91,10 +90,8 @@
 {
 	char oldval = 1;
 #ifdef CONFIG_DEBUG_SPINLOCK
-	if (lock->magic != SPINLOCK_MAGIC)
-		BUG();
-	if (!spin_is_locked(lock))
-		BUG();
+	BUG_ON(lock->magic != SPINLOCK_MAGIC);
+	BUG_ON(!spin_is_locked(lock));
 #endif
 	__asm__ __volatile__(
 		spin_unlock_string
@@ -118,8 +115,8 @@
 #ifdef CONFIG_DEBUG_SPINLOCK
 	__label__ here;
 here:
-	if (lock->magic != SPINLOCK_MAGIC) {
-printk("eip: %p\n", &&here);
+	if (unlikely(lock->magic != SPINLOCK_MAGIC)) {
+		printk("eip: %p\n", &&here);
 		BUG();
 	}
 #endif
@@ -174,8 +171,7 @@
 static inline void _raw_read_lock(rwlock_t *rw)
 {
 #ifdef CONFIG_DEBUG_SPINLOCK
-	if (rw->magic != RWLOCK_MAGIC)
-		BUG();
+	BUG_ON(rw->magic != RWLOCK_MAGIC);
 #endif
 	__build_read_lock(rw, "__read_lock_failed");
 }
@@ -183,8 +179,7 @@
 static inline void _raw_write_lock(rwlock_t *rw)
 {
 #ifdef CONFIG_DEBUG_SPINLOCK
-	if (rw->magic != RWLOCK_MAGIC)
-		BUG();
+	BUG_ON(rw->magic != RWLOCK_MAGIC);
 #endif
 	__build_write_lock(rw, "__write_lock_failed");
 }
diff -Nru a/include/asm-i386/suspend.h b/include/asm-i386/suspend.h
--- a/include/asm-i386/suspend.h	Thu Nov  7 08:57:46 2002
+++ b/include/asm-i386/suspend.h	Sat May 10 07:23:26 2003
@@ -30,18 +30,14 @@
 	unsigned long return_address;
 } __attribute__((packed));
 
-/* We'll access these from assembly, so we'd better have them outside struct */
-extern unsigned long saved_context_eax, saved_context_ebx, saved_context_ecx, saved_context_edx;
-extern unsigned long saved_context_esp, saved_context_ebp, saved_context_esi, saved_context_edi;
-extern unsigned long saved_context_eflags;
-
-
 #define loaddebug(thread,register) \
                __asm__("movl %0,%%db" #register  \
                        : /* no output */ \
                        :"r" ((thread)->debugreg[register]))
 
-extern void fix_processor_context(void);
+extern void save_processor_state(void);
+extern void restore_processor_state(void);
+
 extern void do_magic(int resume);
 
 #ifdef CONFIG_ACPI_SLEEP
diff -Nru a/include/asm-i386/system.h b/include/asm-i386/system.h
--- a/include/asm-i386/system.h	Wed Apr 30 01:07:14 2003
+++ b/include/asm-i386/system.h	Wed Apr 30 16:10:25 2003
@@ -474,5 +474,6 @@
 #define BROKEN_ACPI_Sx		0x0001
 #define BROKEN_INIT_AFTER_S1	0x0002
 #define BROKEN_PNP_BIOS		0x0004
+#define BROKEN_CPUFREQ		0x0008
 
 #endif
diff -Nru a/include/asm-i386/types.h b/include/asm-i386/types.h
--- a/include/asm-i386/types.h	Mon Dec 30 20:14:21 2002
+++ b/include/asm-i386/types.h	Sat May 17 14:09:33 2003
@@ -51,7 +51,7 @@
 
 /* DMA addresses come in generic and 64-bit flavours.  */
 
-#ifdef CONFIG_HIGHMEM
+#ifdef CONFIG_HIGHMEM64G
 typedef u64 dma_addr_t;
 #else
 typedef u32 dma_addr_t;
diff -Nru a/include/asm-i386/uaccess.h b/include/asm-i386/uaccess.h
--- a/include/asm-i386/uaccess.h	Tue Apr  8 17:11:39 2003
+++ b/include/asm-i386/uaccess.h	Mon May 12 21:22:56 2003
@@ -42,8 +42,6 @@
 } ____cacheline_aligned_in_smp movsl_mask;
 #endif
 
-int __verify_write(const void *, unsigned long);
-
 #define __addr_ok(addr) ((unsigned long)(addr) < (current_thread_info()->addr_limit.seg))
 
 /*
@@ -62,8 +60,6 @@
 		:"1" (addr),"g" ((int)(size)),"g" (current_thread_info()->addr_limit.seg)); \
 	flag; })
 
-#ifdef CONFIG_X86_WP_WORKS_OK
-
 /**
  * access_ok: - Checks if a user space pointer is valid
  * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
@@ -85,14 +81,6 @@
  */
 #define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
 
-#else
-
-#define access_ok(type,addr,size) ( (__range_ok(addr,size) == 0) && \
-			 ((type) == VERIFY_READ || boot_cpu_data.wp_works_ok || \
-			  __verify_write((void *)(addr),(size))))
-
-#endif
-
 /**
  * verify_area: - Obsolete, use access_ok()
  * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
@@ -191,14 +179,8 @@
 	__ret_gu;							\
 })
 
-extern void __put_user_1(void);
-extern void __put_user_2(void);
-extern void __put_user_4(void);
-extern void __put_user_8(void);
-
 extern void __put_user_bad(void);
 
-
 /**
  * put_user: - Write a simple value into user space.
  * @x:   Value to copy to user space.
@@ -299,6 +281,8 @@
 		: "=r"(err)					\
 		: "A" (x), "r" (addr), "i"(-EFAULT), "0"(err))
 
+#ifdef CONFIG_X86_WP_WORKS_OK
+
 #define __put_user_size(x,ptr,size,retval,errret)			\
 do {									\
 	retval = 0;							\
@@ -311,6 +295,18 @@
 	}								\
 } while (0)
 
+#else
+
+#define __put_user_size(x,ptr,size,retval,errret)			\
+do {									\
+	__typeof__(*(ptr)) __pus_tmp = x;				\
+	retval = 0;							\
+									\
+	if(unlikely(__copy_to_user_ll(ptr, &__pus_tmp, size) != 0))	\
+		retval = errret;					\
+} while (0)
+
+#endif
 struct __large_struct { unsigned long buf[100]; };
 #define __m(x) (*(struct __large_struct *)(x))
 
diff -Nru a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h
--- a/include/asm-i386/unistd.h	Tue Feb 18 13:54:44 2003
+++ b/include/asm-i386/unistd.h	Wed May  7 22:10:52 2003
@@ -399,6 +399,8 @@
  * What we want is __attribute__((weak,alias("sys_ni_syscall"))),
  * but it doesn't work on all toolchains, so we just do it by hand
  */
+#ifndef cond_syscall
 #define cond_syscall(x) asm(".weak\t" #x "\n\t.set\t" #x ",sys_ni_syscall");
+#endif
 
 #endif /* _ASM_I386_UNISTD_H_ */
diff -Nru a/include/asm-ia64/acpi-ext.h b/include/asm-ia64/acpi-ext.h
--- a/include/asm-ia64/acpi-ext.h	Thu Apr  3 12:32:33 2003
+++ b/include/asm-ia64/acpi-ext.h	Fri Apr 25 10:40:08 2003
@@ -3,30 +3,15 @@
  *
  * Copyright (C) 2003 Hewlett-Packard
  * Copyright (C) Alex Williamson
+ * Copyright (C) Bjorn Helgaas
  *
- * Vendor specific extensions to ACPI.  The HP-specific extensiosn are also used by NEC.
+ * Vendor specific extensions to ACPI.
  */
 #ifndef _ASM_IA64_ACPI_EXT_H
 #define _ASM_IA64_ACPI_EXT_H
 
 #include <linux/types.h>
 
-#define HP_CCSR_LENGTH	0x21
-#define HP_CCSR_TYPE	0x2
-#define HP_CCSR_GUID	EFI_GUID(0x69e9adf9, 0x924f, 0xab5f, \
-				 0xf6, 0x4a, 0x24, 0xd2, 0x01, 0x37, 0x0e, 0xad)
-
-struct acpi_hp_vendor_long {
-	u8      guid_id;
-	u8      guid[16];
-	u8      csr_base[8];
-	u8      csr_length[8];
-};
-
 extern acpi_status hp_acpi_csr_space (acpi_handle, u64 *base, u64 *length);
-extern acpi_status acpi_get_crs (acpi_handle, struct acpi_buffer *);
-extern struct acpi_resource *acpi_get_crs_next (struct acpi_buffer *, int *);
-extern union acpi_resource_data *acpi_get_crs_type (struct acpi_buffer *, int *, int);
-extern void acpi_dispose_crs (struct acpi_buffer *);
 
 #endif /* _ASM_IA64_ACPI_EXT_H */
diff -Nru a/include/asm-ia64/atomic.h b/include/asm-ia64/atomic.h
--- a/include/asm-ia64/atomic.h	Mon Mar 31 16:44:53 2003
+++ b/include/asm-ia64/atomic.h	Sat May 10 02:28:47 2003
@@ -56,11 +56,16 @@
 }
 
 #define atomic_add_return(i,v)						\
-	((__builtin_constant_p(i) &&					\
-	  (   (i ==  1) || (i ==  4) || (i ==  8) || (i ==  16)		\
-	   || (i == -1) || (i == -4) || (i == -8) || (i == -16)))	\
-	 ? ia64_fetch_and_add(i, &(v)->counter)				\
-	 : ia64_atomic_add(i, v))
+({									\
+	int __ia64_aar_i = (i);						\
+	(__builtin_constant_p(i)					\
+	 && (   (__ia64_aar_i ==  1) || (__ia64_aar_i ==   4)		\
+	     || (__ia64_aar_i ==  8) || (__ia64_aar_i ==  16)		\
+	     || (__ia64_aar_i == -1) || (__ia64_aar_i ==  -4)		\
+	     || (__ia64_aar_i == -8) || (__ia64_aar_i == -16)))		\
+		? ia64_fetch_and_add(__ia64_aar_i, &(v)->counter)	\
+		: ia64_atomic_add(__ia64_aar_i, v);			\
+})
 
 /*
  * Atomically add I to V and return TRUE if the resulting value is
@@ -72,13 +77,17 @@
 	return atomic_add_return(i, v) < 0;
 }
 
-
 #define atomic_sub_return(i,v)						\
-	((__builtin_constant_p(i) &&					\
-	  (   (i ==  1) || (i ==  4) || (i ==  8) || (i ==  16)		\
-	   || (i == -1) || (i == -4) || (i == -8) || (i == -16)))	\
-	 ? ia64_fetch_and_add(-(i), &(v)->counter)			\
-	 : ia64_atomic_sub(i, v))
+({									\
+	int __ia64_asr_i = (i);						\
+	(__builtin_constant_p(i)					\
+	 && (   (__ia64_asr_i ==   1) || (__ia64_asr_i ==   4)		\
+	     || (__ia64_asr_i ==   8) || (__ia64_asr_i ==  16)		\
+	     || (__ia64_asr_i ==  -1) || (__ia64_asr_i ==  -4)		\
+	     || (__ia64_asr_i ==  -8) || (__ia64_asr_i == -16)))	\
+		? ia64_fetch_and_add(-__ia64_asr_i, &(v)->counter)	\
+		: ia64_atomic_sub(__ia64_asr_i, v);			\
+})
 
 #define atomic_dec_return(v)		atomic_sub_return(1, (v))
 #define atomic_inc_return(v)		atomic_add_return(1, (v))
diff -Nru a/include/asm-ia64/bitops.h b/include/asm-ia64/bitops.h
--- a/include/asm-ia64/bitops.h	Sat Apr 12 15:37:38 2003
+++ b/include/asm-ia64/bitops.h	Sat May 10 02:28:47 2003
@@ -450,15 +450,15 @@
 
 #ifdef __KERNEL__
 
-#define __clear_bit(nr, addr)        clear_bit(nr, addr)
+#define __clear_bit(nr, addr)		clear_bit(nr, addr)
 
-#define ext2_set_bit                 test_and_set_bit
-#define ext2_set_atomic(l,n,a)	     test_and_set_bit(n,a)
-#define ext2_clear_bit               test_and_clear_bit
-#define ext2_clear_atomic(l,n,a)     test_and_clear_bit(n,a)
-#define ext2_test_bit                test_bit
-#define ext2_find_first_zero_bit     find_first_zero_bit
-#define ext2_find_next_zero_bit      find_next_zero_bit
+#define ext2_set_bit			test_and_set_bit
+#define ext2_set_bit_atomic(l,n,a)	test_and_set_bit(n,a)
+#define ext2_clear_bit			test_and_clear_bit
+#define ext2_clear_bit_atomic(l,n,a)	test_and_clear_bit(n,a)
+#define ext2_test_bit			test_bit
+#define ext2_find_first_zero_bit	find_first_zero_bit
+#define ext2_find_next_zero_bit		find_next_zero_bit
 
 /* Bitmap functions for the minix filesystem.  */
 #define minix_test_and_set_bit(nr,addr)		test_and_set_bit(nr,addr)
diff -Nru a/include/asm-ia64/compat.h b/include/asm-ia64/compat.h
--- a/include/asm-ia64/compat.h	Wed Apr  9 11:51:34 2003
+++ b/include/asm-ia64/compat.h	Fri Apr 18 07:18:38 2003
@@ -102,6 +102,9 @@
 	int		f_spare[6];
 };
 
+#define COMPAT_RLIM_OLD_INFINITY       0x7fffffff
+#define COMPAT_RLIM_INFINITY           0xffffffff
+
 typedef u32		compat_old_sigset_t;	/* at least 32 bits */
 
 #define _COMPAT_NSIG		64
diff -Nru a/include/asm-ia64/dma-mapping.h b/include/asm-ia64/dma-mapping.h
--- a/include/asm-ia64/dma-mapping.h	Sat Dec 21 20:36:53 2002
+++ b/include/asm-ia64/dma-mapping.h	Sat May 10 02:28:47 2003
@@ -1 +1,63 @@
-#include <asm-generic/dma-mapping.h>
+#ifndef _ASM_IA64_DMA_MAPPING_H
+#define _ASM_IA64_DMA_MAPPING_H
+
+/*
+ * Copyright (C) 2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ */
+
+#define dma_alloc_coherent	platform_dma_alloc_coherent
+#define dma_alloc_noncoherent	platform_dma_alloc_coherent	/* coherent mem. is cheap */
+#define dma_free_coherent	platform_dma_free_coherent
+#define dma_free_noncoherent	platform_dma_free_coherent
+#define dma_map_single		platform_dma_map_single
+#define dma_map_sg		platform_dma_map_sg
+#define dma_unmap_single	platform_dma_unmap_single
+#define dma_unmap_sg		platform_dma_unmap_sg
+#define dma_sync_single		platform_dma_sync_single
+#define dma_sync_sg		platform_dma_sync_sg
+
+#define dma_map_page(dev, pg, off, size, dir)				\
+	dma_map_single(dev, page_address(pg) + (off), (size), (dir))
+#define dma_unmap_page(dev, dma_addr, size, dir)			\
+	dma_unmap_single(dev, dma_addr, size, dir)
+
+/*
+ * Rest of this file is part of the "Advanced DMA API".  Use at your own risk.
+ * See Documentation/DMA-API.txt for details.
+ */
+
+#define dma_sync_single_range(dev, dma_handle, offset, size, dir)	\
+	dma_sync_single(dev, dma_handle, size, dir)
+
+#define dma_supported		platform_dma_supported
+
+static inline int
+dma_set_mask (struct device *dev, u64 mask)
+{
+	if (!dev->dma_mask || !dma_supported(dev, mask))
+		return -EIO;
+	*dev->dma_mask = mask;
+	return 0;
+}
+
+static inline int
+dma_get_cache_alignment (void)
+{
+	extern int ia64_max_cacheline_size;
+	return ia64_max_cacheline_size;
+}
+
+static inline void
+dma_cache_sync (void *vaddr, size_t size, enum dma_data_direction dir)
+{
+	/*
+	 * IA-64 is cache-coherent, so this is mostly a no-op.  However, we do need to
+	 * ensure that dma_cache_sync() enforces order, hence the mb().
+	 */
+	mb();
+}
+
+#define dma_is_consistent(dma_handle)	(1)	/* all we do is coherent memory... */
+
+#endif /* _ASM_IA64_DMA_MAPPING_H */
diff -Nru a/include/asm-ia64/hardirq.h b/include/asm-ia64/hardirq.h
--- a/include/asm-ia64/hardirq.h	Wed Feb  5 03:03:22 2003
+++ b/include/asm-ia64/hardirq.h	Mon May 12 18:59:24 2003
@@ -85,7 +85,7 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()		((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-ia64/ia32.h b/include/asm-ia64/ia32.h
--- a/include/asm-ia64/ia32.h	Sun Mar  9 01:34:45 2003
+++ b/include/asm-ia64/ia32.h	Sat May 10 02:28:47 2003
@@ -453,8 +453,6 @@
 struct linux_binprm;
 
 extern void ia32_gdt_init (void);
-extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
-			       sigset_t *set, struct pt_regs *regs);
 extern void ia32_init_addr_space (struct pt_regs *regs);
 extern int ia32_setup_arg_pages (struct linux_binprm *bprm);
 extern int ia32_exception (struct pt_regs *regs, unsigned long isr);
@@ -475,5 +473,9 @@
 	} while(0)
 
 #endif /* !CONFIG_IA32_SUPPORT */
+
+/* Declare this uncondiontally, so we don't get warnings for unreachable code.  */
+extern int ia32_setup_frame1 (int sig, struct k_sigaction *ka, siginfo_t *info,
+			      sigset_t *set, struct pt_regs *regs);
 
 #endif /* _ASM_IA64_IA32_H */
diff -Nru a/include/asm-ia64/intrinsics.h b/include/asm-ia64/intrinsics.h
--- a/include/asm-ia64/intrinsics.h	Mon Mar 31 16:44:53 2003
+++ b/include/asm-ia64/intrinsics.h	Tue May  6 10:56:54 2003
@@ -17,16 +17,16 @@
 extern unsigned long __bad_size_for_ia64_fetch_and_add (void);
 extern unsigned long __bad_increment_for_ia64_fetch_and_add (void);
 
-#define IA64_FETCHADD(tmp,v,n,sz)						\
+#define IA64_FETCHADD(tmp,v,n,sz,sem)						\
 ({										\
 	switch (sz) {								\
 	      case 4:								\
-		__asm__ __volatile__ ("fetchadd4.rel %0=[%1],%2"		\
+		__asm__ __volatile__ ("fetchadd4."sem" %0=[%1],%2"		\
 				      : "=r"(tmp) : "r"(v), "i"(n) : "memory");	\
 		break;								\
 										\
 	      case 8:								\
-		__asm__ __volatile__ ("fetchadd8.rel %0=[%1],%2"		\
+		__asm__ __volatile__ ("fetchadd8."sem" %0=[%1],%2"		\
 				      : "=r"(tmp) : "r"(v), "i"(n) : "memory");	\
 		break;								\
 										\
@@ -35,32 +35,34 @@
 	}									\
 })
 
-#define ia64_fetch_and_add(i,v)								\
+#define ia64_fetchadd(i,v,sem)								\
 ({											\
 	__u64 _tmp;									\
 	volatile __typeof__(*(v)) *_v = (v);						\
 	/* Can't use a switch () here: gcc isn't always smart enough for that... */	\
 	if ((i) == -16)									\
-		IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v)));				\
+		IA64_FETCHADD(_tmp, _v, -16, sizeof(*(v)), sem);			\
 	else if ((i) == -8)								\
-		IA64_FETCHADD(_tmp, _v, -8, sizeof(*(v)));				\
+		IA64_FETCHADD(_tmp, _v, -8, sizeof(*(v)), sem);				\
 	else if ((i) == -4)								\
-		IA64_FETCHADD(_tmp, _v, -4, sizeof(*(v)));				\
+		IA64_FETCHADD(_tmp, _v, -4, sizeof(*(v)), sem);				\
 	else if ((i) == -1)								\
-		IA64_FETCHADD(_tmp, _v, -1, sizeof(*(v)));				\
+		IA64_FETCHADD(_tmp, _v, -1, sizeof(*(v)), sem);				\
 	else if ((i) == 1)								\
-		IA64_FETCHADD(_tmp, _v, 1, sizeof(*(v)));				\
+		IA64_FETCHADD(_tmp, _v, 1, sizeof(*(v)), sem);				\
 	else if ((i) == 4)								\
-		IA64_FETCHADD(_tmp, _v, 4, sizeof(*(v)));				\
+		IA64_FETCHADD(_tmp, _v, 4, sizeof(*(v)), sem);				\
 	else if ((i) == 8)								\
-		IA64_FETCHADD(_tmp, _v, 8, sizeof(*(v)));				\
+		IA64_FETCHADD(_tmp, _v, 8, sizeof(*(v)), sem);				\
 	else if ((i) == 16)								\
-		IA64_FETCHADD(_tmp, _v, 16, sizeof(*(v)));				\
+		IA64_FETCHADD(_tmp, _v, 16, sizeof(*(v)), sem);				\
 	else										\
 		_tmp = __bad_increment_for_ia64_fetch_and_add();			\
-	(__typeof__(*(v))) (_tmp + (i));	/* return new value */			\
+	(__typeof__(*(v))) (_tmp);	/* return old value */				\
 })
 
+#define ia64_fetch_and_add(i,v)	(ia64_fetchadd(i, v, "rel") + (i)) /* return new value */
+
 /*
  * This function doesn't exist, so you'll get a linker error if
  * something tries to do an invalid xchg().
@@ -127,7 +129,7 @@
 	      case 8: _o_ = (__u64) (long) (old); break;				\
 	      default: break;								\
 	}										\
-	 __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_));				\
+	__asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO"(_o_));				\
 	switch (size) {									\
 	      case 1:									\
 		__asm__ __volatile__ ("cmpxchg1."sem" %0=[%1],%2,ar.ccv"		\
diff -Nru a/include/asm-ia64/io.h b/include/asm-ia64/io.h
--- a/include/asm-ia64/io.h	Thu Mar 27 08:56:31 2003
+++ b/include/asm-ia64/io.h	Sat May 10 02:28:47 2003
@@ -13,7 +13,7 @@
  * over and over again with slight variations and possibly making a
  * mistake somewhere.
  *
- * Copyright (C) 1998-2002 Hewlett-Packard Co
+ * Copyright (C) 1998-2003 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  * Copyright (C) 1999 Asit Mallick <asit.k.mallick@intel.com>
  * Copyright (C) 1999 Don Dugger <don.dugger@intel.com>
@@ -32,6 +32,24 @@
  */
 #define IO_SPACE_LIMIT		0xffffffffffffffffUL
 
+#define MAX_IO_SPACES			16
+#define IO_SPACE_BITS			24
+#define IO_SPACE_SIZE			(1UL << IO_SPACE_BITS)
+
+#define IO_SPACE_NR(port)		((port) >> IO_SPACE_BITS)
+#define IO_SPACE_BASE(space)		((space) << IO_SPACE_BITS)
+#define IO_SPACE_PORT(port)		((port) & (IO_SPACE_SIZE - 1))
+
+#define IO_SPACE_SPARSE_ENCODING(p)	((((p) >> 2) << 12) | (p & 0xfff))
+
+struct io_space {
+	unsigned long mmio_base;	/* base in MMIO space */
+	int sparse;
+};
+
+extern struct io_space io_space[];
+extern unsigned int num_io_spaces;
+
 # ifdef __KERNEL__
 
 #include <asm/machvec.h>
@@ -80,12 +98,33 @@
 static inline void*
 __ia64_mk_io_addr (unsigned long port)
 {
-	const unsigned long io_base = __ia64_get_io_port_base();
-	unsigned long addr;
+	struct io_space *space;
+	unsigned long offset;
 
-	addr = io_base | ((port >> 2) << 12) | (port & 0xfff);
-	return (void *) addr;
-}
+	space = &io_space[IO_SPACE_NR(port)];
+	port = IO_SPACE_PORT(port);
+	if (space->sparse)
+		offset = IO_SPACE_SPARSE_ENCODING(port);
+	else
+		offset = port;
+
+	return (void *) (space->mmio_base | offset);
+}
+
+#define __ia64_inb	___ia64_inb
+#define __ia64_inw	___ia64_inw
+#define __ia64_inl	___ia64_inl
+#define __ia64_outb	___ia64_outb
+#define __ia64_outw	___ia64_outw
+#define __ia64_outl	___ia64_outl
+#define __ia64_readb	___ia64_readb
+#define __ia64_readw	___ia64_readw
+#define __ia64_readl	___ia64_readl
+#define __ia64_readq	___ia64_readq
+#define __ia64_writeb	___ia64_writeb
+#define __ia64_writew	___ia64_writew
+#define __ia64_writel	___ia64_writel
+#define __ia64_writeq	___ia64_writeq
 
 /*
  * For the in/out routines, we need to do "mf.a" _after_ doing the I/O access to ensure
@@ -96,7 +135,7 @@
  */
 
 static inline unsigned int
-__ia64_inb (unsigned long port)
+___ia64_inb (unsigned long port)
 {
 	volatile unsigned char *addr = __ia64_mk_io_addr(port);
 	unsigned char ret;
@@ -107,7 +146,7 @@
 }
 
 static inline unsigned int
-__ia64_inw (unsigned long port)
+___ia64_inw (unsigned long port)
 {
 	volatile unsigned short *addr = __ia64_mk_io_addr(port);
 	unsigned short ret;
@@ -118,7 +157,7 @@
 }
 
 static inline unsigned int
-__ia64_inl (unsigned long port)
+___ia64_inl (unsigned long port)
 {
 	volatile unsigned int *addr = __ia64_mk_io_addr(port);
 	unsigned int ret;
@@ -129,7 +168,7 @@
 }
 
 static inline void
-__ia64_outb (unsigned char val, unsigned long port)
+___ia64_outb (unsigned char val, unsigned long port)
 {
 	volatile unsigned char *addr = __ia64_mk_io_addr(port);
 
@@ -138,7 +177,7 @@
 }
 
 static inline void
-__ia64_outw (unsigned short val, unsigned long port)
+___ia64_outw (unsigned short val, unsigned long port)
 {
 	volatile unsigned short *addr = __ia64_mk_io_addr(port);
 
@@ -147,7 +186,7 @@
 }
 
 static inline void
-__ia64_outl (unsigned int val, unsigned long port)
+___ia64_outl (unsigned int val, unsigned long port)
 {
 	volatile unsigned int *addr = __ia64_mk_io_addr(port);
 
@@ -160,17 +199,8 @@
 {
 	unsigned char *dp = dst;
 
-	if (platform_inb == __ia64_inb) {
-		volatile unsigned char *addr = __ia64_mk_io_addr(port);
-
-		__ia64_mf_a();
-		while (count--)
-			*dp++ = *addr;
-		__ia64_mf_a();
-	} else
-		while (count--)
-			*dp++ = platform_inb(port);
-	return;
+	while (count--)
+		*dp++ = platform_inb(port);
 }
 
 static inline void
@@ -178,17 +208,8 @@
 {
 	unsigned short *dp = dst;
 
-	if (platform_inw == __ia64_inw) {
-		volatile unsigned short *addr = __ia64_mk_io_addr(port);
-
-		__ia64_mf_a();
-		while (count--)
-			*dp++ = *addr;
-		__ia64_mf_a();
-	} else
-		while (count--)
-			*dp++ = platform_inw(port);
-	return;
+	while (count--)
+		*dp++ = platform_inw(port);
 }
 
 static inline void
@@ -196,17 +217,8 @@
 {
 	unsigned int *dp = dst;
 
-	if (platform_inl == __ia64_inl) {
-		volatile unsigned int *addr = __ia64_mk_io_addr(port);
-
-		__ia64_mf_a();
-		while (count--)
-			*dp++ = *addr;
-		__ia64_mf_a();
-	} else
-		while (count--)
-			*dp++ = platform_inl(port);
-	return;
+	while (count--)
+		*dp++ = platform_inl(port);
 }
 
 static inline void
@@ -214,16 +226,8 @@
 {
 	const unsigned char *sp = src;
 
-	if (platform_outb == __ia64_outb) {
-		volatile unsigned char *addr = __ia64_mk_io_addr(port);
-
-		while (count--)
-			*addr = *sp++;
-		__ia64_mf_a();
-	} else
-		while (count--)
-			platform_outb(*sp++, port);
-	return;
+	while (count--)
+		platform_outb(*sp++, port);
 }
 
 static inline void
@@ -231,16 +235,8 @@
 {
 	const unsigned short *sp = src;
 
-	if (platform_outw == __ia64_outw) {
-		volatile unsigned short *addr = __ia64_mk_io_addr(port);
-
-		while (count--)
-			*addr = *sp++;
-		__ia64_mf_a();
-	} else
-		while (count--)
-			platform_outw(*sp++, port);
-	return;
+	while (count--)
+		platform_outw(*sp++, port);
 }
 
 static inline void
@@ -248,16 +244,8 @@
 {
 	const unsigned int *sp = src;
 
-	if (platform_outl == __ia64_outl) {
-		volatile unsigned int *addr = __ia64_mk_io_addr(port);
-
-		while (count--)
-			*addr = *sp++;
-		__ia64_mf_a();
-	} else
-		while (count--)
-			platform_outl(*sp++, port);
-	return;
+	while (count--)
+		platform_outl(*sp++, port);
 }
 
 /*
@@ -294,25 +282,25 @@
  * hopefully it'll stay that way).
  */
 static inline unsigned char
-__ia64_readb (void *addr)
+___ia64_readb (void *addr)
 {
 	return *(volatile unsigned char *)addr;
 }
 
 static inline unsigned short
-__ia64_readw (void *addr)
+___ia64_readw (void *addr)
 {
 	return *(volatile unsigned short *)addr;
 }
 
 static inline unsigned int
-__ia64_readl (void *addr)
+___ia64_readl (void *addr)
 {
 	return *(volatile unsigned int *) addr;
 }
 
 static inline unsigned long
-__ia64_readq (void *addr)
+___ia64_readq (void *addr)
 {
 	return *(volatile unsigned long *) addr;
 }
diff -Nru a/include/asm-ia64/iosapic.h b/include/asm-ia64/iosapic.h
--- a/include/asm-ia64/iosapic.h	Wed Feb 19 09:02:36 2003
+++ b/include/asm-ia64/iosapic.h	Tue Apr 22 12:17:15 2003
@@ -57,6 +57,7 @@
 extern int gsi_to_vector (unsigned int gsi);
 extern int gsi_to_irq (unsigned int gsi);
 extern void __init iosapic_parse_prt (void);
+extern void iosapic_enable_intr (unsigned int vector);
 extern int iosapic_register_intr (unsigned int gsi, unsigned long polarity,
 				  unsigned long trigger);
 extern void __init iosapic_override_isa_irq (unsigned int isa_irq, unsigned int gsi,
diff -Nru a/include/asm-ia64/kmap_types.h b/include/asm-ia64/kmap_types.h
--- a/include/asm-ia64/kmap_types.h	Sun Feb  2 23:34:59 2003
+++ b/include/asm-ia64/kmap_types.h	Mon May 12 18:59:24 2003
@@ -3,7 +3,7 @@
 
 #include <linux/config.h>
 
-#if CONFIG_DEBUG_HIGHMEM
+#ifdef CONFIG_DEBUG_HIGHMEM
 # define D(n) __KM_FENCE_##n ,
 #else
 # define D(n)
diff -Nru a/include/asm-ia64/machvec.h b/include/asm-ia64/machvec.h
--- a/include/asm-ia64/machvec.h	Tue Apr  1 01:19:53 2003
+++ b/include/asm-ia64/machvec.h	Sat May 10 02:28:47 2003
@@ -4,7 +4,7 @@
  * Copyright (C) 1999 Silicon Graphics, Inc.
  * Copyright (C) Srinivasa Thirumalachar <sprasad@engr.sgi.com>
  * Copyright (C) Vijay Chander <vijay@engr.sgi.com>
- * Copyright (C) 1999-2001 Hewlett-Packard Co.
+ * Copyright (C) 1999-2001, 2003 Hewlett-Packard Co.
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 #ifndef _ASM_IA64_MACHVEC_H
@@ -14,7 +14,7 @@
 #include <linux/types.h>
 
 /* forward declarations: */
-struct pci_dev;
+struct device;
 struct pt_regs;
 struct scatterlist;
 struct irq_desc;
@@ -33,17 +33,17 @@
 typedef u8 ia64_mv_irq_to_vector (u8);
 typedef unsigned int ia64_mv_local_vector_to_irq (u8 vector);
 
-/* PCI-DMA interface: */
-typedef void ia64_mv_pci_dma_init (void);
-typedef void *ia64_mv_pci_alloc_consistent (struct pci_dev *, size_t, dma_addr_t *);
-typedef void ia64_mv_pci_free_consistent (struct pci_dev *, size_t, void *, dma_addr_t);
-typedef dma_addr_t ia64_mv_pci_map_single (struct pci_dev *, void *, size_t, int);
-typedef void ia64_mv_pci_unmap_single (struct pci_dev *, dma_addr_t, size_t, int);
-typedef int ia64_mv_pci_map_sg (struct pci_dev *, struct scatterlist *, int, int);
-typedef void ia64_mv_pci_unmap_sg (struct pci_dev *, struct scatterlist *, int, int);
-typedef void ia64_mv_pci_dma_sync_single (struct pci_dev *, dma_addr_t, size_t, int);
-typedef void ia64_mv_pci_dma_sync_sg (struct pci_dev *, struct scatterlist *, int, int);
-typedef int ia64_mv_pci_dma_supported (struct pci_dev *, u64);
+/* DMA-mapping interface: */
+typedef void ia64_mv_dma_init (void);
+typedef void *ia64_mv_dma_alloc_coherent (struct device *, size_t, dma_addr_t *, int);
+typedef void ia64_mv_dma_free_coherent (struct device *, size_t, void *, dma_addr_t);
+typedef dma_addr_t ia64_mv_dma_map_single (struct device *, void *, size_t, int);
+typedef void ia64_mv_dma_unmap_single (struct device *, dma_addr_t, size_t, int);
+typedef int ia64_mv_dma_map_sg (struct device *, struct scatterlist *, int, int);
+typedef void ia64_mv_dma_unmap_sg (struct device *, struct scatterlist *, int, int);
+typedef void ia64_mv_dma_sync_single (struct device *, dma_addr_t, size_t, int);
+typedef void ia64_mv_dma_sync_sg (struct device *, struct scatterlist *, int, int);
+typedef int ia64_mv_dma_supported (struct device *, u64);
 
 /*
  * WARNING: The legacy I/O space is _architected_.  Platforms are
@@ -66,6 +66,7 @@
 typedef unsigned long ia64_mv_readq_t (void *);
 
 extern void machvec_noop (void);
+extern void machvec_memory_fence (void);
 
 # if defined (CONFIG_IA64_HP_SIM)
 #  include <asm/machvec_hpsim.h>
@@ -92,16 +93,16 @@
 #  define platform_log_print	ia64_mv.log_print
 #  define platform_send_ipi	ia64_mv.send_ipi
 #  define platform_global_tlb_purge	ia64_mv.global_tlb_purge
-#  define platform_pci_dma_init		ia64_mv.dma_init
-#  define platform_pci_alloc_consistent	ia64_mv.alloc_consistent
-#  define platform_pci_free_consistent	ia64_mv.free_consistent
-#  define platform_pci_map_single	ia64_mv.map_single
-#  define platform_pci_unmap_single	ia64_mv.unmap_single
-#  define platform_pci_map_sg		ia64_mv.map_sg
-#  define platform_pci_unmap_sg		ia64_mv.unmap_sg
-#  define platform_pci_dma_sync_single	ia64_mv.sync_single
-#  define platform_pci_dma_sync_sg	ia64_mv.sync_sg
-#  define platform_pci_dma_supported	ia64_mv.dma_supported
+#  define platform_dma_init		ia64_mv.dma_init
+#  define platform_dma_alloc_coherent	ia64_mv.dma_alloc_coherent
+#  define platform_dma_free_coherent	ia64_mv.dma_free_coherent
+#  define platform_dma_map_single	ia64_mv.dma_map_single
+#  define platform_dma_unmap_single	ia64_mv.dma_unmap_single
+#  define platform_dma_map_sg		ia64_mv.dma_map_sg
+#  define platform_dma_unmap_sg		ia64_mv.dma_unmap_sg
+#  define platform_dma_sync_single	ia64_mv.dma_sync_single
+#  define platform_dma_sync_sg		ia64_mv.dma_sync_sg
+#  define platform_dma_supported	ia64_mv.dma_supported
 #  define platform_irq_desc		ia64_mv.irq_desc
 #  define platform_irq_to_vector	ia64_mv.irq_to_vector
 #  define platform_local_vector_to_irq	ia64_mv.local_vector_to_irq
@@ -119,7 +120,7 @@
 
 /* __attribute__((__aligned__(16))) is required to make size of the
  * structure multiple of 16 bytes.
- * This will fillup the holes created because of section 3.3.1 in 
+ * This will fillup the holes created because of section 3.3.1 in
  * Software Conventions guide.
  */
 struct ia64_machine_vector {
@@ -133,16 +134,16 @@
 	ia64_mv_log_print_t *log_print;
 	ia64_mv_send_ipi_t *send_ipi;
 	ia64_mv_global_tlb_purge_t *global_tlb_purge;
-	ia64_mv_pci_dma_init *dma_init;
-	ia64_mv_pci_alloc_consistent *alloc_consistent;
-	ia64_mv_pci_free_consistent *free_consistent;
-	ia64_mv_pci_map_single *map_single;
-	ia64_mv_pci_unmap_single *unmap_single;
-	ia64_mv_pci_map_sg *map_sg;
-	ia64_mv_pci_unmap_sg *unmap_sg;
-	ia64_mv_pci_dma_sync_single *sync_single;
-	ia64_mv_pci_dma_sync_sg *sync_sg;
-	ia64_mv_pci_dma_supported *dma_supported;
+	ia64_mv_dma_init *dma_init;
+	ia64_mv_dma_alloc_coherent *dma_alloc_coherent;
+	ia64_mv_dma_free_coherent *dma_free_coherent;
+	ia64_mv_dma_map_single *dma_map_single;
+	ia64_mv_dma_unmap_single *dma_unmap_single;
+	ia64_mv_dma_map_sg *dma_map_sg;
+	ia64_mv_dma_unmap_sg *dma_unmap_sg;
+	ia64_mv_dma_sync_single *dma_sync_single;
+	ia64_mv_dma_sync_sg *dma_sync_sg;
+	ia64_mv_dma_supported *dma_supported;
 	ia64_mv_irq_desc *irq_desc;
 	ia64_mv_irq_to_vector *irq_to_vector;
 	ia64_mv_local_vector_to_irq *local_vector_to_irq;
@@ -170,16 +171,16 @@
 	platform_log_print,			\
 	platform_send_ipi,			\
 	platform_global_tlb_purge,		\
-	platform_pci_dma_init,			\
-	platform_pci_alloc_consistent,		\
-	platform_pci_free_consistent,		\
-	platform_pci_map_single,		\
-	platform_pci_unmap_single,		\
-	platform_pci_map_sg,			\
-	platform_pci_unmap_sg,			\
-	platform_pci_dma_sync_single,		\
-	platform_pci_dma_sync_sg,		\
-	platform_pci_dma_supported,		\
+	platform_dma_init,			\
+	platform_dma_alloc_coherent,		\
+	platform_dma_free_coherent,		\
+	platform_dma_map_single,		\
+	platform_dma_unmap_single,		\
+	platform_dma_map_sg,			\
+	platform_dma_unmap_sg,			\
+	platform_dma_sync_single,		\
+	platform_dma_sync_sg,			\
+	platform_dma_supported,			\
 	platform_irq_desc,			\
 	platform_irq_to_vector,			\
 	platform_local_vector_to_irq,		\
@@ -205,16 +206,16 @@
 /*
  * Declare default routines which aren't declared anywhere else:
  */
-extern ia64_mv_pci_dma_init swiotlb_init;
-extern ia64_mv_pci_alloc_consistent swiotlb_alloc_consistent;
-extern ia64_mv_pci_free_consistent swiotlb_free_consistent;
-extern ia64_mv_pci_map_single swiotlb_map_single;
-extern ia64_mv_pci_unmap_single swiotlb_unmap_single;
-extern ia64_mv_pci_map_sg swiotlb_map_sg;
-extern ia64_mv_pci_unmap_sg swiotlb_unmap_sg;
-extern ia64_mv_pci_dma_sync_single swiotlb_sync_single;
-extern ia64_mv_pci_dma_sync_sg swiotlb_sync_sg;
-extern ia64_mv_pci_dma_supported swiotlb_pci_dma_supported;
+extern ia64_mv_dma_init			swiotlb_init;
+extern ia64_mv_dma_alloc_coherent	swiotlb_alloc_coherent;
+extern ia64_mv_dma_free_coherent	swiotlb_free_coherent;
+extern ia64_mv_dma_map_single		swiotlb_map_single;
+extern ia64_mv_dma_unmap_single		swiotlb_unmap_single;
+extern ia64_mv_dma_map_sg		swiotlb_map_sg;
+extern ia64_mv_dma_unmap_sg		swiotlb_unmap_sg;
+extern ia64_mv_dma_sync_single		swiotlb_sync_single;
+extern ia64_mv_dma_sync_sg		swiotlb_sync_sg;
+extern ia64_mv_dma_supported		swiotlb_dma_supported;
 
 /*
  * Define default versions so we can extend machvec for new platforms without having
@@ -247,35 +248,35 @@
 #ifndef platform_global_tlb_purge
 # define platform_global_tlb_purge	ia64_global_tlb_purge /* default to architected version */
 #endif
-#ifndef platform_pci_dma_init
-# define platform_pci_dma_init		swiotlb_init
+#ifndef platform_dma_init
+# define platform_dma_init		swiotlb_init
 #endif
-#ifndef platform_pci_alloc_consistent
-# define platform_pci_alloc_consistent	swiotlb_alloc_consistent
+#ifndef platform_dma_alloc_coherent
+# define platform_dma_alloc_coherent	swiotlb_alloc_coherent
 #endif
-#ifndef platform_pci_free_consistent
-# define platform_pci_free_consistent	swiotlb_free_consistent
+#ifndef platform_dma_free_coherent
+# define platform_dma_free_coherent	swiotlb_free_coherent
 #endif
-#ifndef platform_pci_map_single
-# define platform_pci_map_single	swiotlb_map_single
+#ifndef platform_dma_map_single
+# define platform_dma_map_single	swiotlb_map_single
 #endif
-#ifndef platform_pci_unmap_single
-# define platform_pci_unmap_single	swiotlb_unmap_single
+#ifndef platform_dma_unmap_single
+# define platform_dma_unmap_single	swiotlb_unmap_single
 #endif
-#ifndef platform_pci_map_sg
-# define platform_pci_map_sg		swiotlb_map_sg
+#ifndef platform_dma_map_sg
+# define platform_dma_map_sg		swiotlb_map_sg
 #endif
-#ifndef platform_pci_unmap_sg
-# define platform_pci_unmap_sg		swiotlb_unmap_sg
+#ifndef platform_dma_unmap_sg
+# define platform_dma_unmap_sg		swiotlb_unmap_sg
 #endif
-#ifndef platform_pci_dma_sync_single
-# define platform_pci_dma_sync_single	swiotlb_sync_single
+#ifndef platform_dma_sync_single
+# define platform_dma_sync_single	swiotlb_sync_single
 #endif
-#ifndef platform_pci_dma_sync_sg
-# define platform_pci_dma_sync_sg	swiotlb_sync_sg
+#ifndef platform_dma_sync_sg
+# define platform_dma_sync_sg		swiotlb_sync_sg
 #endif
-#ifndef platform_pci_dma_supported
-# define  platform_pci_dma_supported	swiotlb_pci_dma_supported
+#ifndef platform_dma_supported
+# define  platform_dma_supported	swiotlb_dma_supported
 #endif
 #ifndef platform_irq_desc
 # define platform_irq_desc		__ia64_irq_desc
diff -Nru a/include/asm-ia64/machvec_hpzx1.h b/include/asm-ia64/machvec_hpzx1.h
--- a/include/asm-ia64/machvec_hpzx1.h	Tue Apr  1 01:19:53 2003
+++ b/include/asm-ia64/machvec_hpzx1.h	Sat May 10 02:28:47 2003
@@ -2,13 +2,13 @@
 #define _ASM_IA64_MACHVEC_HPZX1_h
 
 extern ia64_mv_setup_t dig_setup;
-extern ia64_mv_pci_alloc_consistent sba_alloc_consistent;
-extern ia64_mv_pci_free_consistent sba_free_consistent;
-extern ia64_mv_pci_map_single sba_map_single;
-extern ia64_mv_pci_unmap_single sba_unmap_single;
-extern ia64_mv_pci_map_sg sba_map_sg;
-extern ia64_mv_pci_unmap_sg sba_unmap_sg;
-extern ia64_mv_pci_dma_supported sba_dma_supported;
+extern ia64_mv_dma_alloc_coherent	sba_alloc_coherent;
+extern ia64_mv_dma_free_coherent	sba_free_coherent;
+extern ia64_mv_dma_map_single		sba_map_single;
+extern ia64_mv_dma_unmap_single		sba_unmap_single;
+extern ia64_mv_dma_map_sg		sba_map_sg;
+extern ia64_mv_dma_unmap_sg		sba_unmap_sg;
+extern ia64_mv_dma_supported		sba_dma_supported;
 
 /*
  * This stuff has dual use!
@@ -19,15 +19,15 @@
  */
 #define platform_name			"hpzx1"
 #define platform_setup			dig_setup
-#define platform_pci_dma_init		((ia64_mv_pci_dma_init *) machvec_noop)
-#define platform_pci_alloc_consistent	sba_alloc_consistent
-#define platform_pci_free_consistent	sba_free_consistent
-#define platform_pci_map_single		sba_map_single
-#define platform_pci_unmap_single	sba_unmap_single
-#define platform_pci_map_sg		sba_map_sg
-#define platform_pci_unmap_sg		sba_unmap_sg
-#define platform_pci_dma_sync_single	((ia64_mv_pci_dma_sync_single *) machvec_noop)
-#define platform_pci_dma_sync_sg	((ia64_mv_pci_dma_sync_sg *) machvec_noop)
-#define platform_pci_dma_supported	sba_dma_supported
+#define platform_dma_init		((ia64_mv_dma_init *) machvec_noop)
+#define platform_dma_alloc_coherent	sba_alloc_coherent
+#define platform_dma_free_coherent	sba_free_coherent
+#define platform_dma_map_single		sba_map_single
+#define platform_dma_unmap_single	sba_unmap_single
+#define platform_dma_map_sg		sba_map_sg
+#define platform_dma_unmap_sg		sba_unmap_sg
+#define platform_dma_sync_single	((ia64_mv_dma_sync_single *) machvec_memory_fence)
+#define platform_dma_sync_sg		((ia64_mv_dma_sync_sg *) machvec_memory_fence)
+#define platform_dma_supported		sba_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_HPZX1_h */
diff -Nru a/include/asm-ia64/machvec_init.h b/include/asm-ia64/machvec_init.h
--- a/include/asm-ia64/machvec_init.h	Tue Mar 18 01:37:11 2003
+++ b/include/asm-ia64/machvec_init.h	Sat May 10 02:28:47 2003
@@ -1,7 +1,3 @@
-#define __MACHVEC_HDR(n)		<asm/machvec_##n##.h>
-#define __MACHVEC_EXPAND(n)		__MACHVEC_HDR(n)
-#define MACHVEC_PLATFORM_HEADER		__MACHVEC_EXPAND(MACHVEC_PLATFORM_NAME)
-
 #include <asm/machvec.h>
 
 extern ia64_mv_send_ipi_t ia64_send_ipi;
@@ -16,6 +12,10 @@
 extern ia64_mv_outb_t __ia64_outb;
 extern ia64_mv_outw_t __ia64_outw;
 extern ia64_mv_outl_t __ia64_outl;
+extern ia64_mv_readb_t __ia64_readb;
+extern ia64_mv_readw_t __ia64_readw;
+extern ia64_mv_readl_t __ia64_readl;
+extern ia64_mv_readq_t __ia64_readq;
 
 #define MACHVEC_HELPER(name)									\
  struct ia64_machine_vector machvec_##name __attribute__ ((unused, __section__ (".machvec")))	\
diff -Nru a/include/asm-ia64/machvec_sn1.h b/include/asm-ia64/machvec_sn1.h
--- a/include/asm-ia64/machvec_sn1.h	Tue Apr  1 01:19:53 2003
+++ b/include/asm-ia64/machvec_sn1.h	Sat May 10 02:28:47 2003
@@ -44,14 +44,14 @@
 extern ia64_mv_outb_t sn1_outb;
 extern ia64_mv_outw_t sn1_outw;
 extern ia64_mv_outl_t sn1_outl;
-extern ia64_mv_pci_alloc_consistent	sn1_pci_alloc_consistent;
-extern ia64_mv_pci_free_consistent	sn1_pci_free_consistent;
-extern ia64_mv_pci_map_single		sn1_pci_map_single;
-extern ia64_mv_pci_unmap_single		sn1_pci_unmap_single;
-extern ia64_mv_pci_map_sg		sn1_pci_map_sg;
-extern ia64_mv_pci_unmap_sg		sn1_pci_unmap_sg;
-extern ia64_mv_pci_dma_sync_single	sn1_pci_dma_sync_single;
-extern ia64_mv_pci_dma_sync_sg		sn1_pci_dma_sync_sg;
+extern ia64_mv_dma_alloc_coherent	sn1_dma_alloc_coherent;
+extern ia64_mv_dma_free_coherent	sn1_dma_free_coherent;
+extern ia64_mv_dma_map_single		sn1_dma_map_single;
+extern ia64_mv_dma_unmap_single		sn1_dma_unmap_single;
+extern ia64_mv_dma_map_sg		sn1_dma_map_sg;
+extern ia64_mv_dma_unmap_sg		sn1_dma_unmap_sg;
+extern ia64_mv_dma_sync_single		sn1_dma_sync_single;
+extern ia64_mv_dma_sync_sg		sn1_dma_sync_sg;
 
 /*
  * This stuff has dual use!
@@ -72,14 +72,14 @@
 #define platform_outb		sn1_outb
 #define platform_outw		sn1_outw
 #define platform_outl		sn1_outl
-#define platform_pci_dma_init	machvec_noop
-#define platform_pci_alloc_consistent	sn1_pci_alloc_consistent
-#define platform_pci_free_consistent	sn1_pci_free_consistent
-#define platform_pci_map_single		sn1_pci_map_single
-#define platform_pci_unmap_single	sn1_pci_unmap_single
-#define platform_pci_map_sg		sn1_pci_map_sg
-#define platform_pci_unmap_sg		sn1_pci_unmap_sg
-#define platform_pci_dma_sync_single	sn1_pci_dma_sync_single
-#define platform_pci_dma_sync_sg	sn1_pci_dma_sync_sg
+#define platform_dma_init	machvec_noop
+#define platform_dma_alloc_coherent	sn1_dma_alloc_coherent
+#define platform_dma_free_coherent	sn1_dma_free_coherent
+#define platform_dma_map_single		sn1_dma_map_single
+#define platform_dma_unmap_single	sn1_dma_unmap_single
+#define platform_dma_map_sg		sn1_dma_map_sg
+#define platform_dma_unmap_sg		sn1_dma_unmap_sg
+#define platform_dma_sync_single	sn1_dma_sync_single
+#define platform_dma_sync_sg		sn1_dma_sync_sg
 
 #endif /* _ASM_IA64_MACHVEC_SN1_h */
diff -Nru a/include/asm-ia64/machvec_sn2.h b/include/asm-ia64/machvec_sn2.h
--- a/include/asm-ia64/machvec_sn2.h	Tue Apr  1 01:19:53 2003
+++ b/include/asm-ia64/machvec_sn2.h	Sat May 10 02:28:47 2003
@@ -51,15 +51,15 @@
 extern ia64_mv_readw_t __sn_readw;
 extern ia64_mv_readl_t __sn_readl;
 extern ia64_mv_readq_t __sn_readq;
-extern ia64_mv_pci_alloc_consistent	sn_pci_alloc_consistent;
-extern ia64_mv_pci_free_consistent	sn_pci_free_consistent;
-extern ia64_mv_pci_map_single		sn_pci_map_single;
-extern ia64_mv_pci_unmap_single		sn_pci_unmap_single;
-extern ia64_mv_pci_map_sg		sn_pci_map_sg;
-extern ia64_mv_pci_unmap_sg		sn_pci_unmap_sg;
-extern ia64_mv_pci_dma_sync_single	sn_pci_dma_sync_single;
-extern ia64_mv_pci_dma_sync_sg		sn_pci_dma_sync_sg;
-extern ia64_mv_pci_dma_supported	sn_pci_dma_supported;
+extern ia64_mv_dma_alloc_coherent	sn_dma_alloc_coherent;
+extern ia64_mv_dma_free_coherent	sn_dma_free_coherent;
+extern ia64_mv_dma_map_single		sn_dma_map_single;
+extern ia64_mv_dma_unmap_single		sn_dma_unmap_single;
+extern ia64_mv_dma_map_sg		sn_dma_map_sg;
+extern ia64_mv_dma_unmap_sg		sn_dma_unmap_sg;
+extern ia64_mv_dma_sync_single		sn_dma_sync_single;
+extern ia64_mv_dma_sync_sg		sn_dma_sync_sg;
+extern ia64_mv_dma_supported		sn_dma_supported;
 
 /*
  * This stuff has dual use!
@@ -88,15 +88,15 @@
 #define platform_irq_desc		sn_irq_desc
 #define platform_irq_to_vector		sn_irq_to_vector
 #define platform_local_vector_to_irq	sn_local_vector_to_irq
-#define platform_pci_dma_init		machvec_noop
-#define platform_pci_alloc_consistent	sn_pci_alloc_consistent
-#define platform_pci_free_consistent	sn_pci_free_consistent
-#define platform_pci_map_single		sn_pci_map_single
-#define platform_pci_unmap_single	sn_pci_unmap_single
-#define platform_pci_map_sg		sn_pci_map_sg
-#define platform_pci_unmap_sg		sn_pci_unmap_sg
-#define platform_pci_dma_sync_single	sn_pci_dma_sync_single
-#define platform_pci_dma_sync_sg	sn_pci_dma_sync_sg
-#define platform_pci_dma_supported	sn_pci_dma_supported
+#define platform_dma_init		machvec_noop
+#define platform_dma_alloc_coherent	sn_dma_alloc_coherent
+#define platform_dma_free_coherent	sn_dma_free_coherent
+#define platform_dma_map_single		sn_dma_map_single
+#define platform_dma_unmap_single	sn_dma_unmap_single
+#define platform_dma_map_sg		sn_dma_map_sg
+#define platform_dma_unmap_sg		sn_dma_unmap_sg
+#define platform_dma_sync_single	sn_dma_sync_single
+#define platform_dma_sync_sg		sn_dma_sync_sg
+#define platform_dma_supported		sn_dma_supported
 
 #endif /* _ASM_IA64_MACHVEC_SN2_H */
diff -Nru a/include/asm-ia64/mca.h b/include/asm-ia64/mca.h
--- a/include/asm-ia64/mca.h	Fri Mar 21 19:51:16 2003
+++ b/include/asm-ia64/mca.h	Sat May 10 02:28:47 2003
@@ -11,7 +11,10 @@
 #define _ASM_IA64_MCA_H
 
 #if !defined(__ASSEMBLY__)
+
+#include <linux/interrupt.h>
 #include <linux/types.h>
+
 #include <asm/param.h>
 #include <asm/sal.h>
 #include <asm/processor.h>
@@ -129,10 +132,10 @@
 extern void ia64_mca_ucmc_handler(void);
 extern void ia64_monarch_init_handler(void);
 extern void ia64_slave_init_handler(void);
-extern void ia64_mca_rendez_int_handler(int,void *,struct pt_regs *);
-extern void ia64_mca_wakeup_int_handler(int,void *,struct pt_regs *);
-extern void ia64_mca_cmc_int_handler(int,void *,struct pt_regs *);
-extern void ia64_mca_cpe_int_handler(int,void *,struct pt_regs *);
+extern irqreturn_t ia64_mca_rendez_int_handler(int,void *,struct pt_regs *);
+extern irqreturn_t ia64_mca_wakeup_int_handler(int,void *,struct pt_regs *);
+extern irqreturn_t ia64_mca_cmc_int_handler(int,void *,struct pt_regs *);
+extern irqreturn_t ia64_mca_cpe_int_handler(int,void *,struct pt_regs *);
 extern int  ia64_log_print(int,prfunc_t);
 extern void ia64_mca_cmc_vector_setup(void);
 extern int  ia64_mca_check_errors(void);
diff -Nru a/include/asm-ia64/page.h b/include/asm-ia64/page.h
--- a/include/asm-ia64/page.h	Thu Mar  6 13:34:27 2003
+++ b/include/asm-ia64/page.h	Sat May 10 03:13:39 2003
@@ -37,6 +37,8 @@
 
 # if defined(CONFIG_HUGETLB_PAGE_SIZE_4GB)
 #  define HPAGE_SHIFT	32
+# elif defined(CONFIG_HUGETLB_PAGE_SIZE_1GB)
+#  define HPAGE_SHIFT	30
 # elif defined(CONFIG_HUGETLB_PAGE_SIZE_256MB)
 #  define HPAGE_SHIFT	28
 # elif defined(CONFIG_HUGETLB_PAGE_SIZE_64MB)
@@ -89,7 +91,12 @@
 #define virt_addr_valid(kaddr)	pfn_valid(__pa(kaddr) >> PAGE_SHIFT)
 
 #ifndef CONFIG_DISCONTIGMEM
-#define pfn_valid(pfn)		((pfn) < max_mapnr)
+# ifdef CONFIG_VIRTUAL_MEM_MAP
+   extern int ia64_pfn_valid (unsigned long pfn);
+#  define pfn_valid(pfn)	(((pfn) < max_mapnr) && ia64_pfn_valid(pfn))
+# else
+#  define pfn_valid(pfn)	((pfn) < max_mapnr)
+# endif
 #define virt_to_page(kaddr)	pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
 #define page_to_pfn(page)	((unsigned long) (page - mem_map))
 #define pfn_to_page(pfn)	(mem_map + (pfn))
diff -Nru a/include/asm-ia64/pal.h b/include/asm-ia64/pal.h
--- a/include/asm-ia64/pal.h	Thu Sep  5 10:36:12 2002
+++ b/include/asm-ia64/pal.h	Fri Apr 11 18:18:35 2003
@@ -622,7 +622,8 @@
 	u64	pmsa_xip;		/* previous iip		   */
 	u64	pmsa_xpsr;		/* previous psr		   */
 	u64	pmsa_xfs;		/* previous ifs		   */
-	u64	pmsa_reserved[71];	/* pal_min_state_area should total to 1KB */
+	u64	pmsa_br1;		/* branch register 1	   */
+	u64	pmsa_reserved[70];	/* pal_min_state_area should total to 1KB */
 } pal_min_state_area_t;
 
 
diff -Nru a/include/asm-ia64/pci.h b/include/asm-ia64/pci.h
--- a/include/asm-ia64/pci.h	Tue Apr  8 12:08:16 2003
+++ b/include/asm-ia64/pci.h	Sat May 10 02:28:47 2003
@@ -47,18 +47,7 @@
 #define HAVE_ARCH_PCI_MWI 1
 extern int pcibios_prep_mwi (struct pci_dev *);
 
-/*
- * Dynamic DMA mapping API.  See Documentation/DMA-mapping.txt for details.
- */
-#define pci_alloc_consistent		platform_pci_alloc_consistent
-#define pci_free_consistent		platform_pci_free_consistent
-#define pci_map_single			platform_pci_map_single
-#define pci_unmap_single		platform_pci_unmap_single
-#define pci_map_sg			platform_pci_map_sg
-#define pci_unmap_sg			platform_pci_unmap_sg
-#define pci_dma_sync_single		platform_pci_dma_sync_single
-#define pci_dma_sync_sg			platform_pci_dma_sync_sg
-#define pci_dma_supported		platform_pci_dma_supported
+#include <asm-generic/pci-dma-compat.h>
 
 /* pci_unmap_{single,page} is not a nop, thus... */
 #define DECLARE_PCI_UNMAP_ADDR(ADDR_NAME)	\
@@ -74,18 +63,12 @@
 #define pci_unmap_len_set(PTR, LEN_NAME, VAL)		\
 	(((PTR)->LEN_NAME) = (VAL))
 
-#define pci_map_page(dev,pg,off,size,dir)				\
-	pci_map_single((dev), page_address(pg) + (off), (size), (dir))
-#define pci_unmap_page(dev,dma_addr,size,dir)				\
-	pci_unmap_single((dev), (dma_addr), (size), (dir))
-
 /* The ia64 platform always supports 64-bit addressing. */
-#define pci_dac_dma_supported(pci_dev, mask)	(1)
-
-#define pci_dac_page_to_dma(dev,pg,off,dir)	((dma_addr_t) page_to_bus(pg) + (off))
-#define pci_dac_dma_to_page(dev,dma_addr)	(virt_to_page(bus_to_virt(dma_addr)))
-#define pci_dac_dma_to_offset(dev,dma_addr)	((dma_addr) & ~PAGE_MASK)
-#define pci_dac_dma_sync_single(dev,dma_addr,len,dir)	do { /* nothing */ } while (0)
+#define pci_dac_dma_supported(pci_dev, mask)		(1)
+#define pci_dac_page_to_dma(dev,pg,off,dir)		((dma_addr_t) page_to_bus(pg) + (off))
+#define pci_dac_dma_to_page(dev,dma_addr)		(virt_to_page(bus_to_virt(dma_addr)))
+#define pci_dac_dma_to_offset(dev,dma_addr)		((dma_addr) & ~PAGE_MASK)
+#define pci_dac_dma_sync_single(dev,dma_addr,len,dir)	do { mb(); } while (0)
 
 /* Return the index of the PCI controller for device PDEV. */
 #define pci_controller_num(PDEV)	(0)
@@ -97,12 +80,18 @@
 extern int pci_mmap_page_range (struct pci_dev *dev, struct vm_area_struct *vma,
 				enum pci_mmap_state mmap_state, int write_combine);
 
+struct pci_window {
+	struct resource resource;
+	u64 offset;
+};
+
 struct pci_controller {
 	void *acpi_handle;
 	void *iommu;
 	int segment;
 
-	u64 mem_offset;
+	unsigned int windows;
+	struct pci_window *window;
 };
 
 #define PCI_CONTROLLER(busdev) ((struct pci_controller *) busdev->sysdata)
diff -Nru a/include/asm-ia64/percpu.h b/include/asm-ia64/percpu.h
--- a/include/asm-ia64/percpu.h	Mon Oct 21 13:41:47 2002
+++ b/include/asm-ia64/percpu.h	Sat May 10 02:28:47 2003
@@ -5,7 +5,7 @@
 #include <linux/compiler.h>
 
 /*
- * Copyright (C) 2002 Hewlett-Packard Co
+ * Copyright (C) 2002-2003 Hewlett-Packard Co
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  */
 
@@ -34,6 +34,8 @@
 
 #define EXPORT_PER_CPU_SYMBOL(var) EXPORT_SYMBOL(var##__per_cpu)
 #define EXPORT_PER_CPU_SYMBOL_GPL(var) EXPORT_SYMBOL_GPL(var##__per_cpu)
+
+extern void setup_per_cpu_areas (void);
 
 #endif /* !__ASSEMBLY__ */
 
diff -Nru a/include/asm-ia64/perfmon.h b/include/asm-ia64/perfmon.h
--- a/include/asm-ia64/perfmon.h	Thu Feb  6 08:45:24 2003
+++ b/include/asm-ia64/perfmon.h	Tue Apr 15 08:59:04 2003
@@ -41,6 +41,7 @@
 #define PFM_FL_NOTIFY_BLOCK    	 0x04	/* block task on user level notifications */
 #define PFM_FL_SYSTEM_WIDE	 0x08	/* create a system wide context */
 #define PFM_FL_EXCL_IDLE         0x20   /* exclude idle task from system wide session */
+#define PFM_FL_UNSECURE		 0x40   /* allow unsecure monitoring for non self-monitoring task */
 
 /*
  * PMC flags
@@ -125,7 +126,7 @@
  * Define the version numbers for both perfmon as a whole and the sampling buffer format.
  */
 #define PFM_VERSION_MAJ		1U
-#define PFM_VERSION_MIN		3U
+#define PFM_VERSION_MIN		4U
 #define PFM_VERSION		(((PFM_VERSION_MAJ&0xffff)<<16)|(PFM_VERSION_MIN & 0xffff))
 
 #define PFM_SMPL_VERSION_MAJ	1U
diff -Nru a/include/asm-ia64/processor.h b/include/asm-ia64/processor.h
--- a/include/asm-ia64/processor.h	Tue Apr  8 11:58:31 2003
+++ b/include/asm-ia64/processor.h	Sat May 10 02:28:47 2003
@@ -39,6 +39,14 @@
 #define TASK_SIZE		(current->thread.task_size)
 
 /*
+ * MM_VM_SIZE(mm) gives the maximum address (plus 1) which may contain a mapping for
+ * address-space MM.  Note that with 32-bit tasks, this is still DEFAULT_TASK_SIZE,
+ * because the kernel may have installed helper-mappings above TASK_SIZE.  For example,
+ * for x86 emulation, the LDT and GDT are mapped above TASK_SIZE.
+ */
+#define MM_VM_SIZE(mm)		DEFAULT_TASK_SIZE
+
+/*
  * This decides where the kernel will search for a free chunk of vm
  * space during mmap's.
  */
@@ -291,7 +299,7 @@
 
 #define start_thread(regs,new_ip,new_sp) do {							\
 	set_fs(USER_DS);									\
-	regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL | IA64_PSR_SP))	\
+	regs->cr_ipsr = ((regs->cr_ipsr | (IA64_PSR_BITS_TO_SET | IA64_PSR_CPL))		\
 			 & ~(IA64_PSR_BITS_TO_CLEAR | IA64_PSR_RI | IA64_PSR_IS));		\
 	regs->cr_iip = new_ip;									\
 	regs->ar_rsc = 0xf;		/* eager mode, privilege level 3 */			\
diff -Nru a/include/asm-ia64/ptrace.h b/include/asm-ia64/ptrace.h
--- a/include/asm-ia64/ptrace.h	Wed Feb 12 00:11:33 2003
+++ b/include/asm-ia64/ptrace.h	Wed Apr 16 13:01:07 2003
@@ -227,8 +227,10 @@
   })
 
   struct task_struct;			/* forward decl */
+  struct unw_frame_info;		/* forward decl */
 
   extern void show_regs (struct pt_regs *);
+  extern void ia64_do_show_stack (struct unw_frame_info *, void *);
   extern unsigned long ia64_get_user_rbs_end (struct task_struct *, struct pt_regs *,
 					      unsigned long *);
   extern long ia64_peek (struct task_struct *, struct switch_stack *, unsigned long,
diff -Nru a/include/asm-ia64/sal.h b/include/asm-ia64/sal.h
--- a/include/asm-ia64/sal.h	Mon Mar 24 13:43:39 2003
+++ b/include/asm-ia64/sal.h	Tue Apr 22 19:47:07 2003
@@ -226,7 +226,7 @@
 
 /* Encodings for machine check parameter types */
 enum {
-	SAL_MC_PARAM_RENDEZ_INT    = 1,	/* Rendezevous interrupt */
+	SAL_MC_PARAM_RENDEZ_INT    = 1,	/* Rendezvous interrupt */
 	SAL_MC_PARAM_RENDEZ_WAKEUP = 2,	/* Wakeup */
 	SAL_MC_PARAM_CPE_INT	   = 3	/* Corrected Platform Error Int */
 };
diff -Nru a/include/asm-ia64/serial.h b/include/asm-ia64/serial.h
--- a/include/asm-ia64/serial.h	Fri Aug  9 17:16:44 2002
+++ b/include/asm-ia64/serial.h	Wed Apr  9 15:35:27 2003
@@ -59,7 +59,6 @@
 	{ 0, BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS },	/* ttyS2 */	\
 	{ 0, BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS },	/* ttyS3 */
 
-
 #ifdef CONFIG_SERIAL_MANY_PORTS
 #define EXTRA_SERIAL_PORT_DEFNS			\
 	{ 0, BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, 	/* ttyS4 */	\
diff -Nru a/include/asm-ia64/sn/addrs.h b/include/asm-ia64/sn/addrs.h
--- a/include/asm-ia64/sn/addrs.h	Tue Dec  3 10:07:32 2002
+++ b/include/asm-ia64/sn/addrs.h	Mon May 12 18:59:24 2003
@@ -215,7 +215,7 @@
 #define REMOTE_HUB_ADDR(_n, _x)	(HUBREG_CAST (NODE_SWIN_BASE(_n, 1) +	\
 					      0x800000 + (_x)))
 #endif
-#if CONFIG_IA64_SGI_SN1
+#ifdef CONFIG_IA64_SGI_SN1
 #define REMOTE_HUB_PI_ADDR(_n, _sn, _x)	(HUBREG_CAST (NODE_SWIN_BASE(_n, 1) +	\
 					      0x800000 + PIREG(_x, _sn)))
 #endif
diff -Nru a/include/asm-ia64/spinlock.h b/include/asm-ia64/spinlock.h
--- a/include/asm-ia64/spinlock.h	Tue Mar 18 14:59:25 2003
+++ b/include/asm-ia64/spinlock.h	Tue May  6 10:56:54 2003
@@ -22,26 +22,72 @@
 #define SPIN_LOCK_UNLOCKED			(spinlock_t) { 0 }
 #define spin_lock_init(x)			((x)->lock = 0)
 
-#define DEBUG_SPIN_LOCK	0
+#define NEW_LOCK
+#ifdef NEW_LOCK
 
-#if DEBUG_SPIN_LOCK
-
-#include <ia64intrin.h>
+/*
+ * Try to get the lock.  If we fail to get the lock, make a non-standard call to
+ * ia64_spinlock_contention().  We do not use a normal call because that would force all
+ * callers of spin_lock() to be non-leaf routines.  Instead, ia64_spinlock_contention() is
+ * carefully coded to touch only those registers that spin_lock() marks "clobbered".
+ */
 
-#define _raw_spin_lock(x)								\
-do {											\
-	unsigned long _timeout = 1000000000;						\
-	volatile unsigned int _old = 0, _new = 1, *_ptr = &((x)->lock);			\
-	do {										\
-		if (_timeout-- == 0) {							\
-			extern void dump_stack (void);					\
-			printk("kernel DEADLOCK at %s:%d?\n", __FILE__, __LINE__);	\
-			dump_stack();							\
-		}									\
-	} while (__sync_val_compare_and_swap(_ptr, _old, _new) != _old);		\
-} while (0)
+#define IA64_SPINLOCK_CLOBBERS "ar.pfs", "p14", "r28", "r29", "r30", "b6", "memory"
 
+static inline void
+_raw_spin_lock (spinlock_t *lock)
+{
+	register volatile unsigned int *ptr asm ("r31") = &lock->lock;
+
+#if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4)
+# ifdef CONFIG_ITANIUM
+	/* don't use brl on Itanium... */
+	asm volatile ("{\n\t"
+		      "  mov ar.ccv = r0\n\t"
+		      "  mov r28 = ip\n\t"
+		      "  mov r30 = 1;;\n\t"
+		      "}\n\t"
+		      "cmpxchg4.acq r30 = [%1], r30, ar.ccv\n\t"
+		      "movl r29 = ia64_spinlock_contention_pre3_4;;\n\t"
+		      "cmp4.ne p14, p0 = r30, r0\n\t"
+		      "mov b6 = r29;;\n"
+		      "(p14) br.cond.spnt.many b6"
+		      : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS);
+# else
+	asm volatile ("{\n\t"
+		      "  mov ar.ccv = r0\n\t"
+		      "  mov r28 = ip\n\t"
+		      "  mov r30 = 1;;\n\t"
+		      "}\n\t"
+		      "cmpxchg4.acq r30 = [%1], r30, ar.ccv;;\n\t"
+		      "cmp4.ne p14, p0 = r30, r0\n"
+		      "(p14) brl.cond.spnt.many ia64_spinlock_contention_pre3_4"
+		      : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS);
+# endif /* CONFIG_MCKINLEY */
 #else
+# ifdef CONFIG_ITANIUM
+	/* don't use brl on Itanium... */
+	/* mis-declare, so we get the entry-point, not it's function descriptor: */
+	asm volatile ("mov r30 = 1\n\t"
+		      "mov ar.ccv = r0;;\n\t"
+		      "cmpxchg4.acq r30 = [%0], r30, ar.ccv\n\t"
+		      "movl r29 = ia64_spinlock_contention;;\n\t"
+		      "cmp4.ne p14, p0 = r30, r0\n\t"
+		      "mov b6 = r29;;\n"
+		      "(p14) br.call.spnt.many b6 = b6"
+		      : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS);
+# else
+	asm volatile ("mov r30 = 1\n\t"
+		      "mov ar.ccv = r0;;\n\t"
+		      "cmpxchg4.acq r30 = [%0], r30, ar.ccv;;\n\t"
+		      "cmp4.ne p14, p0 = r30, r0\n\t"
+		      "(p14) brl.call.spnt.many b6=ia64_spinlock_contention"
+		      : "=r"(ptr) : "r"(ptr) : IA64_SPINLOCK_CLOBBERS);
+# endif /* CONFIG_MCKINLEY */
+#endif
+}
+
+#else /* !NEW_LOCK */
 
 /*
  * Streamlined test_and_set_bit(0, (x)).  We use test-and-test-and-set
@@ -64,7 +110,7 @@
 	";;\n"							\
 	:: "r"(&(x)->lock) : "ar.ccv", "p7", "r2", "r29", "memory")
 
-#endif /* !DEBUG_SPIN_LOCK */
+#endif /* !NEW_LOCK */
 
 #define spin_is_locked(x)	((x)->lock != 0)
 #define _raw_spin_unlock(x)	do { barrier(); ((spinlock_t *) x)->lock = 0; } while (0)
@@ -72,43 +118,31 @@
 #define spin_unlock_wait(x)	do { barrier(); } while ((x)->lock)
 
 typedef struct {
-	volatile int read_counter:31;
-	volatile int write_lock:1;
+	volatile int read_counter	: 31;
+	volatile int write_lock		:  1;
 } rwlock_t;
 #define RW_LOCK_UNLOCKED (rwlock_t) { 0, 0 }
 
 #define rwlock_init(x)		do { *(x) = RW_LOCK_UNLOCKED; } while(0)
 #define rwlock_is_locked(x)	(*(volatile int *) (x) != 0)
 
-#define _raw_read_lock(rw)							\
-do {										\
-	int __read_lock_tmp = 0;						\
-	__asm__ __volatile__ ("1:\tfetchadd4.acq %0 = [%1], 1\n"		\
-			      ";;\n"						\
-			      "tbit.nz p6,p0 = %0, 31\n"			\
-			      "(p6) br.cond.sptk.few 2f\n"			\
-			      ".section .text.lock,\"ax\"\n"			\
-			      "2:\tfetchadd4.rel %0 = [%1], -1\n"		\
-			      ";;\n"						\
-			      "3:\tld4.acq %0 = [%1]\n"				\
-			      ";;\n"						\
-			      "tbit.nz p6,p0 = %0, 31\n"			\
-			      "(p6) br.cond.sptk.few 3b\n"			\
-			      "br.cond.sptk.few 1b\n"				\
-			      ";;\n"						\
-			      ".previous\n"					\
-			      : "=&r" (__read_lock_tmp)				\
-			      : "r" (rw) : "p6", "memory");			\
-} while(0)
-
-#define _raw_read_unlock(rw)							\
-do {										\
-	int __read_unlock_tmp = 0;						\
-	__asm__ __volatile__ ("fetchadd4.rel %0 = [%1], -1\n"			\
-			      : "=r" (__read_unlock_tmp)			\
-			      : "r" (rw)					\
-			      : "memory");					\
-} while(0)
+#define _raw_read_lock(rw)								\
+do {											\
+	rwlock_t *__read_lock_ptr = (rw);						\
+											\
+	while (unlikely(ia64_fetchadd(1, (int *) __read_lock_ptr, "acq") < 0)) {	\
+		ia64_fetchadd(-1, (int *) __read_lock_ptr, "rel");			\
+		while (*(volatile int *)__read_lock_ptr < 0)				\
+			barrier();							\
+											\
+	}										\
+} while (0)
+
+#define _raw_read_unlock(rw)					\
+do {								\
+	rwlock_t *__read_lock_ptr = (rw);			\
+	ia64_fetchadd(-1, (int *) __read_lock_ptr, "rel");	\
+} while (0)
 
 #define _raw_write_lock(rw)							\
 do {										\
diff -Nru a/include/asm-ia64/system.h b/include/asm-ia64/system.h
--- a/include/asm-ia64/system.h	Tue Apr  1 01:19:53 2003
+++ b/include/asm-ia64/system.h	Sat May 10 02:28:47 2003
@@ -212,48 +212,39 @@
 # define PERFMON_IS_SYSWIDE() (0)
 #endif
 
-#define __switch_to(prev,next,last) do {						\
-	if (((prev)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID))	\
-	    || IS_IA32_PROCESS(ia64_task_regs(prev)) || PERFMON_IS_SYSWIDE())		\
-		ia64_save_extra(prev);							\
-	if (((next)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID))	\
-	    || IS_IA32_PROCESS(ia64_task_regs(next)) || PERFMON_IS_SYSWIDE())		\
-		ia64_load_extra(next);							\
-	(last) = ia64_switch_to((next));						\
+#define IA64_HAS_EXTRA_STATE(t)							\
+	((t)->thread.flags & (IA64_THREAD_DBG_VALID|IA64_THREAD_PM_VALID)	\
+	 || IS_IA32_PROCESS(ia64_task_regs(t)) || PERFMON_IS_SYSWIDE())
+
+#define __switch_to(prev,next,last) do {							 \
+	struct task_struct *__fpu_owner = ia64_get_fpu_owner();					 \
+	if (IA64_HAS_EXTRA_STATE(prev))								 \
+		ia64_save_extra(prev);								 \
+	if (IA64_HAS_EXTRA_STATE(next))								 \
+		ia64_load_extra(next);								 \
+	ia64_psr(ia64_task_regs(next))->dfh =							 \
+		!(__fpu_owner == (next) && ((next)->thread.last_fph_cpu == smp_processor_id())); \
+	(last) = ia64_switch_to((next));							 \
 } while (0)
 
 #ifdef CONFIG_SMP
-
 /*
- * In the SMP case, we save the fph state when context-switching
- * away from a thread that modified fph.  This way, when the thread
- * gets scheduled on another CPU, the CPU can pick up the state from
- * task->thread.fph, avoiding the complication of having to fetch
- * the latest fph state from another CPU.
+ * In the SMP case, we save the fph state when context-switching away from a thread that
+ * modified fph.  This way, when the thread gets scheduled on another CPU, the CPU can
+ * pick up the state from task->thread.fph, avoiding the complication of having to fetch
+ * the latest fph state from another CPU.  In other words: eager save, lazy restore.
  */
-# define switch_to(prev,next,last) do {					\
-	if (ia64_psr(ia64_task_regs(prev))->mfh) {			\
-		ia64_psr(ia64_task_regs(prev))->mfh = 0;		\
-		(prev)->thread.flags |= IA64_THREAD_FPH_VALID;		\
-		__ia64_save_fpu((prev)->thread.fph);			\
-		(prev)->thread.last_fph_cpu = smp_processor_id();	\
-	}								\
-	if ((next)->thread.flags & IA64_THREAD_FPH_VALID) {		\
-		if (((next)->thread.last_fph_cpu == smp_processor_id())	\
-		    && (ia64_get_fpu_owner() == next))			\
-		{							\
-			ia64_psr(ia64_task_regs(next))->dfh = 0;	\
-			ia64_psr(ia64_task_regs(next))->mfh = 0;	\
-		} else							\
-			ia64_psr(ia64_task_regs(next))->dfh = 1;	\
-	}								\
-	__switch_to(prev,next,last);					\
-  } while (0)
-#else
 # define switch_to(prev,next,last) do {						\
-	ia64_psr(ia64_task_regs(next))->dfh = (ia64_get_fpu_owner() != (next));	\
-	__switch_to(prev,next,last);						\
+	if (ia64_psr(ia64_task_regs(prev))->mfh) {				\
+		ia64_psr(ia64_task_regs(prev))->mfh = 0;			\
+		(prev)->thread.flags |= IA64_THREAD_FPH_VALID;			\
+		__ia64_save_fpu((prev)->thread.fph);				\
+		(prev)->thread.last_fph_cpu = smp_processor_id();		\
+	}									\
+	__switch_to(prev, next, last);						\
 } while (0)
+#else
+# define switch_to(prev,next,last)	__switch_to(prev, next, last)
 #endif
 
 /*
diff -Nru a/include/asm-ia64/uaccess.h b/include/asm-ia64/uaccess.h
--- a/include/asm-ia64/uaccess.h	Fri Jan 24 19:45:37 2003
+++ b/include/asm-ia64/uaccess.h	Tue Apr 22 19:47:09 2003
@@ -8,7 +8,7 @@
  * addresses.  Thus, we need to be careful not to let the user to
  * trick us into accessing kernel memory that would normally be
  * inaccessible.  This code is also fairly performance sensitive,
- * so we want to spend as little time doing saftey checks as
+ * so we want to spend as little time doing safety checks as
  * possible.
  *
  * To make matters a bit more interesting, these macros sometimes also
diff -Nru a/include/asm-ia64/unwind.h b/include/asm-ia64/unwind.h
--- a/include/asm-ia64/unwind.h	Mon Mar  3 16:00:00 2003
+++ b/include/asm-ia64/unwind.h	Tue Apr 15 13:16:39 2003
@@ -2,8 +2,8 @@
 #define _ASM_IA64_UNWIND_H
 
 /*
- * Copyright (C) 1999-2000 Hewlett-Packard Co
- * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * Copyright (C) 1999-2000, 2003 Hewlett-Packard Co
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
  *
  * A simple API for unwinding kernel stacks.  This is used for
  * debugging and error reporting purposes.  The kernel doesn't need
@@ -106,6 +106,13 @@
  * Prepare to unwind blocked task t.
  */
 extern void unw_init_from_blocked_task (struct unw_frame_info *info, struct task_struct *t);
+
+/*
+ * Prepare to unwind from interruption.  The pt-regs and switch-stack structures must have
+ * be "adjacent" (no state modifications between pt-regs and switch-stack).
+ */
+extern void unw_init_from_interruption (struct unw_frame_info *info, struct task_struct *t,
+					struct pt_regs *pt, struct switch_stack *sw);
 
 extern void unw_init_frame_info (struct unw_frame_info *info, struct task_struct *t,
 				 struct switch_stack *sw);
diff -Nru a/include/asm-m68k/elf.h b/include/asm-m68k/elf.h
--- a/include/asm-m68k/elf.h	Mon Mar 17 21:31:50 2003
+++ b/include/asm-m68k/elf.h	Mon May 12 07:05:08 2003
@@ -9,6 +9,33 @@
 #include <asm/ptrace.h>
 #include <asm/user.h>
 
+/*
+ * 68k ELF relocation types
+ */
+#define R_68K_NONE	0
+#define R_68K_32	1
+#define R_68K_16	2
+#define R_68K_8		3
+#define R_68K_PC32	4
+#define R_68K_PC16	5
+#define R_68K_PC8	6
+#define R_68K_GOT32	7
+#define R_68K_GOT16	8
+#define R_68K_GOT8	9
+#define R_68K_GOT32O	10
+#define R_68K_GOT16O	11
+#define R_68K_GOT8O	12
+#define R_68K_PLT32	13
+#define R_68K_PLT16	14
+#define R_68K_PLT8	15
+#define R_68K_PLT32O	16
+#define R_68K_PLT16O	17
+#define R_68K_PLT8O	18
+#define R_68K_COPY	19
+#define R_68K_GLOB_DAT	20
+#define R_68K_JMP_SLOT	21
+#define R_68K_RELATIVE	22
+
 typedef unsigned long elf_greg_t;
 
 #define ELF_NGREG (sizeof(struct user_regs_struct) / sizeof(elf_greg_t))
diff -Nru a/include/asm-m68k/hardirq.h b/include/asm-m68k/hardirq.h
--- a/include/asm-m68k/hardirq.h	Tue Sep 17 04:32:36 2002
+++ b/include/asm-m68k/hardirq.h	Mon May 12 18:59:24 2003
@@ -73,7 +73,7 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-m68knommu/hardirq.h b/include/asm-m68knommu/hardirq.h
--- a/include/asm-m68knommu/hardirq.h	Tue Dec 10 16:41:17 2002
+++ b/include/asm-m68knommu/hardirq.h	Mon May 12 18:59:23 2003
@@ -72,13 +72,13 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
 # define IRQ_EXIT_OFFSET HARDIRQ_OFFSET
 #endif
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-mips/elf.h b/include/asm-mips/elf.h
--- a/include/asm-mips/elf.h	Mon Mar 17 21:31:50 2003
+++ b/include/asm-mips/elf.h	Mon May 12 07:11:02 2003
@@ -6,6 +6,91 @@
 #ifndef __ASM_ELF_H
 #define __ASM_ELF_H
 
+#define PT_MIPS_REGINFO		0x70000000
+
+/* Flags in the e_flags field of the header */
+#define EF_MIPS_NOREORDER 0x00000001
+#define EF_MIPS_PIC       0x00000002
+#define EF_MIPS_CPIC      0x00000004
+#define EF_MIPS_ARCH      0xf0000000
+
+#define DT_MIPS_RLD_VERSION	0x70000001
+#define DT_MIPS_TIME_STAMP	0x70000002
+#define DT_MIPS_ICHECKSUM	0x70000003
+#define DT_MIPS_IVERSION	0x70000004
+#define DT_MIPS_FLAGS		0x70000005
+  #define RHF_NONE		  0
+  #define RHF_HARDWAY		  1
+  #define RHF_NOTPOT		  2
+#define DT_MIPS_BASE_ADDRESS	0x70000006
+#define DT_MIPS_CONFLICT	0x70000008
+#define DT_MIPS_LIBLIST		0x70000009
+#define DT_MIPS_LOCAL_GOTNO	0x7000000a
+#define DT_MIPS_CONFLICTNO	0x7000000b
+#define DT_MIPS_LIBLISTNO	0x70000010
+#define DT_MIPS_SYMTABNO	0x70000011
+#define DT_MIPS_UNREFEXTNO	0x70000012
+#define DT_MIPS_GOTSYM		0x70000013
+#define DT_MIPS_HIPAGENO	0x70000014
+#define DT_MIPS_RLD_MAP		0x70000016
+
+#define R_MIPS_NONE		0
+#define R_MIPS_16		1
+#define R_MIPS_32		2
+#define R_MIPS_REL32		3
+#define R_MIPS_26		4
+#define R_MIPS_HI16		5
+#define R_MIPS_LO16		6
+#define R_MIPS_GPREL16		7
+#define R_MIPS_LITERAL		8
+#define R_MIPS_GOT16		9
+#define R_MIPS_PC16		10
+#define R_MIPS_CALL16		11
+#define R_MIPS_GPREL32		12
+/* The remaining relocs are defined on Irix, although they are not
+   in the MIPS ELF ABI.  */
+#define R_MIPS_UNUSED1		13
+#define R_MIPS_UNUSED2		14
+#define R_MIPS_UNUSED3		15
+#define R_MIPS_SHIFT5		16
+#define R_MIPS_SHIFT6		17
+#define R_MIPS_64		18
+#define R_MIPS_GOT_DISP		19
+#define R_MIPS_GOT_PAGE		20
+#define R_MIPS_GOT_OFST		21
+/*
+ * The following two relocation types are specified in the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_GOTHI16		22
+#define R_MIPS_GOTLO16		23
+#define R_MIPS_SUB		24
+#define R_MIPS_INSERT_A		25
+#define R_MIPS_INSERT_B		26
+#define R_MIPS_DELETE		27
+#define R_MIPS_HIGHER		28
+#define R_MIPS_HIGHEST		29
+/*
+ * The following two relocation types are specified in the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_CALLHI16		30
+#define R_MIPS_CALLLO16		31
+/*
+ * This range is reserved for vendor specific relocations.
+ */
+#define R_MIPS_LOVENDOR		100
+#define R_MIPS_HIVENDOR		127
+
+#define SHN_MIPS_ACCOMON	0xff00
+
+#define SHT_MIPS_LIST		0x70000000
+#define SHT_MIPS_CONFLICT	0x70000002
+#define SHT_MIPS_GPTAB		0x70000003
+#define SHT_MIPS_UCODE		0x70000004
+
+#define SHF_MIPS_GPREL	0x10000000
+
 /* ELF register definitions */
 #define ELF_NGREG	45
 #define ELF_NFPREG	33
diff -Nru a/include/asm-mips64/elf.h b/include/asm-mips64/elf.h
--- a/include/asm-mips64/elf.h	Mon Mar 17 21:31:50 2003
+++ b/include/asm-mips64/elf.h	Mon May 12 07:10:54 2003
@@ -9,6 +9,91 @@
 #include <asm/ptrace.h>
 #include <asm/user.h>
 
+#define PT_MIPS_REGINFO		0x70000000
+
+/* Flags in the e_flags field of the header */
+#define EF_MIPS_NOREORDER 0x00000001
+#define EF_MIPS_PIC       0x00000002
+#define EF_MIPS_CPIC      0x00000004
+#define EF_MIPS_ARCH      0xf0000000
+
+#define DT_MIPS_RLD_VERSION	0x70000001
+#define DT_MIPS_TIME_STAMP	0x70000002
+#define DT_MIPS_ICHECKSUM	0x70000003
+#define DT_MIPS_IVERSION	0x70000004
+#define DT_MIPS_FLAGS		0x70000005
+  #define RHF_NONE		  0
+  #define RHF_HARDWAY		  1
+  #define RHF_NOTPOT		  2
+#define DT_MIPS_BASE_ADDRESS	0x70000006
+#define DT_MIPS_CONFLICT	0x70000008
+#define DT_MIPS_LIBLIST		0x70000009
+#define DT_MIPS_LOCAL_GOTNO	0x7000000a
+#define DT_MIPS_CONFLICTNO	0x7000000b
+#define DT_MIPS_LIBLISTNO	0x70000010
+#define DT_MIPS_SYMTABNO	0x70000011
+#define DT_MIPS_UNREFEXTNO	0x70000012
+#define DT_MIPS_GOTSYM		0x70000013
+#define DT_MIPS_HIPAGENO	0x70000014
+#define DT_MIPS_RLD_MAP		0x70000016
+
+#define R_MIPS_NONE		0
+#define R_MIPS_16		1
+#define R_MIPS_32		2
+#define R_MIPS_REL32		3
+#define R_MIPS_26		4
+#define R_MIPS_HI16		5
+#define R_MIPS_LO16		6
+#define R_MIPS_GPREL16		7
+#define R_MIPS_LITERAL		8
+#define R_MIPS_GOT16		9
+#define R_MIPS_PC16		10
+#define R_MIPS_CALL16		11
+#define R_MIPS_GPREL32		12
+/* The remaining relocs are defined on Irix, although they are not
+   in the MIPS ELF ABI.  */
+#define R_MIPS_UNUSED1		13
+#define R_MIPS_UNUSED2		14
+#define R_MIPS_UNUSED3		15
+#define R_MIPS_SHIFT5		16
+#define R_MIPS_SHIFT6		17
+#define R_MIPS_64		18
+#define R_MIPS_GOT_DISP		19
+#define R_MIPS_GOT_PAGE		20
+#define R_MIPS_GOT_OFST		21
+/*
+ * The following two relocation types are specified in the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_GOTHI16		22
+#define R_MIPS_GOTLO16		23
+#define R_MIPS_SUB		24
+#define R_MIPS_INSERT_A		25
+#define R_MIPS_INSERT_B		26
+#define R_MIPS_DELETE		27
+#define R_MIPS_HIGHER		28
+#define R_MIPS_HIGHEST		29
+/*
+ * The following two relocation types are specified in the MIPS ABI
+ * conformance guide version 1.2 but not yet in the psABI.
+ */
+#define R_MIPS_CALLHI16		30
+#define R_MIPS_CALLLO16		31
+/*
+ * This range is reserved for vendor specific relocations.
+ */
+#define R_MIPS_LOVENDOR		100
+#define R_MIPS_HIVENDOR		127
+
+#define SHN_MIPS_ACCOMON	0xff00
+
+#define SHT_MIPS_LIST		0x70000000
+#define SHT_MIPS_CONFLICT	0x70000002
+#define SHT_MIPS_GPTAB		0x70000003
+#define SHT_MIPS_UCODE		0x70000004
+
+#define SHF_MIPS_GPREL	0x10000000
+
 #ifndef ELF_ARCH
 /* ELF register definitions */
 #define ELF_NGREG	45
diff -Nru a/include/asm-parisc/elf.h b/include/asm-parisc/elf.h
--- a/include/asm-parisc/elf.h	Mon Mar 17 21:31:50 2003
+++ b/include/asm-parisc/elf.h	Mon May 12 07:07:23 2003
@@ -9,6 +9,174 @@
 
 #define EM_PARISC 15
 
+/* HPPA specific definitions.  */
+
+/* Legal values for e_flags field of Elf32_Ehdr.  */
+
+#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
+#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
+#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
+#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
+#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
+					      prediction.  */
+#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
+#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
+
+/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
+
+#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
+#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
+#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
+
+/* Additional section indeces.  */
+
+#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
+					      symbols in ANSI C.  */
+#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
+
+/* Legal values for sh_type field of Elf32_Shdr.  */
+
+#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
+#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
+#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
+
+/* Legal values for sh_flags field of Elf32_Shdr.  */
+
+#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
+#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
+#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
+
+/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
+
+#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
+
+#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
+#define STT_HP_STUB		(STT_LOOS + 0x2)
+
+/* HPPA relocs.  */
+
+#define R_PARISC_NONE		0	/* No reloc.  */
+#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
+#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
+#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
+#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
+#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
+#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
+#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
+#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
+#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
+#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
+#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
+#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
+#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
+#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
+#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
+#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
+#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
+#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
+#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
+#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
+#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
+#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
+#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
+#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
+#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
+#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
+#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
+#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
+#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
+#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
+#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
+#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
+#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
+#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
+#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
+#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
+#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
+#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
+#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
+#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
+#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
+#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
+#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
+#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
+#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
+#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
+#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
+#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
+#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
+#define R_PARISC_LORESERVE	128
+#define R_PARISC_COPY		128	/* Copy relocation.  */
+#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
+#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
+#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
+#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
+#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
+#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
+#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
+#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
+#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
+#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
+#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
+#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
+#define R_PARISC_HIRESERVE	255
+
+/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PT_HP_TLS		(PT_LOOS + 0x0)
+#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
+#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
+#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
+#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
+#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
+#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
+#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
+#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
+#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
+#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
+#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
+#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
+#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
+#define PT_HP_STACK		(PT_LOOS + 0x14)
+
+#define PT_PARISC_ARCHEXT	0x70000000
+#define PT_PARISC_UNWIND	0x70000001
+
+/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
+
+#define PF_PARISC_SBP		0x08000000
+
+#define PF_HP_PAGE_SIZE		0x00100000
+#define PF_HP_FAR_SHARED	0x00200000
+#define PF_HP_NEAR_SHARED	0x00400000
+#define PF_HP_CODE		0x01000000
+#define PF_HP_MODIFY		0x02000000
+#define PF_HP_LAZYSWAP		0x04000000
+#define PF_HP_SBP		0x08000000
+
 /*
  * The following definitions are those for 32-bit ELF binaries on a 32-bit kernel
  * and for 64-bit binaries on a 64-bit kernel.  To run 32-bit binaries on a 64-bit
diff -Nru a/include/asm-parisc/hardirq.h b/include/asm-parisc/hardirq.h
--- a/include/asm-parisc/hardirq.h	Tue Oct  8 18:07:37 2002
+++ b/include/asm-parisc/hardirq.h	Mon May 12 18:59:23 2003
@@ -87,7 +87,7 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # error CONFIG_PREEMT currently not supported.
 # define in_atomic()	 BUG()
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
diff -Nru a/include/asm-parisc/kmap_types.h b/include/asm-parisc/kmap_types.h
--- a/include/asm-parisc/kmap_types.h	Sun Mar  2 15:58:28 2003
+++ b/include/asm-parisc/kmap_types.h	Mon May 12 18:59:23 2003
@@ -3,7 +3,7 @@
 
 #include <linux/config.h>
 
-#if CONFIG_DEBUG_HIGHMEM
+#ifdef CONFIG_DEBUG_HIGHMEM
 # define D(n) __KM_FENCE_##n ,
 #else
 # define D(n)
diff -Nru a/include/asm-ppc/agp.h b/include/asm-ppc/agp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc/agp.h	Wed May 14 05:55:16 2003
@@ -0,0 +1,13 @@
+#ifndef AGP_H
+#define AGP_H 1
+
+#include <asm/io.h>
+
+/* nothing much needed here */
+
+#define map_page_into_agp(page) 
+#define unmap_page_from_agp(page) 
+#define flush_agp_mappings() 
+#define flush_agp_cache() mb()
+
+#endif
diff -Nru a/include/asm-ppc/elf.h b/include/asm-ppc/elf.h
--- a/include/asm-ppc/elf.h	Sun Sep 15 21:52:03 2002
+++ b/include/asm-ppc/elf.h	Mon May 12 07:05:39 2003
@@ -8,6 +8,47 @@
 #include <asm/ptrace.h>
 #include <asm/cputable.h>
 
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE		0
+#define R_PPC_ADDR32		1	/* 32bit absolute address */
+#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
+#define R_PPC_ADDR16		3	/* 16bit absolute address */
+#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
+#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN	8
+#define R_PPC_ADDR14_BRNTAKEN	9
+#define R_PPC_REL24		10	/* PC relative 26 bit */
+#define R_PPC_REL14		11	/* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN	12
+#define R_PPC_REL14_BRNTAKEN	13
+#define R_PPC_GOT16		14
+#define R_PPC_GOT16_LO		15
+#define R_PPC_GOT16_HI		16
+#define R_PPC_GOT16_HA		17
+#define R_PPC_PLTREL24		18
+#define R_PPC_COPY		19
+#define R_PPC_GLOB_DAT		20
+#define R_PPC_JMP_SLOT		21
+#define R_PPC_RELATIVE		22
+#define R_PPC_LOCAL24PC		23
+#define R_PPC_UADDR32		24
+#define R_PPC_UADDR16		25
+#define R_PPC_REL32		26
+#define R_PPC_PLT32		27
+#define R_PPC_PLTREL32		28
+#define R_PPC_PLT16_LO		29
+#define R_PPC_PLT16_HI		30
+#define R_PPC_PLT16_HA		31
+#define R_PPC_SDAREL16		32
+#define R_PPC_SECTOFF		33
+#define R_PPC_SECTOFF_LO	34
+#define R_PPC_SECTOFF_HI	35
+#define R_PPC_SECTOFF_HA	36
+/* Keep this the last entry.  */
+#define R_PPC_NUM		37
+
 #define ELF_NGREG	48	/* includes nip, msr, lr, etc. */
 #define ELF_NFPREG	33	/* includes fpscr */
 #define ELF_NVRREG	33	/* includes vscr */
diff -Nru a/include/asm-ppc/hardirq.h b/include/asm-ppc/hardirq.h
--- a/include/asm-ppc/hardirq.h	Wed Dec  4 21:13:44 2002
+++ b/include/asm-ppc/hardirq.h	Mon May 12 18:59:24 2003
@@ -82,7 +82,7 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-ppc/spinlock.h b/include/asm-ppc/spinlock.h
--- a/include/asm-ppc/spinlock.h	Sat Jan  4 00:44:12 2003
+++ b/include/asm-ppc/spinlock.h	Mon May 12 18:59:24 2003
@@ -17,7 +17,7 @@
 } spinlock_t;
 
 #ifdef __KERNEL__
-#if CONFIG_DEBUG_SPINLOCK
+#ifdef CONFIG_DEBUG_SPINLOCK
 #define SPINLOCK_DEBUG_INIT     , 0, 0
 #else
 #define SPINLOCK_DEBUG_INIT     /* */
@@ -86,7 +86,7 @@
 #endif
 } rwlock_t;
 
-#if CONFIG_DEBUG_SPINLOCK
+#ifdef CONFIG_DEBUG_SPINLOCK
 #define RWLOCK_DEBUG_INIT     , 0
 #else
 #define RWLOCK_DEBUG_INIT     /* */
diff -Nru a/include/asm-ppc64/compat.h b/include/asm-ppc64/compat.h
--- a/include/asm-ppc64/compat.h	Tue Apr 15 22:48:21 2003
+++ b/include/asm-ppc64/compat.h	Mon May 19 23:31:53 2003
@@ -119,4 +119,19 @@
 	return (void *)(unsigned long)uptr;
 }
 
+static inline void *compat_alloc_user_space(long len)
+{
+	struct pt_regs *regs = current->thread.regs;
+	unsigned long usp = regs->gpr[1];
+
+	/*
+	 * We cant access below the stack pointer in the 32bit ABI and
+	 * can access 288 bytes in the 64bit ABI
+	 */
+	if (!(test_thread_flag(TIF_32BIT)))
+		usp -= 288;
+
+	return (void *) (usp - len);
+}
+
 #endif /* _ASM_PPC64_COMPAT_H */
diff -Nru a/include/asm-ppc64/elf.h b/include/asm-ppc64/elf.h
--- a/include/asm-ppc64/elf.h	Mon Mar 17 21:31:50 2003
+++ b/include/asm-ppc64/elf.h	Mon May 12 07:05:50 2003
@@ -1,6 +1,47 @@
 #ifndef __PPC64_ELF_H
 #define __PPC64_ELF_H
 
+/* PowerPC relocations defined by the ABIs */
+#define R_PPC_NONE		0
+#define R_PPC_ADDR32		1	/* 32bit absolute address */
+#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
+#define R_PPC_ADDR16		3	/* 16bit absolute address */
+#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
+#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
+#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
+#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
+#define R_PPC_ADDR14_BRTAKEN	8
+#define R_PPC_ADDR14_BRNTAKEN	9
+#define R_PPC_REL24		10	/* PC relative 26 bit */
+#define R_PPC_REL14		11	/* PC relative 16 bit */
+#define R_PPC_REL14_BRTAKEN	12
+#define R_PPC_REL14_BRNTAKEN	13
+#define R_PPC_GOT16		14
+#define R_PPC_GOT16_LO		15
+#define R_PPC_GOT16_HI		16
+#define R_PPC_GOT16_HA		17
+#define R_PPC_PLTREL24		18
+#define R_PPC_COPY		19
+#define R_PPC_GLOB_DAT		20
+#define R_PPC_JMP_SLOT		21
+#define R_PPC_RELATIVE		22
+#define R_PPC_LOCAL24PC		23
+#define R_PPC_UADDR32		24
+#define R_PPC_UADDR16		25
+#define R_PPC_REL32		26
+#define R_PPC_PLT32		27
+#define R_PPC_PLTREL32		28
+#define R_PPC_PLT16_LO		29
+#define R_PPC_PLT16_HI		30
+#define R_PPC_PLT16_HA		31
+#define R_PPC_SDAREL16		32
+#define R_PPC_SECTOFF		33
+#define R_PPC_SECTOFF_LO	34
+#define R_PPC_SECTOFF_HI	35
+#define R_PPC_SECTOFF_HA	36
+/* Keep this the last entry.  */
+#define R_PPC_NUM		37
+
 /*
  * ELF register definitions..
  *
diff -Nru a/include/asm-ppc64/io.h b/include/asm-ppc64/io.h
--- a/include/asm-ppc64/io.h	Sat Dec  7 20:23:44 2002
+++ b/include/asm-ppc64/io.h	Sun Apr 27 14:32:15 2003
@@ -107,7 +107,6 @@
 
 
 #define IO_SPACE_LIMIT ~(0UL)
-#define MEM_SPACE_LIMIT ~(0UL)
 
 
 #ifdef __KERNEL__
diff -Nru a/include/asm-ppc64/mmu.h b/include/asm-ppc64/mmu.h
--- a/include/asm-ppc64/mmu.h	Fri Sep 13 04:19:46 2002
+++ b/include/asm-ppc64/mmu.h	Tue Mar 25 20:30:59 2003
@@ -221,6 +221,13 @@
 
 #endif /* __ASSEMBLY__ */
 
+/*
+ * Location of cpu0's segment table
+ */
+#define STAB0_PAGE	0x9
+#define STAB0_PHYS_ADDR	(STAB0_PAGE<<PAGE_SHIFT)
+#define STAB0_VIRT_ADDR	(KERNELBASE+STAB0_PHYS_ADDR)
+
 /* Block size masks */
 #define BL_128K	0x000
 #define BL_256K 0x001
diff -Nru a/include/asm-ppc64/mmzone.h b/include/asm-ppc64/mmzone.h
--- a/include/asm-ppc64/mmzone.h	Wed Sep 25 17:40:59 2002
+++ b/include/asm-ppc64/mmzone.h	Thu Apr 24 13:05:36 2003
@@ -18,9 +18,9 @@
  * Following are specific to this numa platform.
  */
 
-extern int numa_node_exists[];
 extern int numa_cpu_lookup_table[];
 extern int numa_memory_lookup_table[];
+extern unsigned long numa_cpumask_lookup_table[];
 
 #define MAX_MEMORY (1UL << 41)
 /* 256MB regions */
diff -Nru a/include/asm-ppc64/module.h b/include/asm-ppc64/module.h
--- a/include/asm-ppc64/module.h	Tue Jan 14 00:46:13 2003
+++ b/include/asm-ppc64/module.h	Thu Apr 24 09:29:49 2003
@@ -19,4 +19,8 @@
 asm(".section .stubs,\"ax\",@nobits; .align 3; .previous");
 #endif
 
+struct exception_table_entry;
+void sort_ex_table(struct exception_table_entry *start,
+			struct exception_table_entry *finish);
+
 #endif /* _ASM_PPC64_MODULE_H */
diff -Nru a/include/asm-ppc64/naca.h b/include/asm-ppc64/naca.h
--- a/include/asm-ppc64/naca.h	Thu Jun 20 16:29:14 2002
+++ b/include/asm-ppc64/naca.h	Tue Mar 25 20:30:59 2003
@@ -11,29 +11,41 @@
  */
 
 #include <asm/types.h>
+#include <asm/systemcfg.h>
+
+#ifndef __ASSEMBLY__
 
 struct naca_struct {
-	void *xItVpdAreas;
-	void *xRamDisk;
-	u64 xRamDiskSize;		/* In pages */
-	struct paca_struct *paca;	/* Ptr to an array of pacas */
-	u64 debug_switch;		/* Bits to control debug printing */
-	u16 dCacheL1LineSize;		/* Line size of L1 DCache in bytes */
-	u16 dCacheL1LogLineSize;	/* Log-2 of DCache line size */
-	u16 dCacheL1LinesPerPage;	/* DCache lines per page */
-	u16 iCacheL1LineSize;		/* Line size of L1 ICache in bytes */
-	u16 iCacheL1LogLineSize;	/* Log-2 of ICache line size */
-	u16 iCacheL1LinesPerPage;	/* ICache lines per page */
-	u16 slb_size;			/* SLB size in entries */
-	u64 physicalMemorySize;		/* Size of real memory in bytes */
-	u64 pftSize;			/* Log base 2 of page table size */
-	u64 serialPortAddr;		/* Phyical address of serial port */
-	u8 interrupt_controller;	/* Type of interrupt controller */ 
-	u8 resv0;    			/* Type of interrupt controller */
-	u16 platform;			/* Platform flags */
-	u8 resv1[12];			/* Padding */
+	/*==================================================================
+	 * Cache line 1: 0x0000 - 0x007F
+	 * Kernel only data - undefined for user space
+	 *==================================================================
+	 */
+	void *xItVpdAreas;              /* VPD Data                  0x00 */
+	void *xRamDisk;                 /* iSeries ramdisk           0x08 */
+	u64   xRamDiskSize;		/* In pages                  0x10 */
+	struct paca_struct *paca;	/* Ptr to an array of pacas  0x18 */
+	u64 debug_switch;		/* Debug print control       0x20 */
+	u64 banner;                     /* Ptr to banner string      0x28 */
+	u64 log;                        /* Ptr to log buffer         0x30 */
+	u64 serialPortAddr;		/* Phy addr of serial port   0x38 */
+	u64 interrupt_controller;	/* Type of int controller    0x40 */ 
+	u64 slb_size;			/* SLB size in entries       0x48 */
+	u64 pftSize;			/* Log 2 of page table size  0x50 */
+	void *systemcfg;		/* Pointer to systemcfg data 0x58 */
+	u32 dCacheL1LogLineSize;	/* L1 d-cache line size Log2 0x60 */
+	u32 dCacheL1LinesPerPage;	/* L1 d-cache lines / page   0x64 */
+	u32 iCacheL1LogLineSize;	/* L1 i-cache line size Log2 0x68 */
+	u32 iCacheL1LinesPerPage;	/* L1 i-cache lines / page   0x6c */
+	u64 resv0[2];                   /* Reserved           0x70 - 0x7F */
 };
 
 extern struct naca_struct *naca;
+
+#endif /* __ASSEMBLY__ */
+
+#define NACA_PAGE      0x4
+#define NACA_PHYS_ADDR (NACA_PAGE<<PAGE_SHIFT)
+#define NACA_VIRT_ADDR (KERNELBASE+NACA_PHYS_ADDR)
 
 #endif /* _NACA_H */
diff -Nru a/include/asm-ppc64/page.h b/include/asm-ppc64/page.h
--- a/include/asm-ppc64/page.h	Tue Feb 25 09:57:19 2003
+++ b/include/asm-ppc64/page.h	Tue Mar 25 20:30:59 2003
@@ -14,7 +14,11 @@
 
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT	12
-#define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#ifndef __ASSEMBLY__
+# define PAGE_SIZE	(1UL << PAGE_SHIFT)
+#else
+# define PAGE_SIZE	(1 << PAGE_SHIFT)
+#endif
 #define PAGE_MASK	(~(PAGE_SIZE-1))
 #define PAGE_OFFSET_MASK (PAGE_SIZE-1)
 
@@ -22,6 +26,19 @@
 #define SID_MASK        0xfffffffff
 #define GET_ESID(x)     (((x) >> SID_SHIFT) & SID_MASK)
 
+/* align addr on a size boundary - adjust address up/down if needed */
+#define _ALIGN_UP(addr,size)	(((addr)+((size)-1))&(~((size)-1)))
+#define _ALIGN_DOWN(addr,size)	((addr)&(~((size)-1)))
+
+/* align addr on a size boundary - adjust address up if needed */
+#define _ALIGN(addr,size)     _ALIGN_UP(addr,size)
+
+/* to align the pointer to the (next) double word boundary */
+#define DOUBLEWORD_ALIGN(addr)	_ALIGN(addr,sizeof(unsigned long))
+
+/* to align the pointer to the (next) page boundary */
+#define PAGE_ALIGN(addr)	_ALIGN(addr, PAGE_SIZE)
+
 #ifdef __KERNEL__
 #ifndef __ASSEMBLY__
 #include <asm/naca.h>
@@ -37,7 +54,7 @@
 {
 	unsigned long lines, line_size;
 
-	line_size = naca->dCacheL1LineSize; 
+	line_size = systemcfg->dCacheL1LineSize; 
 	lines = naca->dCacheL1LinesPerPage;
 
 	__asm__ __volatile__(
@@ -113,19 +130,6 @@
 #define __pa(x) ((unsigned long)(x)-PAGE_OFFSET)
 
 #endif /* __ASSEMBLY__ */
-
-/* align addr on a size boundary - adjust address up/down if needed */
-#define _ALIGN_UP(addr,size)	(((addr)+((size)-1))&(~((size)-1)))
-#define _ALIGN_DOWN(addr,size)	((addr)&(~((size)-1)))
-
-/* align addr on a size boundary - adjust address up if needed */
-#define _ALIGN(addr,size)     _ALIGN_UP(addr,size)
-
-/* to align the pointer to the (next) double word boundary */
-#define DOUBLEWORD_ALIGN(addr)	_ALIGN(addr,sizeof(unsigned long))
-
-/* to align the pointer to the (next) page boundary */
-#define PAGE_ALIGN(addr)	_ALIGN(addr, PAGE_SIZE)
 
 #ifdef MODULE
 #define __page_aligned __attribute__((__aligned__(PAGE_SIZE)))
diff -Nru a/include/asm-ppc64/proc_fs.h b/include/asm-ppc64/proc_fs.h
--- a/include/asm-ppc64/proc_fs.h	Thu Feb 14 04:14:36 2002
+++ b/include/asm-ppc64/proc_fs.h	Tue Mar 25 20:30:59 2003
@@ -25,9 +25,14 @@
 
 #include <linux/proc_fs.h>
 
-void pmc_proc_init(struct proc_dir_entry *iSeries_proc);
-void proc_ppc64_init(void);
+struct proc_ppc64_t {
+	struct proc_dir_entry *root;
+	struct proc_dir_entry *naca;
+	struct proc_dir_entry *paca;
+	struct proc_dir_entry *systemcfg;
+	struct proc_dir_entry *rtas;
+};
 
-#include <asm/iSeries/iSeries_proc.h>
+extern struct proc_ppc64_t proc_ppc64;
 
-#endif
+#endif /* _PPC64_PROC_FS_H */
diff -Nru a/include/asm-ppc64/processor.h b/include/asm-ppc64/processor.h
--- a/include/asm-ppc64/processor.h	Mon Mar 10 10:20:31 2003
+++ b/include/asm-ppc64/processor.h	Mon Mar 31 11:43:45 2003
@@ -469,8 +469,6 @@
 #define	  IOCR_SPC	0x00000001
 
 
-/* Processor Version Register */
-
 /* Processor Version Register (PVR) field extraction */
 
 #define	PVR_VER(pvr)  (((pvr) >>  16) & 0xFFFF)	/* Version field */
@@ -595,6 +593,8 @@
 			asm volatile("mfasr %0" : "=r" (rval)); rval;})
 
 #ifndef __ASSEMBLY__
+extern unsigned long *_get_SP(void);
+
 extern int have_of;
 
 struct task_struct;
@@ -654,8 +654,10 @@
 	struct pt_regs	*regs;		/* Pointer to saved register state */
 	mm_segment_t	fs;		/* for get_fs() validation */
 	double		fpr[32];	/* Complete floating point set */
-	unsigned long	fpscr;		/* Floating point status */
-	unsigned int	fpexc_mode;	/* Floating-point exception mode */
+	unsigned long	fpscr;		/* Floating point status (plus pad) */
+	unsigned long	fpexc_mode;	/* Floating-point exception mode */
+	unsigned long	saved_msr;	/* Save MSR across signal handlers */
+	unsigned long	saved_softe;	/* Ditto for Soft Enable/Disable */
 };
 
 #define INIT_SP		(sizeof(init_stack) + (unsigned long) &init_stack)
@@ -702,7 +704,7 @@
 	return ((msr_bits & MSR_FE0) >> 10) | ((msr_bits & MSR_FE1) >> 8);
 }
 
-static inline unsigned int __pack_fe01(unsigned int fpmode)
+static inline unsigned long __pack_fe01(unsigned int fpmode)
 {
 	return ((fpmode << 10) & MSR_FE0) | ((fpmode << 8) & MSR_FE1);
 }
@@ -739,6 +741,15 @@
 
 #define cpu_has_noexecute()	(processor_type() == PV_POWER4 || \
 				 processor_type() == PV_POWER4p)
+
+/* XXX we have to call HV to set when in LPAR */
+#define cpu_has_dabr()		(1)
+
+#define cpu_has_iabr()		(processor_type() != PV_POWER4 && \
+				 processor_type() != PV_POWER4p)
+
+#define cpu_alignexc_sets_dsisr() (processor_type() != PV_POWER4 && \
+				 processor_type() != PV_POWER4p)
 
 #endif /* ASSEMBLY */
 
diff -Nru a/include/asm-ppc64/ptrace.h b/include/asm-ppc64/ptrace.h
--- a/include/asm-ppc64/ptrace.h	Thu Feb 14 04:14:36 2002
+++ b/include/asm-ppc64/ptrace.h	Tue Mar 25 19:38:55 2003
@@ -64,9 +64,8 @@
 
 #define STACK_FRAME_OVERHEAD	112	/* size of minimum stack frame */
 
-/* Size of stack frame allocated when calling signal handler. */
-/* FIXME: What should this be on 64-bit kernel (64 for 32-bit) */
-#define __SIGNAL_FRAMESIZE	64
+/* Size of dummy stack frame allocated when calling signal handler. */
+#define __SIGNAL_FRAMESIZE	128
 #define __SIGNAL_FRAMESIZE32	64
 
 #define instruction_pointer(regs) ((regs)->nip)
diff -Nru a/include/asm-ppc64/rtas.h b/include/asm-ppc64/rtas.h
--- a/include/asm-ppc64/rtas.h	Thu Feb 13 00:47:26 2003
+++ b/include/asm-ppc64/rtas.h	Tue Mar 25 20:30:59 2003
@@ -166,8 +166,6 @@
 extern void rtas_power_off(void);
 extern void rtas_halt(void);
 
-extern struct proc_dir_entry *rtas_proc_dir;
-
 /* Some RTAS ops require a data buffer and that buffer must be < 4G.
  * Rather than having a memory allocator, just use this buffer
  * (get the lock first), make the RTAS call.  Copy the data instead
diff -Nru a/include/asm-ppc64/sigcontext.h b/include/asm-ppc64/sigcontext.h
--- a/include/asm-ppc64/sigcontext.h	Mon Oct  7 23:57:08 2002
+++ b/include/asm-ppc64/sigcontext.h	Tue Mar 25 19:38:55 2003
@@ -9,6 +9,8 @@
  */
 
 #include <asm/ptrace.h>
+#include <asm/elf.h>
+
 
 struct sigcontext {
 	unsigned long	_unused[4];
@@ -16,7 +18,9 @@
 	int		_pad0;
 	unsigned long	handler;
 	unsigned long	oldmask;
-	struct pt_regs 	*regs;
+	struct pt_regs	*regs;
+	elf_gregset_t	gp_regs;
+	elf_fpregset_t	fp_regs;
 };
 
 #endif /* _ASM_PPC64_SIGCONTEXT_H */
diff -Nru a/include/asm-ppc64/systemcfg.h b/include/asm-ppc64/systemcfg.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/asm-ppc64/systemcfg.h	Tue Mar 25 20:31:00 2003
@@ -0,0 +1,109 @@
+#ifndef _SYSTEMCFG_H
+#define _SYSTEMCFG_H
+
+/* 
+ * Copyright (C) 2002 Peter Bergner <bergner@vnet.ibm.com>, IBM
+ *
+ * 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.
+ */
+
+/* Change Activity:
+ * 2002/09/30 : bergner  : Created
+ * End Change Activity 
+ */
+
+
+#ifndef __KERNEL__
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <linux/types.h>
+#endif
+
+/*
+ * If the major version changes we are incompatible.
+ * Minor version changes are a hint.
+ */
+#define SYSTEMCFG_MAJOR 1
+#define SYSTEMCFG_MINOR 0
+
+#ifndef __ASSEMBLY__
+
+struct systemcfg {
+	__u8  eye_catcher[16];		/* Eyecatcher: SYSTEMCFG:PPC64	0x00 */
+	struct {			/* Systemcfg version numbers	     */
+		__u32 major;		/* Major number			0x10 */
+		__u32 minor;		/* Minor number			0x14 */
+	} version;
+
+	__u32 platform;			/* Platform flags		0x18 */
+	__u32 processor;		/* Processor type		0x1C */
+	__u64 processorCount;		/* # of physical processors	0x20 */
+	__u64 physicalMemorySize;	/* Size of real memory(B)	0x28 */
+	__u64 tb_orig_stamp;		/* Timebase at boot		0x30 */
+	__u64 tb_ticks_per_sec;		/* Timebase tics / sec		0x38 */
+	__u64 tb_to_xs;			/* Inverse of TB to 2^20	0x40 */
+	__u64 stamp_xsec;		/*				0x48 */
+	__u64 tb_update_count;		/* Timebase atomicity ctr	0x50 */
+	__u32 tz_minuteswest;		/* Minutes west of Greenwich	0x58 */
+	__u32 tz_dsttime;		/* Type of dst correction	0x5C */
+	__u32 dCacheL1Size;		/* L1 d-cache size		0x60 */
+	__u32 dCacheL1LineSize;		/* L1 d-cache line size		0x64 */
+	__u32 iCacheL1Size;		/* L1 i-cache size		0x68 */
+	__u32 iCacheL1LineSize;		/* L1 i-cache line size		0x6C */
+	__u8  reserved0[3984];		/* Reserve rest of page		0x70 */
+};
+
+#ifdef __KERNEL__
+extern struct systemcfg *systemcfg;
+#else
+
+/* Processor Version Register (PVR) field extraction */
+#define PVR_VER(pvr)  (((pvr) >>  16) & 0xFFFF) /* Version field */
+#define PVR_REV(pvr)  (((pvr) >>   0) & 0xFFFF) /* Revison field */
+
+/* Processor Version Numbers */
+#define PV_NORTHSTAR    0x0033
+#define PV_PULSAR       0x0034
+#define PV_POWER4       0x0035
+#define PV_ICESTAR      0x0036
+#define PV_SSTAR        0x0037
+#define PV_POWER4p      0x0038
+#define PV_630          0x0040
+#define PV_630p         0x0041
+
+/* Platforms supported by PPC64 */
+#define PLATFORM_PSERIES      0x0100
+#define PLATFORM_PSERIES_LPAR 0x0101
+#define PLATFORM_ISERIES_LPAR 0x0201
+
+
+static inline volatile struct systemcfg *systemcfg_init(void)
+{
+	int fd = open("/proc/ppc64/systemcfg", O_RDONLY);
+	volatile struct systemcfg *ret;
+
+	if (fd == -1)
+		return 0;
+	ret = mmap(0, sizeof(struct systemcfg), PROT_READ, MAP_SHARED, fd, 0);
+	close(fd);
+	if (!ret)
+		return 0;
+	if (ret->version.major != SYSTEMCFG_MAJOR || ret->version.minor < SYSTEMCFG_MINOR) {
+		munmap((void *)ret, sizeof(struct systemcfg));
+		return 0;
+	}
+	return ret;
+}
+#endif /* __KERNEL__ */
+
+#endif /* __ASSEMBLY__ */
+
+#define SYSTEMCFG_PAGE      0x5
+#define SYSTEMCFG_PHYS_ADDR (SYSTEMCFG_PAGE<<PAGE_SHIFT)
+#define SYSTEMCFG_VIRT_ADDR (KERNELBASE+SYSTEMCFG_PHYS_ADDR)
+
+#endif /* _SYSTEMCFG_H */
diff -Nru a/include/asm-ppc64/topology.h b/include/asm-ppc64/topology.h
--- a/include/asm-ppc64/topology.h	Wed Mar 12 15:19:15 2003
+++ b/include/asm-ppc64/topology.h	Thu Apr 24 13:05:36 2003
@@ -20,32 +20,23 @@
 	return node;
 }
 
-static inline int node_to_first_cpu(int node)
-{
-	int cpu;
+#define memblk_to_node(memblk)	(memblk)
 
-	for(cpu = 0; cpu < NR_CPUS; cpu++)
-		if (numa_cpu_lookup_table[cpu] == node)
-			return cpu;
-
-	BUG(); /* couldn't find a cpu on given node */
-	return -1;
-}
+#define parent_node(node)	(node)
 
 static inline unsigned long node_to_cpumask(int node)
 {
-	int cpu;
-	unsigned long mask = 0UL;
+	return numa_cpumask_lookup_table[node];
+}
 
-	if (sizeof(unsigned long) * 8 < NR_CPUS)
-		BUG();
+static inline int node_to_first_cpu(int node)
+{
+	return __ffs(node_to_cpumask(node));
+}
 
-	for(cpu = 0; cpu < NR_CPUS; cpu++)
-		if (numa_cpu_lookup_table[cpu] == node)
-			mask |= 1UL << cpu;
+#define node_to_memblk(node)	(node)
 
-	return mask;
-}
+#define pcibus_to_cpumask(bus)	(cpu_online_map)
 
 /* Cross-node load balancing interval. */
 #define NODE_BALANCE_RATE 10
diff -Nru a/include/asm-ppc64/types.h b/include/asm-ppc64/types.h
--- a/include/asm-ppc64/types.h	Mon Dec 30 20:14:21 2002
+++ b/include/asm-ppc64/types.h	Tue Mar 25 19:38:55 2003
@@ -66,6 +66,11 @@
 typedef u32 dma_addr_t;
 typedef u64 dma64_addr_t;
 
+typedef struct {
+	unsigned long entry;
+	unsigned long toc;
+	unsigned long env;
+} func_descr_t;
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
diff -Nru a/include/asm-ppc64/ucontext.h b/include/asm-ppc64/ucontext.h
--- a/include/asm-ppc64/ucontext.h	Wed Sep 25 07:02:10 2002
+++ b/include/asm-ppc64/ucontext.h	Tue Mar 25 19:38:55 2003
@@ -1,8 +1,9 @@
 #ifndef _ASMPPC64_UCONTEXT_H
 #define _ASMPPC64_UCONTEXT_H
 
-/* Copied from i386. 
- *
+#include <asm/sigcontext.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
@@ -13,8 +14,9 @@
 	unsigned long	  uc_flags;
 	struct ucontext  *uc_link;
 	stack_t		  uc_stack;
-	struct sigcontext uc_mcontext;
-	sigset_t	  uc_sigmask;	/* mask last for extensibility */
+	sigset_t	  uc_sigmask;
+	sigset_t	  __unsued[15];	/* Allow for uc_sigmask growth */
+	struct sigcontext uc_mcontext;  /* last for extensibility */
 };
 
 #endif /* _ASMPPC64_UCONTEXT_H */
diff -Nru a/include/asm-ppc64/unistd.h b/include/asm-ppc64/unistd.h
--- a/include/asm-ppc64/unistd.h	Sat Feb 22 00:17:10 2003
+++ b/include/asm-ppc64/unistd.h	Fri Mar 28 10:58:33 2003
@@ -260,7 +260,7 @@
 #define __NR_clock_getres	247
 #define __NR_clock_nanosleep	248
 
-#define __NR_syscalls		249
+#define __NR_syscalls		239
 #ifdef __KERNEL__
 #define NR_syscalls	__NR_syscalls
 #endif
diff -Nru a/include/asm-ppc64/xics.h b/include/asm-ppc64/xics.h
--- a/include/asm-ppc64/xics.h	Sun Dec 15 17:18:19 2002
+++ b/include/asm-ppc64/xics.h	Thu Mar 27 22:31:06 2003
@@ -12,7 +12,17 @@
 #ifndef _PPC64_KERNEL_XICS_H
 #define _PPC64_KERNEL_XICS_H
 
+#include <linux/cache.h>
+
 void xics_init_IRQ(void);
 int xics_get_irq(struct pt_regs *);
+void xics_setup_cpu(void);
+void xics_cause_IPI(int cpu);
+
+struct xics_ipi_struct {
+	volatile unsigned long value;
+} ____cacheline_aligned;
+
+extern struct xics_ipi_struct xics_ipi_message[NR_CPUS] __cacheline_aligned;
 
 #endif /* _PPC64_KERNEL_XICS_H */
diff -Nru a/include/asm-s390/elf.h b/include/asm-s390/elf.h
--- a/include/asm-s390/elf.h	Mon Apr 14 12:11:58 2003
+++ b/include/asm-s390/elf.h	Mon May 12 07:06:05 2003
@@ -9,6 +9,84 @@
 #ifndef __ASMS390_ELF_H
 #define __ASMS390_ELF_H
 
+/* s390 relocations defined by the ABIs */
+#define R_390_NONE		0	/* No reloc.  */
+#define R_390_8			1	/* Direct 8 bit.  */
+#define R_390_12		2	/* Direct 12 bit.  */
+#define R_390_16		3	/* Direct 16 bit.  */
+#define R_390_32		4	/* Direct 32 bit.  */
+#define R_390_PC32		5	/* PC relative 32 bit.	*/
+#define R_390_GOT12		6	/* 12 bit GOT offset.  */
+#define R_390_GOT32		7	/* 32 bit GOT offset.  */
+#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
+#define R_390_COPY		9	/* Copy symbol at runtime.  */
+#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
+#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
+#define R_390_RELATIVE		12	/* Adjust by program base.  */
+#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
+#define R_390_GOTPC		14	/* 32 bit PC rel. offset to GOT.  */
+#define R_390_GOT16		15	/* 16 bit GOT offset.  */
+#define R_390_PC16		16	/* PC relative 16 bit.	*/
+#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
+#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
+#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
+#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
+#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
+#define R_390_64		22	/* Direct 64 bit.  */
+#define R_390_PC64		23	/* PC relative 64 bit.	*/
+#define R_390_GOT64		24	/* 64 bit GOT offset.  */
+#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
+#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
+#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
+#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
+#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
+#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
+#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
+#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
+#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
+#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
+#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
+#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
+#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code. */
+#define R_390_TLS_GDCALL	38	/* Tag for function call in general
+                                           dynamic TLS code.  */
+#define R_390_TLS_LDCALL	39	/* Tag for function call in local
+                                           dynamic TLS code.  */
+#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
+                                           thread local data.  */
+#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
+                                           thread local data.  */
+#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
+                                           block offset.  */
+#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
+                                           block offset.  */
+#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
+                                           block offset.  */
+#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
+                                           thread local data in LD code.  */
+#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
+                                           thread local data in LD code.  */
+#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
+                                           negated static TLS block offset.  */
+#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
+                                           negated static TLS block offset.  */
+#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
+                                           negated static TLS block offset.  */
+#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
+                                           static TLS block.  */
+#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
+                                           static TLS block.  */
+#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
+                                           block.  */
+#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
+                                           block.  */
+#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
+#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.  */
+#define R_390_TLS_TPOFF		56	/* Negate offset in static TLS
+                                           block.  */
+/* Keep this the last entry.  */
+#define R_390_NUM	57
+
 /*
  * ELF register definitions..
  */
diff -Nru a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h
--- a/include/asm-s390/hardirq.h	Mon Apr 14 12:11:44 2003
+++ b/include/asm-s390/hardirq.h	Mon May 12 18:59:24 2003
@@ -82,7 +82,7 @@
 
 #define invoke_softirq() do_call_softirq()
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	(in_interrupt() || preempt_count() == PREEMPT_ACTIVE)
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-sparc/bitops.h b/include/asm-sparc/bitops.h
--- a/include/asm-sparc/bitops.h	Sat Apr 12 15:37:38 2003
+++ b/include/asm-sparc/bitops.h	Mon May 19 17:35:17 2003
@@ -20,7 +20,7 @@
  * within the first byte. Sparc is BIG-Endian. Unless noted otherwise
  * all bit-ops return 0 if bit was previously clear and != 0 otherwise.
  */
-static __inline__ int test_and_set_bit(unsigned long nr, volatile void *addr)
+static __inline__ int test_and_set_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	register unsigned long mask asm("g2");
 	register unsigned long *ADDR asm("g1");
@@ -39,7 +39,7 @@
 	return mask != 0;
 }
 
-static __inline__ void set_bit(unsigned long nr, volatile void *addr)
+static __inline__ void set_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	register unsigned long mask asm("g2");
 	register unsigned long *ADDR asm("g1");
@@ -56,7 +56,7 @@
 	: "g3", "g4", "g5", "g7", "cc");
 }
 
-static __inline__ int test_and_clear_bit(unsigned long nr, volatile void *addr)
+static __inline__ int test_and_clear_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	register unsigned long mask asm("g2");
 	register unsigned long *ADDR asm("g1");
@@ -75,7 +75,7 @@
 	return mask != 0;
 }
 
-static __inline__ void clear_bit(unsigned long nr, volatile void *addr)
+static __inline__ void clear_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	register unsigned long mask asm("g2");
 	register unsigned long *ADDR asm("g1");
@@ -92,7 +92,7 @@
 	: "g3", "g4", "g5", "g7", "cc");
 }
 
-static __inline__ int test_and_change_bit(unsigned long nr, volatile void *addr)
+static __inline__ int test_and_change_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	register unsigned long mask asm("g2");
 	register unsigned long *ADDR asm("g1");
@@ -111,7 +111,7 @@
 	return mask != 0;
 }
 
-static __inline__ void change_bit(unsigned long nr, volatile void *addr)
+static __inline__ void change_bit(unsigned long nr, volatile unsigned long *addr)
 {
 	register unsigned long mask asm("g2");
 	register unsigned long *ADDR asm("g1");
@@ -131,7 +131,7 @@
 /*
  * non-atomic versions
  */
-static __inline__ void __set_bit(int nr, volatile void *addr)
+static __inline__ void __set_bit(int nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x1f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -139,7 +139,7 @@
 	*p |= mask;
 }
 
-static __inline__ void __clear_bit(int nr, volatile void *addr)
+static __inline__ void __clear_bit(int nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x1f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -147,7 +147,7 @@
 	*p &= ~mask;
 }
 
-static __inline__ void __change_bit(int nr, volatile void *addr)
+static __inline__ void __change_bit(int nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x1f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -155,7 +155,7 @@
 	*p ^= mask;
 }
 
-static __inline__ int __test_and_set_bit(int nr, volatile void *addr)
+static __inline__ int __test_and_set_bit(int nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x1f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -165,7 +165,7 @@
 	return (old & mask) != 0;
 }
 
-static __inline__ int __test_and_clear_bit(int nr, volatile void *addr)
+static __inline__ int __test_and_clear_bit(int nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x1f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -175,7 +175,7 @@
 	return (old & mask) != 0;
 }
 
-static __inline__ int __test_and_change_bit(int nr, volatile void *addr)
+static __inline__ int __test_and_change_bit(int nr, volatile unsigned long *addr)
 {
 	unsigned long mask = 1UL << (nr & 0x1f);
 	unsigned long *p = ((unsigned long *)addr) + (nr >> 5);
@@ -189,9 +189,9 @@
 #define smp_mb__after_clear_bit()	do { } while(0)
 
 /* The following routine need not be atomic. */
-static __inline__ int test_bit(int nr, __const__ void *addr)
+static __inline__ int test_bit(int nr, __const__ volatile unsigned long *addr)
 {
-	return (1 & (((__const__ unsigned int *) addr)[nr >> 5] >> (nr & 31))) != 0;
+	return (1UL & (((unsigned long *)addr)[nr >> 5] >> (nr & 31))) != 0UL;
 }
 
 /* The easy/cheese version for now. */
@@ -288,9 +288,10 @@
  * 'size' bits, starting the search at bit 'offset'. This is largely based
  * on Linus's ALPHA routines, which are pretty portable BTW.
  */
-static __inline__ unsigned long find_next_zero_bit(void *addr, unsigned long size, unsigned long offset)
+static __inline__ unsigned long find_next_zero_bit(unsigned long *addr,
+    unsigned long size, unsigned long offset)
 {
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+	unsigned long *p = addr + (offset >> 5);
 	unsigned long result = offset & ~31UL;
 	unsigned long tmp;
 
@@ -361,7 +362,7 @@
 
 /*
  */
-static __inline__ int test_le_bit(int nr, __const__ void * addr)
+static __inline__ int test_le_bit(int nr, __const__ unsigned long * addr)
 {
 	__const__ unsigned char *ADDR = (__const__ unsigned char *) addr;
 	return (ADDR[nr >> 3] >> (nr & 7)) & 1;
@@ -370,7 +371,7 @@
 /*
  * non-atomic versions
  */
-static __inline__ void __set_le_bit(int nr, void *addr)
+static __inline__ void __set_le_bit(int nr, unsigned long *addr)
 {
 	unsigned char *ADDR = (unsigned char *)addr;
 
@@ -378,7 +379,7 @@
 	*ADDR |= 1 << (nr & 0x07);
 }
 
-static __inline__ void __clear_le_bit(int nr, void *addr)
+static __inline__ void __clear_le_bit(int nr, unsigned long *addr)
 {
 	unsigned char *ADDR = (unsigned char *)addr;
 
@@ -386,7 +387,7 @@
 	*ADDR &= ~(1 << (nr & 0x07));
 }
 
-static __inline__ int __test_and_set_le_bit(int nr, void *addr)
+static __inline__ int __test_and_set_le_bit(int nr, unsigned long *addr)
 {
 	int mask, retval;
 	unsigned char *ADDR = (unsigned char *)addr;
@@ -398,7 +399,7 @@
 	return retval;
 }
 
-static __inline__ int __test_and_clear_le_bit(int nr, void *addr)
+static __inline__ int __test_and_clear_le_bit(int nr, unsigned long *addr)
 {
 	int mask, retval;
 	unsigned char *ADDR = (unsigned char *)addr;
@@ -410,9 +411,10 @@
 	return retval;
 }
 
-static __inline__ unsigned long find_next_zero_le_bit(void *addr, unsigned long size, unsigned long offset)
+static __inline__ unsigned long find_next_zero_le_bit(unsigned long *addr,
+    unsigned long size, unsigned long offset)
 {
-	unsigned long *p = ((unsigned long *) addr) + (offset >> 5);
+	unsigned long *p = addr + (offset >> 5);
 	unsigned long result = offset & ~31UL;
 	unsigned long tmp;
 
diff -Nru a/include/asm-sparc/bug.h b/include/asm-sparc/bug.h
--- a/include/asm-sparc/bug.h	Sun Jan  6 03:58:47 2002
+++ b/include/asm-sparc/bug.h	Sun May 18 03:11:54 2003
@@ -2,24 +2,18 @@
 #ifndef _SPARC_BUG_H
 #define _SPARC_BUG_H
 
-/*
- * XXX I am hitting compiler bugs with __builtin_trap. This has
- * hit me before and rusty was blaming his netfilter bugs on
- * this so lets disable it. - Anton
- */
-#if 0
-/* We need the mb()'s so we don't trigger a compiler bug - Anton */
-#define BUG() do { \
-	mb(); \
-	__builtin_trap(); \
-	mb(); \
-} while(0)
-#else
-#define BUG() do { \
-	printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); *(int *)0=0; \
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+extern void do_BUG(const char *file, int line);
+#define BUG() do {					\
+	do_BUG(__FILE__, __LINE__);			\
+	__builtin_trap();				\
 } while (0)
+#else
+#define BUG()		__builtin_trap()
 #endif
 
-#define PAGE_BUG(page)	BUG()
+#define PAGE_BUG(page) do { \
+	BUG(); \
+} while (0)
 
 #endif
diff -Nru a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h
--- a/include/asm-sparc/elf.h	Mon Dec  2 00:20:08 2002
+++ b/include/asm-sparc/elf.h	Mon May 12 07:04:39 2003
@@ -11,6 +11,63 @@
 #include <asm/mbus.h>
 #include <asm/uaccess.h>
 
+/*
+ * Sparc section types
+ */
+#define STT_REGISTER		13
+
+/*
+ * Sparc ELF relocation types
+ */
+#define	R_SPARC_NONE		0
+#define	R_SPARC_8		1
+#define	R_SPARC_16		2
+#define	R_SPARC_32		3
+#define	R_SPARC_DISP8		4
+#define	R_SPARC_DISP16		5
+#define	R_SPARC_DISP32		6
+#define	R_SPARC_WDISP30		7
+#define	R_SPARC_WDISP22		8
+#define	R_SPARC_HI22		9
+#define	R_SPARC_22		10
+#define	R_SPARC_13		11
+#define	R_SPARC_LO10		12
+#define	R_SPARC_GOT10		13
+#define	R_SPARC_GOT13		14
+#define	R_SPARC_GOT22		15
+#define	R_SPARC_PC10		16
+#define	R_SPARC_PC22		17
+#define	R_SPARC_WPLT30		18
+#define	R_SPARC_COPY		19
+#define	R_SPARC_GLOB_DAT	20
+#define	R_SPARC_JMP_SLOT	21
+#define	R_SPARC_RELATIVE	22
+#define	R_SPARC_UA32		23
+#define R_SPARC_PLT32		24
+#define R_SPARC_HIPLT22		25
+#define R_SPARC_LOPLT10		26
+#define R_SPARC_PCPLT32		27
+#define R_SPARC_PCPLT22		28
+#define R_SPARC_PCPLT10		29
+#define R_SPARC_10		30
+#define R_SPARC_11		31
+#define R_SPARC_64		32
+#define R_SPARC_OLO10		33
+#define R_SPARC_WDISP16		40
+#define R_SPARC_WDISP19		41
+#define R_SPARC_7		43
+#define R_SPARC_5		44
+#define R_SPARC_6		45
+
+/* Bits present in AT_HWCAP, primarily for Sparc32.  */
+
+#define HWCAP_SPARC_FLUSH       1    /* CPU supports flush instruction. */
+#define HWCAP_SPARC_STBAR       2
+#define HWCAP_SPARC_SWAP        4
+#define HWCAP_SPARC_MULDIV      8
+#define HWCAP_SPARC_V9		16
+#define HWCAP_SPARC_ULTRA3	32
+
 /* For the most part we present code dumps in the format
  * Solaris does.
  */
diff -Nru a/include/asm-sparc/hardirq.h b/include/asm-sparc/hardirq.h
--- a/include/asm-sparc/hardirq.h	Mon Dec  2 00:21:26 2002
+++ b/include/asm-sparc/hardirq.h	Mon May 12 18:59:24 2003
@@ -9,7 +9,6 @@
 
 #include <linux/config.h>
 #include <linux/threads.h>
-#include <linux/brlock.h>
 #include <linux/spinlock.h>
 #include <linux/cache.h>
 
@@ -90,7 +89,7 @@
 #ifndef CONFIG_SMP
 #define irq_enter()             (preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
@@ -116,7 +115,7 @@
 #define irq_exit()		br_read_unlock(BR_GLOBALIRQ_LOCK)
 #endif
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	(preempt_count() != kernel_locked())
 #else
 # define in_atomic()	(preempt_count() != 0)
diff -Nru a/include/asm-sparc/io-unit.h b/include/asm-sparc/io-unit.h
--- a/include/asm-sparc/io-unit.h	Tue Feb  5 09:39:48 2002
+++ b/include/asm-sparc/io-unit.h	Mon May 19 17:35:17 2003
@@ -41,7 +41,7 @@
 #define IOUPTE_PARITY        0x00000001 /* Parity is checked during DVMA	*/
 
 struct iounit_struct {
-	unsigned int		bmap[(IOUNIT_DMA_SIZE >> (PAGE_SHIFT + 3)) / sizeof(unsigned int)];
+	unsigned long		bmap[(IOUNIT_DMA_SIZE >> (PAGE_SHIFT + 3)) / sizeof(unsigned long)];
 	spinlock_t		lock;
 	iopte_t			*page_table;
 	unsigned long		rotor[3];
diff -Nru a/include/asm-sparc/smp.h b/include/asm-sparc/smp.h
--- a/include/asm-sparc/smp.h	Mon Jan 27 10:32:45 2003
+++ b/include/asm-sparc/smp.h	Sun May 18 02:42:33 2003
@@ -169,9 +169,6 @@
 #endif
 
 #define smp_processor_id() hard_smp_processor_id()
-/* XXX We really need to implement this now.  -DaveM */
-extern __inline__ void smp_send_reschedule(int cpu) { }
-extern __inline__ void smp_send_stop(void) { }
 
 #endif /* !(__ASSEMBLY__) */
 
diff -Nru a/include/asm-sparc64/compat.h b/include/asm-sparc64/compat.h
--- a/include/asm-sparc64/compat.h	Tue Apr 15 22:48:21 2003
+++ b/include/asm-sparc64/compat.h	Mon May 19 23:31:53 2003
@@ -120,4 +120,15 @@
 	return (void *)(unsigned long)uptr;
 }
 
+static __inline__ void *compat_alloc_user_space(long len)
+{
+	struct pt_regs *regs = current_thread_info()->kregs;
+	unsigned long usp = regs->u_regs[UREG_I6];
+
+	if (!(test_thread_flag(TIF_32BIT)))
+		usp += STACK_BIAS;
+
+	return (void *) (usp - len);
+}
+
 #endif /* _ASM_SPARC64_COMPAT_H */
diff -Nru a/include/asm-sparc64/elf.h b/include/asm-sparc64/elf.h
--- a/include/asm-sparc64/elf.h	Sun Jan 19 00:08:32 2003
+++ b/include/asm-sparc64/elf.h	Mon May 12 07:04:53 2003
@@ -13,6 +13,63 @@
 #endif
 
 /*
+ * Sparc section types
+ */
+#define STT_REGISTER		13
+
+/*
+ * Sparc ELF relocation types
+ */
+#define	R_SPARC_NONE		0
+#define	R_SPARC_8		1
+#define	R_SPARC_16		2
+#define	R_SPARC_32		3
+#define	R_SPARC_DISP8		4
+#define	R_SPARC_DISP16		5
+#define	R_SPARC_DISP32		6
+#define	R_SPARC_WDISP30		7
+#define	R_SPARC_WDISP22		8
+#define	R_SPARC_HI22		9
+#define	R_SPARC_22		10
+#define	R_SPARC_13		11
+#define	R_SPARC_LO10		12
+#define	R_SPARC_GOT10		13
+#define	R_SPARC_GOT13		14
+#define	R_SPARC_GOT22		15
+#define	R_SPARC_PC10		16
+#define	R_SPARC_PC22		17
+#define	R_SPARC_WPLT30		18
+#define	R_SPARC_COPY		19
+#define	R_SPARC_GLOB_DAT	20
+#define	R_SPARC_JMP_SLOT	21
+#define	R_SPARC_RELATIVE	22
+#define	R_SPARC_UA32		23
+#define R_SPARC_PLT32		24
+#define R_SPARC_HIPLT22		25
+#define R_SPARC_LOPLT10		26
+#define R_SPARC_PCPLT32		27
+#define R_SPARC_PCPLT22		28
+#define R_SPARC_PCPLT10		29
+#define R_SPARC_10		30
+#define R_SPARC_11		31
+#define R_SPARC_64		32
+#define R_SPARC_OLO10		33
+#define R_SPARC_WDISP16		40
+#define R_SPARC_WDISP19		41
+#define R_SPARC_7		43
+#define R_SPARC_5		44
+#define R_SPARC_6		45
+
+/* Bits present in AT_HWCAP, primarily for Sparc32.  */
+
+#define HWCAP_SPARC_FLUSH       1    /* CPU supports flush instruction. */
+#define HWCAP_SPARC_STBAR       2
+#define HWCAP_SPARC_SWAP        4
+#define HWCAP_SPARC_MULDIV      8
+#define HWCAP_SPARC_V9		16
+#define HWCAP_SPARC_ULTRA3	32
+
+/*
  * These are used to set parameters in the core dumps.
  */
 #ifndef ELF_ARCH
diff -Nru a/include/asm-sparc64/hardirq.h b/include/asm-sparc64/hardirq.h
--- a/include/asm-sparc64/hardirq.h	Thu Feb 27 08:50:08 2003
+++ b/include/asm-sparc64/hardirq.h	Mon May 12 18:59:24 2003
@@ -8,7 +8,6 @@
 
 #include <linux/config.h>
 #include <linux/threads.h>
-#include <linux/brlock.h>
 #include <linux/spinlock.h>
 #include <linux/cache.h>
 
@@ -85,7 +84,7 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()	(preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-um/pgtable.h b/include/asm-um/pgtable.h
--- a/include/asm-um/pgtable.h	Thu Mar  6 08:19:09 2003
+++ b/include/asm-um/pgtable.h	Mon May 12 18:59:23 2003
@@ -71,7 +71,7 @@
 #define VMALLOC_START	(((unsigned long) high_physmem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1))
 #define VMALLOC_VMADDR(x) ((unsigned long)(x))
 
-#if CONFIG_HIGHMEM
+#ifdef CONFIG_HIGHMEM
 # define VMALLOC_END	(PKMAP_BASE-2*PAGE_SIZE)
 #else
 # define VMALLOC_END	(FIXADDR_START-2*PAGE_SIZE)
diff -Nru a/include/asm-v850/hardirq.h b/include/asm-v850/hardirq.h
--- a/include/asm-v850/hardirq.h	Sun Nov 24 17:34:44 2002
+++ b/include/asm-v850/hardirq.h	Mon May 12 18:59:24 2003
@@ -72,7 +72,7 @@
 
 #define irq_enter()		(preempt_count() += HARDIRQ_OFFSET)
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()    (preempt_count() != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/asm-x86_64/compat.h b/include/asm-x86_64/compat.h
--- a/include/asm-x86_64/compat.h	Tue Apr 15 22:48:21 2003
+++ b/include/asm-x86_64/compat.h	Mon May 19 23:31:54 2003
@@ -128,4 +128,10 @@
 	return (void *)(unsigned long)uptr;
 }
 
+static __inline__ void *compat_alloc_user_space(long len)
+{
+	struct pt_regs *regs = (void *)current->thread.rsp0 - sizeof(struct pt_regs); 
+	return (void *)regs->rsp - len; 
+}
+
 #endif /* _ASM_X86_64_COMPAT_H */
diff -Nru a/include/asm-x86_64/elf.h b/include/asm-x86_64/elf.h
--- a/include/asm-x86_64/elf.h	Mon Mar 17 21:31:50 2003
+++ b/include/asm-x86_64/elf.h	Mon May 12 07:06:23 2003
@@ -9,6 +9,27 @@
 #include <asm/user.h>
 #include <asm/processor.h>
 
+/* x86-64 relocation types */
+#define R_X86_64_NONE		0	/* No reloc */
+#define R_X86_64_64		1	/* Direct 64 bit  */
+#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
+#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
+#define R_X86_64_PLT32		4	/* 32 bit PLT address */
+#define R_X86_64_COPY		5	/* Copy symbol at runtime */
+#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
+#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
+#define R_X86_64_RELATIVE	8	/* Adjust by program base */
+#define R_X86_64_GOTPCREL	9	/* 32 bit signed pc relative
+					   offset to GOT */
+#define R_X86_64_32		10	/* Direct 32 bit zero extended */
+#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
+#define R_X86_64_16		12	/* Direct 16 bit zero extended */
+#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
+#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
+#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
+
+#define R_X86_64_NUM		16
+
 typedef unsigned long elf_greg_t;
 
 #define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t))
diff -Nru a/include/asm-x86_64/hardirq.h b/include/asm-x86_64/hardirq.h
--- a/include/asm-x86_64/hardirq.h	Tue Nov 12 15:13:39 2002
+++ b/include/asm-x86_64/hardirq.h	Mon May 12 18:59:23 2003
@@ -81,7 +81,7 @@
 #define nmi_exit()		(preempt_count() -= HARDIRQ_OFFSET)
 
 
-#if CONFIG_PREEMPT
+#ifdef CONFIG_PREEMPT
 # define in_atomic()   ((preempt_count() & ~PREEMPT_ACTIVE) != kernel_locked())
 # define IRQ_EXIT_OFFSET (HARDIRQ_OFFSET-1)
 #else
diff -Nru a/include/linux/agp_backend.h b/include/linux/agp_backend.h
--- a/include/linux/agp_backend.h	Wed Apr  9 15:56:26 2003
+++ b/include/linux/agp_backend.h	Sun Apr 27 13:43:59 2003
@@ -1,5 +1,6 @@
 /*
- * AGPGART module version 0.99
+ * AGPGART module version 0.100
+ * Copyright (C) 2002-2003 Dave Jones
  * Copyright (C) 1999 Jeff Hartmann
  * Copyright (C) 1999 Precision Insight, Inc.
  * Copyright (C) 1999 Xi Graphics, Inc.
@@ -37,45 +38,7 @@
 
 enum chipset_type {
 	NOT_SUPPORTED,
-	INTEL_GENERIC,
-	INTEL_LX,
-	INTEL_BX,
-	INTEL_GX,
-	INTEL_I810,
-	INTEL_I815,
-	INTEL_I820,
-	INTEL_I830_M,
-	INTEL_I845_G,
-	INTEL_I855_PM,
-	INTEL_I865_G,
-	INTEL_I840,
-	INTEL_I845,
-	INTEL_I850,
-	INTEL_I860,
-	INTEL_460GX,
-	INTEL_E7505,
-	VIA_GENERIC,
-	SIS_GENERIC,
-	AMD_GENERIC,
-	AMD_IRONGATE,
-	AMD_761,
-	AMD_762,
-	AMD_8151,
-	ALI_M1541,
-	ALI_M1621,
-	ALI_M1631,
-	ALI_M1632,
-	ALI_M1641,
-	ALI_M1644,
-	ALI_M1647,
-	ALI_M1651,
-	ALI_M1671,
-	ALI_GENERIC,
-	SVWRKS_HE,
-	SVWRKS_LE,
-	SVWRKS_GENERIC,
-	HP_ZX1,
-	ALPHA_CORE_AGP,
+	SUPPORTED,
 };
 
 struct agp_version {
@@ -98,16 +61,11 @@
 } agp_kern_info;
 
 /* 
- * The agp_memory structure has information
- * about the block of agp memory allocated.
- * A caller may manipulate the next and prev
- * pointers to link each allocated item into
- * a list.  These pointers are ignored by the 
- * backend.  Everything else should never be
- * written to, but the caller may read any of
- * the items to detrimine the status of this
- * block of agp memory.
- * 
+ * The agp_memory structure has information about the block of agp memory
+ * allocated.  A caller may manipulate the next and prev pointers to link
+ * each allocated item into a list.  These pointers are ignored by the backend.
+ * Everything else should never be written to, but the caller may read any of
+ * the items to detrimine the status of this block of agp memory. 
  */
 
 typedef struct _agp_memory {
@@ -127,126 +85,19 @@
 #define AGP_NORMAL_MEMORY 0
 
 extern void agp_free_memory(agp_memory *);
-
-/*
- * agp_free_memory :
- * 
- * This function frees memory associated with
- * an agp_memory pointer.  It is the only function
- * that can be called when the backend is not owned
- * by the caller.  (So it can free memory on client
- * death.)
- * 
- * It takes an agp_memory pointer as an argument.
- * 
- */
-
 extern agp_memory *agp_allocate_memory(size_t, u32);
-
-/*
- * agp_allocate_memory :
- * 
- * This function allocates a group of pages of
- * a certain type.
- * 
- * It takes a size_t argument of the number of pages, and
- * an u32 argument of the type of memory to be allocated.  
- * Every agp bridge device will allow you to allocate 
- * AGP_NORMAL_MEMORY which maps to physical ram.  Any other
- * type is device dependent.
- * 
- * It returns NULL whenever memory is unavailable.
- * 
- */
-
 extern int agp_copy_info(agp_kern_info *);
-
-/*
- * agp_copy_info :
- * 
- * This function copies information about the
- * agp bridge device and the state of the agp
- * backend into an agp_kern_info pointer.
- * 
- * It takes an agp_kern_info pointer as an
- * argument.  The caller should insure that
- * this pointer is valid.
- * 
- */
-
 extern int agp_bind_memory(agp_memory *, off_t);
-
-/*
- * agp_bind_memory :
- * 
- * This function binds an agp_memory structure
- * into the graphics aperture translation table.
- * 
- * It takes an agp_memory pointer and an offset into
- * the graphics aperture translation table as arguments
- * 
- * It returns -EINVAL if the pointer == NULL.
- * It returns -EBUSY if the area of the table
- * requested is already in use.
- * 
- */
-
 extern int agp_unbind_memory(agp_memory *);
-
-/* 
- * agp_unbind_memory :
- * 
- * This function removes an agp_memory structure
- * from the graphics aperture translation table.
- * 
- * It takes an agp_memory pointer as an argument.
- * 
- * It returns -EINVAL if this piece of agp_memory
- * is not currently bound to the graphics aperture
- * translation table or if the agp_memory 
- * pointer == NULL
- * 
- */
-
 extern void agp_enable(u32);
-
-/* 
- * agp_enable :
- * 
- * This function initializes the agp point-to-point
- * connection.
- * 
- * It takes an agp mode register as an argument
- * 
- */
-
 extern int agp_backend_acquire(void);
-
-/*
- * agp_backend_acquire :
- * 
- * This Function attempts to acquire the agp
- * backend.
- * 
- * returns -EBUSY if agp is in use,
- * returns 0 if the caller owns the agp backend
- */
-
 extern void agp_backend_release(void);
 
 /*
- * agp_backend_release :
- * 
- * This Function releases the lock on the agp
- * backend.
- * 
- * The caller must insure that the graphics
- * aperture translation table is read for use
- * by another entity.  (Ensure that all memory
- * it bound is unbound.)
- * 
+ * Interface between drm and agp code.  When agp initializes, it makes
+ * the below structure available via inter_module_register(), drm might
+ * use it.  Keith Owens <kaos@ocs.com.au> 28 Oct 2000.
  */
-
 typedef struct {
 	void       (*free_memory)(agp_memory *);
 	agp_memory *(*allocate_memory)(size_t, u32);
@@ -259,11 +110,5 @@
 } drm_agp_t;
 
 extern const drm_agp_t *drm_agp_p;
-
-/*
- * Interface between drm and agp code.  When agp initializes, it makes
- * the above structure available via inter_module_register(), drm might
- * use it.  Keith Owens <kaos@ocs.com.au> 28 Oct 2000.
- */
 
 #endif				/* _AGP_BACKEND_H */
diff -Nru a/include/linux/agpgart.h b/include/linux/agpgart.h
--- a/include/linux/agpgart.h	Mon Jul 15 10:24:13 2002
+++ b/include/linux/agpgart.h	Thu May  1 11:32:16 2003
@@ -27,17 +27,19 @@
 #ifndef _AGP_H
 #define _AGP_H 1
 
+#include <linux/agp_backend.h>
+
 #define AGPIOC_BASE       'A'
-#define AGPIOC_INFO       _IOR (AGPIOC_BASE, 0, agp_info*)
+#define AGPIOC_INFO       _IOR (AGPIOC_BASE, 0, struct agp_info*)
 #define AGPIOC_ACQUIRE    _IO  (AGPIOC_BASE, 1)
 #define AGPIOC_RELEASE    _IO  (AGPIOC_BASE, 2)
-#define AGPIOC_SETUP      _IOW (AGPIOC_BASE, 3, agp_setup*)
-#define AGPIOC_RESERVE    _IOW (AGPIOC_BASE, 4, agp_region*)
-#define AGPIOC_PROTECT    _IOW (AGPIOC_BASE, 5, agp_region*)
-#define AGPIOC_ALLOCATE   _IOWR(AGPIOC_BASE, 6, agp_allocate*)
+#define AGPIOC_SETUP      _IOW (AGPIOC_BASE, 3, struct agp_setup*)
+#define AGPIOC_RESERVE    _IOW (AGPIOC_BASE, 4, struct agp_region*)
+#define AGPIOC_PROTECT    _IOW (AGPIOC_BASE, 5, struct agp_region*)
+#define AGPIOC_ALLOCATE   _IOWR(AGPIOC_BASE, 6, struct agp_allocate*)
 #define AGPIOC_DEALLOCATE _IOW (AGPIOC_BASE, 7, int)
-#define AGPIOC_BIND       _IOW (AGPIOC_BASE, 8, agp_bind*)
-#define AGPIOC_UNBIND     _IOW (AGPIOC_BASE, 9, agp_unbind*)
+#define AGPIOC_BIND       _IOW (AGPIOC_BASE, 8, struct agp_bind*)
+#define AGPIOC_UNBIND     _IOW (AGPIOC_BASE, 9, struct agp_unbind*)
 
 #define AGP_DEVICE      "/dev/agpgart"
 
@@ -112,19 +114,7 @@
 
 #define AGPGART_MINOR 175
 
-#define AGP_UNLOCK()      	up(&(agp_fe.agp_mutex));
-#define AGP_LOCK()    		down(&(agp_fe.agp_mutex));
-#define AGP_LOCK_INIT() 	sema_init(&(agp_fe.agp_mutex), 1)
-
-#ifndef _AGP_BACKEND_H
-struct _agp_version {
-	u16 major;
-	u16 minor;
-} agp_version;
-
-#endif
-
-typedef struct _agp_info {
+struct agp_info {
 	struct agp_version version;	/* version of the driver        */
 	u32 bridge_id;		/* bridge vendor/device         */
 	u32 agp_mode;		/* mode info of bridge          */
@@ -133,34 +123,34 @@
 	size_t pg_total;	/* max pages (swap + system)    */
 	size_t pg_system;	/* max pages (system)           */
 	size_t pg_used;		/* current pages used           */
-} agp_info;
+};
 
-typedef struct _agp_setup {
+struct agp_setup {
 	u32 agp_mode;		/* mode info of bridge          */
-} agp_setup;
+};
 
 /*
  * The "prot" down below needs still a "sleep" flag somehow ...
  */
-typedef struct _agp_segment {
+struct agp_segment {
 	off_t pg_start;		/* starting page to populate    */
 	size_t pg_count;	/* number of pages              */
 	int prot;		/* prot flags for mmap          */
-} agp_segment;
+};
 
-typedef struct _agp_segment_priv {
+struct agp_segment_priv {
 	off_t pg_start;
 	size_t pg_count;
 	pgprot_t prot;
-} agp_segment_priv;
+};
 
-typedef struct _agp_region {
+struct agp_region {
 	pid_t pid;		/* pid of process               */
 	size_t seg_count;	/* number of segments           */
-	struct _agp_segment *seg_list;
-} agp_region;
+	struct agp_segment *seg_list;
+};
 
-typedef struct _agp_allocate {
+struct agp_allocate {
 	int key;		/* tag of allocation            */
 	size_t pg_count;	/* number of pages              */
 	u32 type;		/* 0 == normal, other devspec   */
@@ -168,34 +158,34 @@
 				 * need a phys address of the     
 				 * actual page behind the gatt    
 				 * table)                        */
-} agp_allocate;
+};
 
-typedef struct _agp_bind {
+struct agp_bind {
 	int key;		/* tag of allocation            */
 	off_t pg_start;		/* starting page to populate    */
-} agp_bind;
+};
 
-typedef struct _agp_unbind {
+struct agp_unbind {
 	int key;		/* tag of allocation            */
 	u32 priority;		/* priority for paging out      */
-} agp_unbind;
+};
 
-typedef struct _agp_client {
-	struct _agp_client *next;
-	struct _agp_client *prev;
+struct agp_client {
+	struct agp_client *next;
+	struct agp_client *prev;
 	pid_t pid;
 	int num_segments;
-	agp_segment_priv **segments;
-} agp_client;
+	struct agp_segment_priv **segments;
+};
 
-typedef struct _agp_controller {
-	struct _agp_controller *next;
-	struct _agp_controller *prev;
+struct agp_controller {
+	struct agp_controller *next;
+	struct agp_controller *prev;
 	pid_t pid;
 	int num_clients;
 	agp_memory *pool;
-	agp_client *clients;
-} agp_controller;
+	struct agp_client *clients;
+};
 
 #define AGP_FF_ALLOW_CLIENT		0
 #define AGP_FF_ALLOW_CONTROLLER 	1
@@ -203,18 +193,18 @@
 #define AGP_FF_IS_CONTROLLER		3
 #define AGP_FF_IS_VALID 		4
 
-typedef struct _agp_file_private {
-	struct _agp_file_private *next;
-	struct _agp_file_private *prev;
+struct agp_file_private {
+	struct agp_file_private *next;
+	struct agp_file_private *prev;
 	pid_t my_pid;
 	long access_flags;	/* long req'd for set_bit --RR */
-} agp_file_private;
+};
 
 struct agp_front_data {
 	struct semaphore agp_mutex;
-	agp_controller *current_controller;
-	agp_controller *controllers;
-	agp_file_private *file_priv_list;
+	struct agp_controller *current_controller;
+	struct agp_controller *controllers;
+	struct agp_file_private *file_priv_list;
 	u8 used_by_controller;
 	u8 backend_acquired;
 };
diff -Nru a/include/linux/atm_he.h b/include/linux/atm_he.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/atm_he.h	Wed May  7 01:47:26 2003
@@ -0,0 +1,20 @@
+/* atm_he.h */
+
+#ifndef LINUX_ATM_HE_H
+#define LINUX_ATM_HE_H
+
+#include <linux/atmioc.h>
+
+#define HE_GET_REG	_IOW('a', ATMIOC_SARPRV, struct atmif_sioc)
+
+#define HE_REGTYPE_PCI	1
+#define HE_REGTYPE_RCM	2
+#define HE_REGTYPE_TCM	3
+#define HE_REGTYPE_MBOX	4
+
+struct he_ioctl_reg {
+	unsigned addr, val;
+	char type;
+};
+
+#endif /* LINUX_ATM_HE_H */
diff -Nru a/include/linux/atmbr2684.h b/include/linux/atmbr2684.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/atmbr2684.h	Wed May  7 02:00:48 2003
@@ -0,0 +1,101 @@
+#ifndef _LINUX_ATMBR2684_H
+#define _LINUX_ATMBR2684_H
+
+#include <linux/atm.h>
+#include <linux/if.h>		/* For IFNAMSIZ */
+
+/*
+ * Type of media we're bridging (ethernet, token ring, etc)  Currently only
+ * ethernet is supported
+ */
+#define BR2684_MEDIA_ETHERNET	(0)	/* 802.3 */
+#define BR2684_MEDIA_802_4	(1)	/* 802.4 */
+#define BR2684_MEDIA_TR		(2)	/* 802.5 - token ring */
+#define BR2684_MEDIA_FDDI	(3)
+#define BR2684_MEDIA_802_6	(4)	/* 802.6 */
+
+/*
+ * Is there FCS inbound on this VC?  This currently isn't supported.
+ */
+#define BR2684_FCSIN_NO		(0)
+#define BR2684_FCSIN_IGNORE	(1)
+#define BR2684_FCSIN_VERIFY	(2)
+
+/*
+ * Is there FCS outbound on this VC?  This currently isn't supported.
+ */
+#define BR2684_FCSOUT_NO	(0)
+#define BR2684_FCSOUT_SENDZERO	(1)
+#define BR2684_FCSOUT_GENERATE	(2)
+
+/*
+ * Does this VC include LLC encapsulation?
+ */
+#define BR2684_ENCAPS_VC	(0)	/* VC-mux */
+#define BR2684_ENCAPS_LLC	(1)
+#define BR2684_ENCAPS_AUTODETECT (2)	/* Unsuported */
+
+/*
+ * This is for the ATM_NEWBACKENDIF call - these are like socket families:
+ * the first element of the structure is the backend number and the rest
+ * is per-backend specific
+ */
+struct atm_newif_br2684 {
+	atm_backend_t	backend_num;	/* ATM_BACKEND_BR2684 */
+	int		media;		/* BR2684_MEDIA_* */
+	char		ifname[IFNAMSIZ];
+	int		mtu;
+};
+
+/*
+ * This structure is used to specify a br2684 interface - either by a
+ * positive integer (returned by ATM_NEWBACKENDIF) or the interfaces name
+ */
+#define BR2684_FIND_BYNOTHING	(0)
+#define BR2684_FIND_BYNUM	(1)
+#define BR2684_FIND_BYIFNAME	(2)
+struct br2684_if_spec {
+	int method;			/* BR2684_FIND_* */
+	union {
+		char		ifname[IFNAMSIZ];
+		int		devnum;
+	} spec;
+};
+
+/*
+ * This is for the ATM_SETBACKEND call - these are like socket families:
+ * the first element of the structure is the backend number and the rest
+ * is per-backend specific
+ */
+struct atm_backend_br2684 {
+	atm_backend_t	backend_num;	/* ATM_BACKEND_BR2684 */
+	struct br2684_if_spec ifspec;
+	int	fcs_in;		/* BR2684_FCSIN_* */
+	int	fcs_out;	/* BR2684_FCSOUT_* */
+	int	fcs_auto;	/* 1: fcs_{in,out} disabled if no FCS rx'ed */
+	int	encaps;		/* BR2684_ENCAPS_* */
+	int	has_vpiid;	/* 1: use vpn_id - Unsupported */
+	__u8	vpn_id[7];
+	int	send_padding;	/* unsupported */
+	int	min_size;	/* we will pad smaller packets than this */
+};
+
+/*
+ * The BR2684_SETFILT ioctl is an experimental mechanism for folks
+ * terminating a large number of IP-only vcc's.  When netfilter allows
+ * efficient per-if in/out filters, this support will be removed
+ */
+struct br2684_filter {
+	__u32	prefix;		/* network byte order */
+	__u32	netmask;	/* 0 = disable filter */
+};
+
+struct br2684_filter_set {
+	struct br2684_if_spec ifspec;
+	struct br2684_filter filter;
+};
+
+#define BR2684_SETFILT	_IOW( 'a', ATMIOC_BACKEND + 0, \
+				struct br2684_filter_set)
+
+#endif /* _LINUX_ATMBR2684_H */
diff -Nru a/include/linux/atmdev.h b/include/linux/atmdev.h
--- a/include/linux/atmdev.h	Sat Mar  8 13:09:15 2003
+++ b/include/linux/atmdev.h	Thu May 15 17:20:17 2003
@@ -30,9 +30,6 @@
 #define ATM_DS3_PCR	(8000*12)
 			/* DS3: 12 cells in a 125 usec time slot */
 
-#define ATM_PDU_OVHD	0	/* number of bytes to charge against buffer
-				   quota per PDU */
-
 #define atm_sk(__sk) ((struct atm_vcc *)(__sk)->protinfo)
 #define ATM_SD(s)	(atm_sk((s)->sk))
 
@@ -96,6 +93,8 @@
 					/* enable or disable single-copy */
 #define ATM_SETBACKEND	_IOW('a',ATMIOC_SPECIAL+2,atm_backend_t)
 					/* set backend handler */
+#define ATM_NEWBACKENDIF _IOW('a',ATMIOC_SPECIAL+3,atm_backend_t)
+					/* use backend to make new if */
 
 /*
  * These are backend handkers that can be set via the ATM_SETBACKEND call
@@ -104,7 +103,7 @@
  */
 #define ATM_BACKEND_RAW		0	
 #define ATM_BACKEND_PPP		1	/* PPPoATM - RFC2364 */
-#define ATM_BACKEND_BR_2684	2	/* Bridged RFC1483/2684 */
+#define ATM_BACKEND_BR2684	2	/* Bridged RFC1483/2684 */
 
 /* for ATM_GETTYPE */
 #define ATM_ITFTYP_LEN	8	/* maximum length of interface type name */
@@ -287,10 +286,6 @@
 	struct atm_sap	sap;		/* SAP */
 	void (*push)(struct atm_vcc *vcc,struct sk_buff *skb);
 	void (*pop)(struct atm_vcc *vcc,struct sk_buff *skb); /* optional */
-	struct sk_buff *(*alloc_tx)(struct atm_vcc *vcc,unsigned int size);
-					/* TX allocation routine - can be */
-					/* modified by protocol or by driver.*/
-					/* NOTE: this interface will change */
 	int (*push_oam)(struct atm_vcc *vcc,void *cell);
 	int (*send)(struct atm_vcc *vcc,struct sk_buff *skb);
 	void		*dev_data;	/* per-device data */
@@ -304,9 +299,6 @@
 	struct sockaddr_atmsvc local;
 	struct sockaddr_atmsvc remote;
 	void (*callback)(struct atm_vcc *vcc);
-	struct sk_buff_head listenq;
-	int		backlog_quota;	/* number of connection requests we */
-					/* can still accept */
 	int		reply;		/* also used by ATMTCP */
 	/* Multipoint part ------------------------------------------------- */
 	struct atm_vcc	*session;	/* session VCC descriptor */
@@ -339,6 +331,8 @@
 	struct k_atm_dev_stats stats;	/* statistics */
 	char		signal;		/* signal status (ATM_PHY_SIG_*) */
 	int		link_rate;	/* link rate (default: OC3) */
+	atomic_t	refcnt;		/* reference count */
+	spinlock_t	lock;		/* protect internal members */
 #ifdef CONFIG_PROC_FS
 	struct proc_dir_entry *proc_entry; /* proc entry */
 	char *proc_name;		/* proc entry name */
@@ -379,8 +373,6 @@
 	void (*feedback)(struct atm_vcc *vcc,struct sk_buff *skb,
 	    unsigned long start,unsigned long dest,int len);
 	int (*change_qos)(struct atm_vcc *vcc,struct atm_qos *qos,int flags);
-	void (*free_rx_skb)(struct atm_vcc *vcc, struct sk_buff *skb);
-		/* @@@ temporary hack */
 	int (*proc_read)(struct atm_dev *dev,loff_t *pos,char *page);
 	struct module *owner;
 };
@@ -395,7 +387,6 @@
 
 struct atm_skb_data {
 	struct atm_vcc	*vcc;		/* ATM VCC */
-	int		iovcnt;		/* 0 for "normal" operation */
 	unsigned long	atm_options;	/* ATM layer options */
 };
 
@@ -403,7 +394,7 @@
 
 struct atm_dev *atm_dev_register(const char *type,const struct atmdev_ops *ops,
     int number,unsigned long *flags); /* number == -1: pick first available */
-struct atm_dev *atm_find_dev(int number);
+struct atm_dev *atm_dev_lookup(int number);
 void atm_dev_deregister(struct atm_dev *dev);
 void shutdown_atm_dev(struct atm_dev *dev);
 void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev);
@@ -414,27 +405,43 @@
  *
  */
 
-static __inline__ int atm_guess_pdu2truesize(int pdu_size)
+static inline int atm_guess_pdu2truesize(int pdu_size)
 {
 	return ((pdu_size+15) & ~15) + sizeof(struct sk_buff);
 }
 
 
-static __inline__ void atm_force_charge(struct atm_vcc *vcc,int truesize)
+static inline void atm_force_charge(struct atm_vcc *vcc,int truesize)
+{
+	atomic_add(truesize, &vcc->sk->rmem_alloc);
+}
+
+
+static inline void atm_return(struct atm_vcc *vcc,int truesize)
 {
-	atomic_add(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc);
+	atomic_sub(truesize, &vcc->sk->rmem_alloc);
 }
 
 
-static __inline__ void atm_return(struct atm_vcc *vcc,int truesize)
+static inline int atm_may_send(struct atm_vcc *vcc,unsigned int size)
 {
-	atomic_sub(truesize+ATM_PDU_OVHD,&vcc->sk->rmem_alloc);
+	return (size + atomic_read(&vcc->sk->wmem_alloc)) < vcc->sk->sndbuf;
 }
 
 
-static __inline__ int atm_may_send(struct atm_vcc *vcc,unsigned int size)
+static inline void atm_dev_hold(struct atm_dev *dev)
 {
-	return size+atomic_read(&vcc->sk->wmem_alloc)+ATM_PDU_OVHD < vcc->sk->sndbuf;
+	atomic_inc(&dev->refcnt);
+}
+
+
+static inline void atm_dev_release(struct atm_dev *dev)
+{
+	atomic_dec(&dev->refcnt);
+
+	if ((atomic_read(&dev->refcnt) == 1) &&
+	    test_bit(ATM_DF_CLOSE,&dev->flags))
+		shutdown_atm_dev(dev);
 }
 
 
diff -Nru a/include/linux/bio.h b/include/linux/bio.h
--- a/include/linux/bio.h	Wed Apr  2 22:51:00 2003
+++ b/include/linux/bio.h	Thu May  8 02:30:11 2003
@@ -131,6 +131,7 @@
 #define bio_iovec(bio)		bio_iovec_idx((bio), (bio)->bi_idx)
 #define bio_page(bio)		bio_iovec((bio))->bv_page
 #define bio_offset(bio)		bio_iovec((bio))->bv_offset
+#define bio_segments(bio)	((bio)->bi_vcnt - (bio)->bi_idx)
 #define bio_sectors(bio)	((bio)->bi_size >> 9)
 #define bio_cur_sectors(bio)	(bio_iovec(bio)->bv_len >> 9)
 #define bio_data(bio)		(page_address(bio_page((bio))) + bio_offset((bio)))
@@ -226,12 +227,12 @@
 #ifdef CONFIG_HIGHMEM
 /*
  * remember to add offset! and never ever reenable interrupts between a
- * bio_kmap_irq and bio_kunmap_irq!!
+ * bvec_kmap_irq and bvec_kunmap_irq!!
  *
  * This function MUST be inlined - it plays with the CPU interrupt flags.
  * Hence the `extern inline'.
  */
-extern inline char *bio_kmap_irq(struct bio *bio, unsigned long *flags)
+extern inline char *bvec_kmap_irq(struct bio_vec *bvec, unsigned long *flags)
 {
 	unsigned long addr;
 
@@ -240,15 +241,15 @@
 	 * balancing is a lot nicer this way
 	 */
 	local_irq_save(*flags);
-	addr = (unsigned long) kmap_atomic(bio_page(bio), KM_BIO_SRC_IRQ);
+	addr = (unsigned long) kmap_atomic(bvec->bv_page, KM_BIO_SRC_IRQ);
 
 	if (addr & ~PAGE_MASK)
 		BUG();
 
-	return (char *) addr + bio_offset(bio);
+	return (char *) addr + bvec->bv_offset;
 }
 
-extern inline void bio_kunmap_irq(char *buffer, unsigned long *flags)
+extern inline void bvec_kunmap_irq(char *buffer, unsigned long *flags)
 {
 	unsigned long ptr = (unsigned long) buffer & PAGE_MASK;
 
@@ -257,8 +258,19 @@
 }
 
 #else
-#define bio_kmap_irq(bio, flags)	(bio_data(bio))
-#define bio_kunmap_irq(buf, flags)	do { *(flags) = 0; } while (0)
+#define bvec_kmap_irq(bvec, flags)	(page_address((bvec)->bv_page) + (bvec)->bv_offset)
+#define bvec_kunmap_irq(buf, flags)	do { *(flags) = 0; } while (0)
 #endif
+
+extern inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx,
+				   unsigned long *flags)
+{
+	return bvec_kmap_irq(bio_iovec_idx(bio, idx), flags);
+}
+#define __bio_kunmap_irq(buf, flags)	bvec_kunmap_irq(buf, flags)
+
+#define bio_kmap_irq(bio, flags) \
+	__bio_kmap_irq((bio), (bio)->bi_idx, (flags))
+#define bio_kunmap_irq(buf,flags)	__bio_kunmap_irq(buf, flags)
 
 #endif /* __LINUX_BIO_H */
diff -Nru a/include/linux/blkdev.h b/include/linux/blkdev.h
--- a/include/linux/blkdev.h	Thu May  1 10:21:03 2003
+++ b/include/linux/blkdev.h	Thu May  8 02:30:11 2003
@@ -10,6 +10,8 @@
 #include <linux/pagemap.h>
 #include <linux/backing-dev.h>
 #include <linux/wait.h>
+#include <linux/mempool.h>
+#include <linux/bio.h>
 
 #include <asm/scatterlist.h>
 
@@ -18,10 +20,12 @@
 struct elevator_s;
 typedef struct elevator_s elevator_t;
 
+#define BLKDEV_MIN_RQ	4
+#define BLKDEV_MAX_RQ	128
+
 struct request_list {
-	unsigned int count;
-	struct list_head free;
-	wait_queue_head_t wait;
+	int count[2];
+	mempool_t *rq_pool;
 };
 
 /*
@@ -33,25 +37,35 @@
 				     * blkdev_dequeue_request! */
 	unsigned long flags;		/* see REQ_ bits below */
 
-	sector_t sector;
-	unsigned long nr_sectors;
+	/* Maintain bio traversal state for part by part I/O submission.
+	 * hard_* are block layer internals, no driver should touch them!
+	 */
+
+	sector_t sector;		/* next sector to submit */
+	unsigned long nr_sectors;	/* no. of sectors left to submit */
+	/* no. of sectors left to submit in the current segment */
 	unsigned int current_nr_sectors;
 
+	sector_t hard_sector;		/* next sector to complete */
+	unsigned long hard_nr_sectors;	/* no. of sectors left to complete */
+	/* no. of sectors left to complete in the current segment */
+	unsigned int hard_cur_sectors;
+
+	/* no. of segments left to submit in the current bio */
+	unsigned short nr_cbio_segments;
+	/* no. of sectors left to submit in the current bio */
+	unsigned long nr_cbio_sectors;
+
+	struct bio *cbio;		/* next bio to submit */
+	struct bio *bio;		/* next unfinished bio to complete */
+	struct bio *biotail;
+
 	void *elevator_private;
 
 	int rq_status;	/* should split this into a few status bits */
 	struct gendisk *rq_disk;
 	int errors;
 	unsigned long start_time;
-	sector_t hard_sector;		/* the hard_* are block layer
-					 * internals, no driver should
-					 * touch them
-					 */
-	unsigned long hard_nr_sectors;
-	unsigned int hard_cur_sectors;
-
-	struct bio *bio;
-	struct bio *biotail;
 
 	/* Number of scatter-gather DMA addr+len pairs after
 	 * physical address coalescing is performed.
@@ -180,7 +194,7 @@
 	/*
 	 * the queue request freelist, one for reads and one for writes
 	 */
-	struct request_list	rq[2];
+	struct request_list	rq;
 
 	request_fn_proc		*request_fn;
 	merge_request_fn	*back_merge_fn;
@@ -281,6 +295,32 @@
  */
 #define blk_queue_headactive(q, head_active)
 
+/* current index into bio being processed for submission */
+#define blk_rq_idx(rq)	((rq)->cbio->bi_vcnt - (rq)->nr_cbio_segments)
+
+/* current bio vector being processed */
+#define blk_rq_vec(rq)	(bio_iovec_idx((rq)->cbio, blk_rq_idx(rq)))
+
+/* current offset with respect to start of the segment being submitted */
+#define blk_rq_offset(rq) \
+	(((rq)->hard_cur_sectors - (rq)->current_nr_sectors) << 9)
+
+/*
+ * temporarily mapping a (possible) highmem bio (typically for PIO transfer)
+ */
+
+/* Assumes rq->cbio != NULL */
+static inline char * rq_map_buffer(struct request *rq, unsigned long *flags)
+{
+	return (__bio_kmap_irq(rq->cbio, blk_rq_idx(rq), flags)
+		+ blk_rq_offset(rq));
+}
+
+static inline void rq_unmap_buffer(char *buffer, unsigned long *flags)
+{
+	__bio_kunmap_irq(buffer, flags);
+}
+
 /*
  * q->prep_rq_fn return values
  */
@@ -301,7 +341,7 @@
 #define BLK_BOUNCE_ANY		((u64)blk_max_pfn << PAGE_SHIFT)
 #define BLK_BOUNCE_ISA		(ISA_DMA_THRESHOLD)
 
-#if CONFIG_MMU
+#ifdef CONFIG_MMU
 extern int init_emergency_isa_pool(void);
 extern void blk_queue_bounce(request_queue_t *q, struct bio **bio);
 #else
@@ -329,7 +369,6 @@
 extern void blk_attempt_remerge(request_queue_t *, struct request *);
 extern void __blk_attempt_remerge(request_queue_t *, struct request *);
 extern struct request *blk_get_request(request_queue_t *, int, int);
-extern struct request *__blk_get_request(request_queue_t *, int);
 extern void blk_put_request(struct request *);
 extern void blk_insert_request(request_queue_t *, struct request *, int, void *);
 extern void blk_plug_device(request_queue_t *);
@@ -360,6 +399,7 @@
 extern int end_that_request_first(struct request *, int, int);
 extern int end_that_request_chunk(struct request *, int, int);
 extern void end_that_request_last(struct request *);
+extern int process_that_request_first(struct request *, unsigned int);
 extern void end_request(struct request *req, int uptodate);
 
 static inline void blkdev_dequeue_request(struct request *req)
diff -Nru a/include/linux/blkpg.h b/include/linux/blkpg.h
--- a/include/linux/blkpg.h	Tue Oct 15 13:49:02 2002
+++ b/include/linux/blkpg.h	Wed May  7 21:18:43 2003
@@ -54,10 +54,4 @@
 	char volname[BLKPG_VOLNAMELTH];	/* volume label */
 };
 
-#ifdef __KERNEL__
-
-extern char * partition_name(dev_t dev);
-
-#endif /* __KERNEL__ */
-
 #endif /* _LINUX_BLKPG_H */
diff -Nru a/include/linux/brlock.h b/include/linux/brlock.h
--- a/include/linux/brlock.h	Tue Sep 24 09:24:23 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,222 +0,0 @@
-#ifndef __LINUX_BRLOCK_H
-#define __LINUX_BRLOCK_H
-
-/*
- * 'Big Reader' read-write spinlocks.
- *
- * super-fast read/write locks, with write-side penalty. The point
- * is to have a per-CPU read/write lock. Readers lock their CPU-local
- * readlock, writers must lock all locks to get write access. These
- * CPU-read-write locks are semantically identical to normal rwlocks.
- * Memory usage is higher as well. (NR_CPUS*L1_CACHE_BYTES bytes)
- *
- * The most important feature is that these spinlocks do not cause
- * cacheline ping-pong in the 'most readonly data' case.
- *
- * Copyright 2000, Ingo Molnar <mingo@redhat.com>
- *
- * Registry idea and naming [ crutial! :-) ] by:
- *
- *                 David S. Miller <davem@redhat.com>
- *
- * David has an implementation that doesn't use atomic operations in
- * the read branch via memory ordering tricks - i guess we need to
- * split this up into a per-arch thing? The atomicity issue is a
- * secondary item in profiles, at least on x86 platforms.
- *
- * The atomic op version overhead is indeed a big deal on
- * load-locked/store-conditional cpus (ALPHA/MIPS/PPC) and
- * compare-and-swap cpus (Sparc64).  So we control which
- * implementation to use with a __BRLOCK_USE_ATOMICS define. -DaveM
- *
- */
-
-/* Register bigreader lock indices here. */
-enum brlock_indices {
-	BR_NETPROTO_LOCK,
-	__BR_END
-};
-
-#include <linux/config.h>
-
-#ifdef CONFIG_SMP
-
-#include <linux/cache.h>
-#include <linux/spinlock.h>
-
-#if defined(__i386__) || defined(__ia64__) || defined(__x86_64__)
-#define __BRLOCK_USE_ATOMICS
-#else
-#undef __BRLOCK_USE_ATOMICS
-#endif
-
-#ifdef __BRLOCK_USE_ATOMICS
-typedef rwlock_t	brlock_read_lock_t;
-#else
-typedef unsigned int	brlock_read_lock_t;
-#endif
-
-/*
- * align last allocated index to the next cacheline:
- */
-#define __BR_IDX_MAX \
-	(((sizeof(brlock_read_lock_t)*__BR_END + SMP_CACHE_BYTES-1) & ~(SMP_CACHE_BYTES-1)) / sizeof(brlock_read_lock_t))
-
-extern brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX];
-
-#ifndef __BRLOCK_USE_ATOMICS
-struct br_wrlock {
-	spinlock_t lock;
-} __attribute__ ((__aligned__(SMP_CACHE_BYTES)));
-
-extern struct br_wrlock __br_write_locks[__BR_IDX_MAX];
-#endif
-
-extern void __br_lock_usage_bug (void);
-
-#ifdef __BRLOCK_USE_ATOMICS
-
-static inline void br_read_lock (enum brlock_indices idx)
-{
-	/*
-	 * This causes a link-time bug message if an
-	 * invalid index is used:
-	 */
-	if (idx >= __BR_END)
-		__br_lock_usage_bug();
-
-	preempt_disable();
-	_raw_read_lock(&__brlock_array[smp_processor_id()][idx]);
-}
-
-static inline void br_read_unlock (enum brlock_indices idx)
-{
-	if (idx >= __BR_END)
-		__br_lock_usage_bug();
-
-	read_unlock(&__brlock_array[smp_processor_id()][idx]);
-}
-
-#else /* ! __BRLOCK_USE_ATOMICS */
-static inline void br_read_lock (enum brlock_indices idx)
-{
-	unsigned int *ctr;
-	spinlock_t *lock;
-
-	/*
-	 * This causes a link-time bug message if an
-	 * invalid index is used:
-	 */
-	if (idx >= __BR_END)
-		__br_lock_usage_bug();
-
-	preempt_disable();
-	ctr = &__brlock_array[smp_processor_id()][idx];
-	lock = &__br_write_locks[idx].lock;
-again:
-	(*ctr)++;
-	mb();
-	if (spin_is_locked(lock)) {
-		(*ctr)--;
-		wmb(); /*
-			* The release of the ctr must become visible
-			* to the other cpus eventually thus wmb(),
-			* we don't care if spin_is_locked is reordered
-			* before the releasing of the ctr.
-			* However IMHO this wmb() is superflous even in theory.
-			* It would not be superflous only if on the
-			* other CPUs doing a ldl_l instead of an ldl
-			* would make a difference and I don't think this is
-			* the case.
-			* I'd like to clarify this issue further
-			* but for now this is a slow path so adding the
-			* wmb() will keep us on the safe side.
-			*/
-		while (spin_is_locked(lock))
-			barrier();
-		goto again;
-	}
-}
-
-static inline void br_read_unlock (enum brlock_indices idx)
-{
-	unsigned int *ctr;
-
-	if (idx >= __BR_END)
-		__br_lock_usage_bug();
-
-	ctr = &__brlock_array[smp_processor_id()][idx];
-
-	wmb();
-	(*ctr)--;
-	preempt_enable();
-}
-#endif /* __BRLOCK_USE_ATOMICS */
-
-/* write path not inlined - it's rare and larger */
-
-extern void FASTCALL(__br_write_lock (enum brlock_indices idx));
-extern void FASTCALL(__br_write_unlock (enum brlock_indices idx));
-
-static inline void br_write_lock (enum brlock_indices idx)
-{
-	if (idx >= __BR_END)
-		__br_lock_usage_bug();
-	__br_write_lock(idx);
-}
-
-static inline void br_write_unlock (enum brlock_indices idx)
-{
-	if (idx >= __BR_END)
-		__br_lock_usage_bug();
-	__br_write_unlock(idx);
-}
-
-#else
-# define br_read_lock(idx)	({ (void)(idx); preempt_disable(); })
-# define br_read_unlock(idx)	({ (void)(idx); preempt_enable(); })
-# define br_write_lock(idx)	({ (void)(idx); preempt_disable(); })
-# define br_write_unlock(idx)	({ (void)(idx); preempt_enable(); })
-#endif	/* CONFIG_SMP */
-
-/*
- * Now enumerate all of the possible sw/hw IRQ protected
- * versions of the interfaces.
- */
-#define br_read_lock_irqsave(idx, flags) \
-	do { local_irq_save(flags); br_read_lock(idx); } while (0)
-
-#define br_read_lock_irq(idx) \
-	do { local_irq_disable(); br_read_lock(idx); } while (0)
-
-#define br_read_lock_bh(idx) \
-	do { local_bh_disable(); br_read_lock(idx); } while (0)
-
-#define br_write_lock_irqsave(idx, flags) \
-	do { local_irq_save(flags); br_write_lock(idx); } while (0)
-
-#define br_write_lock_irq(idx) \
-	do { local_irq_disable(); br_write_lock(idx); } while (0)
-
-#define br_write_lock_bh(idx) \
-	do { local_bh_disable(); br_write_lock(idx); } while (0)
-
-#define br_read_unlock_irqrestore(idx, flags) \
-	do { br_read_unlock(irx); local_irq_restore(flags); } while (0)
-
-#define br_read_unlock_irq(idx) \
-	do { br_read_unlock(idx); local_irq_enable(); } while (0)
-
-#define br_read_unlock_bh(idx) \
-	do { br_read_unlock(idx); local_bh_enable(); } while (0)
-
-#define br_write_unlock_irqrestore(idx, flags) \
-	do { br_write_unlock(irx); local_irq_restore(flags); } while (0)
-
-#define br_write_unlock_irq(idx) \
-	do { br_write_unlock(idx); local_irq_enable(); } while (0)
-
-#define br_write_unlock_bh(idx) \
-	do { br_write_unlock(idx); local_bh_enable(); } while (0)
-
-#endif /* __LINUX_BRLOCK_H */
diff -Nru a/include/linux/brlvger.h b/include/linux/brlvger.h
--- a/include/linux/brlvger.h	Thu Apr 25 15:13:00 2002
+++ b/include/linux/brlvger.h	Tue May  6 17:18:13 2003
@@ -30,16 +30,8 @@
 #define BRLVGER_DISPLAY_OFF	3
 #define BRLVGER_BUZZ		4
 
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define MAX_NR_BRLVGER_DEVS	256
-#define BRLVGER_MINOR		0
-#else
-/* Number of supported devices, and range of covered minors */
-#define MAX_NR_BRLVGER_DEVS	4
-
 /* Base minor for the char devices */
 #define BRLVGER_MINOR		128
-#endif
 
 /* Size of some fields */
 #define BRLVGER_HWVER_SIZE	2
diff -Nru a/include/linux/capability.h b/include/linux/capability.h
--- a/include/linux/capability.h	Mon Jun  3 02:31:20 2002
+++ b/include/linux/capability.h	Mon May 12 14:35:19 2003
@@ -14,6 +14,7 @@
 #define _LINUX_CAPABILITY_H
 
 #include <linux/types.h>
+#include <linux/compiler.h>
 
 /* User-level do most of the mapping between kernel and user
    capabilities based on the version tag given by the kernel. The
@@ -31,13 +32,13 @@
 typedef struct __user_cap_header_struct {
 	__u32 version;
 	int pid;
-} *cap_user_header_t;
+} __user *cap_user_header_t;
  
 typedef struct __user_cap_data_struct {
         __u32 effective;
         __u32 permitted;
         __u32 inheritable;
-} *cap_user_data_t;
+} __user *cap_user_data_t;
   
 #ifdef __KERNEL__
 
diff -Nru a/include/linux/cpu.h b/include/linux/cpu.h
--- a/include/linux/cpu.h	Fri Nov  8 20:08:32 2002
+++ b/include/linux/cpu.h	Fri May  9 09:24:16 2003
@@ -29,6 +29,7 @@
 };
 
 extern int register_cpu(struct cpu *, int, struct node *);
+extern struct class cpu_class;
 
 /* Stop CPUs going up and down. */
 extern struct semaphore cpucontrol;
diff -Nru a/include/linux/cpufreq.h b/include/linux/cpufreq.h
--- a/include/linux/cpufreq.h	Mon Apr 28 23:50:13 2003
+++ b/include/linux/cpufreq.h	Mon May 12 21:23:15 2003
@@ -311,4 +311,7 @@
 
 #endif /* CONFIG_CPU_FREQ_TABLE */
 
+/* Currently exported only for the proc interface, remove when that goes */
+extern struct cpufreq_driver *cpufreq_driver;
+
 #endif /* _LINUX_CPUFREQ_H */
diff -Nru a/include/linux/cyclomx.h b/include/linux/cyclomx.h
--- a/include/linux/cyclomx.h	Mon Feb  4 23:44:27 2002
+++ b/include/linux/cyclomx.h	Tue May 20 07:19:38 2003
@@ -1,10 +1,12 @@
+#ifndef	_CYCLOMX_H
+#define	_CYCLOMX_H
 /*
 * cyclomx.h	Cyclom 2X WAN Link Driver.
 *		User-level API definitions.
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
 *
 * Based on wanpipe.h by Gene Kozin <genek@compuserve.com>
 *
@@ -21,8 +23,6 @@
 * 1998/12/27	acme		cleanup: PACKED not needed
 * 1998/08/08	acme		Version 0.0.1
 */
-#ifndef	_CYCLOMX_H
-#define	_CYCLOMX_H
 
 #include <linux/config.h>
 #include <linux/wanrouter.h>
@@ -43,19 +43,18 @@
  * This structure is needed because we handle multiple cards, otherwise
  * static data would do it.
  */
-typedef struct cycx {
-	char devname[WAN_DRVNAME_SZ+1];	/* card name */
-	cycxhw_t hw;			/* hardware configuration */
-	wan_device_t wandev;		/* WAN device data space */
-	u32 open_cnt;			/* number of open interfaces */
+struct cycx_device {
+	char devname[WAN_DRVNAME_SZ + 1];/* card name */
+	struct cycx_hw hw;		/* hardware configuration */
+	struct wan_device wandev;	/* WAN device data space */
 	u32 state_tick;			/* link state timestamp */
 	spinlock_t lock;
 	char in_isr;			/* interrupt-in-service flag */
 	char buff_int_mode_unbusy;      /* flag for carrying out dev_tint */
 	wait_queue_head_t wait_stats;  /* to wait for the STATS indication */
 	u32 mbox;			/* -> mailbox */
-	void (*isr)(struct cycx* card);	/* interrupt service routine */
-	int (*exec)(struct cycx* card, void* u_cmd, void* u_data);
+	void (*isr)(struct cycx_device* card);	/* interrupt service routine */
+	int (*exec)(struct cycx_device* card, void* u_cmd, void* u_data);
 	union {
 #ifdef CONFIG_CYCLOMX_X25
 		struct { /* X.25 specific data */
@@ -63,21 +62,19 @@
 			u32 hi_pvc;
 			u32 lo_svc;
 			u32 hi_svc;
-			TX25Stats stats;
+			struct cycx_x25_stats stats;
 			spinlock_t lock;
 			u32 connection_keys;
 		} x;
 #endif
 	} u;
-} cycx_t;
+};
 
 /* Public Functions */
-void cyclomx_mod_inc_use_count (cycx_t *card);		/* cycx_main.c */
-void cyclomx_mod_dec_use_count (cycx_t *card);		/* cycx_main.c */
-void cyclomx_set_state (cycx_t *card, int state);	/* cycx_main.c */
+void cycx_set_state(struct cycx_device *card, int state);
 
 #ifdef CONFIG_CYCLOMX_X25
-int cyx_init (cycx_t *card, wandev_conf_t *conf);	/* cycx_x25.c */
+int cycx_x25_wan_init(struct cycx_device *card, wandev_conf_t *conf);
 #endif
 #endif	/* __KERNEL__ */
 #endif	/* _CYCLOMX_H */
diff -Nru a/include/linux/cycx_cfm.h b/include/linux/cycx_cfm.h
--- a/include/linux/cycx_cfm.h	Tue Feb  5 09:39:42 2002
+++ b/include/linux/cycx_cfm.h	Thu May 15 19:24:05 2003
@@ -4,7 +4,7 @@
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
 *
 * Based on sdlasfm.h by Gene Kozin <74604.152@compuserve.com>
 *
@@ -45,38 +45,57 @@
 
 #define	CFID_X25_2X	5200
 
-/* Data Types */
+/**
+ *	struct cycx_fw_info - firmware module information.
+ *	@codeid - firmware ID
+ *	@version - firmware version number
+ *	@adapter - compatible adapter types
+ *	@memsize - minimum memory size
+ *	@reserved - reserved
+ *	@startoffs - entry point offset
+ *	@winoffs - dual-port memory window offset
+ *	@codeoffs - code load offset
+ *	@codesize - code size
+ *	@dataoffs - configuration data load offset
+ *	@datasize - configuration data size
+ */
+struct cycx_fw_info {
+	unsigned short	codeid;
+	unsigned short	version;
+	unsigned short	adapter[CFM_MAX_CYCX];
+	unsigned long	memsize;
+	unsigned short	reserved[2];
+	unsigned short	startoffs;
+	unsigned short	winoffs;
+	unsigned short	codeoffs;
+	unsigned long	codesize;
+	unsigned short	dataoffs;
+	unsigned long	datasize;
+};
+
+/**
+ *	struct cycx_firmware - CYCX firmware file structure
+ *	@signature - CFM file signature
+ *	@version - file format version
+ *	@checksum - info + image
+ *	@reserved - reserved
+ *	@descr - description string
+ *	@info - firmware module info
+ *	@image - code image (variable size)
+ */
+struct cycx_firmware {
+	char		    signature[80];
+	unsigned short	    version;
+	unsigned short	    checksum;
+	unsigned short	    reserved[6];
+	char		    descr[CFM_DESCR_LEN];
+	struct cycx_fw_info info;
+	unsigned char	    image[1];
+};
 
-typedef struct	cfm_info		/* firmware module information */
-{
-	unsigned short	codeid;		/* firmware ID */
-	unsigned short	version;	/* firmware version number */
-	unsigned short	adapter[CFM_MAX_CYCX]; /* compatible adapter types */
-	unsigned long	memsize;	/* minimum memory size */
-	unsigned short	reserved[2];	/* reserved */
-	unsigned short	startoffs;	/* entry point offset */
-	unsigned short	winoffs;	/* dual-port memory window offset */
-	unsigned short	codeoffs;	/* code load offset */
-	unsigned long	codesize;	/* code size */
-	unsigned short	dataoffs;	/* configuration data load offset */
-	unsigned long	datasize;	/* configuration data size */
-} cfm_info_t;
-
-typedef struct cfm			/* CYCX firmware file structure */
-{
-	char		signature[80];	/* CFM file signature */
-	unsigned short	version;	/* file format version */
-	unsigned short	checksum;	/* info + image */
-	unsigned short	reserved[6];	/* reserved */
-	char		descr[CFM_DESCR_LEN]; /* description string */
-	cfm_info_t	info;		/* firmware module info */
-	unsigned char	image[1];	/* code image (variable size) */
-} cfm_t;
-
-typedef struct cycx_header_s {
+struct cycx_fw_header {
 	unsigned long  reset_size;
 	unsigned long  data_size;
 	unsigned long  code_size;
-} cycx_header_t;
-
+};
 #endif	/* _CYCX_CFM_H */
diff -Nru a/include/linux/cycx_drv.h b/include/linux/cycx_drv.h
--- a/include/linux/cycx_drv.h	Tue Feb  5 09:39:42 2002
+++ b/include/linux/cycx_drv.h	Thu May 15 19:33:21 2003
@@ -3,7 +3,7 @@
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
 *
 * Based on sdladrv.h by Gene Kozin <genek@compuserve.com>
 *
@@ -37,28 +37,29 @@
 #define	DATA_OFFSET	0x0100	/* For code and data files load */
 #define	START_OFFSET	0x3ff0	/* 80186 starts here */
 
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
-#endif
-
-/* Data Structures */
-/* Adapter hardware configuration. Pointer to this structure is passed to all
- * APIs.  */
-typedef struct cycxhw {
-	u32 fwid;		/* firmware ID */
-	int irq;		/* interrupt request level */
-	u32 dpmbase;		/* dual-port memory base */
-	u32 dpmsize;		/* dual-port memory size */
+/**
+ *	struct cycx_hw - Adapter hardware configuration
+ *	@fwid - firmware ID
+ *	@irq - interrupt request level
+ *	@dpmbase - dual-port memory base
+ *	@dpmsize - dual-port memory size
+ *	@reserved - reserved for future use
+ */
+struct cycx_hw {
+	u32 fwid;
+	int irq;
+	u32 dpmbase;
+	u32 dpmsize;
 	u32 reserved[5];
-} cycxhw_t;
+};
 
 /* Function Prototypes */
-extern int cycx_setup (cycxhw_t *hw, void *sfm, u32 len);
-extern int cycx_down (cycxhw_t *hw);
-extern int cycx_peek (cycxhw_t *hw, u32 addr, void *buf, u32 len);
-extern int cycx_poke (cycxhw_t *hw, u32 addr, void *buf, u32 len);
-extern int cycx_exec (u32 addr);
+extern int cycx_setup(struct cycx_hw *hw, void *sfm, u32 len);
+extern int cycx_down(struct cycx_hw *hw);
+extern int cycx_peek(struct cycx_hw *hw, u32 addr, void *buf, u32 len);
+extern int cycx_poke(struct cycx_hw *hw, u32 addr, void *buf, u32 len);
+extern int cycx_exec(u32 addr);
 
-extern void cycx_inten (cycxhw_t *hw);
-extern void cycx_intr (cycxhw_t *hw);
+extern void cycx_inten(struct cycx_hw *hw);
+extern void cycx_intr(struct cycx_hw *hw);
 #endif	/* _CYCX_DRV_H */
diff -Nru a/include/linux/cycx_x25.h b/include/linux/cycx_x25.h
--- a/include/linux/cycx_x25.h	Tue Feb  5 09:39:42 2002
+++ b/include/linux/cycx_x25.h	Thu May 15 19:24:06 2003
@@ -1,9 +1,11 @@
+#ifndef	_CYCX_X25_H
+#define	_CYCX_X25_H
 /*
 * cycx_x25.h	Cyclom X.25 firmware API definitions.
 *
 * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 *
-* Copyright:	(c) 1998-2000 Arnaldo Carvalho de Melo
+* Copyright:	(c) 1998-2003 Arnaldo Carvalho de Melo
 *
 * Based on sdla_x25.h by Gene Kozin <74604.152@compuserve.com>
 *
@@ -20,9 +22,6 @@
 *					 TX25Cmd & TX25Config structs
 *					 typedef'ed
 */
-#ifndef	_CYCX_X25_H
-#define	_CYCX_X25_H
-
 #ifndef PACKED
 #define PACKED __attribute__((packed))
 #endif 
@@ -38,13 +37,12 @@
 
 /* Data Structures */
 /* X.25 Command Block. */
-typedef struct X25Cmd
-{
+struct cycx_x25_cmd {
 	u16 command PACKED;
 	u16 link    PACKED; /* values: 0 or 1 */
 	u16 len     PACKED; /* values: 0 thru 0x205 (517) */
 	u32 buf     PACKED;
-} TX25Cmd;
+};
 
 /* Defines for the 'command' field. */
 #define X25_CONNECT_REQUEST             0x4401
@@ -74,26 +72,45 @@
 #define X25_N2TRACEXC                   0x4702
 #define X25_N3TRACEXC                   0x4703
 
-typedef struct X25Config {
-	u8  link	PACKED; /* link number */
-	u8  speed	PACKED; /* line speed */
-	u8  clock	PACKED; /* internal/external */
-	u8  n2		PACKED; /* # of level 2 retransm.(values: 1 thru FF) */
-	u8  n2win	PACKED; /* level 2 window (values: 1 thru 7) */
-	u8  n3win	PACKED; /* level 3 window (values: 1 thru 7) */
-	u8  nvc		PACKED; /* # of logical channels (values: 1 thru 64) */
-	u8  pktlen	PACKED; /* level 3 packet lenght - log base 2 of size */
-	u8  locaddr	PACKED; /* my address */
-	u8  remaddr	PACKED; /* remote address */
-	u16 t1		PACKED;	/* time, in seconds */
-	u16 t2		PACKED;	/* time, in seconds */
-	u8  t21		PACKED;	/* time, in seconds */
-	u8  npvc	PACKED;	/* # of permanent virt. circuits (1 thru nvc) */
-	u8  t23		PACKED;	/* time, in seconds */
-	u8  flags	PACKED;	/* see dosx25.doc, in portuguese, for details */
-} TX25Config;
+/**
+ *	struct cycx_x25_config - cyclom2x x25 firmware configuration
+ *	@link - link number
+ *	@speed - line speed
+ *	@clock - internal/external
+ *	@n2 - # of level 2 retransm.(values: 1 thru FF)
+ *	@n2win - level 2 window (values: 1 thru 7)
+ *	@n3win - level 3 window (values: 1 thru 7)
+ *	@nvc - # of logical channels (values: 1 thru 64)
+ *	@pktlen - level 3 packet lenght - log base 2 of size
+ *	@locaddr - my address
+ *	@remaddr - remote address
+ *	@t1 - time, in seconds
+ *	@t2 - time, in seconds
+ *	@t21 - time, in seconds
+ *	@npvc - # of permanent virt. circuits (1 thru nvc)
+ *	@t23 - time, in seconds
+ *	@flags - see dosx25.doc, in portuguese, for details
+ */
+struct cycx_x25_config {
+	u8  link	PACKED;
+	u8  speed	PACKED;
+	u8  clock	PACKED;
+	u8  n2		PACKED;
+	u8  n2win	PACKED;
+	u8  n3win	PACKED;
+	u8  nvc		PACKED;
+	u8  pktlen	PACKED;
+	u8  locaddr	PACKED;
+	u8  remaddr	PACKED;
+	u16 t1		PACKED;
+	u16 t2		PACKED;
+	u8  t21		PACKED;
+	u8  npvc	PACKED;
+	u8  t23		PACKED;
+	u8  flags	PACKED;
+};
 
-typedef struct X25Stats {
+struct cycx_x25_stats {
 	u16 rx_crc_errors	PACKED;
 	u16 rx_over_errors	PACKED;
 	u16 n2_tx_frames 	PACKED;
@@ -104,5 +121,5 @@
 	u16 n3_rx_packets 	PACKED;
 	u16 tx_aborts	 	PACKED;
 	u16 rx_aborts	 	PACKED;
-} TX25Stats;
+};
 #endif	/* _CYCX_X25_H */
diff -Nru a/include/linux/devfs_fs_kernel.h b/include/linux/devfs_fs_kernel.h
--- a/include/linux/devfs_fs_kernel.h	Fri Apr 25 08:21:07 2003
+++ b/include/linux/devfs_fs_kernel.h	Mon May 12 21:23:09 2003
@@ -11,22 +11,11 @@
 
 #define DEVFS_SUPER_MAGIC                0x1373
 
-#define DEVFS_FL_NONE           0x000 /* This helps to make code more readable
-				         no, it doesn't  --hch */
-#define DEVFS_FL_DEFAULT        DEVFS_FL_NONE
-
-
-typedef struct devfs_entry * devfs_handle_t;
-
-struct gendisk;
-
 #ifdef CONFIG_DEVFS_FS
-extern devfs_handle_t devfs_register (devfs_handle_t dir, const char *name,
-				      unsigned int flags,
-				      unsigned int major, unsigned int minor,
-				      umode_t mode, void *ops, void *info);
 extern int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
 	__attribute__((format (printf, 3, 4)));
+extern int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...)
+	__attribute__((format (printf, 3, 4)));
 extern int devfs_mk_symlink(const char *name, const char *link);
 extern int devfs_mk_dir(const char *fmt, ...)
 	__attribute__((format (printf, 1, 2)));
@@ -34,20 +23,13 @@
 	__attribute__((format (printf, 1, 2)));
 extern int devfs_register_tape(const char *name);
 extern void devfs_unregister_tape(int num);
-extern void devfs_register_partition(struct gendisk *dev, int part);
 extern void mount_devfs_fs(void);
 #else  /*  CONFIG_DEVFS_FS  */
-static inline devfs_handle_t devfs_register (devfs_handle_t dir,
-					     const char *name,
-					     unsigned int flags,
-					     unsigned int major,
-					     unsigned int minor,
-					     umode_t mode,
-					     void *ops, void *info)
+static inline int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
 {
-    return NULL;
+	return 0;
 }
-static inline int devfs_mk_bdev(dev_t dev, umode_t mode, const char *fmt, ...)
+static inline int devfs_mk_cdev(dev_t dev, umode_t mode, const char *fmt, ...)
 {
 	return 0;
 }
@@ -67,9 +49,6 @@
     return -1;
 }
 static inline void devfs_unregister_tape(int num)
-{
-}
-static inline void devfs_register_partition(struct gendisk *dev, int part)
 {
 }
 static inline void mount_devfs_fs (void)
diff -Nru a/include/linux/device.h b/include/linux/device.h
--- a/include/linux/device.h	Mon Apr 28 23:05:23 2003
+++ b/include/linux/device.h	Thu May 15 14:54:57 2003
@@ -29,13 +29,14 @@
 #include <linux/list.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
+#include <linux/ioport.h>
 #include <asm/semaphore.h>
 #include <asm/atomic.h>
 
 #define DEVICE_NAME_SIZE	50
 #define DEVICE_NAME_HALF	__stringify(20)	/* Less than half to accommodate slop */
 #define DEVICE_ID_SIZE		32
-#define BUS_ID_SIZE		20
+#define BUS_ID_SIZE		KOBJ_NAME_LEN
 
 
 enum {
@@ -388,6 +389,8 @@
 	char		* name;
 	u32		id;
 	struct device	dev;
+	u32		num_resources;
+	struct resource	* resource;
 };
 
 extern int platform_device_register(struct platform_device *);
diff -Nru a/include/linux/divert.h b/include/linux/divert.h
--- a/include/linux/divert.h	Tue Feb  5 09:39:43 2002
+++ b/include/linux/divert.h	Tue May 20 18:56:26 2003
@@ -107,11 +107,24 @@
 
 /* diverter functions */
 #include <linux/skbuff.h>
+
+#ifdef CONFIG_NET_DIVERT
 int alloc_divert_blk(struct net_device *);
 void free_divert_blk(struct net_device *);
 int divert_ioctl(unsigned int cmd, struct divert_cf *arg);
 void divert_frame(struct sk_buff *skb);
+static inline void handle_diverter(struct sk_buff *skb)
+{
+	/* if diversion is supported on device, then divert */
+	if (skb->dev->divert && skb->dev->divert->divert)
+		divert_frame(skb);
+}
 
+#else
+# define alloc_divert_blk(dev)		(0)
+# define free_divert_blk(dev)		do {} while (0)
+# define divert_ioctl(cmd, arg)		(-ENOPKG)
+# define handle_diverter(skb)		do {} while (0)
+#endif
 #endif 
-
 #endif	/* _LINUX_DIVERT_H */
diff -Nru a/include/linux/efi.h b/include/linux/efi.h
--- a/include/linux/efi.h	Thu Aug 29 15:23:25 2002
+++ b/include/linux/efi.h	Sat May 10 02:28:47 2003
@@ -7,7 +7,7 @@
  *
  * Copyright (C) 1999 VA Linux Systems
  * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
- * Copyright (C) 1999, 2002 Hewlett-Packard Co.
+ * Copyright (C) 1999, 2002-2003 Hewlett-Packard Co.
  *	David Mosberger-Tang <davidm@hpl.hp.com>
  *	Stephane Eranian <eranian@hpl.hp.com>
  */
@@ -21,12 +21,12 @@
 #include <asm/system.h>
 
 #define EFI_SUCCESS		0
-#define EFI_LOAD_ERROR          (1L | (1L << 63))
-#define EFI_INVALID_PARAMETER	(2L | (1L << 63))
-#define EFI_UNSUPPORTED		(3L | (1L << 63))
-#define EFI_BAD_BUFFER_SIZE     (4L | (1L << 63))
-#define EFI_BUFFER_TOO_SMALL	(5L | (1L << 63))
-#define EFI_NOT_FOUND          (14L | (1L << 63))
+#define EFI_LOAD_ERROR          ( 1 | (1UL << 63))
+#define EFI_INVALID_PARAMETER	( 2 | (1UL << 63))
+#define EFI_UNSUPPORTED		( 3 | (1UL << 63))
+#define EFI_BAD_BUFFER_SIZE     ( 4 | (1UL << 63))
+#define EFI_BUFFER_TOO_SMALL	( 5 | (1UL << 63))
+#define EFI_NOT_FOUND		(14 | (1UL << 63))
 
 typedef unsigned long efi_status_t;
 typedef u8 efi_bool_t;
@@ -260,7 +260,7 @@
 extern void efi_init (void);
 extern void efi_map_pal_code (void);
 extern void efi_memmap_walk (efi_freemem_callback_t callback, void *arg);
-extern void efi_gettimeofday (struct timeval *tv);
+extern void efi_gettimeofday (struct timespec *ts);
 extern void efi_enter_virtual_mode (void);	/* switch EFI to virtual mode, if possible */
 extern u64 efi_get_iobase (void);
 extern u32 efi_mem_type (unsigned long phys_addr);
diff -Nru a/include/linux/elevator.h b/include/linux/elevator.h
--- a/include/linux/elevator.h	Thu May  1 10:21:24 2003
+++ b/include/linux/elevator.h	Fri May  9 02:36:45 2003
@@ -15,6 +15,8 @@
 typedef void (elevator_remove_req_fn) (request_queue_t *, struct request *);
 typedef struct request *(elevator_request_list_fn) (request_queue_t *, struct request *);
 typedef struct list_head *(elevator_get_sort_head_fn) (request_queue_t *, struct request *);
+typedef int (elevator_set_req_fn) (request_queue_t *, struct request *, int);
+typedef void (elevator_put_req_fn) (request_queue_t *, struct request *);
 
 typedef int (elevator_init_fn) (request_queue_t *, elevator_t *);
 typedef void (elevator_exit_fn) (request_queue_t *, elevator_t *);
@@ -34,6 +36,9 @@
 	elevator_request_list_fn *elevator_former_req_fn;
 	elevator_request_list_fn *elevator_latter_req_fn;
 
+	elevator_set_req_fn *elevator_set_req_fn;
+	elevator_put_req_fn *elevator_put_req_fn;
+
 	elevator_init_fn *elevator_init_fn;
 	elevator_exit_fn *elevator_exit_fn;
 
@@ -59,6 +64,8 @@
 extern struct request *elv_latter_request(request_queue_t *, struct request *);
 extern int elv_register_queue(struct gendisk *);
 extern void elv_unregister_queue(struct gendisk *);
+extern int elv_set_request(request_queue_t *, struct request *, int);
+extern void elv_put_request(request_queue_t *, struct request *);
 
 #define __elv_add_request_pos(q, rq, pos)	\
 	(q)->elevator.elevator_add_req_fn((q), (rq), (pos))
diff -Nru a/include/linux/elf.h b/include/linux/elf.h
--- a/include/linux/elf.h	Tue Apr 22 19:48:09 2003
+++ b/include/linux/elf.h	Mon May 12 14:17:18 2003
@@ -34,13 +34,6 @@
 #define PT_LOPROC  0x70000000
 #define PT_HIPROC  0x7fffffff
 #define PT_GNU_EH_FRAME		0x6474e550
-#define PT_MIPS_REGINFO		0x70000000
-
-/* Flags in the e_flags field of the header */
-#define EF_MIPS_NOREORDER 0x00000001
-#define EF_MIPS_PIC       0x00000002
-#define EF_MIPS_CPIC      0x00000004
-#define EF_MIPS_ARCH      0xf0000000
 
 /* These constants define the different elf file types */
 #define ET_NONE   0
@@ -130,25 +123,6 @@
 #define DT_JMPREL	23
 #define DT_LOPROC	0x70000000
 #define DT_HIPROC	0x7fffffff
-#define DT_MIPS_RLD_VERSION	0x70000001
-#define DT_MIPS_TIME_STAMP	0x70000002
-#define DT_MIPS_ICHECKSUM	0x70000003
-#define DT_MIPS_IVERSION	0x70000004
-#define DT_MIPS_FLAGS		0x70000005
-  #define RHF_NONE		  0
-  #define RHF_HARDWAY		  1
-  #define RHF_NOTPOT		  2
-#define DT_MIPS_BASE_ADDRESS	0x70000006
-#define DT_MIPS_CONFLICT	0x70000008
-#define DT_MIPS_LIBLIST		0x70000009
-#define DT_MIPS_LOCAL_GOTNO	0x7000000a
-#define DT_MIPS_CONFLICTNO	0x7000000b
-#define DT_MIPS_LIBLISTNO	0x70000010
-#define DT_MIPS_SYMTABNO	0x70000011
-#define DT_MIPS_UNREFEXTNO	0x70000012
-#define DT_MIPS_GOTSYM		0x70000013
-#define DT_MIPS_HIPAGENO	0x70000014
-#define DT_MIPS_RLD_MAP		0x70000016
 
 /* This info is needed when parsing the symbol table */
 #define STB_LOCAL  0
@@ -212,508 +186,6 @@
 #define ELF64_R_SYM(i)			((i) >> 32)
 #define ELF64_R_TYPE(i)			((i) & 0xffffffff)
 
-#define R_ARM_NONE	0
-#define R_ARM_PC24	1
-#define R_ARM_ABS32	2
-
-#define R_386_NONE	0
-#define R_386_32	1
-#define R_386_PC32	2
-#define R_386_GOT32	3
-#define R_386_PLT32	4
-#define R_386_COPY	5
-#define R_386_GLOB_DAT	6
-#define R_386_JMP_SLOT	7
-#define R_386_RELATIVE	8
-#define R_386_GOTOFF	9
-#define R_386_GOTPC	10
-#define R_386_NUM	11
-
-#define R_MIPS_NONE		0
-#define R_MIPS_16		1
-#define R_MIPS_32		2
-#define R_MIPS_REL32		3
-#define R_MIPS_26		4
-#define R_MIPS_HI16		5
-#define R_MIPS_LO16		6
-#define R_MIPS_GPREL16		7
-#define R_MIPS_LITERAL		8
-#define R_MIPS_GOT16		9
-#define R_MIPS_PC16		10
-#define R_MIPS_CALL16		11
-#define R_MIPS_GPREL32		12
-/* The remaining relocs are defined on Irix, although they are not
-   in the MIPS ELF ABI.  */
-#define R_MIPS_UNUSED1		13
-#define R_MIPS_UNUSED2		14
-#define R_MIPS_UNUSED3		15
-#define R_MIPS_SHIFT5		16
-#define R_MIPS_SHIFT6		17
-#define R_MIPS_64		18
-#define R_MIPS_GOT_DISP		19
-#define R_MIPS_GOT_PAGE		20
-#define R_MIPS_GOT_OFST		21
-/*
- * The following two relocation types are specified in the MIPS ABI
- * conformance guide version 1.2 but not yet in the psABI.
- */
-#define R_MIPS_GOTHI16		22
-#define R_MIPS_GOTLO16		23
-#define R_MIPS_SUB		24
-#define R_MIPS_INSERT_A		25
-#define R_MIPS_INSERT_B		26
-#define R_MIPS_DELETE		27
-#define R_MIPS_HIGHER		28
-#define R_MIPS_HIGHEST		29
-/*
- * The following two relocation types are specified in the MIPS ABI
- * conformance guide version 1.2 but not yet in the psABI.
- */
-#define R_MIPS_CALLHI16		30
-#define R_MIPS_CALLLO16		31
-/*
- * This range is reserved for vendor specific relocations.
- */
-#define R_MIPS_LOVENDOR		100
-#define R_MIPS_HIVENDOR		127
-
-/*
- * Sparc section types
- */
-#define STT_REGISTER		13
-
-/*
- * Sparc ELF relocation types
- */
-#define	R_SPARC_NONE		0
-#define	R_SPARC_8		1
-#define	R_SPARC_16		2
-#define	R_SPARC_32		3
-#define	R_SPARC_DISP8		4
-#define	R_SPARC_DISP16		5
-#define	R_SPARC_DISP32		6
-#define	R_SPARC_WDISP30		7
-#define	R_SPARC_WDISP22		8
-#define	R_SPARC_HI22		9
-#define	R_SPARC_22		10
-#define	R_SPARC_13		11
-#define	R_SPARC_LO10		12
-#define	R_SPARC_GOT10		13
-#define	R_SPARC_GOT13		14
-#define	R_SPARC_GOT22		15
-#define	R_SPARC_PC10		16
-#define	R_SPARC_PC22		17
-#define	R_SPARC_WPLT30		18
-#define	R_SPARC_COPY		19
-#define	R_SPARC_GLOB_DAT	20
-#define	R_SPARC_JMP_SLOT	21
-#define	R_SPARC_RELATIVE	22
-#define	R_SPARC_UA32		23
-#define R_SPARC_PLT32		24
-#define R_SPARC_HIPLT22		25
-#define R_SPARC_LOPLT10		26
-#define R_SPARC_PCPLT32		27
-#define R_SPARC_PCPLT22		28
-#define R_SPARC_PCPLT10		29
-#define R_SPARC_10		30
-#define R_SPARC_11		31
-#define R_SPARC_64		32
-#define R_SPARC_OLO10		33
-#define R_SPARC_WDISP16		40
-#define R_SPARC_WDISP19		41
-#define R_SPARC_7		43
-#define R_SPARC_5		44
-#define R_SPARC_6		45
-
-/* Bits present in AT_HWCAP, primarily for Sparc32.  */
-
-#define HWCAP_SPARC_FLUSH       1    /* CPU supports flush instruction. */
-#define HWCAP_SPARC_STBAR       2
-#define HWCAP_SPARC_SWAP        4
-#define HWCAP_SPARC_MULDIV      8
-#define HWCAP_SPARC_V9		16
-#define HWCAP_SPARC_ULTRA3	32
-
-/*
- * 68k ELF relocation types
- */
-#define R_68K_NONE	0
-#define R_68K_32	1
-#define R_68K_16	2
-#define R_68K_8		3
-#define R_68K_PC32	4
-#define R_68K_PC16	5
-#define R_68K_PC8	6
-#define R_68K_GOT32	7
-#define R_68K_GOT16	8
-#define R_68K_GOT8	9
-#define R_68K_GOT32O	10
-#define R_68K_GOT16O	11
-#define R_68K_GOT8O	12
-#define R_68K_PLT32	13
-#define R_68K_PLT16	14
-#define R_68K_PLT8	15
-#define R_68K_PLT32O	16
-#define R_68K_PLT16O	17
-#define R_68K_PLT8O	18
-#define R_68K_COPY	19
-#define R_68K_GLOB_DAT	20
-#define R_68K_JMP_SLOT	21
-#define R_68K_RELATIVE	22
-
-/*
- * Alpha ELF relocation types
- */
-#define R_ALPHA_NONE            0       /* No reloc */
-#define R_ALPHA_REFLONG         1       /* Direct 32 bit */
-#define R_ALPHA_REFQUAD         2       /* Direct 64 bit */
-#define R_ALPHA_GPREL32         3       /* GP relative 32 bit */
-#define R_ALPHA_LITERAL         4       /* GP relative 16 bit w/optimization */
-#define R_ALPHA_LITUSE          5       /* Optimization hint for LITERAL */
-#define R_ALPHA_GPDISP          6       /* Add displacement to GP */
-#define R_ALPHA_BRADDR          7       /* PC+4 relative 23 bit shifted */
-#define R_ALPHA_HINT            8       /* PC+4 relative 16 bit shifted */
-#define R_ALPHA_SREL16          9       /* PC relative 16 bit */
-#define R_ALPHA_SREL32          10      /* PC relative 32 bit */
-#define R_ALPHA_SREL64          11      /* PC relative 64 bit */
-#define R_ALPHA_GPRELHIGH       17      /* GP relative 32 bit, high 16 bits */
-#define R_ALPHA_GPRELLOW        18      /* GP relative 32 bit, low 16 bits */
-#define R_ALPHA_GPREL16         19      /* GP relative 16 bit */
-#define R_ALPHA_COPY            24      /* Copy symbol at runtime */
-#define R_ALPHA_GLOB_DAT        25      /* Create GOT entry */
-#define R_ALPHA_JMP_SLOT        26      /* Create PLT entry */
-#define R_ALPHA_RELATIVE        27      /* Adjust by program base */
-#define R_ALPHA_BRSGP		28
-#define R_ALPHA_TLSGD           29
-#define R_ALPHA_TLS_LDM         30
-#define R_ALPHA_DTPMOD64        31
-#define R_ALPHA_GOTDTPREL       32
-#define R_ALPHA_DTPREL64        33
-#define R_ALPHA_DTPRELHI        34
-#define R_ALPHA_DTPRELLO        35
-#define R_ALPHA_DTPREL16        36
-#define R_ALPHA_GOTTPREL        37
-#define R_ALPHA_TPREL64         38
-#define R_ALPHA_TPRELHI         39
-#define R_ALPHA_TPRELLO         40
-#define R_ALPHA_TPREL16         41
-
-#define SHF_ALPHA_GPREL		0x10000000
-
-
-/* PowerPC relocations defined by the ABIs */
-#define R_PPC_NONE		0
-#define R_PPC_ADDR32		1	/* 32bit absolute address */
-#define R_PPC_ADDR24		2	/* 26bit address, 2 bits ignored.  */
-#define R_PPC_ADDR16		3	/* 16bit absolute address */
-#define R_PPC_ADDR16_LO		4	/* lower 16bit of absolute address */
-#define R_PPC_ADDR16_HI		5	/* high 16bit of absolute address */
-#define R_PPC_ADDR16_HA		6	/* adjusted high 16bit */
-#define R_PPC_ADDR14		7	/* 16bit address, 2 bits ignored */
-#define R_PPC_ADDR14_BRTAKEN	8
-#define R_PPC_ADDR14_BRNTAKEN	9
-#define R_PPC_REL24		10	/* PC relative 26 bit */
-#define R_PPC_REL14		11	/* PC relative 16 bit */
-#define R_PPC_REL14_BRTAKEN	12
-#define R_PPC_REL14_BRNTAKEN	13
-#define R_PPC_GOT16		14
-#define R_PPC_GOT16_LO		15
-#define R_PPC_GOT16_HI		16
-#define R_PPC_GOT16_HA		17
-#define R_PPC_PLTREL24		18
-#define R_PPC_COPY		19
-#define R_PPC_GLOB_DAT		20
-#define R_PPC_JMP_SLOT		21
-#define R_PPC_RELATIVE		22
-#define R_PPC_LOCAL24PC		23
-#define R_PPC_UADDR32		24
-#define R_PPC_UADDR16		25
-#define R_PPC_REL32		26
-#define R_PPC_PLT32		27
-#define R_PPC_PLTREL32		28
-#define R_PPC_PLT16_LO		29
-#define R_PPC_PLT16_HI		30
-#define R_PPC_PLT16_HA		31
-#define R_PPC_SDAREL16		32
-#define R_PPC_SECTOFF		33
-#define R_PPC_SECTOFF_LO	34
-#define R_PPC_SECTOFF_HI	35
-#define R_PPC_SECTOFF_HA	36
-/* Keep this the last entry.  */
-#define R_PPC_NUM		37
-
-/* s390 relocations defined by the ABIs */
-#define R_390_NONE		0	/* No reloc.  */
-#define R_390_8			1	/* Direct 8 bit.  */
-#define R_390_12		2	/* Direct 12 bit.  */
-#define R_390_16		3	/* Direct 16 bit.  */
-#define R_390_32		4	/* Direct 32 bit.  */
-#define R_390_PC32		5	/* PC relative 32 bit.	*/
-#define R_390_GOT12		6	/* 12 bit GOT offset.  */
-#define R_390_GOT32		7	/* 32 bit GOT offset.  */
-#define R_390_PLT32		8	/* 32 bit PC relative PLT address.  */
-#define R_390_COPY		9	/* Copy symbol at runtime.  */
-#define R_390_GLOB_DAT		10	/* Create GOT entry.  */
-#define R_390_JMP_SLOT		11	/* Create PLT entry.  */
-#define R_390_RELATIVE		12	/* Adjust by program base.  */
-#define R_390_GOTOFF32		13	/* 32 bit offset to GOT.	 */
-#define R_390_GOTPC		14	/* 32 bit PC rel. offset to GOT.  */
-#define R_390_GOT16		15	/* 16 bit GOT offset.  */
-#define R_390_PC16		16	/* PC relative 16 bit.	*/
-#define R_390_PC16DBL		17	/* PC relative 16 bit shifted by 1.  */
-#define R_390_PLT16DBL		18	/* 16 bit PC rel. PLT shifted by 1.  */
-#define R_390_PC32DBL		19	/* PC relative 32 bit shifted by 1.  */
-#define R_390_PLT32DBL		20	/* 32 bit PC rel. PLT shifted by 1.  */
-#define R_390_GOTPCDBL		21	/* 32 bit PC rel. GOT shifted by 1.  */
-#define R_390_64		22	/* Direct 64 bit.  */
-#define R_390_PC64		23	/* PC relative 64 bit.	*/
-#define R_390_GOT64		24	/* 64 bit GOT offset.  */
-#define R_390_PLT64		25	/* 64 bit PC relative PLT address.  */
-#define R_390_GOTENT		26	/* 32 bit PC rel. to GOT entry >> 1. */
-#define R_390_GOTOFF16		27	/* 16 bit offset to GOT. */
-#define R_390_GOTOFF64		28	/* 64 bit offset to GOT. */
-#define R_390_GOTPLT12		29	/* 12 bit offset to jump slot.	*/
-#define R_390_GOTPLT16		30	/* 16 bit offset to jump slot.	*/
-#define R_390_GOTPLT32		31	/* 32 bit offset to jump slot.	*/
-#define R_390_GOTPLT64		32	/* 64 bit offset to jump slot.	*/
-#define R_390_GOTPLTENT		33	/* 32 bit rel. offset to jump slot.  */
-#define R_390_PLTOFF16		34	/* 16 bit offset from GOT to PLT. */
-#define R_390_PLTOFF32		35	/* 32 bit offset from GOT to PLT. */
-#define R_390_PLTOFF64		36	/* 16 bit offset from GOT to PLT. */
-#define R_390_TLS_LOAD		37	/* Tag for load insn in TLS code. */
-#define R_390_TLS_GDCALL	38	/* Tag for function call in general
-                                           dynamic TLS code.  */
-#define R_390_TLS_LDCALL	39	/* Tag for function call in local
-                                           dynamic TLS code.  */
-#define R_390_TLS_GD32		40	/* Direct 32 bit for general dynamic
-                                           thread local data.  */
-#define R_390_TLS_GD64		41	/* Direct 64 bit for general dynamic
-                                           thread local data.  */
-#define R_390_TLS_GOTIE12	42	/* 12 bit GOT offset for static TLS
-                                           block offset.  */
-#define R_390_TLS_GOTIE32	43	/* 32 bit GOT offset for static TLS
-                                           block offset.  */
-#define R_390_TLS_GOTIE64	44	/* 64 bit GOT offset for static TLS
-                                           block offset.  */
-#define R_390_TLS_LDM32		45	/* Direct 32 bit for local dynamic
-                                           thread local data in LD code.  */
-#define R_390_TLS_LDM64		46	/* Direct 64 bit for local dynamic
-                                           thread local data in LD code.  */
-#define R_390_TLS_IE32		47	/* 32 bit address of GOT entry for
-                                           negated static TLS block offset.  */
-#define R_390_TLS_IE64		48	/* 64 bit address of GOT entry for
-                                           negated static TLS block offset.  */
-#define R_390_TLS_IEENT		49	/* 32 bit rel. offset to GOT entry for
-                                           negated static TLS block offset.  */
-#define R_390_TLS_LE32		50	/* 32 bit negated offset relative to
-                                           static TLS block.  */
-#define R_390_TLS_LE64		51	/* 64 bit negated offset relative to
-                                           static TLS block.  */
-#define R_390_TLS_LDO32		52	/* 32 bit offset relative to TLS
-                                           block.  */
-#define R_390_TLS_LDO64		53	/* 64 bit offset relative to TLS
-                                           block.  */
-#define R_390_TLS_DTPMOD	54	/* ID of module containing symbol.  */
-#define R_390_TLS_DTPOFF	55	/* Offset in TLS block.  */
-#define R_390_TLS_TPOFF		56	/* Negate offset in static TLS
-                                           block.  */
-/* Keep this the last entry.  */
-#define R_390_NUM	57
-
-/* x86-64 relocation types */
-#define R_X86_64_NONE		0	/* No reloc */
-#define R_X86_64_64		1	/* Direct 64 bit  */
-#define R_X86_64_PC32		2	/* PC relative 32 bit signed */
-#define R_X86_64_GOT32		3	/* 32 bit GOT entry */
-#define R_X86_64_PLT32		4	/* 32 bit PLT address */
-#define R_X86_64_COPY		5	/* Copy symbol at runtime */
-#define R_X86_64_GLOB_DAT	6	/* Create GOT entry */
-#define R_X86_64_JUMP_SLOT	7	/* Create PLT entry */
-#define R_X86_64_RELATIVE	8	/* Adjust by program base */
-#define R_X86_64_GOTPCREL	9	/* 32 bit signed pc relative
-					   offset to GOT */
-#define R_X86_64_32		10	/* Direct 32 bit zero extended */
-#define R_X86_64_32S		11	/* Direct 32 bit sign extended */
-#define R_X86_64_16		12	/* Direct 16 bit zero extended */
-#define R_X86_64_PC16		13	/* 16 bit sign extended pc relative */
-#define R_X86_64_8		14	/* Direct 8 bit sign extended  */
-#define R_X86_64_PC8		15	/* 8 bit sign extended pc relative */
-
-#define R_X86_64_NUM		16
-
-/* Legal values for e_flags field of Elf64_Ehdr.  */
-
-#define EF_ALPHA_32BIT		1	/* All addresses are below 2GB */
-
-/* HPPA specific definitions.  */
-
-/* Legal values for e_flags field of Elf32_Ehdr.  */
-
-#define EF_PARISC_TRAPNIL	0x00010000 /* Trap nil pointer dereference.  */
-#define EF_PARISC_EXT		0x00020000 /* Program uses arch. extensions. */
-#define EF_PARISC_LSB		0x00040000 /* Program expects little endian. */
-#define EF_PARISC_WIDE		0x00080000 /* Program expects wide mode.  */
-#define EF_PARISC_NO_KABP	0x00100000 /* No kernel assisted branch
-					      prediction.  */
-#define EF_PARISC_LAZYSWAP	0x00400000 /* Allow lazy swapping.  */
-#define EF_PARISC_ARCH		0x0000ffff /* Architecture version.  */
-
-/* Defined values for `e_flags & EF_PARISC_ARCH' are:  */
-
-#define EFA_PARISC_1_0		    0x020b /* PA-RISC 1.0 big-endian.  */
-#define EFA_PARISC_1_1		    0x0210 /* PA-RISC 1.1 big-endian.  */
-#define EFA_PARISC_2_0		    0x0214 /* PA-RISC 2.0 big-endian.  */
-
-/* Additional section indeces.  */
-
-#define SHN_PARISC_ANSI_COMMON	0xff00	   /* Section for tenatively declared
-					      symbols in ANSI C.  */
-#define SHN_PARISC_HUGE_COMMON	0xff01	   /* Common blocks in huge model.  */
-
-/* Legal values for sh_type field of Elf32_Shdr.  */
-
-#define SHT_PARISC_EXT		0x70000000 /* Contains product specific ext. */
-#define SHT_PARISC_UNWIND	0x70000001 /* Unwind information.  */
-#define SHT_PARISC_DOC		0x70000002 /* Debug info for optimized code. */
-
-/* Legal values for sh_flags field of Elf32_Shdr.  */
-
-#define SHF_PARISC_SHORT	0x20000000 /* Section with short addressing. */
-#define SHF_PARISC_HUGE		0x40000000 /* Section far from gp.  */
-#define SHF_PARISC_SBP		0x80000000 /* Static branch prediction code. */
-
-/* Legal values for ST_TYPE subfield of st_info (symbol type).  */
-
-#define STT_PARISC_MILLICODE	13	/* Millicode function entry point.  */
-
-#define STT_HP_OPAQUE		(STT_LOOS + 0x1)
-#define STT_HP_STUB		(STT_LOOS + 0x2)
-
-/* HPPA relocs.  */
-
-#define R_PARISC_NONE		0	/* No reloc.  */
-#define R_PARISC_DIR32		1	/* Direct 32-bit reference.  */
-#define R_PARISC_DIR21L		2	/* Left 21 bits of eff. address.  */
-#define R_PARISC_DIR17R		3	/* Right 17 bits of eff. address.  */
-#define R_PARISC_DIR17F		4	/* 17 bits of eff. address.  */
-#define R_PARISC_DIR14R		6	/* Right 14 bits of eff. address.  */
-#define R_PARISC_PCREL32	9	/* 32-bit rel. address.  */
-#define R_PARISC_PCREL21L	10	/* Left 21 bits of rel. address.  */
-#define R_PARISC_PCREL17R	11	/* Right 17 bits of rel. address.  */
-#define R_PARISC_PCREL17F	12	/* 17 bits of rel. address.  */
-#define R_PARISC_PCREL14R	14	/* Right 14 bits of rel. address.  */
-#define R_PARISC_DPREL21L	18	/* Left 21 bits of rel. address.  */
-#define R_PARISC_DPREL14R	22	/* Right 14 bits of rel. address.  */
-#define R_PARISC_GPREL21L	26	/* GP-relative, left 21 bits.  */
-#define R_PARISC_GPREL14R	30	/* GP-relative, right 14 bits.  */
-#define R_PARISC_LTOFF21L	34	/* LT-relative, left 21 bits.  */
-#define R_PARISC_LTOFF14R	38	/* LT-relative, right 14 bits.  */
-#define R_PARISC_SECREL32	41	/* 32 bits section rel. address.  */
-#define R_PARISC_SEGBASE	48	/* No relocation, set segment base.  */
-#define R_PARISC_SEGREL32	49	/* 32 bits segment rel. address.  */
-#define R_PARISC_PLTOFF21L	50	/* PLT rel. address, left 21 bits.  */
-#define R_PARISC_PLTOFF14R	54	/* PLT rel. address, right 14 bits.  */
-#define R_PARISC_LTOFF_FPTR32	57	/* 32 bits LT-rel. function pointer. */
-#define R_PARISC_LTOFF_FPTR21L	58	/* LT-rel. fct ptr, left 21 bits. */
-#define R_PARISC_LTOFF_FPTR14R	62	/* LT-rel. fct ptr, right 14 bits. */
-#define R_PARISC_FPTR64		64	/* 64 bits function address.  */
-#define R_PARISC_PLABEL32	65	/* 32 bits function address.  */
-#define R_PARISC_PCREL64	72	/* 64 bits PC-rel. address.  */
-#define R_PARISC_PCREL22F	74	/* 22 bits PC-rel. address.  */
-#define R_PARISC_PCREL14WR	75	/* PC-rel. address, right 14 bits.  */
-#define R_PARISC_PCREL14DR	76	/* PC rel. address, right 14 bits.  */
-#define R_PARISC_PCREL16F	77	/* 16 bits PC-rel. address.  */
-#define R_PARISC_PCREL16WF	78	/* 16 bits PC-rel. address.  */
-#define R_PARISC_PCREL16DF	79	/* 16 bits PC-rel. address.  */
-#define R_PARISC_DIR64		80	/* 64 bits of eff. address.  */
-#define R_PARISC_DIR14WR	83	/* 14 bits of eff. address.  */
-#define R_PARISC_DIR14DR	84	/* 14 bits of eff. address.  */
-#define R_PARISC_DIR16F		85	/* 16 bits of eff. address.  */
-#define R_PARISC_DIR16WF	86	/* 16 bits of eff. address.  */
-#define R_PARISC_DIR16DF	87	/* 16 bits of eff. address.  */
-#define R_PARISC_GPREL64	88	/* 64 bits of GP-rel. address.  */
-#define R_PARISC_GPREL14WR	91	/* GP-rel. address, right 14 bits.  */
-#define R_PARISC_GPREL14DR	92	/* GP-rel. address, right 14 bits.  */
-#define R_PARISC_GPREL16F	93	/* 16 bits GP-rel. address.  */
-#define R_PARISC_GPREL16WF	94	/* 16 bits GP-rel. address.  */
-#define R_PARISC_GPREL16DF	95	/* 16 bits GP-rel. address.  */
-#define R_PARISC_LTOFF64	96	/* 64 bits LT-rel. address.  */
-#define R_PARISC_LTOFF14WR	99	/* LT-rel. address, right 14 bits.  */
-#define R_PARISC_LTOFF14DR	100	/* LT-rel. address, right 14 bits.  */
-#define R_PARISC_LTOFF16F	101	/* 16 bits LT-rel. address.  */
-#define R_PARISC_LTOFF16WF	102	/* 16 bits LT-rel. address.  */
-#define R_PARISC_LTOFF16DF	103	/* 16 bits LT-rel. address.  */
-#define R_PARISC_SECREL64	104	/* 64 bits section rel. address.  */
-#define R_PARISC_SEGREL64	112	/* 64 bits segment rel. address.  */
-#define R_PARISC_PLTOFF14WR	115	/* PLT-rel. address, right 14 bits.  */
-#define R_PARISC_PLTOFF14DR	116	/* PLT-rel. address, right 14 bits.  */
-#define R_PARISC_PLTOFF16F	117	/* 16 bits LT-rel. address.  */
-#define R_PARISC_PLTOFF16WF	118	/* 16 bits PLT-rel. address.  */
-#define R_PARISC_PLTOFF16DF	119	/* 16 bits PLT-rel. address.  */
-#define R_PARISC_LTOFF_FPTR64	120	/* 64 bits LT-rel. function ptr.  */
-#define R_PARISC_LTOFF_FPTR14WR	123	/* LT-rel. fct. ptr., right 14 bits. */
-#define R_PARISC_LTOFF_FPTR14DR	124	/* LT-rel. fct. ptr., right 14 bits. */
-#define R_PARISC_LTOFF_FPTR16F	125	/* 16 bits LT-rel. function ptr.  */
-#define R_PARISC_LTOFF_FPTR16WF	126	/* 16 bits LT-rel. function ptr.  */
-#define R_PARISC_LTOFF_FPTR16DF	127	/* 16 bits LT-rel. function ptr.  */
-#define R_PARISC_LORESERVE	128
-#define R_PARISC_COPY		128	/* Copy relocation.  */
-#define R_PARISC_IPLT		129	/* Dynamic reloc, imported PLT */
-#define R_PARISC_EPLT		130	/* Dynamic reloc, exported PLT */
-#define R_PARISC_TPREL32	153	/* 32 bits TP-rel. address.  */
-#define R_PARISC_TPREL21L	154	/* TP-rel. address, left 21 bits.  */
-#define R_PARISC_TPREL14R	158	/* TP-rel. address, right 14 bits.  */
-#define R_PARISC_LTOFF_TP21L	162	/* LT-TP-rel. address, left 21 bits. */
-#define R_PARISC_LTOFF_TP14R	166	/* LT-TP-rel. address, right 14 bits.*/
-#define R_PARISC_LTOFF_TP14F	167	/* 14 bits LT-TP-rel. address.  */
-#define R_PARISC_TPREL64	216	/* 64 bits TP-rel. address.  */
-#define R_PARISC_TPREL14WR	219	/* TP-rel. address, right 14 bits.  */
-#define R_PARISC_TPREL14DR	220	/* TP-rel. address, right 14 bits.  */
-#define R_PARISC_TPREL16F	221	/* 16 bits TP-rel. address.  */
-#define R_PARISC_TPREL16WF	222	/* 16 bits TP-rel. address.  */
-#define R_PARISC_TPREL16DF	223	/* 16 bits TP-rel. address.  */
-#define R_PARISC_LTOFF_TP64	224	/* 64 bits LT-TP-rel. address.  */
-#define R_PARISC_LTOFF_TP14WR	227	/* LT-TP-rel. address, right 14 bits.*/
-#define R_PARISC_LTOFF_TP14DR	228	/* LT-TP-rel. address, right 14 bits.*/
-#define R_PARISC_LTOFF_TP16F	229	/* 16 bits LT-TP-rel. address.  */
-#define R_PARISC_LTOFF_TP16WF	230	/* 16 bits LT-TP-rel. address.  */
-#define R_PARISC_LTOFF_TP16DF	231	/* 16 bits LT-TP-rel. address.  */
-#define R_PARISC_HIRESERVE	255
-
-/* Legal values for p_type field of Elf32_Phdr/Elf64_Phdr.  */
-
-#define PT_HP_TLS		(PT_LOOS + 0x0)
-#define PT_HP_CORE_NONE		(PT_LOOS + 0x1)
-#define PT_HP_CORE_VERSION	(PT_LOOS + 0x2)
-#define PT_HP_CORE_KERNEL	(PT_LOOS + 0x3)
-#define PT_HP_CORE_COMM		(PT_LOOS + 0x4)
-#define PT_HP_CORE_PROC		(PT_LOOS + 0x5)
-#define PT_HP_CORE_LOADABLE	(PT_LOOS + 0x6)
-#define PT_HP_CORE_STACK	(PT_LOOS + 0x7)
-#define PT_HP_CORE_SHM		(PT_LOOS + 0x8)
-#define PT_HP_CORE_MMF		(PT_LOOS + 0x9)
-#define PT_HP_PARALLEL		(PT_LOOS + 0x10)
-#define PT_HP_FASTBIND		(PT_LOOS + 0x11)
-#define PT_HP_OPT_ANNOT		(PT_LOOS + 0x12)
-#define PT_HP_HSL_ANNOT		(PT_LOOS + 0x13)
-#define PT_HP_STACK		(PT_LOOS + 0x14)
-
-#define PT_PARISC_ARCHEXT	0x70000000
-#define PT_PARISC_UNWIND	0x70000001
-
-/* Legal values for p_flags field of Elf32_Phdr/Elf64_Phdr.  */
-
-#define PF_PARISC_SBP		0x08000000
-
-#define PF_HP_PAGE_SIZE		0x00100000
-#define PF_HP_FAR_SHARED	0x00200000
-#define PF_HP_NEAR_SHARED	0x00400000
-#define PF_HP_CODE		0x01000000
-#define PF_HP_MODIFY		0x02000000
-#define PF_HP_LAZYSWAP		0x04000000
-#define PF_HP_SBP		0x08000000
-
-
 typedef struct elf32_rel {
   Elf32_Addr	r_offset;
   Elf32_Word	r_info;
@@ -837,17 +309,12 @@
 #define SHT_HIPROC	0x7fffffff
 #define SHT_LOUSER	0x80000000
 #define SHT_HIUSER	0xffffffff
-#define SHT_MIPS_LIST		0x70000000
-#define SHT_MIPS_CONFLICT	0x70000002
-#define SHT_MIPS_GPTAB		0x70000003
-#define SHT_MIPS_UCODE		0x70000004
 
 /* sh_flags */
 #define SHF_WRITE	0x1
 #define SHF_ALLOC	0x2
 #define SHF_EXECINSTR	0x4
 #define SHF_MASKPROC	0xf0000000
-#define SHF_MIPS_GPREL	0x10000000
 
 /* special section indexes */
 #define SHN_UNDEF	0
@@ -857,7 +324,6 @@
 #define SHN_ABS		0xfff1
 #define SHN_COMMON	0xfff2
 #define SHN_HIRESERVE	0xffff
-#define SHN_MIPS_ACCOMON	0xff00
  
 typedef struct {
   Elf32_Word	sh_name;
diff -Nru a/include/linux/ext3_fs.h b/include/linux/ext3_fs.h
--- a/include/linux/ext3_fs.h	Sun Mar 16 22:33:16 2003
+++ b/include/linux/ext3_fs.h	Mon May 12 21:23:29 2003
@@ -625,6 +625,8 @@
 	u32		*seed;
 };
 
+#define EXT3_HTREE_EOF	0x7fffffff
+
 #ifdef __KERNEL__
 /*
  * Control parameters used by ext3_htree_next_block
diff -Nru a/include/linux/file.h b/include/linux/file.h
--- a/include/linux/file.h	Wed Apr  9 06:42:36 2003
+++ b/include/linux/file.h	Wed May  7 21:20:23 2003
@@ -35,7 +35,15 @@
 
 extern void FASTCALL(__fput(struct file *));
 extern void FASTCALL(fput(struct file *));
+
+static inline void fput_light(struct file *file, int fput_needed)
+{
+	if (unlikely(fput_needed))
+		fput(file);
+}
+
 extern struct file * FASTCALL(fget(unsigned int fd));
+extern struct file * FASTCALL(fget_light(unsigned int fd, int *fput_needed));
 extern void FASTCALL(set_close_on_exec(unsigned int fd, int flag));
 extern void put_filp(struct file *);
 extern int get_unused_fd(void);
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h	Tue Apr 29 14:42:50 2003
+++ b/include/linux/fs.h	Sat May 17 14:09:32 2003
@@ -206,8 +206,8 @@
 #include <asm/semaphore.h>
 #include <asm/byteorder.h>
 
+/* Used to be a macro which just called the function, now just a function */
 extern void update_atime (struct inode *);
-#define UPDATE_ATIME(inode) update_atime (inode)
 
 extern void inode_init(unsigned long);
 extern void mnt_init(unsigned long);
@@ -313,7 +313,7 @@
 struct address_space {
 	struct inode		*host;		/* owner: inode, block_device */
 	struct radix_tree_root	page_tree;	/* radix tree of all pages */
-	spinlock_t		page_lock;	/* and rwlock protecting it */
+	spinlock_t		page_lock;	/* and spinlock protecting it */
 	struct list_head	clean_pages;	/* list of clean pages */
 	struct list_head	dirty_pages;	/* list of dirty pages */
 	struct list_head	locked_pages;	/* list of locked pages */
@@ -521,12 +521,12 @@
 
 #include <linux/fcntl.h>
 
-extern int fcntl_getlk(struct file *, struct flock *);
-extern int fcntl_setlk(struct file *, unsigned int, struct flock *);
+extern int fcntl_getlk(struct file *, struct flock __user *);
+extern int fcntl_setlk(struct file *, unsigned int, struct flock __user *);
 
 #if BITS_PER_LONG == 32
-extern int fcntl_getlk64(struct file *, struct flock64 *);
-extern int fcntl_setlk64(struct file *, unsigned int, struct flock64 *);
+extern int fcntl_getlk64(struct file *, struct flock64 __user *);
+extern int fcntl_setlk64(struct file *, unsigned int, struct flock64 __user *);
 #endif
 
 /* fs/locks.c */
@@ -691,7 +691,7 @@
 typedef struct {
 	size_t written;
 	size_t count;
-	char * buf;
+	char __user * buf;
 	int error;
 } read_descriptor_t;
 
@@ -722,7 +722,7 @@
 	int (*lock) (struct file *, int, struct file_lock *);
 	ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
 	ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
-	ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
+	ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void __user *);
 	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
 	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
 };
@@ -1017,7 +1017,7 @@
 
 /* fs/open.c */
 
-asmlinkage long sys_open(const char *, int, int);
+asmlinkage long sys_open(const char __user *, int, int);
 asmlinkage long sys_close(unsigned int);	/* yes, it's really unsigned */
 extern int do_truncate(struct dentry *, loff_t start);
 
@@ -1113,6 +1113,10 @@
 extern int filemap_fdatawait(struct address_space *);
 extern void sync_supers(void);
 extern void sync_filesystems(int wait);
+extern void emergency_sync(void);
+extern void emergency_remount(void);
+extern int do_remount_sb(struct super_block *sb, int flags,
+			void *data, int force);
 extern sector_t bmap(struct inode *, sector_t);
 extern int setattr_mask(unsigned int);
 extern int notify_change(struct dentry *, struct iattr *);
@@ -1203,15 +1207,15 @@
 int generic_write_checks(struct inode *inode, struct file *file,
 			loff_t *pos, size_t *count, int isblk);
 extern ssize_t generic_file_write(struct file *, const char __user *, size_t, loff_t *);
-extern ssize_t generic_file_aio_read(struct kiocb *, char *, size_t, loff_t);
-extern ssize_t generic_file_aio_write(struct kiocb *, const char *, size_t, loff_t);
+extern ssize_t generic_file_aio_read(struct kiocb *, char __user *, size_t, loff_t);
+extern ssize_t generic_file_aio_write(struct kiocb *, const char __user *, size_t, loff_t);
 extern ssize_t generic_file_aio_write_nolock(struct kiocb *, const struct iovec *,
 				unsigned long, loff_t *);
 extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos);
 extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos);
 ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov,
 				unsigned long nr_segs, loff_t *ppos);
-extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
+extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void __user *);
 extern void do_generic_mapping_read(struct address_space *, struct file_ra_state *, struct file *,
 				    loff_t *, read_descriptor_t *, read_actor_t);
 extern void
@@ -1259,8 +1263,8 @@
 
 extern int vfs_readdir(struct file *, filldir_t, void *);
 
-extern int vfs_stat(char *, struct kstat *);
-extern int vfs_lstat(char *, struct kstat *);
+extern int vfs_stat(char __user *, struct kstat *);
+extern int vfs_lstat(char __user *, struct kstat *);
 extern int vfs_fstat(unsigned int, struct kstat *);
 
 extern struct file_system_type *get_fs_type(const char *name);
@@ -1287,7 +1291,7 @@
 				unsigned offset, unsigned to);
 
 extern struct dentry *simple_lookup(struct inode *, struct dentry *);
-extern ssize_t generic_read_dir(struct file *, char *, size_t, loff_t *);
+extern ssize_t generic_read_dir(struct file *, char __user *, size_t, loff_t *);
 extern struct file_operations simple_dir_operations;
 extern struct inode_operations simple_dir_inode_operations;
 struct tree_descr { char *name; struct file_operations *ops; int mode; };
diff -Nru a/include/linux/futex.h b/include/linux/futex.h
--- a/include/linux/futex.h	Sat Feb 15 05:16:19 2003
+++ b/include/linux/futex.h	Mon May 12 14:35:19 2003
@@ -6,6 +6,6 @@
 #define FUTEX_WAKE (1)
 #define FUTEX_FD (2)
 
-extern asmlinkage long sys_futex(u32 *uaddr, int op, int val, struct timespec *utime);
+extern asmlinkage long sys_futex(u32 __user *uaddr, int op, int val, struct timespec __user *utime);
 
 #endif
diff -Nru a/include/linux/i2c-id.h b/include/linux/i2c-id.h
--- a/include/linux/i2c-id.h	Tue Mar 11 12:21:11 2003
+++ b/include/linux/i2c-id.h	Sun May 11 15:50:47 2003
@@ -245,7 +245,7 @@
 #define I2C_HW_SMBUS_SIS5595	0x06
 #define I2C_HW_SMBUS_ALI1535	0x07
 #define I2C_HW_SMBUS_SIS630	0x08
-#define I2C_HW_SMBUS_SIS645	0x09
+#define I2C_HW_SMBUS_SIS96X	0x09
 #define I2C_HW_SMBUS_AMD8111	0x0a
 #define I2C_HW_SMBUS_SCX200	0x0b
 #define I2C_HW_SMBUS_NFORCE2	0x0c
diff -Nru a/include/linux/i2c.h b/include/linux/i2c.h
--- a/include/linux/i2c.h	Thu Apr 24 06:36:20 2003
+++ b/include/linux/i2c.h	Tue May  6 18:29:59 2003
@@ -39,12 +39,6 @@
 
 /* --- General options ------------------------------------------------	*/
 
-#define I2C_ALGO_MAX	4		/* control memory consumption	*/
-#define I2C_ADAP_MAX	16
-#define I2C_DRIVER_MAX	16
-#define I2C_CLIENT_MAX	32
-#define I2C_DUMMY_MAX 4
-
 struct i2c_msg;
 struct i2c_algorithm;
 struct i2c_adapter;
@@ -131,6 +125,7 @@
 	 * i2c_attach_client.
 	 */
 	int (*attach_adapter)(struct i2c_adapter *);
+	int (*detach_adapter)(struct i2c_adapter *);
 
 	/* tells the driver that a client is about to be deleted & gives it 
 	 * the chance to remove its private data. Also, if the client struct
@@ -145,6 +140,7 @@
 	int (*command)(struct i2c_client *client,unsigned int cmd, void *arg);
 
 	struct device_driver driver;
+	struct list_head list;
 };
 #define to_i2c_driver(d) container_of(d, struct i2c_driver, driver)
 
@@ -169,6 +165,7 @@
 	int usage_count;		/* How many accesses currently  */
 					/* to the client		*/
 	struct device dev;		/* the device structure		*/
+	struct list_head list;
 };
 #define to_i2c_client(d) container_of(d, struct i2c_client, dev)
 
@@ -228,6 +225,7 @@
 	struct module *owner;
 	unsigned int id;/* == is algo->id | hwdep.struct->id, 		*/
 			/* for registered values see below		*/
+	unsigned int class;
 	struct i2c_algorithm *algo;/* the algorithm to access the bus	*/
 	void *algo_data;
 
@@ -236,20 +234,23 @@
 	int (*client_unregister)(struct i2c_client *);
 
 	/* data fields that are valid for all devices	*/
-	struct semaphore bus;
-	struct semaphore list;  
+	struct semaphore bus_lock;
+	struct semaphore clist_lock;
 	unsigned int flags;/* flags specifying div. data		*/
 
-	struct i2c_client *clients[I2C_CLIENT_MAX];
-
 	int timeout;
 	int retries;
-	struct device dev;	/* the adapter device */
+	struct device dev;		/* the adapter device */
+	struct class_device class_dev;	/* the class device */
 
 #ifdef CONFIG_PROC_FS 
 	/* No need to set this when you initialize the adapter          */
 	int inode;
 #endif /* def CONFIG_PROC_FS */
+
+	int nr;
+	struct list_head clients;
+	struct list_head list;
 };
 #define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
 
@@ -265,7 +266,11 @@
 
 /*flags for the driver struct: */
 #define I2C_DF_NOTIFY	0x01		/* notify on bus (de/a)ttaches 	*/
-#define I2C_DF_DUMMY	0x02		/* do not connect any clients */
+#if 0
+/* this flag is gone -- there is a (optional) driver->detach_adapter
+ * callback now which can be used instead */
+# define I2C_DF_DUMMY	0x02
+#endif
 
 /*flags for the client struct: */
 #define I2C_CLIENT_ALLOW_USE		0x01	/* Client allows access */
@@ -275,6 +280,14 @@
 #define I2C_CLIENT_TEN	0x10			/* we have a ten bit chip address	*/
 						/* Must equal I2C_M_TEN below */
 
+/* i2c adapter classes (bitmask) */
+#define I2C_ADAP_CLASS_SMBUS		(1<<0)	/* lm_sensors, ... */
+#define I2C_ADAP_CLASS_TV_ANALOG	(1<<1)	/* bttv + friends */
+#define I2C_ADAP_CLASS_TV_DIGITAL	(1<<2)	/* dbv cards */
+#define I2C_ADAP_CLASS_DDC		(1<<3)	/* i2c-matroxfb ? */
+#define I2C_ADAP_CLASS_CAM_ANALOG	(1<<4)	/* camera with analog CCD */
+#define I2C_ADAP_CLASS_CAM_DIGITAL	(1<<5)	/* most webcams */
+
 /* i2c_client_address_data is the struct for holding default client
  * addresses for a driver and for the parameters supplied on the
  * command line
@@ -331,6 +344,11 @@
 extern int i2c_use_client(struct i2c_client *);
 extern int i2c_release_client(struct i2c_client *);
 
+/* call the i2c_client->command() of all attached clients with
+ * the given arguments */
+extern void i2c_clients_command(struct i2c_adapter *adap,
+				unsigned int cmd, void *arg);
+
 /* returns -EBUSY if address has been taken, 0 if not. Note that the only
    other place at which this is called is within i2c_attach_client; so
    you can cheat by simply not registering. Not recommended, of course! */
@@ -352,7 +370,8 @@
  * or -1 if the adapter was not registered. 
  */
 extern int i2c_adapter_id(struct i2c_adapter *adap);
-
+extern struct i2c_adapter* i2c_get_adapter(int id);
+extern void i2c_put_adapter(struct i2c_adapter *adap);
 
 
 /* Return the functionality mask */
diff -Nru a/include/linux/if_arcnet.h b/include/linux/if_arcnet.h
--- a/include/linux/if_arcnet.h	Tue Feb  5 09:39:42 2002
+++ b/include/linux/if_arcnet.h	Thu May 15 17:23:26 2003
@@ -25,6 +25,7 @@
 
 /* RFC1201 Protocol ID's */
 #define ARC_P_IP		212	/* 0xD4 */
+#define ARC_P_IPV6		196	/* 0xC4: RFC2497 */
 #define ARC_P_ARP		213	/* 0xD5 */
 #define ARC_P_RARP		214	/* 0xD6 */
 #define ARC_P_IPX		250	/* 0xFA */
@@ -44,6 +45,9 @@
 #define ARC_P_POWERLAN_BEACON2	243	/* 0xF3 */
 #define ARC_P_LANSOFT		251	/* 0xFB - what is this? */
 #define ARC_P_ATALK		0xDD
+
+/* Hardware address length */
+#define ARCNET_ALEN	1
 
 /*
  * The RFC1201-specific components of an arcnet packet header.
diff -Nru a/include/linux/if_ether.h b/include/linux/if_ether.h
--- a/include/linux/if_ether.h	Sat Aug  3 17:19:03 2002
+++ b/include/linux/if_ether.h	Thu May  8 14:34:31 2003
@@ -61,6 +61,8 @@
 #define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
 #define ETH_P_PPP_DISC	0x8863		/* PPPoE discovery messages     */
 #define ETH_P_PPP_SES	0x8864		/* PPPoE session messages	*/
+#define ETH_P_MPLS_UC	0x8847		/* MPLS Unicast traffic		*/
+#define ETH_P_MPLS_MC	0x8848		/* MPLS Multicast traffic	*/
 #define ETH_P_ATMMPOA	0x884c		/* MultiProtocol Over ATM	*/
 #define ETH_P_ATMFATE	0x8884		/* Frame-based ATM Transport
 					 * over Ethernet
diff -Nru a/include/linux/if_frad.h b/include/linux/if_frad.h
--- a/include/linux/if_frad.h	Mon Feb  4 23:38:17 2002
+++ b/include/linux/if_frad.h	Thu May  8 18:29:19 2003
@@ -192,7 +192,7 @@
 int register_frad(const char *name);
 int unregister_frad(const char *name);
 
-extern int (*dlci_ioctl_hook)(unsigned int, void *);
+extern void dlci_ioctl_set(int (*hook)(unsigned int, void *));
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/if_wanpipe.h b/include/linux/if_wanpipe.h
--- a/include/linux/if_wanpipe.h	Sun Feb 16 16:22:42 2003
+++ b/include/linux/if_wanpipe.h	Thu May 15 14:42:07 2003
@@ -101,16 +101,12 @@
 
 #ifdef __KERNEL__
 
-#ifndef netdevice_t
-#define netdevice_t struct net_device
-#endif
-
 /* Private wanpipe socket structures. */
 struct wanpipe_opt
 {
 	void   *mbox;		/* Mail box  */
 	void   *card; 		/* Card bouded to */
-	netdevice_t *dev;	/* Bounded device */
+	struct net_device *dev;	/* Bounded device */
 	unsigned short lcn;	/* Binded LCN */
 	unsigned char  svc;	/* 0=pvc, 1=svc */
 	unsigned char  timer;   /* flag for delayed transmit*/	
diff -Nru a/include/linux/if_wanpipe_common.h b/include/linux/if_wanpipe_common.h
--- a/include/linux/if_wanpipe_common.h	Sun Feb 16 16:22:42 2003
+++ b/include/linux/if_wanpipe_common.h	Thu May 15 14:42:07 2003
@@ -19,11 +19,8 @@
 
 #include <linux/version.h>
 
-#define netdevice_t struct net_device
-
-
 typedef struct {
-	netdevice_t *slave;
+	struct net_device *slave;
 	atomic_t packet_sent;
 	atomic_t receive_block;
 	atomic_t command;
@@ -32,8 +29,8 @@
 	long common_critical;
 	struct timer_list *tx_timer;
 	struct sock *sk;		/* Wanpipe Sock bind's here */ 
-	int   (*func) (struct sk_buff *, netdevice_t *, 
-                       struct sock *);
+	int (*func)(struct sk_buff *skb, struct net_device *dev, 
+		    struct sock *sk);
 
 	struct work_struct wanpipe_work;    /* deferred keventd work */
 	unsigned char rw_bind;			  /* Sock bind state */
diff -Nru a/include/linux/input.h b/include/linux/input.h
--- a/include/linux/input.h	Mon Apr 28 23:32:21 2003
+++ b/include/linux/input.h	Fri May  2 06:55:04 2003
@@ -894,9 +894,6 @@
 int input_accept_process(struct input_handle *handle, struct file *file);
 int input_flush_device(struct input_handle* handle, struct file* file);
 
-/* will go away once devfs_register gets sanitized */
-void input_register_minor(char *name, int minor, int minor_base);
-
 void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
 
 #define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c))
diff -Nru a/include/linux/ip.h b/include/linux/ip.h
--- a/include/linux/ip.h	Tue Apr 15 23:53:17 2003
+++ b/include/linux/ip.h	Fri May 16 14:02:36 2003
@@ -113,7 +113,7 @@
 	__u16			dport;		/* Destination port */
 	__u16			num;		/* Local port */
 	__u32			saddr;		/* Sending source */
-	int			ttl;		/* TTL setting */
+	int			uc_ttl;		/* Unicast TTL */
 	int			tos;		/* TOS */
 	unsigned	   	cmsg_flags;
 	struct ip_options	*opt;
@@ -196,6 +196,12 @@
 	__u32 spi;
 	__u32 seq_no;		/* Sequence number */
 	__u8  enc_data[0];	/* Variable len but >=8. Mind the 64 bit alignment! */
+};
+
+struct ip_comp_hdr {
+	__u8 nexthdr;
+	__u8 flags;
+	__u16 cpi;
 };
 
 #endif	/* _LINUX_IP_H */
diff -Nru a/include/linux/ipv6.h b/include/linux/ipv6.h
--- a/include/linux/ipv6.h	Thu Apr  3 04:24:10 2003
+++ b/include/linux/ipv6.h	Fri May 16 14:02:36 2003
@@ -89,6 +89,12 @@
 	__u8  enc_data[0];      /* Length variable but >=8. Mind the 64 bit alignment! */
 };
 
+struct ipv6_comp_hdr {
+	__u8 nexthdr;
+	__u8 flags;
+	__u16 cpi;
+};
+
 /*
  *	IPv6 fixed header
  *
@@ -121,6 +127,7 @@
 #include <linux/icmpv6.h>
 #include <net/if_inet6.h>       /* struct ipv6_mc_socklist */
 #include <linux/tcp.h>
+#include <linux/udp.h>
 
 /* 
    This structure contains results of exthdrs parsing
@@ -178,6 +185,11 @@
 
 	struct ipv6_txoptions	*opt;
 	struct sk_buff		*pktoptions;
+	struct {
+		struct ipv6_txoptions *opt;
+		struct rt6_info	*rt;
+		struct flowi *fl;
+	} cork;
 };
 
 struct raw6_opt {
@@ -200,6 +212,7 @@
 	struct sock	  sk;
 	struct ipv6_pinfo *pinet6;
 	struct inet_opt   inet;
+	struct udp_opt	  udp;
 	struct ipv6_pinfo inet6;
 };
 
diff -Nru a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h
--- a/include/linux/ipv6_route.h	Tue Feb  5 09:39:41 2002
+++ b/include/linux/ipv6_route.h	Thu May 15 23:27:55 2003
@@ -13,15 +13,6 @@
 #ifndef _LINUX_IPV6_ROUTE_H
 #define _LINUX_IPV6_ROUTE_H
 
-enum
-{
-	RTA_IPV6_UNSPEC,
-	RTA_IPV6_HOPLIMIT,
-};
-
-#define	RTA_IPV6_MAX RTA_IPV6_HOPLIMIT
-
-
 #define RTF_DEFAULT	0x00010000	/* default - learned via ND	*/
 #define RTF_ALLONLINK	0x00020000	/* fallback, no routers on link	*/
 #define RTF_ADDRCONF	0x00040000	/* addrconf route - RA		*/
diff -Nru a/include/linux/ipx.h b/include/linux/ipx.h
--- a/include/linux/ipx.h	Fri Aug  2 20:45:54 2002
+++ b/include/linux/ipx.h	Sat May  3 20:36:51 2003
@@ -5,8 +5,7 @@
 #define IPX_NODE_LEN	6
 #define IPX_MTU		576
 
-struct sockaddr_ipx
-{
+struct sockaddr_ipx {
 	sa_family_t	sipx_family;
 	__u16		sipx_port;
 	__u32		sipx_network;
@@ -16,9 +15,8 @@
 };
 
 /*
- *	So we can fit the extra info for SIOCSIFADDR into the address nicely
+ * So we can fit the extra info for SIOCSIFADDR into the address nicely
  */
- 
 #define sipx_special	sipx_port
 #define sipx_action	sipx_zero
 #define IPX_DLTITF	0
@@ -56,14 +54,13 @@
  * OLD Route Definition for backward compatibility.
  */
 
-struct ipx_route_def
-{
-	__u32         ipx_network;
-	__u32         ipx_router_network;
+struct ipx_route_def {
+	__u32		ipx_network;
+	__u32		ipx_router_network;
 #define IPX_ROUTE_NO_ROUTER	0
-	unsigned char ipx_router_node[IPX_NODE_LEN];
-	unsigned char ipx_device[16];
-	unsigned short ipx_flags;
+	unsigned char	ipx_router_node[IPX_NODE_LEN];
+	unsigned char	ipx_device[16];
+	unsigned short	ipx_flags;
 #define IPX_RT_SNAP		8
 #define IPX_RT_8022		4
 #define IPX_RT_BLUEBOOK		2
@@ -71,7 +68,7 @@
 };
 
 #define SIOCAIPXITFCRT		(SIOCPROTOPRIVATE)
-#define SIOCAIPXPRISLT		(SIOCPROTOPRIVATE+1)
-#define SIOCIPXCFGDATA		(SIOCPROTOPRIVATE+2)
-#define SIOCIPXNCPCONN		(SIOCPROTOPRIVATE+3)
-#endif /* def _IPX_H_ */
+#define SIOCAIPXPRISLT		(SIOCPROTOPRIVATE + 1)
+#define SIOCIPXCFGDATA		(SIOCPROTOPRIVATE + 2)
+#define SIOCIPXNCPCONN		(SIOCPROTOPRIVATE + 3)
+#endif /* _IPX_H_ */
diff -Nru a/include/linux/kernel.h b/include/linux/kernel.h
--- a/include/linux/kernel.h	Wed Apr  9 01:01:38 2003
+++ b/include/linux/kernel.h	Mon May 19 23:48:31 2003
@@ -82,8 +82,6 @@
 extern int get_option(char **str, int *pint);
 extern char *get_options(const char *str, int nints, int *ints);
 extern unsigned long long memparse(char *ptr, char **retptr);
-extern void dev_probe_lock(void);
-extern void dev_probe_unlock(void);
 
 extern int kernel_text_address(unsigned long addr);
 extern int session_of_pgrp(int pgrp);
@@ -135,6 +133,16 @@
 	((unsigned char *)&addr)[1], \
 	((unsigned char *)&addr)[2], \
 	((unsigned char *)&addr)[3]
+
+#define NIP6(addr) \
+	ntohs((addr).s6_addr16[0]), \
+	ntohs((addr).s6_addr16[1]), \
+	ntohs((addr).s6_addr16[2]), \
+	ntohs((addr).s6_addr16[3]), \
+	ntohs((addr).s6_addr16[4]), \
+	ntohs((addr).s6_addr16[5]), \
+	ntohs((addr).s6_addr16[6]), \
+	ntohs((addr).s6_addr16[7])
 
 #if defined(__LITTLE_ENDIAN)
 #define HIPQUAD(addr) \
diff -Nru a/include/linux/kmod.h b/include/linux/kmod.h
--- a/include/linux/kmod.h	Wed Feb 12 19:35:39 2003
+++ b/include/linux/kmod.h	Sat May 17 12:39:13 2003
@@ -24,12 +24,12 @@
 #include <linux/compiler.h>
 
 #ifdef CONFIG_KMOD
-extern int request_module(const char * name);
+extern int request_module(const char * name, ...) __attribute__ ((format (printf, 1, 2)));
 #else
-static inline int request_module(const char * name) { return -ENOSYS; }
+static inline int request_module(const char * name, ...) { return -ENOSYS; }
 #endif
 
-#define try_then_request_module(x, mod) ((x) ?: request_module(mod), (x))
+#define try_then_request_module(x, mod...) ((x) ?: request_module(mod), (x))
 extern int call_usermodehelper(char *path, char *argv[], char *envp[], int wait);
 
 #ifdef CONFIG_HOTPLUG
diff -Nru a/include/linux/list.h b/include/linux/list.h
--- a/include/linux/list.h	Wed Apr 30 00:58:01 2003
+++ b/include/linux/list.h	Sun May  4 20:57:20 2003
@@ -297,6 +297,19 @@
 		     prefetch(pos->member.next))
 
 /**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+ * @pos:	the type * to use as a loop counter.
+ * @n:		another type * to use as temporary storage
+ * @head:	the head for your list.
+ * @member:	the name of the list_struct within the struct.
+ */
+#define list_for_each_entry_safe(pos, n, head, member)			\
+	for (pos = list_entry((head)->next, typeof(*pos), member),	\
+		n = list_entry(pos->member.next, typeof(*pos), member);	\
+	     &pos->member != (head); 					\
+	     pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
  * list_for_each_rcu	-	iterate over an rcu-protected list
  * @pos:	the &struct list_head to use as a loop counter.
  * @head:	the head for your list.
diff -Nru a/include/linux/major.h b/include/linux/major.h
--- a/include/linux/major.h	Tue Mar 18 07:58:33 2003
+++ b/include/linux/major.h	Fri May  2 06:55:04 2003
@@ -27,6 +27,7 @@
 #define MUX_MAJOR		11	/* PA-RISC only */
 #define QIC02_TAPE_MAJOR	12
 #define XT_DISK_MAJOR		13
+#define INPUT_MAJOR		13
 #define SOUND_MAJOR		14
 #define CDU31A_CDROM_MAJOR	15
 #define JOYSTICK_MAJOR		15
diff -Nru a/include/linux/mm.h b/include/linux/mm.h
--- a/include/linux/mm.h	Sat Apr 19 23:22:50 2003
+++ b/include/linux/mm.h	Sat May 17 14:09:59 2003
@@ -23,8 +23,13 @@
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
+#include <asm/processor.h>
 #include <asm/atomic.h>
 
+#ifndef MM_VM_SIZE
+#define MM_VM_SIZE(mm)	TASK_SIZE
+#endif
+
 /*
  * Linux kernel virtual memory manager primitives.
  * The idea being to have a "virtual" mm in the same way
@@ -106,10 +111,14 @@
 #define VM_ACCOUNT	0x00100000	/* Is a VM accounted object */
 #define VM_HUGETLB	0x00400000	/* Huge TLB Page VM */
 
+#ifndef VM_STACK_DEFAULT_FLAGS		/* arch can override this */
+#define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
+#endif
+
 #ifdef CONFIG_STACK_GROWSUP
-#define VM_STACK_FLAGS	(VM_GROWSUP | VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT)
+#define VM_STACK_FLAGS	(VM_GROWSUP | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
 #else
-#define VM_STACK_FLAGS	(VM_GROWSDOWN | VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT)
+#define VM_STACK_FLAGS	(VM_GROWSDOWN | VM_STACK_DEFAULT_FLAGS | VM_ACCOUNT)
 #endif
 
 #define VM_READHINTMASK			(VM_SEQ_READ | VM_RAND_READ)
@@ -209,7 +218,7 @@
  */
 #define put_page_testzero(p)				\
 	({						\
-		BUG_ON(page_count(page) == 0);		\
+		BUG_ON(page_count(p) == 0);		\
 		atomic_dec_and_test(&(p)->count);	\
 	})
 
@@ -421,7 +430,8 @@
 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 long sys_remap_file_pages(unsigned long start, unsigned long size, unsigned long prot, unsigned long pgoff, unsigned long nonblock);
-
+void put_dirty_page(struct task_struct *tsk, struct page *page,
+			unsigned long address, pgprot_t prot);
 
 int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start,
 		int len, int write, int force, struct page **pages, struct vm_area_struct **vmas);
diff -Nru a/include/linux/mmzone.h b/include/linux/mmzone.h
--- a/include/linux/mmzone.h	Mon Feb  3 23:46:59 2003
+++ b/include/linux/mmzone.h	Tue Apr 22 09:33:54 2003
@@ -146,6 +146,7 @@
 #define ZONE_NORMAL		1
 #define ZONE_HIGHMEM		2
 #define MAX_NR_ZONES		3
+#define GFP_ZONEMASK	0x03
 
 /*
  * One allocation request operates on a zonelist. A zonelist
@@ -162,7 +163,6 @@
 	struct zone *zones[MAX_NUMNODES * MAX_NR_ZONES + 1]; // NULL delimited
 };
 
-#define GFP_ZONEMASK	0x0f
 
 /*
  * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM
@@ -178,7 +178,7 @@
 struct bootmem_data;
 typedef struct pglist_data {
 	struct zone node_zones[MAX_NR_ZONES];
-	struct zonelist node_zonelists[GFP_ZONEMASK+1];
+	struct zonelist node_zonelists[MAX_NR_ZONES];
 	int nr_zones;
 	struct page *node_mem_map;
 	unsigned long *valid_addr_bitmap;
diff -Nru a/include/linux/module.h b/include/linux/module.h
--- a/include/linux/module.h	Sun Apr 13 22:45:15 2003
+++ b/include/linux/module.h	Mon May 19 18:25:07 2003
@@ -437,7 +437,6 @@
 #endif /* MODULE */
 
 #define symbol_request(x) try_then_request_module(symbol_get(x), "symbol:" #x)
-#define SET_MODULE_OWNER(dev) ((dev)->owner = THIS_MODULE)
 
 /* BELOW HERE ALL THESE ARE OBSOLETE AND WILL VANISH */
 
diff -Nru a/include/linux/moduleloader.h b/include/linux/moduleloader.h
--- a/include/linux/moduleloader.h	Mon Jan 13 09:46:25 2003
+++ b/include/linux/moduleloader.h	Mon May 12 21:23:07 2003
@@ -41,4 +41,7 @@
 		    const Elf_Shdr *sechdrs,
 		    struct module *mod);
 
+/* Any cleanup needed when module leaves. */
+void module_arch_cleanup(struct module *mod);
+
 #endif
diff -Nru a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h
--- a/include/linux/msdos_fs.h	Tue Dec 31 17:16:31 2002
+++ b/include/linux/msdos_fs.h	Mon May 12 21:23:11 2003
@@ -146,8 +146,7 @@
 	__u32   reserved1[120];	/* Nothing as far as I can tell */
 	__u32   signature2;	/* 0x61417272L */
 	__u32   free_clusters;	/* Free cluster count.  -1 if unknown */
-	__u32   next_cluster;	/* Most recently allocated cluster.
-				 * Unused under Linux. */
+	__u32   next_cluster;	/* Most recently allocated cluster */
 	__u32   reserved2[4];
 };
 
diff -Nru a/include/linux/msg.h b/include/linux/msg.h
--- a/include/linux/msg.h	Wed Dec 18 05:36:54 2002
+++ b/include/linux/msg.h	Fri May  9 14:23:37 2003
@@ -94,9 +94,9 @@
 };
 
 asmlinkage long sys_msgget (key_t key, int msgflg);
-asmlinkage long sys_msgsnd (int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
-asmlinkage long sys_msgrcv (int msqid, struct msgbuf *msgp, size_t msgsz, long msgtyp, int msgflg);
-asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds *buf);
+asmlinkage long sys_msgsnd (int msqid, struct msgbuf __user *msgp, size_t msgsz, int msgflg);
+asmlinkage long sys_msgrcv (int msqid, struct msgbuf __user *msgp, size_t msgsz, long msgtyp, int msgflg);
+asmlinkage long sys_msgctl (int msqid, int cmd, struct msqid_ds __user *buf);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/net.h b/include/linux/net.h
--- a/include/linux/net.h	Fri May  2 22:55:11 2003
+++ b/include/linux/net.h	Mon May 12 14:35:19 2003
@@ -96,18 +96,18 @@
 	struct module	*owner;
 	int		(*release)   (struct socket *sock);
 	int		(*bind)	     (struct socket *sock,
-				      struct sockaddr *umyaddr,
+				      struct sockaddr *myaddr,
 				      int sockaddr_len);
 	int		(*connect)   (struct socket *sock,
-				      struct sockaddr *uservaddr,
+				      struct sockaddr *vaddr,
 				      int sockaddr_len, int flags);
 	int		(*socketpair)(struct socket *sock1,
 				      struct socket *sock2);
 	int		(*accept)    (struct socket *sock,
 				      struct socket *newsock, int flags);
 	int		(*getname)   (struct socket *sock,
-				      struct sockaddr *uaddr,
-				      int *usockaddr_len, int peer);
+				      struct sockaddr *addr,
+				      int *sockaddr_len, int peer);
 	unsigned int	(*poll)	     (struct file *file, struct socket *sock,
 				      struct poll_table_struct *wait);
 	int		(*ioctl)     (struct socket *sock, unsigned int cmd,
@@ -115,9 +115,9 @@
 	int		(*listen)    (struct socket *sock, int len);
 	int		(*shutdown)  (struct socket *sock, int flags);
 	int		(*setsockopt)(struct socket *sock, int level,
-				      int optname, char *optval, int optlen);
+				      int optname, char __user *optval, int optlen);
 	int		(*getsockopt)(struct socket *sock, int level,
-				      int optname, char *optval, int *optlen);
+				      int optname, char __user *optval, int __user *optlen);
 	int		(*sendmsg)   (struct kiocb *iocb, struct socket *sock,
 				      struct msghdr *m, int total_len);
 	int		(*recvmsg)   (struct kiocb *iocb, struct socket *sock,
diff -Nru a/include/linux/netdevice.h b/include/linux/netdevice.h
--- a/include/linux/netdevice.h	Thu Apr  3 04:44:39 2003
+++ b/include/linux/netdevice.h	Tue May 20 19:59:14 2003
@@ -28,7 +28,7 @@
 #include <linux/if.h>
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
-#include <linux/kobject.h>
+#include <linux/device.h>
 
 #include <asm/atomic.h>
 #include <asm/cache.h>
@@ -427,9 +427,6 @@
 	int			(*neigh_setup)(struct net_device *dev, struct neigh_parms *);
 	int			(*accept_fastpath)(struct net_device *, struct dst_entry*);
 
-	/* open/release and usage marking */
-	struct module *owner;
-
 	/* bridge stuff */
 	struct net_bridge_port	*br_port;
 
@@ -444,10 +441,22 @@
 	struct divert_blk	*divert;
 #endif /* CONFIG_NET_DIVERT */
 
-	/* generic object representation */
-	struct kobject kobj;
+	/* generic device structure used in constructing class */
+	struct device		*dev;
+
+	/* class/net/name entry */
+	struct class_device	class_dev;
+
+	/* statistics sub-directory */
+	struct kobject		stats_kobj;
 };
 
+#define SET_MODULE_OWNER(dev) do { } while (0)
+/* Set the sysfs physical device reference for the network logical device
+ * if set prior to registration will cause a symlink during initialization.
+ */
+#define SET_NETDEV_DEV(net, pdev)	((net)->dev = (pdev))
+
 
 struct packet_type 
 {
@@ -456,7 +465,7 @@
 	int			(*func) (struct sk_buff *, struct net_device *,
 					 struct packet_type *);
 	void			*data;	/* Private to the packet type		*/
-	struct packet_type	*next;
+	struct list_head	list;
 };
 
 
@@ -472,6 +481,7 @@
 extern struct net_device    *dev_getbyhwaddr(unsigned short type, char *hwaddr);
 extern void		dev_add_pack(struct packet_type *pt);
 extern void		dev_remove_pack(struct packet_type *pt);
+extern void		__dev_remove_pack(struct packet_type *pt);
 extern int		dev_get(const char *name);
 extern struct net_device	*dev_get_by_flags(unsigned short flags,
 						  unsigned short mask);
@@ -562,12 +572,12 @@
 	set_bit(__LINK_STATE_XOFF, &dev->state);
 }
 
-static inline int netif_queue_stopped(struct net_device *dev)
+static inline int netif_queue_stopped(const struct net_device *dev)
 {
 	return test_bit(__LINK_STATE_XOFF, &dev->state);
 }
 
-static inline int netif_running(struct net_device *dev)
+static inline int netif_running(const struct net_device *dev)
 {
 	return test_bit(__LINK_STATE_START, &dev->state);
 }
@@ -607,7 +617,9 @@
 #define HAVE_NETIF_RECEIVE_SKB 1
 extern int		netif_receive_skb(struct sk_buff *skb);
 extern int		dev_ioctl(unsigned int cmd, void *);
+extern unsigned		dev_get_flags(const struct net_device *);
 extern int		dev_change_flags(struct net_device *, unsigned);
+extern int		dev_set_mtu(struct net_device *, int);
 extern void		dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev);
 
 extern void		dev_init(void);
@@ -625,12 +637,12 @@
        return err;
 }
 
-extern int netdev_finish_unregister(struct net_device *dev);
+/* Called by rtnetlink.c:rtnl_unlock() */
+extern void netdev_run_todo(void);
 
 static inline void dev_put(struct net_device *dev)
 {
-	if (atomic_dec_and_test(&dev->refcnt))
-		netdev_finish_unregister(dev);
+	atomic_dec(&dev->refcnt);
 }
 
 #define __dev_put(dev) atomic_dec(&(dev)->refcnt)
@@ -643,7 +655,7 @@
 
 extern void linkwatch_fire_event(struct net_device *dev);
 
-static inline int netif_carrier_ok(struct net_device *dev)
+static inline int netif_carrier_ok(const struct net_device *dev)
 {
 	return !test_bit(__LINK_STATE_NOCARRIER, &dev->state);
 }
diff -Nru a/include/linux/netfilter_ipv4/compat_firewall.h b/include/linux/netfilter_ipv4/compat_firewall.h
--- a/include/linux/netfilter_ipv4/compat_firewall.h	Tue Feb  5 09:39:43 2002
+++ b/include/linux/netfilter_ipv4/compat_firewall.h	Tue May 13 13:25:32 2003
@@ -21,20 +21,20 @@
 {
 	struct firewall_ops *next;
 	int (*fw_forward)(struct firewall_ops *this, int pf,
-			  struct net_device *dev, void *phdr, void *arg,
+			  struct net_device *dev, void *arg,
 			  struct sk_buff **pskb);
 	int (*fw_input)(struct firewall_ops *this, int pf,
-			struct net_device *dev, void *phdr, void *arg,
+			struct net_device *dev, void *arg,
 			struct sk_buff **pskb);
 	int (*fw_output)(struct firewall_ops *this, int pf,
-			 struct net_device *dev, void *phdr, void *arg,
+			 struct net_device *dev, void *arg,
 			 struct sk_buff **pskb);
 	/* These may be NULL. */
 	int (*fw_acct_in)(struct firewall_ops *this, int pf,
-			  struct net_device *dev, void *phdr, void *arg,
+			  struct net_device *dev, void *arg,
 			  struct sk_buff **pskb);
 	int (*fw_acct_out)(struct firewall_ops *this, int pf,
-			   struct net_device *dev, void *phdr, void *arg,
+			   struct net_device *dev, void *arg,
 			   struct sk_buff **pskb);
 };
 
diff -Nru a/include/linux/netfilter_ipv4/ip_nat_core.h b/include/linux/netfilter_ipv4/ip_nat_core.h
--- a/include/linux/netfilter_ipv4/ip_nat_core.h	Tue Feb  5 09:39:43 2002
+++ b/include/linux/netfilter_ipv4/ip_nat_core.h	Sat May 17 15:37:24 2003
@@ -16,10 +16,10 @@
 
 extern struct list_head protos;
 
-extern unsigned int icmp_reply_translation(struct sk_buff *skb,
-					   struct ip_conntrack *conntrack,
-					   unsigned int hooknum,
-					   int dir);
+extern int icmp_reply_translation(struct sk_buff **pskb,
+				  struct ip_conntrack *conntrack,
+				  unsigned int hooknum,
+				  int dir);
 
 extern void replace_in_hashes(struct ip_conntrack *conntrack,
 			      struct ip_nat_info *info);
diff -Nru a/include/linux/netfilter_ipv4/ip_nat_helper.h b/include/linux/netfilter_ipv4/ip_nat_helper.h
--- a/include/linux/netfilter_ipv4/ip_nat_helper.h	Fri Jan 10 00:58:59 2003
+++ b/include/linux/netfilter_ipv4/ip_nat_helper.h	Tue May  6 01:04:01 2003
@@ -43,22 +43,23 @@
 
 extern int ip_nat_helper_register(struct ip_nat_helper *me);
 extern void ip_nat_helper_unregister(struct ip_nat_helper *me);
+
+/* These return true or false. */
 extern int ip_nat_mangle_tcp_packet(struct sk_buff **skb,
 				struct ip_conntrack *ct,
 				enum ip_conntrack_info ctinfo,
 				unsigned int match_offset,
 				unsigned int match_len,
-				char *rep_buffer,
+				const char *rep_buffer,
 				unsigned int rep_len);
 extern int ip_nat_mangle_udp_packet(struct sk_buff **skb,
 				struct ip_conntrack *ct,
 				enum ip_conntrack_info ctinfo,
 				unsigned int match_offset,
 				unsigned int match_len,
-				char *rep_buffer,
+				const char *rep_buffer,
 				unsigned int rep_len);
-extern int ip_nat_seq_adjust(struct sk_buff *skb,
-				struct ip_conntrack *ct,
-				enum ip_conntrack_info ctinfo);
-extern void ip_nat_delete_sack(struct sk_buff *skb);
+extern int ip_nat_seq_adjust(struct sk_buff **pskb, 
+			     struct ip_conntrack *ct, 
+			     enum ip_conntrack_info ctinfo);
 #endif
diff -Nru a/include/linux/netfilter_ipv4/ip_nat_protocol.h b/include/linux/netfilter_ipv4/ip_nat_protocol.h
--- a/include/linux/netfilter_ipv4/ip_nat_protocol.h	Tue Feb  5 09:39:43 2002
+++ b/include/linux/netfilter_ipv4/ip_nat_protocol.h	Tue May  6 01:04:01 2003
@@ -18,10 +18,11 @@
 	unsigned int protonum;
 
 	/* Do a packet translation according to the ip_nat_proto_manip
-	 * and manip type. */
-	void (*manip_pkt)(struct iphdr *iph, size_t len,
-			  const struct ip_conntrack_manip *manip,
-			  enum ip_nat_manip_type maniptype);
+	 * and manip type.  Return true if succeeded. */
+	int (*manip_pkt)(struct sk_buff **pskb,
+			 unsigned int hdroff,
+			 const struct ip_conntrack_manip *manip,
+			 enum ip_nat_manip_type maniptype);
 
 	/* Is the manipable part of the tuple between min and max incl? */
 	int (*in_range)(const struct ip_conntrack_tuple *tuple,
diff -Nru a/include/linux/netfilter_ipv4/ipfwadm_core.h b/include/linux/netfilter_ipv4/ipfwadm_core.h
--- a/include/linux/netfilter_ipv4/ipfwadm_core.h	Tue Feb  5 09:39:43 2002
+++ b/include/linux/netfilter_ipv4/ipfwadm_core.h	Tue May 13 13:25:32 2003
@@ -250,7 +250,7 @@
 
 extern int ip_fw_masq_timeouts(void *user, int len);
 
-extern int ip_fw_chk(struct iphdr *, struct net_device *, __u16 *,
+extern int ip_fw_chk(struct sk_buff **, struct net_device *, __u16 *,
 		     struct ip_fw *, int, int);
 #endif /* KERNEL */
 #endif /* _IP_FW_H */
diff -Nru a/include/linux/netfilter_ipv4.h b/include/linux/netfilter_ipv4.h
--- a/include/linux/netfilter_ipv4.h	Mon Oct 28 05:06:31 2002
+++ b/include/linux/netfilter_ipv4.h	Sat May 17 15:37:24 2003
@@ -75,6 +75,12 @@
 #endif /*CONFIG_NETFILTER_DEBUG*/
 
 extern int ip_route_me_harder(struct sk_buff **pskb);
+
+/* Call this before modifying an existing IP packet: ensures it is
+   modifiable and linear to the point you care about (writable_len).
+   Returns true or false. */
+extern int skb_ip_make_writable(struct sk_buff **pskb,
+				unsigned int writable_len);
 #endif /*__KERNEL__*/
 
 #endif /*__LINUX_IP_NETFILTER_H*/
diff -Nru a/include/linux/nfs.h b/include/linux/nfs.h
--- a/include/linux/nfs.h	Mon Oct 14 07:03:25 2002
+++ b/include/linux/nfs.h	Mon May 19 23:34:37 2003
@@ -85,9 +85,9 @@
 	NFSERR_NOFILEHANDLE = 10020,	/*       v4 */
 	NFSERR_MINOR_VERS_MISMATCH = 10021,   /* v4 */
 	NFSERR_STALE_CLIENTID = 10022,	/*       v4 */
-	NFSERR_STALE_STATEID = 10023,	/*       v4 */
-	NFSERR_OLD_STATEID = 10024,	/*       v4 */
-	NFSERR_BAD_STATEID = 10025,	/*       v4 */
+	NFSERR_STALE_STATEID = 10023,   /*       v4 */
+	NFSERR_OLD_STATEID = 10024,     /*       v4 */
+	NFSERR_BAD_STATEID = 10025,     /*       v4 */  
 	NFSERR_BAD_SEQID = 10026,	/*       v4 */
 	NFSERR_NOT_SAME = 10027,	/*       v4 */
 	NFSERR_LOCK_RANGE = 10028,	/*       v4 */
@@ -99,7 +99,8 @@
 	NFSERR_RECLAIM_BAD = 10034,	/*       v4 */
 	NFSERR_RECLAIM_CONFLICT = 10035,/*       v4 */
 	NFSERR_BAD_XDR = 10036,		/*       v4 */
-	NFSERR_LOCKS_HELD = 10037	/*       v4 */
+	NFSERR_LOCKS_HELD = 10037,	/*       v4 */
+	NFSERR_REPLAY_ME = 10038	/*       v4 */
 };
 
 /* NFSv2 file types - beware, these are not the same in NFSv3 */
diff -Nru a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
--- a/include/linux/nfs_fs_sb.h	Mon Apr  7 15:46:22 2003
+++ b/include/linux/nfs_fs_sb.h	Mon May 12 11:11:38 2003
@@ -27,7 +27,7 @@
 	char *			hostname;	/* remote hostname */
 	struct nfs_fh		fh;
 	struct sockaddr_in	addr;
-#if CONFIG_NFS_V4
+#ifdef CONFIG_NFS_V4
 	/* Our own IP address, as a null-terminated string.
 	 * This is used to generate the clientid, and the callback address.
 	 */
diff -Nru a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
--- a/include/linux/nfsd/export.h	Tue Mar 11 20:07:11 2003
+++ b/include/linux/nfsd/export.h	Mon May 19 23:34:38 2003
@@ -100,7 +100,7 @@
 				   struct cache_req *reqp);
 int			exp_rootfh(struct auth_domain *, 
 					char *path, struct knfsd_fh *, int maxsize);
-int			exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp);
+int			exp_pseudoroot(struct auth_domain *, struct svc_fh *fhp, struct cache_req *creq);
 int			nfserrno(int errno);
 
 extern void expkey_put(struct cache_head *item, struct cache_detail *cd);
diff -Nru a/include/linux/nfsd/nfsd.h b/include/linux/nfsd/nfsd.h
--- a/include/linux/nfsd/nfsd.h	Tue Apr 15 12:40:54 2003
+++ b/include/linux/nfsd/nfsd.h	Mon May 19 23:34:37 2003
@@ -40,7 +40,7 @@
 #define MAY_OWNER_OVERRIDE	64
 #define	MAY_LOCAL_ACCESS	128 /* IRIX doing local access check on device special file*/
 #if (MAY_SATTR | MAY_TRUNC | MAY_LOCK | MAY_OWNER_OVERRIDE | MAY_LOCAL_ACCESS) & (MAY_READ | MAY_WRITE | MAY_EXEC)
-# error "please use a different value for MAY_SATTR or MAY_TRUNC or MAY_LOCK or MAY_OWNER_OVERRIDE."
+# error "please use a different value for MAY_SATTR or MAY_TRUNC or MAY_LOCK or MAY_LOCAL_ACCESS or MAY_OWNER_OVERRIDE."
 #endif
 #define MAY_CREATE		(MAY_EXEC|MAY_WRITE)
 #define MAY_REMOVE		(MAY_EXEC|MAY_WRITE|MAY_TRUNC)
@@ -170,6 +170,7 @@
 #define	nfserr_serverfault	__constant_htonl(NFSERR_SERVERFAULT)
 #define	nfserr_badtype		__constant_htonl(NFSERR_BADTYPE)
 #define	nfserr_jukebox		__constant_htonl(NFSERR_JUKEBOX)
+#define nfserr_expired          __constant_htonl(NFSERR_EXPIRED)
 #define	nfserr_bad_cookie	__constant_htonl(NFSERR_BAD_COOKIE)
 #define	nfserr_same		__constant_htonl(NFSERR_SAME)
 #define	nfserr_clid_inuse	__constant_htonl(NFSERR_CLID_INUSE)
@@ -177,6 +178,11 @@
 #define	nfserr_resource		__constant_htonl(NFSERR_RESOURCE)
 #define	nfserr_nofilehandle	__constant_htonl(NFSERR_NOFILEHANDLE)
 #define	nfserr_minor_vers_mismatch	__constant_htonl(NFSERR_MINOR_VERS_MISMATCH)
+#define nfserr_share_denied	__constant_htonl(NFSERR_SHARE_DENIED)
+#define nfserr_stale_stateid	__constant_htonl(NFSERR_STALE_STATEID)
+#define nfserr_old_stateid	__constant_htonl(NFSERR_OLD_STATEID)
+#define nfserr_bad_stateid	__constant_htonl(NFSERR_BAD_STATEID)
+#define nfserr_bad_seqid	__constant_htonl(NFSERR_BAD_SEQID)
 #define	nfserr_symlink		__constant_htonl(NFSERR_SYMLINK)
 #define	nfserr_not_same		__constant_htonl(NFSERR_NOT_SAME)
 #define	nfserr_readdir_nospc	__constant_htonl(NFSERR_READDIR_NOSPC)
diff -Nru a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h
--- a/include/linux/nfsd/state.h	Sat Apr 12 23:15:50 2003
+++ b/include/linux/nfsd/state.h	Mon May 19 23:34:37 2003
@@ -39,9 +39,25 @@
 
 #include <linux/list.h>
 
-#define NFSD4_CLIENT_MAXNAME 1024
+#define NFS4_OPAQUE_LIMIT 1024
+typedef struct {
+	u32             cl_boot;
+	u32             cl_id;
+} clientid_t;
 
-extern int nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid);
+typedef struct {
+	u32             so_boot;
+	u32             so_stateownerid;
+	u32             so_fileid;
+} stateid_opaque_t;
+
+typedef struct {
+	u32                     si_generation;
+	stateid_opaque_t        si_opaque;
+} stateid_t;
+#define si_boot           si_opaque.so_boot
+#define si_stateownerid   si_opaque.so_stateownerid
+#define si_fileid         si_opaque.so_fileid
 
 /*
  * struct nfs4_client - one per client.  Clientids live here.
@@ -49,10 +65,14 @@
  *
  * 	o Each nfs4_clients is also hashed by name 
  * 	  (the opaque quantity initially sent by the client to identify itself).
+ * 	  
+ *	o cl_perclient list is used to ensure no dangling stateowner references
+ *	  when we expire the nfs4_client
  */
 struct nfs4_client {
 	struct list_head	cl_idhash; 	/* hash by cl_clientid.id */
 	struct list_head	cl_strhash; 	/* hash by cl_name */
+	struct list_head	cl_perclient; 	/* list: stateowners */
 	struct xdr_netobj	cl_name; 	/* id generated by client */
 	nfs4_verifier		cl_verifier; 	/* generated by client */
 	u32			cl_addr; 	/* client ipaddress */
@@ -60,4 +80,66 @@
 	clientid_t		cl_clientid;	/* generated by server */
 	nfs4_verifier		cl_confirm;	/* generated by server */
 };
+
+static inline void
+update_stateid(stateid_t *stateid)
+{
+stateid->si_generation++;
+}
+
+
+/*
+* nfs4_stateowner can either be an open_owner, or (eventually) a lock_owner
+*
+*    o so_peropenstate list is used to ensure no dangling nfs4_stateid
+*              reverences when we release a stateowner.
+*/
+struct nfs4_stateowner {
+	struct list_head        so_strhash;   /* hash by op_name */
+	struct list_head        so_perclient; /* nfs4_client->cl_perclient */
+	struct list_head        so_peropenstate; /* list: nfs4_stateid */
+	u32                     so_id;
+	struct nfs4_client *    so_client;
+	u32                     so_seqid;    
+	struct xdr_netobj       so_owner;     /* open owner name */
+	int                     so_confirmed; /* successful OPEN_CONFIRM? */
+};
+
+typedef struct {
+	u32                     dev; /* super_block->s_dev */
+	unsigned long           ino;
+	u32                     generation;
+} nfs4_ino_desc_t;
+
+/*
+*  nfs4_file: a file opened by some number of (open) nfs4_stateowners.
+*    o fi_perfile list is used to search for conflicting 
+*      share_acces, share_deny on the file.
+*/
+struct nfs4_file {
+	struct list_head        fi_hash;    /* hash by nfs4_ino_desc_t fields */
+	struct list_head        fi_perfile; /* list: nfs4_stateid */
+	nfs4_ino_desc_t         fi_ino;
+	u32                     fi_id;      /* used with stateowner->so_id 
+					     * for openstateid_hashtbl hash */
+};
+
+/*
+* nfs4_stateid can either be an open stateid or (eventually) a lock stateid
+*
+* (open)nfs4_stateid: one per (open)nfs4_stateowner, nfs4_file
+*/
+
+struct nfs4_stateid {
+	struct list_head              st_perfile; /* file_hashtbl[]*/
+	struct list_head              st_peropenstate; /* nfs4_stateowner->so_peropenstate */
+	struct nfs4_stateowner      * st_stateowner;
+	struct nfs4_file            * st_file;
+	stateid_t                     st_stateid;
+	struct file                   st_vfs_file;
+	int                           st_vfs_set;
+	unsigned int                  st_share_access;
+	unsigned int                  st_share_deny;
+};
+
 #endif   /* NFSD4_STATE_H */
diff -Nru a/include/linux/nfsd/xdr4.h b/include/linux/nfsd/xdr4.h
--- a/include/linux/nfsd/xdr4.h	Mon Feb 17 13:50:11 2003
+++ b/include/linux/nfsd/xdr4.h	Mon May 19 23:34:37 2003
@@ -41,27 +41,6 @@
 
 #define NFSD4_MAX_TAGLEN	128
 
-typedef struct {
-	u32		cl_boot;
-	u32		cl_id;
-} clientid_t;
-
-typedef u32 stateid_boot_t;        /* used to detect stale stateids */
-typedef u32 stateid_lockowner_t;   /* lockowner id - used in various places */
-typedef u32 stateid_file_t;        /* identifies a unique file per lockowner */
-typedef u32 stateid_generation_t;  /* used to update stateids */
-
-typedef struct {
-	stateid_boot_t		so_boot;
-	stateid_lockowner_t	so_lockowner;
-	stateid_file_t		so_file;
-} stateid_other_t;
-
-typedef struct {
-	stateid_generation_t	st_generation;
-	stateid_other_t		st_other;
-} stateid_t;
-
 typedef u32 delegation_zero_t;
 typedef u32 delegation_boot_t;
 typedef u64 delegation_id_t;
@@ -143,8 +122,7 @@
 
 struct nfsd4_open {
 	u32		op_claim_type;      /* request */
-	u32		op_namelen;	    /* request - everything but CLAIM_PREV */
-	char *		op_name;	    /* request - everything but CLAIM_PREV */
+	struct xdr_netobj op_fname;	    /* request - everything but CLAIM_PREV */
 	u32		op_delegate_type;   /* request - CLAIM_PREV only */
 	delegation_stateid_t	op_delegate_stateid; /* request - CLAIM_DELEGATE_CUR only */
 	u32		op_create;     	    /* request */
@@ -155,8 +133,7 @@
 		nfs4_verifier	verf;		                     /* EXCLUSIVE4 */
 	} u;
 	clientid_t	op_clientid;        /* request */
-	u32		op_ownerlen;        /* request */
-	char *		op_owner;           /* request */
+	struct xdr_netobj op_owner;           /* request */
 	u32		op_seqid;           /* request */
 	u32		op_share_access;    /* request */
 	u32		op_share_deny;      /* request */
@@ -164,6 +141,7 @@
 	struct nfsd4_change_info  op_cinfo; /* response */
 	u32		op_rflags;          /* response */
 	int		op_truncate;        /* used during processing */
+	struct nfs4_stateowner *op_stateowner; /* used during processing */
 
 };
 #define op_iattr	u.iattr
@@ -343,7 +321,10 @@
 void nfsd4_encode_operation(struct nfsd4_compoundres *, struct nfsd4_op *);
 int nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
 		       struct dentry *dentry, u32 *buffer, int *countp, u32 *bmval);
-
+extern int nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_setclientid *setclid);
+extern int nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_setclientid_confirm *setclientid_confirm);
+extern int nfsd4_process_open1(struct nfsd4_open *open);
+extern int nfsd4_process_open2(struct svc_rqst *rqstp, struct svc_fh *current_fh, struct nfsd4_open *open);
 #endif
 
 /*
diff -Nru a/include/linux/pagemap.h b/include/linux/pagemap.h
--- a/include/linux/pagemap.h	Thu Apr 17 22:12:10 2003
+++ b/include/linux/pagemap.h	Mon May 12 14:35:19 2003
@@ -172,7 +172,7 @@
  * This assumes that two userspace pages are always sufficient.  That's
  * not true if PAGE_CACHE_SIZE > PAGE_SIZE.
  */
-static inline int fault_in_pages_writeable(char *uaddr, int size)
+static inline int fault_in_pages_writeable(char __user *uaddr, int size)
 {
 	int ret;
 
@@ -182,7 +182,7 @@
 	 */
 	ret = __put_user(0, uaddr);
 	if (ret == 0) {
-		char *end = uaddr + size - 1;
+		char __user *end = uaddr + size - 1;
 
 		/*
 		 * If the page was already mapped, this will get a cache miss
@@ -195,14 +195,14 @@
 	return ret;
 }
 
-static inline void fault_in_pages_readable(const char *uaddr, int size)
+static inline void fault_in_pages_readable(const char __user *uaddr, int size)
 {
 	volatile char c;
 	int ret;
 
 	ret = __get_user(c, (char *)uaddr);
 	if (ret == 0) {
-		const char *end = uaddr + size - 1;
+		const char __user *end = uaddr + size - 1;
 
 		if (((unsigned long)uaddr & PAGE_MASK) !=
 				((unsigned long)end & PAGE_MASK))
diff -Nru a/include/linux/pci_ids.h b/include/linux/pci_ids.h
--- a/include/linux/pci_ids.h	Thu May  1 13:42:38 2003
+++ b/include/linux/pci_ids.h	Mon May 19 18:28:58 2003
@@ -569,6 +569,9 @@
 #define PCI_DEVICE_ID_SI_751		0x0751
 #define PCI_DEVICE_ID_SI_752		0x0752
 #define PCI_DEVICE_ID_SI_900		0x0900
+#define PCI_DEVICE_ID_SI_961		0x0961
+#define PCI_DEVICE_ID_SI_962		0x0962
+#define PCI_DEVICE_ID_SI_963		0x0963
 #define PCI_DEVICE_ID_SI_5107		0x5107
 #define PCI_DEVICE_ID_SI_5300		0x5300
 #define PCI_DEVICE_ID_SI_5511		0x5511
@@ -605,6 +608,7 @@
 #define PCI_DEVICE_ID_HP_ZX1_SBA	0x1229
 #define PCI_DEVICE_ID_HP_ZX1_IOC	0x122a
 #define PCI_DEVICE_ID_HP_ZX1_LBA	0x122e
+#define PCI_DEVICE_ID_HP_SX1000_IOC	0x127c
 #define PCI_DEVICE_ID_HP_DIVA_EVEREST	0x1282
 #define PCI_DEVICE_ID_HP_DIVA_AUX	0x1290
 
@@ -1007,7 +1011,9 @@
 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_550XGL	0x017B
 #define PCI_DEVICE_ID_NVIDIA_QUADRO4_500_GOGL	0x017C
 #define PCI_DEVICE_ID_NVIDIA_IGEFORCE2		0x01a0
+#define PCI_DEVICE_ID_NVIDIA_NFORCE		0x01a4
 #define PCI_DEVICE_ID_NVIDIA_NFORCE_IDE		0x01bc
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2		0x01e0
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3		0x0200
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1		0x0201
 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2		0x0202
@@ -1125,6 +1131,7 @@
 #define PCI_DEVICE_ID_VIA_8754		0x3168
 #define PCI_DEVICE_ID_VIA_8235		0x3177
 #define PCI_DEVICE_ID_VIA_P4N333	0x3178
+#define PCI_DEVICE_ID_VIA_K8T400M_0	0x3188
 #define PCI_DEVICE_ID_VIA_8377_0	0x3189
 #define PCI_DEVICE_ID_VIA_KM400		0x3205
 #define PCI_DEVICE_ID_VIA_P4M400	0x3209
@@ -1902,10 +1909,13 @@
 #define PCI_DEVICE_ID_INTEL_82845G_IG	0x2562
 #define PCI_DEVICE_ID_INTEL_82865_HB	0x2570
 #define PCI_DEVICE_ID_INTEL_82865_IG	0x2572
+#define PCI_DEVICE_ID_INTEL_82875_HB	0x2578
+#define PCI_DEVICE_ID_INTEL_82875_IG	0x257b
+#define PCI_DEVICE_ID_INTEL_82855PM_HB	0x3340
 #define PCI_DEVICE_ID_INTEL_82830_HB	0x3575
 #define PCI_DEVICE_ID_INTEL_82830_CGC	0x3577
-#define PCI_DEVICE_ID_INTEL_82855_HB	0x3580
-#define PCI_DEVICE_ID_INTEL_82855_IG	0x3582
+#define PCI_DEVICE_ID_INTEL_82855GM_HB	0x3580
+#define PCI_DEVICE_ID_INTEL_82855GM_IG	0x3582
 #define PCI_DEVICE_ID_INTEL_80310	0x530d
 #define PCI_DEVICE_ID_INTEL_82371SB_0	0x7000
 #define PCI_DEVICE_ID_INTEL_82371SB_1	0x7010
diff -Nru a/include/linux/pfkeyv2.h b/include/linux/pfkeyv2.h
--- a/include/linux/pfkeyv2.h	Thu Apr  3 05:19:44 2003
+++ b/include/linux/pfkeyv2.h	Tue May  6 00:10:21 2003
@@ -275,8 +275,8 @@
 
 /* Encryption algorithms */
 #define SADB_EALG_NONE			0
-#define SADB_EALG_DESCBC		1
-#define SADB_EALG_3DESCBC		2
+#define SADB_EALG_DESCBC		2
+#define SADB_EALG_3DESCBC		3
 #define SADB_X_EALG_CASTCBC		6
 #define SADB_X_EALG_BLOWFISHCBC		7
 #define SADB_EALG_NULL			11
diff -Nru a/include/linux/ppp_defs.h b/include/linux/ppp_defs.h
--- a/include/linux/ppp_defs.h	Tue Feb  5 09:39:40 2002
+++ b/include/linux/ppp_defs.h	Thu May  8 15:00:57 2003
@@ -74,12 +74,15 @@
 #define PPP_IPV6	0x57	/* Internet Protocol Version 6 */
 #define PPP_COMPFRAG	0xfb	/* fragment compressed below bundle */
 #define PPP_COMP	0xfd	/* compressed packet */
+#define PPP_MPLS_UC	0x0281	/* Multi Protocol Label Switching - Unicast */
+#define PPP_MPLS_MC	0x0283	/* Multi Protocol Label Switching - Multicast */
 #define PPP_IPCP	0x8021	/* IP Control Protocol */
 #define PPP_ATCP	0x8029	/* AppleTalk Control Protocol */
 #define PPP_IPXCP	0x802b	/* IPX Control Protocol */
 #define PPP_IPV6CP	0x8057	/* IPv6 Control Protocol */
 #define PPP_CCPFRAG	0x80fb	/* CCP at link level (below MP bundle) */
 #define PPP_CCP		0x80fd	/* Compression Control Protocol */
+#define PPP_MPLSCP	0x80fd	/* MPLS Control Protocol */
 #define PPP_LCP		0xc021	/* Link Control Protocol */
 #define PPP_PAP		0xc023	/* Password Authentication Protocol */
 #define PPP_LQR		0xc025	/* Link Quality Report protocol */
diff -Nru a/include/linux/proc_fs.h b/include/linux/proc_fs.h
--- a/include/linux/proc_fs.h	Mon Aug 12 16:20:00 2002
+++ b/include/linux/proc_fs.h	Mon May 12 11:10:09 2003
@@ -48,7 +48,7 @@
 
 typedef	int (read_proc_t)(char *page, char **start, off_t off,
 			  int count, int *eof, void *data);
-typedef	int (write_proc_t)(struct file *file, const char *buffer,
+typedef	int (write_proc_t)(struct file *file, const char __user *buffer,
 			   unsigned long count, void *data);
 typedef int (get_info_t)(char *, char **, off_t, int);
 
@@ -163,6 +163,15 @@
 	return create_proc_info_entry(name,mode,proc_net,get_info);
 }
 
+static inline struct proc_dir_entry *proc_net_fops_create(const char *name,
+	mode_t mode, struct file_operations *fops)
+{
+	struct proc_dir_entry *res = create_proc_entry(name, mode, proc_net);
+	if (res)
+		res->proc_fops = fops;
+	return res;
+}
+
 static inline void proc_net_remove(const char *name)
 {
 	remove_proc_entry(name,proc_net);
@@ -171,7 +180,7 @@
 #else
 
 #define proc_root_driver NULL
-
+#define proc_net_fops_create(name,mode,fops) do {} while(0)
 static inline struct proc_dir_entry *proc_net_create(const char *name, mode_t mode, 
 	get_info_t *get_info) {return NULL;}
 static inline void proc_net_remove(const char *name) {}
diff -Nru a/include/linux/ptrace.h b/include/linux/ptrace.h
--- a/include/linux/ptrace.h	Sat Feb 15 19:30:17 2003
+++ b/include/linux/ptrace.h	Mon May 12 14:35:19 2003
@@ -69,8 +69,8 @@
 #include <linux/compiler.h>		/* For unlikely.  */
 #include <linux/sched.h>		/* For struct task_struct.  */
 
-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);
+extern int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len);
+extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len);
 extern int ptrace_attach(struct task_struct *tsk);
 extern int ptrace_detach(struct task_struct *, unsigned int);
 extern void ptrace_disable(struct task_struct *);
diff -Nru a/include/linux/raid/md.h b/include/linux/raid/md.h
--- a/include/linux/raid/md.h	Thu Apr  3 17:21:33 2003
+++ b/include/linux/raid/md.h	Wed May  7 21:18:43 2003
@@ -61,9 +61,20 @@
 #define MD_MINOR_VERSION                90
 #define MD_PATCHLEVEL_VERSION           0
 
-extern inline char * bdev_partition_name (struct block_device *bdev)
+/*
+ * XXX(hch): This function is broken.  Someone who understands the md
+ * code needs to go through all callers, check whether bdev could
+ * be NULL and replace it with direct calls to bdevmame.
+ *
+ * This would also fix the returns buffer on stack issue nicely :)
+ */
+static inline const char *bdev_partition_name (struct block_device *bdev)
 {
-	return partition_name(bdev ? bdev->bd_dev : 0);
+	char b[BDEVNAME_SIZE];
+
+	if (!bdev)
+		return __bdevname(0, b);
+	return bdevname(bdev, b);
 }
 extern int register_md_personality (int p_num, mdk_personality_t *p);
 extern int unregister_md_personality (int p_num);
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h	Sat Dec  7 02:14:35 2002
+++ b/include/linux/reiserfs_fs.h	Sat May 17 14:09:36 2003
@@ -1268,6 +1268,7 @@
 
 /* Size of pointer to the unformatted node. */
 #define UNFM_P_SIZE (sizeof(unp_t))
+#define UNFM_P_SHIFT 2
 
 // in in-core inode key is stored on le form
 #define INODE_PKEY(inode) ((struct key *)(REISERFS_I(inode)->i_key))
@@ -1838,7 +1839,7 @@
 void padd_item (char * item, int total_length, int length);
 
 /* inode.c */
-
+void restart_transaction(struct reiserfs_transaction_handle *th, struct inode *inode, struct path *path);
 void reiserfs_read_locked_inode(struct inode * inode, struct reiserfs_iget_args *args) ;
 int reiserfs_find_actor(struct inode * inode, void *p) ;
 int reiserfs_init_locked_inode(struct inode * inode, void *p) ;
@@ -2111,6 +2112,7 @@
 #endif
 void reiserfs_claim_blocks_to_be_allocated( struct super_block *sb, int blocks);
 void reiserfs_release_claimed_blocks( struct super_block *sb, int blocks);
+int reiserfs_can_fit_pages(struct super_block *sb);
 
 /* hashes.c */
 __u32 keyed_hash (const signed char *msg, int len);
diff -Nru a/include/linux/reiserfs_fs_sb.h b/include/linux/reiserfs_fs_sb.h
--- a/include/linux/reiserfs_fs_sb.h	Tue Oct  1 08:31:59 2002
+++ b/include/linux/reiserfs_fs_sb.h	Sat May 17 14:09:36 2003
@@ -397,6 +397,7 @@
     reiserfs_proc_info_data_t s_proc_info_data;
     struct proc_dir_entry *procdir;
     int reserved_blocks; /* amount of blocks reserved for further allocations */
+    spinlock_t bitmap_lock; /* this lock on now only used to protect reserved_blocks variable */
 };
 
 /* Definitions of reiserfs on-disk properties: */
diff -Nru a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
--- a/include/linux/rtnetlink.h	Sun Feb 23 22:46:32 2003
+++ b/include/linux/rtnetlink.h	Mon May 19 23:22:52 2003
@@ -78,7 +78,7 @@
 
 
 /******************************************************************************
- *		Definitions used in routing table administation.
+ *		Definitions used in routing table administration.
  ****/
 
 struct rtmsg
@@ -129,14 +129,14 @@
 #define RTPROT_STATIC	4	/* Route installed by administrator	*/
 
 /* Values of protocol >= RTPROT_STATIC are not interpreted by kernel;
-   they just passed from user and back as is.
+   they are just passed from user and back as is.
    It will be used by hypothetical multiple routing daemons.
    Note that protocol values should be standardized in order to
    avoid conflicts.
  */
 
 #define RTPROT_GATED	8	/* Apparently, GateD */
-#define RTPROT_RA	9	/* RDISC/ND router advertisments */
+#define RTPROT_RA	9	/* RDISC/ND router advertisements */
 #define RTPROT_MRT	10	/* Merit MRT */
 #define RTPROT_ZEBRA	11	/* Zebra */
 #define RTPROT_BIRD	12	/* BIRD */
@@ -210,8 +210,8 @@
 
 /* RTM_MULTIPATH --- array of struct rtnexthop.
  *
- * "struct rtnexthop" describres all necessary nexthop information,
- * i.e. parameters of path to a destination via this nextop.
+ * "struct rtnexthop" describes all necessary nexthop information,
+ * i.e. parameters of path to a destination via this nexthop.
  *
  * At the moment it is impossible to set different prefsrc, mtu, window
  * and rtt for different paths from multipath.
@@ -282,9 +282,11 @@
 #define RTAX_ADVMSS RTAX_ADVMSS
 	RTAX_REORDERING,
 #define RTAX_REORDERING RTAX_REORDERING
+	RTAX_HOPLIMIT,
+#define RTAX_HOPLIMIT RTAX_HOPLIMIT
 };
 
-#define RTAX_MAX RTAX_REORDERING
+#define RTAX_MAX RTAX_HOPLIMIT
 
 struct rta_session
 {
@@ -485,7 +487,7 @@
 
    Comments:
    - Combination IFF_BROADCAST|IFF_POINTOPOINT is invalid
-   - If neiher of these three flags are set;
+   - If neither of these three flags are set;
      the interface is NBMA.
 
    - IFF_MULTICAST does not mean anything special:
diff -Nru a/include/linux/sched.h b/include/linux/sched.h
--- a/include/linux/sched.h	Fri Apr 25 18:38:40 2003
+++ b/include/linux/sched.h	Sun May 18 17:00:00 2003
@@ -294,6 +294,7 @@
 
 typedef struct prio_array prio_array_t;
 struct backing_dev_info;
+struct reclaim_state;
 
 /* POSIX.1b interval timer structure. */
 struct k_itimer {
@@ -370,8 +371,8 @@
 
 	wait_queue_head_t wait_chldexit;	/* for wait4() */
 	struct completion *vfork_done;		/* for vfork() */
-	int *set_child_tid;			/* CLONE_CHILD_SETTID */
-	int *clear_child_tid;			/* CLONE_CHILD_CLEARTID */
+	int __user *set_child_tid;		/* CLONE_CHILD_SETTID */
+	int __user *clear_child_tid;		/* CLONE_CHILD_CLEARTID */
 
 	unsigned long rt_priority;
 	unsigned long it_real_value, it_prof_value, it_virt_value;
@@ -433,6 +434,10 @@
 
 /* journalling filesystem info */
 	void *journal_info;
+
+/* VM state */
+	struct reclaim_state *reclaim_state;
+
 	struct dentry *proc_dentry;
 	struct backing_dev_info *backing_dev_info;
 
@@ -525,6 +530,7 @@
 
 extern int FASTCALL(wake_up_state(struct task_struct * tsk, unsigned int state));
 extern int FASTCALL(wake_up_process(struct task_struct * tsk));
+extern int FASTCALL(wake_up_process_kick(struct task_struct * tsk));
 extern void FASTCALL(wake_up_forked_process(struct task_struct * tsk));
 extern void FASTCALL(sched_exit(task_t * p));
 
@@ -558,7 +564,7 @@
 extern int kill_sl(pid_t, int, int);
 extern int kill_proc(pid_t, int, int);
 extern int do_sigaction(int, const struct k_sigaction *, struct k_sigaction *);
-extern int do_sigaltstack(const stack_t *, stack_t *, unsigned long);
+extern int do_sigaltstack(const stack_t __user *, stack_t __user *, unsigned long);
 
 /* These can be the second arg to send_sig_info/send_group_sig_info.  */
 #define SEND_SIG_NOINFO ((struct siginfo *) 0)
@@ -631,14 +637,14 @@
 extern task_t *child_reaper;
 
 extern int do_execve(char *, char __user * __user *, char __user * __user *, struct pt_regs *);
-extern struct task_struct *do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int *, int *);
+extern long do_fork(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
+extern struct task_struct * copy_process(unsigned long, unsigned long, struct pt_regs *, unsigned long, int __user *, int __user *);
 
 #ifdef CONFIG_SMP
 extern void wait_task_inactive(task_t * p);
 #else
 #define wait_task_inactive(p)	do { } while (0)
 #endif
-extern void kick_if_running(task_t * p);
 
 #define remove_parent(p)	list_del_init(&(p)->sibling)
 #define add_parent(p, parent)	list_add_tail(&(p)->sibling,&(parent)->children)
diff -Nru a/include/linux/security.h b/include/linux/security.h
--- a/include/linux/security.h	Mon Mar 10 13:12:23 2003
+++ b/include/linux/security.h	Fri May  9 14:23:37 2003
@@ -361,6 +361,9 @@
  * 	Check permission before setting the extended attributes
  * 	@value identified by @name for @dentry.
  * 	Return 0 if permission is granted.
+ * @inode_post_setxattr:
+ * 	Update inode security field after successful setxattr operation.
+ * 	@value identified by @name for @dentry.
  * @inode_getxattr:
  * 	Check permission before obtaining the extended attributes
  * 	identified by @name for @dentry.
@@ -1036,6 +1039,8 @@
         void (*inode_delete) (struct inode *inode);
 	int (*inode_setxattr) (struct dentry *dentry, char *name, void *value,
 			       size_t size, int flags);
+	void (*inode_post_setxattr) (struct dentry *dentry, char *name, void *value,
+				     size_t size, int flags);
 	int (*inode_getxattr) (struct dentry *dentry, char *name);
 	int (*inode_listxattr) (struct dentry *dentry);
 	int (*inode_removexattr) (struct dentry *dentry, char *name);
@@ -1464,6 +1469,12 @@
 	return security_ops->inode_setxattr (dentry, name, value, size, flags);
 }
 
+static inline void security_inode_post_setxattr (struct dentry *dentry, char *name,
+						void *value, size_t size, int flags)
+{
+	security_ops->inode_post_setxattr (dentry, name, value, size, flags);
+}
+
 static inline int security_inode_getxattr (struct dentry *dentry, char *name)
 {
 	return security_ops->inode_getxattr (dentry, name);
@@ -1718,7 +1729,7 @@
 }
 
 static inline int security_shm_shmat (struct shmid_kernel * shp, 
-				      char *shmaddr, int shmflg)
+				      char __user *shmaddr, int shmflg)
 {
 	return security_ops->shm_shmat(shp, shmaddr, shmflg);
 }
@@ -2063,6 +2074,10 @@
 	return 0;
 }
 
+static inline void security_inode_post_setxattr (struct dentry *dentry, char *name,
+						 void *value, size_t size, int flags)
+{ }
+
 static inline int security_inode_getxattr (struct dentry *dentry, char *name)
 {
 	return 0;
@@ -2307,7 +2322,7 @@
 }
 
 static inline int security_shm_shmat (struct shmid_kernel * shp, 
-				      char *shmaddr, int shmflg)
+				      char __user *shmaddr, int shmflg)
 {
 	return 0;
 }
diff -Nru a/include/linux/sem.h b/include/linux/sem.h
--- a/include/linux/sem.h	Sat Dec 14 09:40:48 2002
+++ b/include/linux/sem.h	Fri May  9 14:23:37 2003
@@ -138,10 +138,10 @@
 };
 
 asmlinkage long sys_semget (key_t key, int nsems, int semflg);
-asmlinkage long sys_semop (int semid, struct sembuf *sops, unsigned nsops);
+asmlinkage long sys_semop (int semid, struct sembuf __user *sops, unsigned nsops);
 asmlinkage long sys_semctl (int semid, int semnum, int cmd, union semun arg);
-asmlinkage long sys_semtimedop(int semid, struct sembuf *sops,
-			unsigned nsops, const struct timespec *timeout);
+asmlinkage long sys_semtimedop(int semid, struct sembuf __user *sops,
+			unsigned nsops, const struct timespec __user *timeout);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/seq_file.h b/include/linux/seq_file.h
--- a/include/linux/seq_file.h	Wed May 22 05:37:00 2002
+++ b/include/linux/seq_file.h	Mon May 19 08:48:34 2003
@@ -8,6 +8,8 @@
 
 struct seq_operations;
 struct file;
+struct vfsmount;
+struct dentry;
 struct inode;
 
 struct seq_file {
@@ -29,7 +31,7 @@
 };
 
 int seq_open(struct file *, struct seq_operations *);
-ssize_t seq_read(struct file *, char *, size_t, loff_t *);
+ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
 loff_t seq_lseek(struct file *, loff_t, int);
 int seq_release(struct inode *, struct file *);
 int seq_escape(struct seq_file *, const char *, const char *);
@@ -58,7 +60,10 @@
 int seq_printf(struct seq_file *, const char *, ...)
 	__attribute__ ((format (printf,2,3)));
 
+int seq_path(struct seq_file *, struct vfsmount *, struct dentry *, char *);
+
 int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
 int single_release(struct inode *, struct file *);
+int seq_release_private(struct inode *, struct file *);
 #endif
 #endif
diff -Nru a/include/linux/shm.h b/include/linux/shm.h
--- a/include/linux/shm.h	Sun Oct 20 06:01:15 2002
+++ b/include/linux/shm.h	Fri May  9 14:23:37 2003
@@ -90,10 +90,10 @@
 #define SHM_LOCKED      02000   /* segment will not be swapped */
 #define SHM_HUGETLB     04000   /* segment will use huge TLB pages */
 
+long sys_shmat (int shmid, char __user *shmaddr, int shmflg, unsigned long *addr);
 asmlinkage long sys_shmget (key_t key, size_t size, int flag);
-asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, unsigned long *addr);
-asmlinkage long sys_shmdt (char *shmaddr);
-asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf);
+asmlinkage long sys_shmdt (char __user *shmaddr);
+asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf);
 
 #endif /* __KERNEL__ */
 
diff -Nru a/include/linux/signal.h b/include/linux/signal.h
--- a/include/linux/signal.h	Tue Feb 18 13:54:44 2003
+++ b/include/linux/signal.h	Mon May 12 14:35:19 2003
@@ -201,7 +201,7 @@
 	sig->tail = &sig->head;
 }
 
-extern long do_sigpending(void *, unsigned long);
+extern long do_sigpending(void __user *, unsigned long);
 extern int sigprocmask(int, sigset_t *, sigset_t *);
 
 #ifndef HAVE_ARCH_GET_SIGNAL_TO_DELIVER
diff -Nru a/include/linux/skbuff.h b/include/linux/skbuff.h
--- a/include/linux/skbuff.h	Tue Mar 25 05:09:07 2003
+++ b/include/linux/skbuff.h	Mon May 12 14:21:06 2003
@@ -792,6 +792,15 @@
 	return len + skb_headlen(skb);
 }
 
+static inline void skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size)
+{
+	skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+	frag->page = page;
+	frag->page_offset = off;
+	frag->size = size;
+	skb_shinfo(skb)->nr_frags = i+1;
+}
+
 #define SKB_PAGE_ASSERT(skb) do { if (skb_shinfo(skb)->nr_frags) \
 					BUG(); } while (0)
 #define SKB_FRAG_ASSERT(skb) do { if (skb_shinfo(skb)->frag_list) \
diff -Nru a/include/linux/slab.h b/include/linux/slab.h
--- a/include/linux/slab.h	Thu Apr 24 05:17:14 2003
+++ b/include/linux/slab.h	Wed May  7 21:17:55 2003
@@ -49,7 +49,6 @@
 
 /* prototypes */
 extern void kmem_cache_init(void);
-extern void kmem_cache_sizes_init(void);
 
 extern kmem_cache_t *kmem_find_general_cachep(size_t, int gfpflags);
 extern kmem_cache_t *kmem_cache_create(const char *, size_t, size_t, unsigned long,
diff -Nru a/include/linux/smp.h b/include/linux/smp.h
--- a/include/linux/smp.h	Sun Mar  2 18:13:32 2003
+++ b/include/linux/smp.h	Wed May 14 23:44:04 2003
@@ -74,10 +74,6 @@
  */
 extern int smp_threads_ready;
 
-extern volatile unsigned long smp_msg_data;
-extern volatile int smp_src_cpu;
-extern volatile int smp_msg_id;
-
 #define MSG_ALL_BUT_SELF	0x8000	/* Assume <32768 CPU's */
 #define MSG_ALL			0x8001
 
diff -Nru a/include/linux/smp_lock.h b/include/linux/smp_lock.h
--- a/include/linux/smp_lock.h	Fri Aug 23 04:56:39 2002
+++ b/include/linux/smp_lock.h	Mon May 12 20:05:54 2003
@@ -5,7 +5,7 @@
 #include <linux/sched.h>
 #include <linux/spinlock.h>
 
-#if CONFIG_SMP || CONFIG_PREEMPT
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 
 extern spinlock_t kernel_flag;
 
diff -Nru a/include/linux/socket.h b/include/linux/socket.h
--- a/include/linux/socket.h	Sun Mar 23 22:06:53 2003
+++ b/include/linux/socket.h	Mon May 12 14:35:19 2003
@@ -9,6 +9,7 @@
 #include <linux/sockios.h>		/* the SIOCxxx I/O controls	*/
 #include <linux/uio.h>			/* iovec support		*/
 #include <linux/types.h>		/* pid_t			*/
+#include <linux/compiler.h>		/* __user			*/
 
 typedef unsigned short	sa_family_t;
 
@@ -242,8 +243,8 @@
 #define MSG_CMSG_COMPAT	0		/* We never have 32 bit fixups */
 #endif
 
-extern asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags);
-extern asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned flags);
+extern asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags);
+extern asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned flags);
 
 
 
@@ -285,8 +286,8 @@
 extern int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode);
 extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
 extern void memcpy_tokerneliovec(struct iovec *iov, unsigned char *kdata, int len);
-extern int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen);
-extern int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr);
+extern int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ulen);
+extern int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr);
 extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data);
 
 #endif
diff -Nru a/include/linux/spinlock.h b/include/linux/spinlock.h
--- a/include/linux/spinlock.h	Tue Feb 11 09:58:54 2003
+++ b/include/linux/spinlock.h	Wed May 14 23:43:57 2003
@@ -79,10 +79,10 @@
 	do { \
 	 	CHECK_LOCK(x); \
 		if ((x)->lock&&(x)->babble) { \
+			(x)->babble--; \
 			printk("%s:%d: spin_lock(%s:%p) already locked by %s/%d\n", \
 					__FILE__,__LINE__, (x)->module, \
 					(x), (x)->owner, (x)->oline); \
-			(x)->babble--; \
 		} \
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
@@ -95,10 +95,10 @@
 	({ \
 	 	CHECK_LOCK(x); \
 		if ((x)->lock&&(x)->babble) { \
+			(x)->babble--; \
 			printk("%s:%d: spin_is_locked(%s:%p) already locked by %s/%d\n", \
 					__FILE__,__LINE__, (x)->module, \
 					(x), (x)->owner, (x)->oline); \
-			(x)->babble--; \
 		} \
 		0; \
 	})
@@ -109,10 +109,10 @@
 	({ \
 	 	CHECK_LOCK(x); \
 		if ((x)->lock&&(x)->babble) { \
+			(x)->babble--; \
 			printk("%s:%d: spin_trylock(%s:%p) already locked by %s/%d\n", \
 					__FILE__,__LINE__, (x)->module, \
 					(x), (x)->owner, (x)->oline); \
-			(x)->babble--; \
 		} \
 		(x)->lock = 1; \
 		(x)->owner = __FILE__; \
@@ -124,10 +124,10 @@
 	do { \
 	 	CHECK_LOCK(x); \
 		if ((x)->lock&&(x)->babble) { \
+			(x)->babble--; \
 			printk("%s:%d: spin_unlock_wait(%s:%p) owned by %s/%d\n", \
 					__FILE__,__LINE__, (x)->module, (x), \
 					(x)->owner, (x)->oline); \
-			(x)->babble--; \
 		}\
 	} while (0)
 
@@ -135,9 +135,9 @@
 	do { \
 	 	CHECK_LOCK(x); \
 		if (!(x)->lock&&(x)->babble) { \
+			(x)->babble--; \
 			printk("%s:%d: spin_unlock(%s:%p) not locked\n", \
 					__FILE__,__LINE__, (x)->module, (x));\
-			(x)->babble--; \
 		} \
 		(x)->lock = 0; \
 	} while (0)
diff -Nru a/include/linux/sunrpc/rpc_pipe_fs.h b/include/linux/sunrpc/rpc_pipe_fs.h
--- a/include/linux/sunrpc/rpc_pipe_fs.h	Sun Jan 12 13:39:49 2003
+++ b/include/linux/sunrpc/rpc_pipe_fs.h	Tue May 13 13:42:28 2003
@@ -12,8 +12,8 @@
 };
 
 struct rpc_pipe_ops {
-	ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char *, size_t);
-	ssize_t (*downcall)(struct file *, const char *, size_t);
+	ssize_t (*upcall)(struct file *, struct rpc_pipe_msg *, char __user *, size_t);
+	ssize_t (*downcall)(struct file *, const char __user *, size_t);
 	void (*destroy_msg)(struct rpc_pipe_msg *);
 };
 
diff -Nru a/include/linux/sunrpc/svc.h b/include/linux/sunrpc/svc.h
--- a/include/linux/sunrpc/svc.h	Mon Feb 17 13:46:20 2003
+++ b/include/linux/sunrpc/svc.h	Tue May  6 07:20:53 2003
@@ -176,8 +176,10 @@
 {
 	if (rqstp->rq_arghi <= rqstp->rq_argused)
 		return -ENOMEM;
-	rqstp->rq_respages[rqstp->rq_resused++] =
-		rqstp->rq_argpages[--rqstp->rq_arghi];
+	rqstp->rq_arghi--;
+	rqstp->rq_respages[rqstp->rq_resused] =
+		rqstp->rq_argpages[rqstp->rq_arghi];
+	rqstp->rq_resused++;
 	return 0;
 }
 
diff -Nru a/include/linux/sunrpc/xdr.h b/include/linux/sunrpc/xdr.h
--- a/include/linux/sunrpc/xdr.h	Sun Jan 12 13:40:13 2003
+++ b/include/linux/sunrpc/xdr.h	Wed May  7 04:07:31 2003
@@ -157,6 +157,11 @@
 extern void xdr_partial_copy_from_skb(struct xdr_buf *, unsigned int,
 		skb_reader_t *, skb_read_actor_t);
 
+struct socket;
+struct sockaddr;
+extern int xdr_sendpages(struct socket *, struct sockaddr *, int,
+		struct xdr_buf *, unsigned int, int);
+
 /*
  * Provide some simple tools for XDR buffer overflow-checking etc.
  */
diff -Nru a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
--- a/include/linux/sunrpc/xprt.h	Sun Jan 12 13:39:47 2003
+++ b/include/linux/sunrpc/xprt.h	Wed May  7 04:03:10 2003
@@ -198,7 +198,7 @@
 
 #define XPRT_CONNECT	0
 
-#define xprt_connected(xp)		(!(xp)->stream || test_bit(XPRT_CONNECT, &(xp)->sockstate))
+#define xprt_connected(xp)		(test_bit(XPRT_CONNECT, &(xp)->sockstate))
 #define xprt_set_connected(xp)		(set_bit(XPRT_CONNECT, &(xp)->sockstate))
 #define xprt_test_and_set_connected(xp)	(test_and_set_bit(XPRT_CONNECT, &(xp)->sockstate))
 #define xprt_clear_connected(xp)	(clear_bit(XPRT_CONNECT, &(xp)->sockstate))
diff -Nru a/include/linux/swap.h b/include/linux/swap.h
--- a/include/linux/swap.h	Thu Mar 27 21:14:03 2003
+++ b/include/linux/swap.h	Wed May  7 21:19:58 2003
@@ -66,6 +66,14 @@
 	unsigned long val;
 } swp_entry_t;
 
+/*
+ * current->reclaim_state points to one of these when a task is running
+ * memory reclaim
+ */
+struct reclaim_state {
+	unsigned long reclaimed_slab;
+};
+
 #ifdef __KERNEL__
 
 struct address_space;
diff -Nru a/include/linux/sysctl.h b/include/linux/sysctl.h
--- a/include/linux/sysctl.h	Sat May  3 00:42:29 2003
+++ b/include/linux/sysctl.h	Mon May 12 11:25:49 2003
@@ -36,11 +36,11 @@
 				   member of a struct __sysctl_args to have? */
 
 struct __sysctl_args {
-	int *name;
+	int __user *name;
 	int nlen;
-	void *oldval;
-	size_t *oldlenp;
-	void *newval;
+	void __user *oldval;
+	size_t __user *oldlenp;
+	void __user *newval;
 	size_t newlen;
 	unsigned long __unused[4];
 };
@@ -674,40 +674,40 @@
 
 #ifdef __KERNEL__
 
-extern asmlinkage long sys_sysctl(struct __sysctl_args *);
+extern asmlinkage long sys_sysctl(struct __sysctl_args __user *);
 extern void sysctl_init(void);
 
 typedef struct ctl_table ctl_table;
 
-typedef int ctl_handler (ctl_table *table, int *name, int nlen,
+typedef int ctl_handler (ctl_table *table, int __user *name, int nlen,
 			 void __user *oldval, size_t __user *oldlenp,
 			 void __user *newval, size_t newlen, 
 			 void **context);
 
 typedef int proc_handler (ctl_table *ctl, int write, struct file * filp,
-			  void *buffer, size_t *lenp);
+			  void __user *buffer, size_t *lenp);
 
 extern int proc_dostring(ctl_table *, int, struct file *,
-			 void *, size_t *);
+			 void __user *, size_t *);
 extern int proc_dointvec(ctl_table *, int, struct file *,
-			 void *, size_t *);
+			 void __user *, size_t *);
 extern int proc_dointvec_bset(ctl_table *, int, struct file *,
-			      void *, size_t *);
+			      void __user *, size_t *);
 extern int proc_dointvec_minmax(ctl_table *, int, struct file *,
-				void *, size_t *);
+				void __user *, size_t *);
 extern int proc_dointvec_jiffies(ctl_table *, int, struct file *,
-				 void *, size_t *);
+				 void __user *, size_t *);
 extern int proc_doulongvec_minmax(ctl_table *, int, struct file *,
-				  void *, size_t *);
+				  void __user *, size_t *);
 extern int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int,
-				      struct file *, void *, size_t *);
+				      struct file *, void __user *, size_t *);
 
-extern int do_sysctl (int *name, int nlen,
-		      void *oldval, size_t *oldlenp,
-		      void *newval, size_t newlen);
+extern int do_sysctl (int __user *name, int nlen,
+		      void __user *oldval, size_t __user *oldlenp,
+		      void __user *newval, size_t newlen);
 
 extern int do_sysctl_strategy (ctl_table *table, 
-			       int *name, int nlen,
+			       int __user *name, int nlen,
 			       void __user *oldval, size_t __user *oldlenp,
 			       void __user *newval, size_t newlen, void ** context);
 
diff -Nru a/include/linux/sysfs.h b/include/linux/sysfs.h
--- a/include/linux/sysfs.h	Mon Mar  3 14:44:10 2003
+++ b/include/linux/sysfs.h	Wed Apr 16 14:11:21 2003
@@ -16,18 +16,11 @@
 	mode_t			mode;
 };
 
-struct sysfs_bin_buffer {
-	u8 * 	data;
-	size_t	size;
-	size_t	count;
-	loff_t	offset;
-};
-
 struct bin_attribute {
 	struct attribute	attr;
 	size_t			size;
-	ssize_t (*read)(struct kobject *, struct sysfs_bin_buffer *);
-	ssize_t (*write)(struct kobject *, struct sysfs_bin_buffer *);
+	ssize_t (*read)(struct kobject *, char *, loff_t, size_t);
+	ssize_t (*write)(struct kobject *, char *, loff_t, size_t);
 };
 
 struct sysfs_ops {
diff -Nru a/include/linux/sysrq.h b/include/linux/sysrq.h
--- a/include/linux/sysrq.h	Thu Jun 27 15:32:51 2002
+++ b/include/linux/sysrq.h	Wed May  7 21:18:01 2003
@@ -92,21 +92,3 @@
 #define unregister_sysrq_key(ig,nore) __reterr()
 
 #endif
-
-
-/* Deferred actions */
-
-extern int emergency_sync_scheduled;
-
-#define EMERG_SYNC 1
-#define EMERG_REMOUNT 2
-
-void do_emergency_sync(void);
-
-#ifdef CONFIG_MAGIC_SYSRQ
-#define CHECK_EMERGENCY_SYNC			\
-	if (emergency_sync_scheduled)		\
-		do_emergency_sync();
-#else
-#define CHECK_EMERGENCY_SYNC
-#endif
diff -Nru a/include/linux/time.h b/include/linux/time.h
--- a/include/linux/time.h	Sat Apr 19 23:22:26 2003
+++ b/include/linux/time.h	Mon May 12 16:41:16 2003
@@ -204,7 +204,7 @@
 extern int do_sys_settimeofday(struct timeval *tv, struct timezone *tz);
 extern void clock_was_set(void); // call when ever the clock is set
 extern long do_nanosleep(struct timespec *t);
-extern long do_utimes(char * filename, struct timeval * times);
+extern long do_utimes(char __user * filename, struct timeval * times);
 #endif
 
 #define FD_SETSIZE		__FD_SETSIZE
diff -Nru a/include/linux/tpqic02.h b/include/linux/tpqic02.h
--- a/include/linux/tpqic02.h	Tue Feb  5 07:23:18 2002
+++ b/include/linux/tpqic02.h	Mon May 12 20:10:40 2003
@@ -12,7 +12,7 @@
 
 #include <linux/config.h>
 
-#if CONFIG_QIC02_TAPE || CONFIG_QIC02_TAPE_MODULE
+#if defined(CONFIG_QIC02_TAPE) || defined(CONFIG_QIC02_TAPE_MODULE)
 
 /* need to have QIC02_TAPE_DRIVE and QIC02_TAPE_IFC expand to something */
 #include <linux/mtio.h>
diff -Nru a/include/linux/tty.h b/include/linux/tty.h
--- a/include/linux/tty.h	Mon Apr 21 20:58:43 2003
+++ b/include/linux/tty.h	Wed May  7 15:50:58 2003
@@ -243,6 +243,7 @@
 #define L_PENDIN(tty)	_L_FLAG((tty),PENDIN)
 #define L_IEXTEN(tty)	_L_FLAG((tty),IEXTEN)
 
+struct device;
 /*
  * Where all of the state associated with a tty is kept while the tty
  * is open.  Since the termios state should be kept even if the tty
@@ -380,7 +381,7 @@
 extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc);
 extern int tty_register_driver(struct tty_driver *driver);
 extern int tty_unregister_driver(struct tty_driver *driver);
-extern void tty_register_device(struct tty_driver *driver, unsigned index);
+extern void tty_register_device(struct tty_driver *driver, unsigned index, struct device *dev);
 extern void tty_unregister_device(struct tty_driver *driver, unsigned index);
 extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp,
 			     int buflen);
diff -Nru a/include/linux/usb.h b/include/linux/usb.h
--- a/include/linux/usb.h	Thu Apr 24 22:21:45 2003
+++ b/include/linux/usb.h	Tue May  6 17:17:25 2003
@@ -73,13 +73,22 @@
 /**
  * struct usb_interface - what usb device drivers talk to
  * @altsetting: array of interface descriptors, one for each alternate
- * 	setting that may be selected.  each one includes a set of
- * 	endpoint configurations.
+ * 	setting that may be selected.  Each one includes a set of
+ * 	endpoint configurations and will be in numberic order,
+ * 	0..num_altsetting.
  * @num_altsetting: number of altsettings defined.
  * @act_altsetting: index of current altsetting.  this number is always
  *	less than num_altsetting.  after the device is configured, each
  *	interface uses its default setting of zero.
+ * @max_altsetting:
+ * @minor: the minor number assigned to this interface, if this
+ *	interface is bound to a driver that uses the USB major number.
+ *	If this interface does not use the USB major, this field should
+ *	be unused.  The driver should set this value in the probe()
+ *	function of the driver, after it has been assigned a minor
+ *	number from the USB core by calling usb_register_dev().
  * @dev: driver model's view of this device
+ * @class_dev: driver model's class view of this device.
  *
  * USB device drivers attach to interfaces on a physical device.  Each
  * interface encapsulates a single high level function, such as feeding
@@ -111,10 +120,12 @@
 	unsigned max_altsetting;	/* total memory allocated */
 
 	struct usb_driver *driver;	/* driver */
-	kdev_t kdev;			/* node this interface is bound to */
+	int minor;			/* minor number this interface is bound to */
 	struct device dev;		/* interface specific device info */
+	struct class_device class_dev;
 };
 #define	to_usb_interface(d) container_of(d, struct usb_interface, dev)
+#define class_dev_to_usb_interface(d) container_of(d, struct usb_interface, class_dev)
 #define	interface_to_usbdev(intf) \
 	container_of(intf->dev.parent, struct usb_device, dev)
 
@@ -279,7 +290,7 @@
 const struct usb_device_id *usb_match_id(struct usb_interface *interface,
 					 const struct usb_device_id *id);
 
-extern struct usb_interface *usb_find_interface(struct usb_driver *drv, kdev_t kdev);
+extern struct usb_interface *usb_find_interface(struct usb_driver *drv, int minor);
 extern struct usb_interface *usb_ifnum_to_if(struct usb_device *dev, unsigned ifnum);
 
 
@@ -433,6 +444,25 @@
 
 extern struct bus_type usb_bus_type;
 
+/**
+ * struct usb_class_driver - identifies a USB driver that wants to use the USB major number
+ * @name: devfs name for this driver.  Will also be used by the driver
+ *	class code to create a usb class device.
+ * @fops: pointer to the struct file_operations of this driver.
+ * @mode: the mode for the devfs file to be created for this driver.
+ * @minor_base: the start of the minor range for this driver.
+ *
+ * This structure is used for the usb_register_dev() and
+ * usb_unregister_dev() functions, to consolodate a number of the
+ * paramaters used for them.
+ */
+struct usb_class_driver {
+	char *name;
+	struct file_operations *fops;
+	mode_t mode;
+	int minor_base;	
+};
+
 /*
  * use these in module_init()/module_exit()
  * and don't forget MODULE_DEVICE_TABLE(usb, ...)
@@ -440,8 +470,10 @@
 extern int usb_register(struct usb_driver *);
 extern void usb_deregister(struct usb_driver *);
 
-extern int usb_register_dev(struct file_operations *fops, int minor, int num_minors, int *start_minor);
-extern void usb_deregister_dev(int num_minors, int start_minor);
+extern int usb_register_dev(struct usb_interface *intf,
+			    struct usb_class_driver *class_driver);
+extern void usb_deregister_dev(struct usb_interface *intf,
+			       struct usb_class_driver *class_driver);
 
 extern int usb_device_probe(struct device *dev);
 extern int usb_device_remove(struct device *dev);
diff -Nru a/include/linux/usb_gadget.h b/include/linux/usb_gadget.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/linux/usb_gadget.h	Thu May  8 04:25:02 2003
@@ -0,0 +1,696 @@
+/*
+ * <linux/usb_gadget.h>
+ *
+ * We call the USB code inside a Linux-based peripheral device a "gadget"
+ * driver, except for the hardware-specific bus glue.  One USB host can
+ * master many USB gadgets, but the gadgets are only slaved to one host.
+ *
+ *
+ * (c) Copyright 2002-2003 by David Brownell
+ * All Rights Reserved.
+ *
+ * This software is licensed under the GNU GPL version 2.
+ *
+ * ALTERNATIVELY, the kernel API documentation which is included in this
+ * software may also be licenced under the "GNU Free Documentation
+ * License" (version 1.2 or, at your choice, any later version), when
+ * used as part of the "USB Gadget API for Linux" documentation.
+ */
+
+#ifndef __LINUX_USB_GADGET_H
+#define __LINUX_USB_GADGET_H
+
+#ifdef __KERNEL__
+
+struct usb_ep;
+
+/**
+ * struct usb_request - describes one i/o request
+ * @buf: Buffer used for data.  Always provide this; some controllers
+ * 	only use PIO, or don't use DMA for some endpoints.
+ * @dma: DMA address corresponding to 'buf'.  If you don't set this
+ * 	field, and the usb controller needs one, it is responsible
+ * 	for mapping and unmapping the buffer.
+ * @length: Length of that data
+ * @no_interrupt: If true, hints that no completion irq is needed.
+ *	Helpful sometimes with deep request queues.
+ * @zero: If true, when writing data, makes the last packet be "short"
+ *     by adding a zero length packet as needed;
+ * @short_not_ok: When reading data, makes short packets be
+ *     treated as errors (queue stops advancing till cleanup).
+ * @complete: Function called when request completes
+ * @context: For use by the completion callback
+ * @list: For use by the gadget driver.
+ * @status: Reports completion code, zero or a negative errno.
+ * 	Normally, faults block the transfer queue from advancing until
+ * 	the completion callback returns.
+ * 	Code "-ESHUTDOWN" indicates completion caused by device disconnect,
+ * 	or when the driver disabled the endpoint.
+ * @actual: Reports actual bytes transferred.  For reads (OUT
+ * 	transfers) this may be less than the requested length.  If the
+ * 	short_not_ok flag is set, short reads are treated as errors
+ * 	even when status otherwise indicates successful completion.
+ * 	Note that for writes (IN transfers) the data bytes may still
+ * 	reside in a device-side FIFO.
+ *
+ * These are allocated/freed through the endpoint they're used with.  The
+ * hardware's driver can add extra per-request data to the memory it returns,
+ * which often avoids separate memory allocations (potential failures),
+ * later when the request is queued.
+ *
+ * Request flags affect request handling, such as whether a zero length
+ * packet is written (the "zero" flag), whether a short read should be
+ * treated as an error (blocking request queue advance, the "short_not_ok"
+ * flag), or hinting that an interrupt is not required (the "no_interrupt"
+ * flag, for use with deep request queues).
+ *
+ * Bulk endpoints can use any size buffers, and can also be used for interrupt
+ * transfers. interrupt-only endpoints can be much less functional.
+ */
+	// NOTE this is analagous to 'struct urb' on the host side,
+	// except that it's thinner and promotes more pre-allocation.
+	//
+	// ISSUE should this be allocated through the device?
+
+struct usb_request {
+	void			*buf;
+	unsigned		length;
+	dma_addr_t		dma;
+
+	unsigned		no_interrupt : 1,
+				zero : 1,
+				short_not_ok : 1;
+
+	void			(*complete)(struct usb_ep *ep,
+					struct usb_request *req);
+	void			*context;
+	struct list_head	list;
+
+	int			status;
+	unsigned		actual;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* endpoint-specific parts of the api to the usb controller hardware.
+ * unlike the urb model, (de)multiplexing layers are not required.
+ * (so this api could slash overhead if used on the host side...)
+ *
+ * note that device side usb controllers commonly differ in how many
+ * endpoints they support, as well as their capabilities.
+ */
+struct usb_ep_ops {
+	int (*enable) (struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc);
+	int (*disable) (struct usb_ep *ep);
+
+	struct usb_request *(*alloc_request) (struct usb_ep *ep,
+		int gfp_flags);
+	void (*free_request) (struct usb_ep *ep, struct usb_request *req);
+
+	void *(*alloc_buffer) (struct usb_ep *ep, unsigned bytes,
+		dma_addr_t *dma, int gfp_flags);
+	void (*free_buffer) (struct usb_ep *ep, void *buf, dma_addr_t dma,
+		unsigned bytes);
+	// NOTE:  on 2.5, drivers may also use dma_map() and
+	// dma_sync_single() to manage dma overhead. 
+
+	int (*queue) (struct usb_ep *ep, struct usb_request *req,
+		int gfp_flags);
+	int (*dequeue) (struct usb_ep *ep, struct usb_request *req);
+
+	int (*set_halt) (struct usb_ep *ep, int value);
+	int (*fifo_status) (struct usb_ep *ep);
+	void (*fifo_flush) (struct usb_ep *ep);
+};
+
+/**
+ * struct usb_ep - device side representation of USB endpoint
+ * @name:identifier for the endpoint, such as "ep-a" or "ep9in-bulk"
+ * @ep_list:the gadget's ep_list holds all of its endpoints
+ * @maxpacket:the maximum packet size used on this endpoint, as
+ * 	configured when the endpoint was enabled.
+ * @driver_data:for use by the gadget driver.  all other fields are
+ * 	read-only to gadget drivers.
+ *
+ * the bus controller driver lists all the general purpose endpoints in
+ * gadget->ep_list.  the control endpoint (gadget->ep0) is not in that list,
+ * and is accessed only in response to a driver setup() callback.
+ */
+struct usb_ep {
+	void			*driver_data;
+
+	const char		*name;
+	const struct usb_ep_ops	*ops;
+	struct list_head	ep_list;
+	unsigned		maxpacket : 16;
+};
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * usb_ep_enable - configure endpoint, making it usable
+ * @ep:the endpoint being configured.  may not be the endpoint named "ep0".
+ * 	drivers discover endpoints through the ep_list of a usb_gadget.
+ * @desc:descriptor for desired behavior.  caller guarantees this pointer
+ * 	remains valid until the endpoint is disabled; the data byte order
+ * 	is little-endian (usb-standard).
+ *
+ * when configurations are set, or when interface settings change, the driver
+ * will enable or disable the relevant endpoints.  while it is enabled, an
+ * endpoint may be used for i/o until the driver receives a disconnect() from
+ * the host or until the endpoint is disabled.
+ *
+ * the ep0 implementation (which calls this routine) must ensure that the
+ * hardware capabilities of each endpoint match the descriptor provided
+ * for it.  for example, an endpoint named "ep2in-bulk" would be usable
+ * for interrupt transfers as well as bulk, but it likely couldn't be used
+ * for iso transfers or for endpoint 14.  some endpoints are fully
+ * configurable, with more generic names like "ep-a".  (remember that for
+ * USB, "in" means "towards the USB master".)
+ *
+ * returns zero, or a negative error code.
+ */
+static inline int
+usb_ep_enable (struct usb_ep *ep, const struct usb_endpoint_descriptor *desc)
+{
+	return ep->ops->enable (ep, desc);
+}
+
+/**
+ * usb_ep_disable - endpoint is no longer usable
+ * @ep:the endpoint being unconfigured.  may not be the endpoint named "ep0".
+ *
+ * no other task may be using this endpoint when this is called.
+ * any pending and uncompleted requests will complete with status
+ * indicating disconnect (-ESHUTDOWN) before this call returns.
+ * gadget drivers must call usb_ep_enable() again before queueing
+ * requests to the endpoint.
+ *
+ * returns zero, or a negative error code.
+ */
+static inline int
+usb_ep_disable (struct usb_ep *ep)
+{
+	return ep->ops->disable (ep);
+}
+
+/**
+ * usb_ep_alloc_request - allocate a request object to use with this endpoint
+ * @ep:the endpoint to be used with with the request
+ * @gfp_flags:GFP_* flags to use
+ *
+ * Request objects must be allocated with this call, since they normally
+ * need controller-specific setup and may even need endpoint-specific
+ * resources such as allocation of DMA descriptors.
+ * Requests may be submitted with usb_ep_queue(), and receive a single
+ * completion callback.  Free requests with usb_ep_free_request(), when
+ * they are no longer needed.
+ *
+ * Returns the request, or null if one could not be allocated.
+ */
+static inline struct usb_request *
+usb_ep_alloc_request (struct usb_ep *ep, int gfp_flags)
+{
+	return ep->ops->alloc_request (ep, gfp_flags);
+}
+
+/**
+ * usb_ep_free_request - frees a request object
+ * @ep:the endpoint associated with the request
+ * @req:the request being freed
+ *
+ * Reverses the effect of usb_ep_alloc_request().
+ * Caller guarantees the request is not queued, and that it will
+ * no longer be requeued (or otherwise used).
+ */
+static inline void
+usb_ep_free_request (struct usb_ep *ep, struct usb_request *req)
+{
+	ep->ops->free_request (ep, req);
+}
+
+/**
+ * usb_ep_alloc_buffer - allocate an I/O buffer
+ * @ep:the endpoint associated with the buffer
+ * @len:length of the desired buffer
+ * @dma:pointer to the buffer's DMA address; must be valid
+ * @gfp_flags:GFP_* flags to use
+ *
+ * Returns a new buffer, or null if one could not be allocated.
+ * The buffer is suitably aligned for dma, if that endpoint uses DMA,
+ * and the caller won't have to care about dma-inconsistency
+ * or any hidden "bounce buffer" mechanism.  No additional per-request
+ * DMA mapping will be required for such buffers.
+ * Free it later with usb_ep_free_buffer().
+ *
+ * You don't need to use this call to allocate I/O buffers unless you
+ * want to make sure drivers don't incur costs for such "bounce buffer"
+ * copies or per-request DMA mappings.
+ */
+static inline void *
+usb_ep_alloc_buffer (struct usb_ep *ep, unsigned len, dma_addr_t *dma,
+	int gfp_flags)
+{
+	return ep->ops->alloc_buffer (ep, len, dma, gfp_flags);
+}
+
+/**
+ * usb_ep_free_buffer - frees an i/o buffer
+ * @ep:the endpoint associated with the buffer
+ * @buf:CPU view address of the buffer
+ * @dma:the buffer's DMA address
+ * @len:length of the buffer
+ *
+ * reverses the effect of usb_ep_alloc_buffer().
+ * caller guarantees the buffer will no longer be accessed
+ */
+static inline void
+usb_ep_free_buffer (struct usb_ep *ep, void *buf, dma_addr_t dma, unsigned len)
+{
+	ep->ops->free_buffer (ep, buf, dma, len);
+}
+
+/**
+ * usb_ep_queue - queues (submits) an I/O request to an endpoint.
+ * @ep:the endpoint associated with the request
+ * @req:the request being submitted
+ * @gfp_flags: GFP_* flags to use in case the lower level driver couldn't
+ * 	pre-allocate all necessary memory with the request.
+ *
+ * This tells the device controller to perform the specified request through
+ * that endpoint (reading or writing a buffer).  When the request completes,
+ * including being canceled by usb_ep_dequeue(), the request's completion
+ * routine is called to return the request to the driver.  Any endpoint
+ * (except control endpoints like ep0) may have more than one transfer
+ * request queued; they complete in FIFO order.  Once a gadget driver
+ * submits a request, that request may not be examined or modified until it
+ * is given back to that driver through the completion callback.
+ *
+ * Each request is turned into one or more packets.  The controller driver
+ * never merges adjacent requests into the same packet.  OUT transfers
+ * will sometimes use data that's already buffered in the hardware.
+ *
+ * Bulk endpoints can queue any amount of data; the transfer is packetized
+ * automatically.  The last packet will be short if the request doesn't fill it
+ * out completely.  Zero length packets (ZLPs) should be avoided in portable
+ * protocols since not all usb hardware can successfully handle zero length
+ * packets.  (ZLPs may be explicitly written, and may be implicitly written if
+ * the request 'zero' flag is set.)  Bulk endpoints may also be used
+ * for interrupt transfers; but the reverse is not true, and some endpoints
+ * won't support every interrupt transfer.  (Such as 768 byte packets.)
+ *
+ * Interrupt-only endpoints are less functional than bulk endpoints, for
+ * example by not supporting queueing or not handling buffers that are
+ * larger than the endpoint's maxpacket size.  They may also treat data
+ * toggle differently.
+ *
+ * Control endpoints ... after getting a setup() callback, the driver queues
+ * one response (optional if it would be zero length).  That enables the
+ * status ack, after transfering data as specified in the response.  Setup
+ * functions may return negative error codes to generate protocol stalls.
+ *
+ * For periodic endpoints, like interrupt or isochronous ones, the usb host
+ * arranges to poll once per interval, and the gadget driver usually will
+ * have queued some data to transfer at that time.
+ *
+ * Returns zero, or a negative error code.  Endpoints that are not enabled,
+ * or which are enabled but halted, report errors; errors will also be
+ * reported when the usb peripheral is disconnected.
+ */
+static inline int
+usb_ep_queue (struct usb_ep *ep, struct usb_request *req, int gfp_flags)
+{
+	return ep->ops->queue (ep, req, gfp_flags);
+}
+
+/**
+ * usb_ep_dequeue - dequeues (cancels, unlinks) an I/O request from an endpoint
+ * @ep:the endpoint associated with the request
+ * @req:the request being canceled
+ *
+ * if the request is still active on the endpoint, it is dequeued and its
+ * completion routine is called (with status -ECONNRESET); else a negative
+ * error code is returned.
+ *
+ * note that some hardware can't clear out write fifos (to unlink the request
+ * at the head of the queue) except as part of disconnecting from usb.  such
+ * restrictions prevent drivers from supporting configuration changes,
+ * even to configuration zero (a "chapter 9" requirement).
+ */
+static inline int usb_ep_dequeue (struct usb_ep *ep, struct usb_request *req)
+{
+	return ep->ops->dequeue (ep, req);
+}
+
+/**
+ * usb_ep_set_halt - sets the endpoint halt feature.
+ * @ep: the non-isochronous endpoint being stalled
+ *
+ * Use this to stall an endpoint, perhaps as an error report.
+ * Except for control endpoints,
+ * the endpoint stays halted (will not stream any data) until the host
+ * clears this feature; drivers may need to empty the endpoint's request
+ * queue first, to make sure no inappropriate transfers happen.
+ *
+ * Returns zero, or a negative error code.  On success, this call sets
+ * underlying hardware state that blocks data transfers.
+ */
+static inline int
+usb_ep_set_halt (struct usb_ep *ep)
+{
+	return ep->ops->set_halt (ep, 1);
+}
+
+/**
+ * usb_ep_clear_halt - clears endpoint halt, and resets toggle
+ * @ep:the bulk or interrupt endpoint being reset
+ *
+ * use this when responding to the standard usb "set interface" request,
+ * for endpoints that aren't reconfigured, after clearing any other state
+ * in the endpoint's i/o queue.
+ *
+ * returns zero, or a negative error code.  on success, this call clears
+ * the underlying hardware state reflecting endpoint halt and data toggle.
+ */
+static inline int
+usb_ep_clear_halt (struct usb_ep *ep)
+{
+	return ep->ops->set_halt (ep, 0);
+}
+
+/**
+ * usb_ep_fifo_status - returns number of bytes in fifo, or error
+ * @ep: the endpoint whose fifo status is being checked.
+ *
+ * FIFO endpoints may have "unclaimed data" in them in certain cases,
+ * such as after aborted transfers.  Hosts may not have collected all
+ * the IN data written by the gadget driver, as reported by a request
+ * completion.  The gadget driver may not have collected all the data
+ * written OUT to it by the host.  Drivers that need precise handling for
+ * fault reporting or recovery may need to use this call.
+ *
+ * This returns the number of such bytes in the fifo, or a negative
+ * errno if the endpoint doesn't use a FIFO or doesn't support such
+ * precise handling.
+ */
+static inline int
+usb_ep_fifo_status (struct usb_ep *ep)
+{
+	if (ep->ops->fifo_status)
+		return ep->ops->fifo_status (ep);
+	else
+		return -EOPNOTSUPP;
+}
+
+/**
+ * usb_ep_fifo_flush - flushes contents of a fifo
+ * @ep: the endpoint whose fifo is being flushed.
+ *
+ * This call may be used to flush the "unclaimed data" that may exist in
+ * an endpoint fifo after abnormal transaction terminations.  The call
+ * must never be used except when endpoint is not being used for any
+ * protocol translation.
+ */
+static inline void
+usb_ep_fifo_flush (struct usb_ep *ep)
+{
+	if (ep->ops->fifo_flush)
+		ep->ops->fifo_flush (ep);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+struct usb_gadget;
+
+/* the rest of the api to the controller hardware: device operations,
+ * which don't involve endpoints (or i/o).
+ */
+struct usb_gadget_ops {
+	int	(*get_frame)(struct usb_gadget *);
+	int	(*wakeup)(struct usb_gadget *);
+	int	(*set_selfpowered) (struct usb_gadget *, int value);
+	int	(*ioctl)(struct usb_gadget *,
+				unsigned code, unsigned long param);
+};
+
+/**
+ * struct usb_gadget - represents a usb slave device
+ * @ep0: Endpoint zero, used when reading or writing responses to
+ * 	driver setup() requests
+ * @ep_list: List of other endpoints supported by the device.
+ * @speed: Speed of current connection to USB host.
+ * @name: Identifies the controller hardware type.  Used in diagnostics
+ * 	and sometimes configuration.
+ *
+ * Gadgets have a mostly-portable "gadget driver" implementing device
+ * functions, handling all usb configurations and interfaces.  They
+ * also have a hardware-specific driver (accessed through ops vectors),
+ * which insulates the gadget driver from hardware details and packages
+ * the hardware endpoints through generic i/o queues.
+ *
+ * Except for the driver data, all fields in this structure are
+ * read-only to the gadget driver.  That driver data is part of the
+ * "driver model" infrastructure in 2.5 (and later) kernels, and for
+ * earlier systems is grouped in a similar structure that's not known
+ * to the rest of the kernel.
+ */
+struct usb_gadget {
+	/* readonly to gadget driver */
+	const struct usb_gadget_ops	*ops;
+	struct usb_ep			*ep0;
+	struct list_head		ep_list;	/* of usb_ep */
+	enum usb_device_speed		speed;
+	const char			*name;
+
+	/* use this to allocate dma-coherent buffers or set up
+	 * dma mappings.  or print diagnostics, etc.
+	 */
+	struct device			dev;
+};
+
+static inline void set_gadget_data (struct usb_gadget *gadget, void *data)
+	{ dev_set_drvdata (&gadget->dev, data); }
+static inline void *get_gadget_data (struct usb_gadget *gadget)
+	{ return dev_get_drvdata (&gadget->dev); }
+
+/* iterates the non-control endpoints; 'tmp' is a struct usb_ep pointer */
+#define gadget_for_each_ep(tmp,gadget) \
+	list_for_each_entry(tmp, &(gadget)->ep_list, ep_list)
+
+
+/**
+ * usb_gadget_frame_number - returns the current frame number
+ * @gadget: controller that reports the frame number
+ *
+ * Returns the usb frame number, normally eleven bits from a SOF packet,
+ * or negative errno if this device doesn't support this capability.
+ */
+static inline int usb_gadget_frame_number (struct usb_gadget *gadget)
+{
+	return gadget->ops->get_frame (gadget);
+}
+
+/**
+ * usb_gadget_wakeup - tries to wake up the host connected to this gadget
+ * @gadget: controller used to wake up the host
+ *
+ * Returns zero on success, else negative error code if the hardware
+ * doesn't support such attempts, or its support has not been enabled
+ * by the usb host.  Drivers must return device descriptors that report
+ * their ability to support this, or hosts won't enable it.
+ */
+static inline int usb_gadget_wakeup (struct usb_gadget *gadget)
+{
+	if (!gadget->ops->wakeup)
+		return -EOPNOTSUPP;
+	return gadget->ops->wakeup (gadget);
+}
+
+/**
+ * usb_gadget_set_selfpowered - sets the device selfpowered feature.
+ * @gadget:the device being declared as self-powered
+ *
+ * this affects the device status reported by the hardware driver
+ * to reflect that it now has a local power supply.
+ *
+ * returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_set_selfpowered (struct usb_gadget *gadget)
+{
+	if (!gadget->ops->set_selfpowered)
+		return -EOPNOTSUPP;
+	return gadget->ops->set_selfpowered (gadget, 1);
+}
+
+/**
+ * usb_gadget_clear_selfpowered - clear the device selfpowered feature.
+ * @gadget:the device being declared as bus-powered
+ *
+ * this affects the device status reported by the hardware driver.
+ * some hardware may not support bus-powered operation, in which
+ * case this feature's value can never change.
+ *
+ * returns zero on success, else negative errno.
+ */
+static inline int
+usb_gadget_clear_selfpowered (struct usb_gadget *gadget)
+{
+	if (!gadget->ops->set_selfpowered)
+		return -EOPNOTSUPP;
+	return gadget->ops->set_selfpowered (gadget, 0);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
+/**
+ * struct usb_gadget_driver - driver for usb 'slave' devices
+ * @function: String describing the gadget's function
+ * @speed: Highest speed the driver handles.
+ * @bind: Invoked when the driver is bound to a gadget, usually
+ * 	after registering the driver.
+ * 	At that point, ep0 is fully initialized, and ep_list holds
+ * 	the currently-available endpoints.
+ * 	Called in a context that permits sleeping.
+ * @setup: Invoked for ep0 control requests that aren't handled by
+ * 	the hardware level driver. Most calls must be handled by
+ * 	the gadget driver, including descriptor and configuration
+ * 	management.  The 16 bit members of the setup data are in
+ * 	cpu order. Called in_interrupt; this may not sleep.  Driver
+ *	queues a response to ep0, or returns negative to stall.
+ * @disconnect: Invoked after all transfers have been stopped,
+ * 	when the host is disconnected.  May be called in_interrupt; this
+ * 	may not sleep.
+ * @unbind: Invoked when the driver is unbound from a gadget,
+ * 	usually from rmmod (after a disconnect is reported).
+ * 	Called in a context that permits sleeping.
+ * @suspend: Invoked on USB suspend.  May be called in_interrupt.
+ * @resume: Invoked on USB resume.  May be called in_interrupt.
+ *
+ * Devices are disabled till a gadget driver successfully bind()s, which
+ * means the driver will handle setup() requests needed to enumerate (and
+ * meet "chapter 9" requirements) then do some useful work.
+ *
+ * Drivers use hardware-specific knowledge to configure the usb hardware.
+ * endpoint addressing is only one of several hardware characteristics that
+ * are in descriptors the ep0 implementation returns from setup() calls.
+ *
+ * Except for ep0 implementation, most driver code shouldn't need change to
+ * run on top of different usb controllers.  It'll use endpoints set up by
+ * that ep0 implementation.
+ *
+ * The usb controller driver handles a few standard usb requests.  Those
+ * include set_address, and feature flags for devices, interfaces, and
+ * endpoints (the get_status, set_feature, and clear_feature requests).
+ *
+ * Accordingly, the driver's setup() callback must always implement all
+ * get_descriptor requests, returning at least a device descriptor and
+ * a configuration descriptor.  Drivers must make sure the endpoint
+ * descriptors match any hardware constraints. Some hardware also constrains
+ * other descriptors. (The pxa250 allows only configurations 1, 2, or 3).
+ *
+ * The driver's setup() callback must also implement set_configuration,
+ * and should also implement set_interface, get_configuration, and
+ * get_interface.  Setting a configuration (or interface) is where
+ * endpoints should be activated or (config 0) shut down.
+ *
+ * (Note that only the default control endpoint is supported.  Neither
+ * hosts nor devices generally support control traffic except to ep0.)
+ *
+ * Most devices will ignore USB suspend/resume operations, and so will
+ * not provide those callbacks.  However, some may need to change modes
+ * when the host is not longer directing those activities.  For example,
+ * local controls (buttons, dials, etc) may need to be re-enabled since
+ * the (remote) host can't do that any longer. 
+ */
+struct usb_gadget_driver {
+	char			*function;
+	enum usb_device_speed	speed;
+	int			(*bind)(struct usb_gadget *);
+	void			(*unbind)(struct usb_gadget *);
+	int			(*setup)(struct usb_gadget *,
+					const struct usb_ctrlrequest *);
+	void			(*disconnect)(struct usb_gadget *);
+	void			(*suspend)(struct usb_gadget *);
+	void			(*resume)(struct usb_gadget *);
+
+	// FIXME support safe rmmod
+	struct device_driver	driver;
+};
+
+
+
+/*-------------------------------------------------------------------------*/
+
+/* driver modules register and unregister, as usual.
+ * these calls must be made in a context that can sleep.
+ *
+ * these will usually be implemented directly by the hardware-dependent
+ * usb bus interface driver, which will only support a single driver.
+ */
+
+/**
+ * usb_gadget_register_driver - register a gadget driver
+ * @driver:the driver being registered
+ *
+ * Call this in your gadget driver's module initialization function,
+ * to tell the underlying usb controller driver about your driver.
+ * The driver's bind() function will be called to bind it to a
+ * gadget.  This function must be called in a context that can sleep.
+ */
+int usb_gadget_register_driver (struct usb_gadget_driver *driver);
+
+/**
+ * usb_gadget_unregister_driver - unregister a gadget driver
+ * @driver:the driver being unregistered
+ *
+ * Call this in your gadget driver's module cleanup function,
+ * to tell the underlying usb controller that your driver is
+ * going away.  If the controller is connected to a USB host,
+ * it will first disconnect().  The driver is also requested
+ * to unbind() and clean up any device state, before this procedure
+ * finally returns.
+ * This function must be called in a context that can sleep.
+ */
+int usb_gadget_unregister_driver (struct usb_gadget_driver *driver);
+
+/*-------------------------------------------------------------------------*/
+
+/* utility to simplify dealing with string descriptors */
+
+/**
+ * struct usb_string - wraps a C string and its USB id
+ * @id:the (nonzero) ID for this string
+ * @s:the string, in ISO-8859/1 characters
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap a string
+ * together with its ID.
+ */
+struct usb_string {
+	u8			id;
+	const char		*s;
+};
+
+/**
+ * struct usb_gadget_strings - a set of USB strings in a given language
+ * @language:identifies the strings' language (0x0409 for en-us)
+ * @strings:array of strings with their ids
+ *
+ * If you're using usb_gadget_get_string(), use this to wrap all the
+ * strings for a given language.
+ */
+struct usb_gadget_strings {
+	u16			language;	/* 0x0409 for en-us */
+	struct usb_string	*strings;
+};
+
+/* put descriptor for string with that id into buf (buflen >= 256) */
+int usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf);
+
+
+#endif  /* __KERNEL__ */
+
+#endif	/* __LINUX_USB_GADGET_H */
diff -Nru a/include/linux/wait.h b/include/linux/wait.h
--- a/include/linux/wait.h	Fri Nov 15 07:36:32 2002
+++ b/include/linux/wait.h	Sun May 18 17:00:00 2003
@@ -111,15 +111,12 @@
 #define wake_up(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 1)
 #define wake_up_nr(x, nr)		__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, nr)
 #define wake_up_all(x)			__wake_up((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0)
+#define wake_up_all_sync(x)			__wake_up_sync((x),TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, 0)
 #define wake_up_interruptible(x)	__wake_up((x),TASK_INTERRUPTIBLE, 1)
 #define wake_up_interruptible_nr(x, nr)	__wake_up((x),TASK_INTERRUPTIBLE, nr)
 #define wake_up_interruptible_all(x)	__wake_up((x),TASK_INTERRUPTIBLE, 0)
 #define	wake_up_locked(x)		__wake_up_locked((x), TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE)
-#ifdef CONFIG_SMP
 #define wake_up_interruptible_sync(x)   __wake_up_sync((x),TASK_INTERRUPTIBLE, 1)
-#else
-#define wake_up_interruptible_sync(x)   __wake_up((x),TASK_INTERRUPTIBLE, 1)
-#endif
 
 #define __wait_event(wq, condition) 					\
 do {									\
diff -Nru a/include/linux/wanpipe.h b/include/linux/wanpipe.h
--- a/include/linux/wanpipe.h	Sun Feb 16 16:22:42 2003
+++ b/include/linux/wanpipe.h	Thu May 15 14:42:07 2003
@@ -39,8 +39,6 @@
 #ifndef	_WANPIPE_H
 #define	_WANPIPE_H
 
-#define netdevice_t struct net_device
-
 #include <linux/wanrouter.h>
 
 /* Defines */
@@ -286,7 +284,7 @@
 {
 	char devname[WAN_DRVNAME_SZ+1];	/* card name */
 	sdlahw_t hw;			/* hardware configuration */
-	wan_device_t wandev;		/* WAN device data space */
+	struct wan_device wandev;	/* WAN device data space */
 	
 	unsigned open_cnt;		/* number of open interfaces */
 	unsigned long state_tick;	/* link state timestamp */
@@ -335,22 +333,22 @@
 			u32 hi_pvc;
 			u32 lo_svc;
 			u32 hi_svc;
-			netdevice_t *svc_to_dev_map[MAX_X25_LCN];
-			netdevice_t *pvc_to_dev_map[MAX_X25_LCN];
-			netdevice_t *tx_dev;
-			netdevice_t *cmd_dev;
+			struct net_device *svc_to_dev_map[MAX_X25_LCN];
+			struct net_device *pvc_to_dev_map[MAX_X25_LCN];
+			struct net_device *tx_dev;
+			struct net_device *cmd_dev;
 			u32 no_dev;
 			volatile u8 *hdlc_buf_status;
 			u32 tx_interrupts_pending;
                         u16 timer_int_enabled;
-			netdevice_t *poll_device;
+			struct net_device *poll_device;
 			atomic_t command_busy;
 
 			u16 udp_pkt_lgth;
                         u32 udp_type;
                         u8  udp_pkt_src;
 			u32 udp_lcn;
-                        netdevice_t * udp_dev;
+                        struct net_device *udp_dev;
                         s8 udp_pkt_data[MAX_LGTH_UDP_MGNT_PKT];
 
 		 	u8 LAPB_hdlc;		/* Option to turn off X25 and run only LAPB */
@@ -369,7 +367,7 @@
 			unsigned rx_top;	/* S508 receive buffer end */
 			unsigned short node_dlci[100];
 			unsigned short dlci_num;
-                        netdevice_t *dlci_to_dev_map[991 + 1];
+                        struct net_device *dlci_to_dev_map[991 + 1];
                         unsigned tx_interrupts_pending;
                         unsigned short timer_int_enabled;
                         unsigned short udp_pkt_lgth;
@@ -382,7 +380,7 @@
                         void *curr_trc_el;      		/* current trace element */
                         unsigned short trc_bfr_space; 		/* trace buffer space */
 			unsigned char  update_comms_stats;
-			netdevice_t *arp_dev;
+			struct net_device *arp_dev;
 			spinlock_t if_send_lock;
 		} f;
 		struct			/****** PPP-specific data ***********/
@@ -483,10 +481,10 @@
 
 extern void wanpipe_queue_work (struct work_struct *);
 extern void wanpipe_mark_bh (void);
-extern void wakeup_sk_bh (netdevice_t *);
-extern int change_dev_flags (netdevice_t *, unsigned); 
-extern unsigned long get_ip_address (netdevice_t *dev, int option);
-extern void add_gateway(sdla_t *, netdevice_t *);
+extern void wakeup_sk_bh(struct net_device *dev);
+extern int change_dev_flags(struct net_device *dev, unsigned flags);
+extern unsigned long get_ip_address(struct net_device *dev, int option);
+extern void add_gateway(sdla_t *card, struct net_device *dev);
 
 
 #endif	/* __KERNEL__ */
diff -Nru a/include/linux/wanrouter.h b/include/linux/wanrouter.h
--- a/include/linux/wanrouter.h	Sun Feb 16 16:22:42 2003
+++ b/include/linux/wanrouter.h	Thu May 15 14:42:07 2003
@@ -44,8 +44,6 @@
 * Jan 02, 1997	Gene Kozin	Initial version (based on wanpipe.h).
 *****************************************************************************/
 
-#define netdevice_t struct net_device
-
 #include <linux/spinlock.h>       /* Support for SMP Locking */
 
 #ifndef	_ROUTER_H
@@ -462,8 +460,7 @@
 /*----------------------------------------------------------------------------
  * WAN device data space.
  */
-typedef struct wan_device
-{
+struct wan_device {
 	unsigned magic;			/* magic number */
 	char* name;			/* -> WAN device name (ASCIIZ) */
 	void* private;			/* -> driver private data */
@@ -506,27 +503,29 @@
 	int (*update) (struct wan_device *wandev);
 	int (*ioctl) (struct wan_device *wandev, unsigned cmd,
 		unsigned long arg);
-	int (*new_if) (struct wan_device *wandev, netdevice_t *dev,
-		wanif_conf_t *conf);
-	int (*del_if) (struct wan_device *wandev, netdevice_t *dev);
+	int (*new_if)(struct wan_device *wandev, struct net_device *dev,
+		      wanif_conf_t *conf);
+	int (*del_if)(struct wan_device *wandev, struct net_device *dev);
 					/****** maintained by the router ****/
 	struct wan_device* next;	/* -> next device */
-	netdevice_t* dev;		/* list of network interfaces */
+	struct net_device* dev;		/* list of network interfaces */
 	unsigned ndev;			/* number of interfaces */
 	struct proc_dir_entry *dent;	/* proc filesystem entry */
-} wan_device_t;
+};
 
 /* Public functions available for device drivers */
-extern int register_wan_device(wan_device_t *wandev);
+extern int register_wan_device(struct wan_device *wandev);
 extern int unregister_wan_device(char *name);
-unsigned short wanrouter_type_trans(struct sk_buff *skb, netdevice_t *dev);
-int wanrouter_encapsulate(struct sk_buff *skb, netdevice_t *dev,unsigned short type);
+unsigned short wanrouter_type_trans(struct sk_buff *skb,
+				    struct net_device *dev);
+int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev,
+			  unsigned short type);
 
 /* Proc interface functions. These must not be called by the drivers! */
 extern int wanrouter_proc_init(void);
 extern void wanrouter_proc_cleanup(void);
-extern int wanrouter_proc_add(wan_device_t *wandev);
-extern int wanrouter_proc_delete(wan_device_t *wandev);
+extern int wanrouter_proc_add(struct wan_device *wandev);
+extern int wanrouter_proc_delete(struct wan_device *wandev);
 extern int wanrouter_ioctl( struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg);
 
 extern void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
@@ -535,7 +534,7 @@
 
 
 /* Public Data */
-extern wan_device_t *router_devlist;	/* list of registered devices */
+extern struct wan_device *router_devlist;	/* list of registered devices */
 
 #endif	/* __KERNEL__ */
 #endif	/* _ROUTER_H */
diff -Nru a/include/linux/wireless.h b/include/linux/wireless.h
--- a/include/linux/wireless.h	Sat Feb 15 11:33:03 2003
+++ b/include/linux/wireless.h	Thu May  1 10:03:22 2003
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	15	12.7.02
+ * Version :	16	2.4.03
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
@@ -69,6 +69,8 @@
 
 /***************************** INCLUDES *****************************/
 
+/* To minimise problems in user space, I might remove those headers
+ * at some point. Jean II */
 #include <linux/types.h>		/* for "caddr_t" et al		*/
 #include <linux/socket.h>		/* for "struct sockaddr" et al	*/
 #include <linux/if.h>			/* for IFNAMSIZ and co... */
@@ -80,7 +82,7 @@
  * (there is some stuff that will be added in the future...)
  * I just plan to increment with each new version.
  */
-#define WIRELESS_EXT	15
+#define WIRELESS_EXT	16
 
 /*
  * Changes :
@@ -163,6 +165,16 @@
  *	- Add IW_TXPOW_RANGE for range of Tx Powers
  *	- Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
  *	- Add IW_MODE_MONITOR for passive monitor
+ *
+ * V15 to V16
+ * ----------
+ *	- Increase the number of bitrates in iw_range to 32 (for 802.11g)
+ *	- Increase the number of frequencies in iw_range to 32 (for 802.11b+a)
+ *	- Reshuffle struct iw_range for increases, add filler
+ *	- Increase IW_MAX_AP to 64 for driver returning a lot of addresses
+ *	- Remove IW_MAX_GET_SPY because conflict with enhanced spy support
+ *	- Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
+ *	- Add IW_ENCODE_TEMP and iw_range->encoding_login_index
  */
 
 /**************************** CONSTANTS ****************************/
@@ -196,9 +208,11 @@
 /* SIOCGIWSTATS is strictly used between user space and the kernel, and
  * is never passed to the driver (i.e. the driver will never see it). */
 
-/* Mobile IP support (statistics per MAC address) */
+/* Spy support (statistics per MAC address - used for Mobile IP support) */
 #define SIOCSIWSPY	0x8B10		/* set spy addresses */
 #define SIOCGIWSPY	0x8B11		/* get spy info (quality of link) */
+#define SIOCSIWTHRSPY	0x8B12		/* set spy threshold (spy event) */
+#define SIOCGIWTHRSPY	0x8B13		/* get spy threshold */
 
 /* Access Point manipulation */
 #define SIOCSIWAP	0x8B14		/* set access point MAC addresses */
@@ -306,13 +320,13 @@
 /* ----------------------- OTHER CONSTANTS ----------------------- */
 
 /* Maximum frequencies in the range struct */
-#define IW_MAX_FREQUENCIES	16
+#define IW_MAX_FREQUENCIES	32
 /* Note : if you have something like 80 frequencies,
  * don't increase this constant and don't fill the frequency list.
  * The user will be able to set by channel anyway... */
 
 /* Maximum bit rates in the range struct */
-#define IW_MAX_BITRATES		8
+#define IW_MAX_BITRATES		32
 
 /* Maximum tx powers in the range struct */
 #define IW_MAX_TXPOWER		8
@@ -320,12 +334,11 @@
  * a few of them in the struct iw_range. */
 
 /* Maximum of address that you may set with SPY */
-#define IW_MAX_SPY		8	/* set */
-#define IW_MAX_GET_SPY		64	/* get */
+#define IW_MAX_SPY		8
 
 /* Maximum of address that you may get in the
    list of access points in range */
-#define IW_MAX_AP		8
+#define IW_MAX_AP		64
 
 /* Maximum size of the ESSID and NICKN strings */
 #define IW_ESSID_MAX_SIZE	32
@@ -354,7 +367,8 @@
 #define IW_ENCODE_ENABLED	0x0000	/* Encoding enabled */
 #define IW_ENCODE_RESTRICTED	0x4000	/* Refuse non-encoded packets */
 #define IW_ENCODE_OPEN		0x2000	/* Accept non-encoded packets */
-#define IW_ENCODE_NOKEY         0x0800  /* Key is write only, so not present */
+#define IW_ENCODE_NOKEY		0x0800  /* Key is write only, so not present */
+#define IW_ENCODE_TEMP		0x0400  /* Temporary key */
 
 /* Power management flags available (along with the value, if any) */
 #define IW_POWER_ON		0x0000	/* No details... */
@@ -482,6 +496,17 @@
 	__u32		beacon;		/* Missed beacons/superframe */
 };
 
+/*
+ *	Quality range (for spy threshold)
+ */
+struct	iw_thrspy
+{
+	struct sockaddr		addr;		/* Source address (hw/mac) */
+	struct iw_quality	qual;		/* Quality of the link */
+	struct iw_quality	low;		/* Low threshold */
+	struct iw_quality	high;		/* High threshold */
+};
+
 /* ------------------------ WIRELESS STATS ------------------------ */
 /*
  * Wireless statistics (used for /proc/net/wireless)
@@ -534,7 +559,7 @@
 	struct iw_quality qual;		/* Quality part of statistics */
 
 	struct sockaddr	ap_addr;	/* Access point address */
-	struct sockaddr	addr;		/* Destination address (hw) */
+	struct sockaddr	addr;		/* Destination address (hw/mac) */
 
 	struct iw_param	param;		/* Other small parameters */
 	struct iw_point	data;		/* Other large parameters */
@@ -582,17 +607,31 @@
 	__u32		min_nwid;	/* Minimal NWID we are able to set */
 	__u32		max_nwid;	/* Maximal NWID we are able to set */
 
-	/* Frequency */
-	__u16		num_channels;	/* Number of channels [0; num - 1] */
-	__u8		num_frequency;	/* Number of entry in the list */
-	struct iw_freq	freq[IW_MAX_FREQUENCIES];	/* list */
-	/* Note : this frequency list doesn't need to fit channel numbers */
+	/* Old Frequency (backward compat - moved lower ) */
+	__u16		old_num_channels;
+	__u8		old_num_frequency;
+	/* Filler to keep "version" at the same offset */
+	__s32		old_freq[6];
 
 	/* signal level threshold range */
 	__s32	sensitivity;
 
 	/* Quality of link & SNR stuff */
+	/* Quality range (link, level, noise)
+	 * If the quality is absolute, it will be in the range [0 ; max_qual],
+	 * if the quality is dBm, it will be in the range [max_qual ; 0].
+	 * Don't forget that we use 8 bit arithmetics... */
 	struct iw_quality	max_qual;	/* Quality of the link */
+	/* This should contain the average/typical values of the quality
+	 * indicator. This should be the threshold between a "good" and
+	 * a "bad" link (example : monitor going from green to orange).
+	 * Currently, user space apps like quality monitors don't have any
+	 * way to calibrate the measurement. With this, they can split
+	 * the range between 0 and max_qual in different quality level
+	 * (using a geometric subdivision centered on the average).
+	 * I expect that people doing the user space apps will feedback
+	 * us on which value we need to put in each driver... */
+	struct iw_quality	avg_qual;	/* Quality of the link */
 
 	/* Rates */
 	__u8		num_bitrates;	/* Number of entries in the list */
@@ -619,6 +658,8 @@
 	__u16	encoding_size[IW_MAX_ENCODING_SIZES];	/* Different token sizes */
 	__u8	num_encoding_sizes;	/* Number of entry in the list */
 	__u8	max_encoding_tokens;	/* Max number of tokens */
+	/* For drivers that need a "login/passwd" form */
+	__u8	encoding_login_index;	/* token index for login token */
 
 	/* Transmit power */
 	__u16		txpower_capa;	/* What options are supported */
@@ -638,18 +679,12 @@
 	__s32		min_r_time;	/* Minimal retry lifetime */
 	__s32		max_r_time;	/* Maximal retry lifetime */
 
-	/* Average quality of link & SNR */
-	struct iw_quality	avg_qual;	/* Quality of the link */
-	/* This should contain the average/typical values of the quality
-	 * indicator. This should be the threshold between a "good" and
-	 * a "bad" link (example : monitor going from green to orange).
-	 * Currently, user space apps like quality monitors don't have any
-	 * way to calibrate the measurement. With this, they can split
-	 * the range between 0 and max_qual in different quality level
-	 * (using a geometric subdivision centered on the average).
-	 * I expect that people doing the user space apps will feedback
-	 * us on which value we need to put in each driver...
-	 */
+	/* Frequency */
+	__u16		num_channels;	/* Number of channels [0; num - 1] */
+	__u8		num_frequency;	/* Number of entry in the list */
+	struct iw_freq	freq[IW_MAX_FREQUENCIES];	/* list */
+	/* Note : this frequency list doesn't need to fit channel numbers,
+	 * because each entry contain its channel index */
 };
 
 /*
diff -Nru a/include/media/audiochip.h b/include/media/audiochip.h
--- a/include/media/audiochip.h	Wed Mar 12 06:07:06 2003
+++ b/include/media/audiochip.h	Sat May 17 14:09:44 2003
@@ -18,6 +18,15 @@
 #define AUDIO_MUTE         0x80
 #define AUDIO_UNMUTE       0x81
 
+/* all the stuff below is obsolete and just here for reference.  I'll
+ * remove it once the driver is tested and works fine.
+ *
+ * Instead creating alot of tiny API's for all kinds of different
+ * chips, we'll just pass throuth the v4l ioctl structs (v4l2 not
+ * yet...).  It is a bit less flexible, but most/all used i2c chips
+ * make sense in v4l context only.  So I think that's acceptable...
+ */
+
 /* misc stuff to pass around config info to i2c chips */
 #define AUDC_CONFIG_PINNACLE  _IOW('m',32,int)
 
diff -Nru a/include/media/tuner.h b/include/media/tuner.h
--- a/include/media/tuner.h	Wed Mar 12 06:07:06 2003
+++ b/include/media/tuner.h	Sat May 17 14:09:45 2003
@@ -64,7 +64,7 @@
 #define TUNER_LG_PAL_NEW_TAPC   37
 #define TUNER_PHILIPS_FM1216ME_MK3  38
 #define TUNER_LG_NTSC_NEW_TAPC   39
-
+#define TUNER_HITACHI_NTSC       40
 
 
 
@@ -83,6 +83,7 @@
 #define SHARP   6
 #define Samsung 7
 #define Microtune 8
+#define HITACHI 9
 
 #define TUNER_SET_TYPE               _IOW('t',1,int)    /* set tuner type */
 #define TUNER_SET_TVFREQ             _IOW('t',2,int)    /* set tv freq */
diff -Nru a/include/media/video-buf.h b/include/media/video-buf.h
--- a/include/media/video-buf.h	Wed Mar 12 06:07:06 2003
+++ b/include/media/video-buf.h	Sat May 17 14:09:40 2003
@@ -196,6 +196,7 @@
 int  videobuf_queue_is_busy(struct videobuf_queue *q);
 void videobuf_queue_cancel(struct file *file, struct videobuf_queue *q);
 
+enum v4l2_field videobuf_next_field(struct videobuf_queue *q);
 void videobuf_status(struct v4l2_buffer *b, struct videobuf_buffer *vb,
 		     enum v4l2_buf_type type);
 int videobuf_reqbufs(struct file *file, struct videobuf_queue *q,
diff -Nru a/include/net/atmclip.h b/include/net/atmclip.h
--- a/include/net/atmclip.h	Tue Feb  5 09:39:49 2002
+++ b/include/net/atmclip.h	Tue May 13 17:05:28 2003
@@ -55,13 +55,22 @@
 };
 
 
-extern struct atm_vcc *atmarpd; /* ugly */
-extern struct neigh_table clip_tbl;
+#ifdef __KERNEL__
+struct atm_clip_ops {
+	int (*clip_create)(int number);
+	int (*clip_mkip)(struct atm_vcc *vcc,int timeout);
+	int (*clip_setentry)(struct atm_vcc *vcc,u32 ip);
+	int (*clip_encap)(struct atm_vcc *vcc,int mode);
+	void (*clip_push)(struct atm_vcc *vcc,struct sk_buff *skb);
+	int (*atm_init_atmarp)(struct atm_vcc *vcc);
+	struct module *owner;
+};
 
-int clip_create(int number);
-int clip_mkip(struct atm_vcc *vcc,int timeout);
-int clip_setentry(struct atm_vcc *vcc,u32 ip);
-int clip_encap(struct atm_vcc *vcc,int mode);
-void atm_clip_init(void);
+void atm_clip_ops_set(struct atm_clip_ops *);
+int try_atm_clip_ops(void);
+
+extern struct neigh_table *clip_tbl_hook;
+extern struct atm_clip_ops *atm_clip_ops;
+#endif
 
 #endif
diff -Nru a/include/net/ax25.h b/include/net/ax25.h
--- a/include/net/ax25.h	Thu Aug  8 05:04:50 2002
+++ b/include/net/ax25.h	Wed May 14 20:25:03 2003
@@ -360,8 +360,8 @@
 extern void ax25_register_sysctl(void);
 extern void ax25_unregister_sysctl(void);
 #else
-extern inline void ax25_register_sysctl(void) {};
-extern inline void ax25_unregister_sysctl(void) {};
+static inline void ax25_register_sysctl(void) {};
+static inline void ax25_unregister_sysctl(void) {};
 #endif /* CONFIG_SYSCTL */
 
 #endif
diff -Nru a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h
--- a/include/net/bluetooth/l2cap.h	Fri Nov 22 07:09:05 2002
+++ b/include/net/bluetooth/l2cap.h	Fri May  9 12:01:19 2003
@@ -231,8 +231,10 @@
 	struct sock 		*prev_c;
 };
 
-#define CONF_REQ_SENT    0x01
-#define CONF_INPUT_DONE  0x02
-#define CONF_OUTPUT_DONE 0x04
+#define L2CAP_CONF_REQ_SENT    0x01
+#define L2CAP_CONF_INPUT_DONE  0x02
+#define L2CAP_CONF_OUTPUT_DONE 0x04
+
+void l2cap_load(void);
 
 #endif /* __L2CAP_H */
diff -Nru a/include/net/bluetooth/rfcomm.h b/include/net/bluetooth/rfcomm.h
--- a/include/net/bluetooth/rfcomm.h	Sun Apr 27 17:18:01 2003
+++ b/include/net/bluetooth/rfcomm.h	Fri May  9 21:43:01 2003
@@ -185,10 +185,11 @@
 	atomic_t      refcnt;
 	u8            dlci;
 	u8            addr;
-
-	uint          mtu;
+	u8            priority;
 	u8            v24_sig;
+	u8            mscex;
 
+	uint          mtu;
 	uint          credits;
 	uint          rx_credits;
 	uint          tx_credits;
@@ -212,6 +213,11 @@
 #define RFCOMM_SCHED_TX     2
 #define RFCOMM_SCHED_TIMEO  3
 #define RFCOMM_SCHED_WAKEUP 31
+
+/* MSC exchange flags */
+#define RFCOMM_MSCEX_TX     1
+#define RFCOMM_MSCEX_RX     2
+#define RFCOMM_MSCEX_OK     (RFCOMM_MSCEX_TX + RFCOMM_MSCEX_RX)
 
 extern struct task_struct *rfcomm_thread;
 extern unsigned long rfcomm_event;
diff -Nru a/include/net/compat.h b/include/net/compat.h
--- a/include/net/compat.h	Tue Apr  1 21:03:04 2003
+++ b/include/net/compat.h	Mon May 12 14:35:19 2003
@@ -27,7 +27,7 @@
 #define compat_msghdr	msghdr		/* to avoid compiler warnings */
 #endif /* defined(CONFIG_COMPAT) */
 
-extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr *);
+extern int get_compat_msghdr(struct msghdr *, struct compat_msghdr __user *);
 extern int verify_compat_iovec(struct msghdr *, struct iovec *, char *, int);
 extern asmlinkage long compat_sys_sendmsg(int,struct compat_msghdr *,unsigned);
 extern asmlinkage long compat_sys_recvmsg(int,struct compat_msghdr *,unsigned);
diff -Nru a/include/net/dn_dev.h b/include/net/dn_dev.h
--- a/include/net/dn_dev.h	Fri Apr 18 10:42:53 2003
+++ b/include/net/dn_dev.h	Tue May  6 00:58:43 2003
@@ -71,7 +71,6 @@
 #define DN_DEV_MPOINT 4
 	int state;                /* Initial state                      */
 	int forwarding;	          /* 0=EndNode, 1=L1Router, 2=L2Router  */
-	unsigned short blksize;   /* Block Size                         */
 	unsigned long t2;         /* Default value of t2                */
 	unsigned long t3;         /* Default value of t3                */
 	int priority;             /* Priority to be a router            */
diff -Nru a/include/net/dn_fib.h b/include/net/dn_fib.h
--- a/include/net/dn_fib.h	Fri Apr 18 10:42:53 2003
+++ b/include/net/dn_fib.h	Thu May 15 23:27:55 2003
@@ -1,6 +1,9 @@
 #ifndef _NET_DN_FIB_H
 #define _NET_DN_FIB_H
 
+/* WARNING: The ordering of these elements must match ordering
+ *          of RTA_* rtnetlink attribute numbers.
+ */
 struct dn_kern_rta
 {
         void            *rta_dst;
@@ -13,8 +16,9 @@
         struct rtattr   *rta_mx;
         struct rtattr   *rta_mp;
         unsigned char   *rta_protoinfo;
-        unsigned char   *rta_flow;
+        u32             *rta_flow;
         struct rta_cacheinfo *rta_ci;
+	struct rta_session *rta_sess;
 };
 
 struct dn_fib_res {
@@ -101,10 +105,6 @@
 	int (*lookup)(struct dn_fib_table *t, const struct flowi *fl,
 			struct dn_fib_res *res);
 	int (*flush)(struct dn_fib_table *t);
-#ifdef CONFIG_PROC_FS
-	int (*get_info)(struct dn_fib_table *table, char *buf,
-			int first, int count);
-#endif /* CONFIG_PROC_FS */
 	int (*dump)(struct dn_fib_table *t, struct sk_buff *skb, struct netlink_callback *cb);
 
 	unsigned char data[0];
@@ -183,6 +183,9 @@
 extern struct dn_fib_table *dn_fib_tables[];
 
 #else /* Endnode */
+
+#define dn_fib_init() (0)
+#define dn_fib_cleanup() (0)
 
 #define dn_fib_lookup(fl, res) (-ESRCH)
 #define dn_fib_info_put(fi) do { } while(0)
diff -Nru a/include/net/dn_route.h b/include/net/dn_route.h
--- a/include/net/dn_route.h	Fri Apr 18 10:42:53 2003
+++ b/include/net/dn_route.h	Tue May  6 00:58:43 2003
@@ -74,7 +74,7 @@
 	__u16 rt_saddr;
 	__u16 rt_daddr;
 	__u16 rt_gateway;
-	__u16 __padding;
+	__u16 rt_local_src;	/* Source used for forwarding packets */
 	__u16 rt_src_map;
 	__u16 rt_dst_map;
 
diff -Nru a/include/net/flow.h b/include/net/flow.h
--- a/include/net/flow.h	Fri Apr 18 10:42:53 2003
+++ b/include/net/flow.h	Thu May 15 21:05:01 2003
@@ -75,4 +75,16 @@
 #define fl_icmp_code	uli_u.icmpt.code
 #define fl_ipsec_spi	uli_u.spi
 };
+
+#define FLOW_DIR_IN	0
+#define FLOW_DIR_OUT	1
+#define FLOW_DIR_FWD	2
+
+typedef void (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir,
+			       void **objp, atomic_t **obj_refp);
+
+extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
+			       flow_resolve_t resolver);
+extern atomic_t flow_cache_genid;
+
 #endif
diff -Nru a/include/net/if_inet6.h b/include/net/if_inet6.h
--- a/include/net/if_inet6.h	Fri Apr 25 21:06:34 2003
+++ b/include/net/if_inet6.h	Thu May 15 17:25:02 2003
@@ -264,5 +264,10 @@
 		buf[5]=0x00;
 	}
 }
+
+static inline void ipv6_arcnet_mc_map(const struct in6_addr *addr, char *buf)
+{
+	buf[0] = 0x00;
+}
 #endif
 #endif
diff -Nru a/include/net/ip.h b/include/net/ip.h
--- a/include/net/ip.h	Thu May  1 03:21:46 2003
+++ b/include/net/ip.h	Sat May 17 23:02:40 2003
@@ -141,7 +141,7 @@
 void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *arg,
 		   unsigned int len); 
 
-extern __inline__ int ip_finish_output(struct sk_buff *skb);
+extern int ip_finish_output(struct sk_buff *skb);
 
 struct ipv4_config
 {
@@ -230,6 +230,23 @@
 	buf[3]=addr&0x7F;
 }
 
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+#include <linux/ipv6.h>
+#endif
+
+static __inline__ void inet_reset_saddr(struct sock *sk)
+{
+	inet_sk(sk)->rcv_saddr = inet_sk(sk)->saddr = 0;
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+	if (sk->family == PF_INET6) {
+		struct ipv6_pinfo *np = inet6_sk(sk);
+
+		memset(&np->saddr, 0, sizeof(np->saddr));
+		memset(&np->rcv_saddr, 0, sizeof(np->rcv_saddr));
+	}
+#endif
+}
+
 #endif
 
 extern int	ip_call_ra_chain(struct sk_buff *skb);
@@ -280,5 +297,16 @@
 
 extern int ip_seq_release(struct inode *inode, struct file *file);
 extern int ipv4_proc_init(void);
+
+/* sysctl helpers - any sysctl which holds a value that ends up being
+ * fed into the routing cache should use these handlers.
+ */
+int ipv4_doint_and_flush(ctl_table *ctl, int write,
+			 struct file* filp, void *buffer,
+			 size_t *lenp);
+int ipv4_doint_and_flush_strategy(ctl_table *table, int *name, int nlen,
+				  void *oldval, size_t *oldlenp,
+				  void *newval, size_t newlen, 
+				  void **context);
 
 #endif	/* _IP_H */
diff -Nru a/include/net/ip6_fib.h b/include/net/ip6_fib.h
--- a/include/net/ip6_fib.h	Thu Apr 10 23:43:33 2003
+++ b/include/net/ip6_fib.h	Thu May 15 23:27:55 2003
@@ -67,7 +67,6 @@
 	
 	u32				rt6i_flags;
 	u32				rt6i_metric;
-	u8				rt6i_hoplimit;
 	atomic_t			rt6i_ref;
 
 	struct rt6key			rt6i_dst;
@@ -163,10 +162,12 @@
 
 extern int			fib6_add(struct fib6_node *root,
 					 struct rt6_info *rt,
-					 struct nlmsghdr *nlh);
+					 struct nlmsghdr *nlh,
+					 void *rtattr);
 
 extern int			fib6_del(struct rt6_info *rt,
-					 struct nlmsghdr *nlh);
+					 struct nlmsghdr *nlh,
+					 void *rtattr);
 
 extern void			inet6_rt_notify(int event, struct rt6_info *rt,
 						struct nlmsghdr *nlh);
diff -Nru a/include/net/ip6_route.h b/include/net/ip6_route.h
--- a/include/net/ip6_route.h	Tue Apr 22 23:57:43 2003
+++ b/include/net/ip6_route.h	Thu May  8 17:43:20 2003
@@ -38,9 +38,11 @@
 extern int			ipv6_route_ioctl(unsigned int cmd, void *arg);
 
 extern int			ip6_route_add(struct in6_rtmsg *rtmsg,
-					      struct nlmsghdr *);
+					      struct nlmsghdr *,
+					      void *rtattr);
 extern int			ip6_del_rt(struct rt6_info *,
-					   struct nlmsghdr *);
+					   struct nlmsghdr *,
+					   void *rtattr);
 
 extern int			ip6_rt_addr_add(struct in6_addr *addr,
 						struct net_device *dev);
diff -Nru a/include/net/ip_fib.h b/include/net/ip_fib.h
--- a/include/net/ip_fib.h	Thu Nov 14 06:48:50 2002
+++ b/include/net/ip_fib.h	Thu May 15 23:27:55 2003
@@ -20,6 +20,9 @@
 #include <net/flow.h>
 #include <linux/seq_file.h>
 
+/* WARNING: The ordering of these elements must match ordering
+ *          of RTA_* rtnetlink attribute numbers.
+ */
 struct kern_rta
 {
 	void		*rta_dst;
@@ -32,8 +35,9 @@
 	struct rtattr	*rta_mx;
 	struct rtattr	*rta_mp;
 	unsigned char	*rta_protoinfo;
-	unsigned char	*rta_flow;
+	u32		*rta_flow;
 	struct rta_cacheinfo *rta_ci;
+	struct rta_session *rta_sess;
 };
 
 struct fib_nh
diff -Nru a/include/net/ipcomp.h b/include/net/ipcomp.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/include/net/ipcomp.h	Fri May 16 14:02:27 2003
@@ -0,0 +1,12 @@
+#ifndef _NET_IPCOMP_H
+#define _NET_IPCOMP_H
+
+#define IPCOMP_SCRATCH_SIZE     65400
+
+struct ipcomp_data {
+	u16 threshold;
+	u8 *scratch;
+	struct crypto_tfm *tfm;
+};
+
+#endif
diff -Nru a/include/net/ipv6.h b/include/net/ipv6.h
--- a/include/net/ipv6.h	Fri Apr 25 21:06:34 2003
+++ b/include/net/ipv6.h	Fri May 16 14:02:36 2003
@@ -315,6 +315,27 @@
 					       unsigned length,
 					       struct ipv6_txoptions *opt,
 					       int hlimit, int flags);
+extern int			ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr);
+
+extern int			ip6_append_data(struct sock *sk,
+						int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb),
+		    				void *from,
+						int length,
+						int transhdrlen,
+		      				int hlimit,
+						struct ipv6_txoptions *opt,
+						struct flowi *fl,
+						struct rt6_info *rt,
+						unsigned int flags);
+
+extern int			ip6_push_pending_frames(struct sock *sk);
+
+extern void			ip6_flush_pending_frames(struct sock *sk);
+
+extern int			ip6_dst_lookup(struct sock *sk,
+					       struct dst_entry **dst,
+					       struct flowi *fl,
+					       struct in6_addr **saddr);
 
 /*
  *	skb processing functions
diff -Nru a/include/net/ipx.h b/include/net/ipx.h
--- a/include/net/ipx.h	Sat Oct  5 20:04:47 2002
+++ b/include/net/ipx.h	Fri May 16 11:47:00 2003
@@ -12,6 +12,7 @@
 #include <linux/netdevice.h>
 #include <net/datalink.h>
 #include <linux/ipx.h>
+#include <linux/list.h>
 
 struct ipx_address {
 	__u32   net;
@@ -25,11 +26,11 @@
 #define IPX_MAX_PPROP_HOPS 8
 
 struct ipxhdr {
-	__u16           ipx_checksum __attribute__ ((packed));
+	__u16			ipx_checksum __attribute__ ((packed));
 #define IPX_NO_CHECKSUM	0xFFFF
-	__u16           ipx_pktsize __attribute__ ((packed));
-	__u8            ipx_tctrl;
-	__u8            ipx_type;
+	__u16			ipx_pktsize __attribute__ ((packed));
+	__u8			ipx_tctrl;
+	__u8			ipx_type;
 #define IPX_TYPE_UNKNOWN	0x00
 #define IPX_TYPE_RIP		0x01	/* may also be 0 */
 #define IPX_TYPE_SAP		0x04	/* may also be 0 */
@@ -47,42 +48,42 @@
 
 struct ipx_interface {
 	/* IPX address */
-	__u32           if_netnum;
-	unsigned char	if_node[IPX_NODE_LEN];
-	atomic_t        refcnt;
+	__u32			if_netnum;
+	unsigned char		if_node[IPX_NODE_LEN];
+	atomic_t		refcnt;
 
 	/* physical device info */
 	struct net_device	*if_dev;
 	struct datalink_proto	*if_dlink;
-	unsigned short	if_dlink_type;
+	unsigned short		if_dlink_type;
 
 	/* socket support */
-	unsigned short	if_sknum;
-	struct sock	*if_sklist;
-	spinlock_t      if_sklist_lock;
+	unsigned short		if_sknum;
+	struct sock		*if_sklist;
+	spinlock_t		if_sklist_lock;
 
 	/* administrative overhead */
-	int		if_ipx_offset;
-	unsigned char	if_internal;
-	unsigned char	if_primary;
+	int			if_ipx_offset;
+	unsigned char		if_internal;
+	unsigned char		if_primary;
 	
-	struct ipx_interface	*if_next;
+	struct list_head	node; /* node in ipx_interfaces list */
 };
 
 struct ipx_route {
-	__u32         ir_net;
+	__u32			ir_net;
 	struct ipx_interface	*ir_intrfc;
-	unsigned char ir_routed;
-	unsigned char ir_router_node[IPX_NODE_LEN];
-	struct ipx_route	*ir_next;
-	atomic_t      refcnt;
+	unsigned char		ir_routed;
+	unsigned char		ir_router_node[IPX_NODE_LEN];
+	struct list_head	node; /* node in ipx_routes list */
+	atomic_t		refcnt;
 };
 
 #ifdef __KERNEL__
 struct ipx_cb {
-	u8 ipx_tctrl;
-	u32 ipx_dest_net;
-	u32 ipx_source_net;
+	u8	ipx_tctrl;
+	u32	ipx_dest_net;
+	u32	ipx_source_net;
 	struct {
 		u32 netnum;
 		int index;
@@ -92,14 +93,16 @@
 struct ipx_opt {
 	struct ipx_address	dest_addr;
 	struct ipx_interface	*intrfc;
-	unsigned short	port;
+	unsigned short		port;
 #ifdef CONFIG_IPX_INTERN
-	unsigned char	node[IPX_NODE_LEN];
+	unsigned char		node[IPX_NODE_LEN];
 #endif
-	unsigned short	type;
-	/* To handle special ncp connection-handling sockets for mars_nwe,
- 	 * the connection number must be stored in the socket. */
-	unsigned short	ipx_ncp_conn;
+	unsigned short		type;
+	/*
+	 * To handle special ncp connection-handling sockets for mars_nwe,
+ 	 * the connection number must be stored in the socket.
+	 */
+	unsigned short		ipx_ncp_conn;
 };
 
 #define ipx_sk(__sk) ((struct ipx_opt *)(__sk)->protinfo)
@@ -108,10 +111,11 @@
 #define IPX_MIN_EPHEMERAL_SOCKET	0x4000
 #define IPX_MAX_EPHEMERAL_SOCKET	0x7fff
 
-extern struct ipx_route *ipx_routes;
+extern struct list_head ipx_routes;
 extern rwlock_t ipx_routes_lock;
 
-extern struct ipx_interface *ipx_interfaces;
+extern struct list_head ipx_interfaces;
+extern struct ipx_interface *ipx_interfaces_head(void);
 extern spinlock_t ipx_interfaces_lock;
 
 extern struct ipx_interface *ipx_primary_net;
@@ -121,4 +125,36 @@
 
 extern const char *ipx_frame_name(unsigned short);
 extern const char *ipx_device_name(struct ipx_interface *intrfc);
-#endif /* def _NET_INET_IPX_H_ */
+
+static __inline__ void ipxitf_hold(struct ipx_interface *intrfc)
+{
+	atomic_inc(&intrfc->refcnt);
+}
+
+extern void ipxitf_down(struct ipx_interface *intrfc);
+
+static __inline__ void ipxitf_put(struct ipx_interface *intrfc)
+{
+	if (atomic_dec_and_test(&intrfc->refcnt))
+		ipxitf_down(intrfc);
+}
+
+extern void __ipxitf_down(struct ipx_interface *intrfc);
+
+static __inline__ void __ipxitf_put(struct ipx_interface *intrfc)
+{
+	if (atomic_dec_and_test(&intrfc->refcnt))
+		__ipxitf_down(intrfc);
+}
+
+static __inline__ void ipxrtr_hold(struct ipx_route *rt)
+{
+	        atomic_inc(&rt->refcnt);
+}
+
+static __inline__ void ipxrtr_put(struct ipx_route *rt)
+{
+	        if (atomic_dec_and_test(&rt->refcnt))
+			                kfree(rt);
+}
+#endif /* _NET_INET_IPX_H_ */
diff -Nru a/include/net/iw_handler.h b/include/net/iw_handler.h
--- a/include/net/iw_handler.h	Tue Feb 25 09:45:37 2003
+++ b/include/net/iw_handler.h	Thu May  1 10:03:22 2003
@@ -1,7 +1,7 @@
 /*
  * This file define the new driver API for Wireless Extensions
  *
- * Version :	4	21.6.02
+ * Version :	5	4.12.02
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
  * Copyright (c) 2001-2002 Jean Tourrilhes, All Rights Reserved.
@@ -206,7 +206,7 @@
  * will be needed...
  * I just plan to increment with each new version.
  */
-#define IW_HANDLER_VERSION	4
+#define IW_HANDLER_VERSION	5
 
 /*
  * Changes :
@@ -220,10 +220,18 @@
  * V3 to V4
  * --------
  *	- Reshuffle IW_HEADER_TYPE_XXX to map IW_PRIV_TYPE_XXX changes
+ *
+ * V4 to V5
+ * --------
+ *	- Add new spy support : struct iw_spy_data & prototypes
  */
 
 /**************************** CONSTANTS ****************************/
 
+/* Enable enhanced spy support. Disable to reduce footprint */
+#define IW_WIRELESS_SPY
+#define IW_WIRELESS_THRSPY
+
 /* Special error message for the driver to indicate that we
  * should do a commit after return from the iw_handler */
 #define EIWCOMMIT	EINPROGRESS
@@ -315,6 +323,9 @@
 	 * We will automatically export that to user space... */
 	struct iw_priv_args *	private_args;
 
+	/* Driver enhanced spy support */
+	long			spy_offset;	/* Spy data offset */
+
 	/* In the long term, get_wireless_stats will move from
 	 * 'struct net_device' to here, to minimise bloat. */
 };
@@ -350,6 +361,33 @@
 
 /* Need to think of short header translation table. Later. */
 
+/* --------------------- ENHANCED SPY SUPPORT --------------------- */
+/*
+ * In the old days, the driver was handling spy support all by itself.
+ * Now, the driver can delegate this task to Wireless Extensions.
+ * It needs to include this struct in its private part and use the
+ * standard spy iw_handler.
+ */
+
+/*
+ * Instance specific spy data, i.e. addresses spied and quality for them.
+ */
+struct iw_spy_data
+{
+#ifdef IW_WIRELESS_SPY
+	/* --- Standard spy support --- */
+	int			spy_number;
+	u_char			spy_address[IW_MAX_SPY][ETH_ALEN];
+	struct iw_quality	spy_stat[IW_MAX_SPY];
+#ifdef IW_WIRELESS_THRSPY
+	/* --- Enhanced spy support (event) */
+	struct iw_quality	spy_thr_low;	/* Low threshold */
+	struct iw_quality	spy_thr_high;	/* High threshold */
+	u_char			spy_thr_under[IW_MAX_SPY];
+#endif /* IW_WIRELESS_THRSPY */
+#endif /* IW_WIRELESS_SPY */
+};
+
 /**************************** PROTOTYPES ****************************/
 /*
  * Functions part of the Wireless Extensions (defined in net/core/wireless.c).
@@ -375,6 +413,31 @@
 
 /* We may need a function to send a stream of events to user space.
  * More on that later... */
+
+/* Standard handler for SIOCSIWSPY */
+extern int iw_handler_set_spy(struct net_device *	dev,
+			      struct iw_request_info *	info,
+			      union iwreq_data *	wrqu,
+			      char *			extra);
+/* Standard handler for SIOCGIWSPY */
+extern int iw_handler_get_spy(struct net_device *	dev,
+			      struct iw_request_info *	info,
+			      union iwreq_data *	wrqu,
+			      char *			extra);
+/* Standard handler for SIOCSIWTHRSPY */
+extern int iw_handler_set_thrspy(struct net_device *	dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *	wrqu,
+				 char *			extra);
+/* Standard handler for SIOCGIWTHRSPY */
+extern int iw_handler_get_thrspy(struct net_device *	dev,
+				 struct iw_request_info *info,
+				 union iwreq_data *	wrqu,
+				 char *			extra);
+/* Driver call to update spy records */
+extern void wireless_spy_update(struct net_device *	dev,
+				unsigned char *		address,
+				struct iw_quality *	wstats);
 
 /************************* INLINE FUNTIONS *************************/
 /*
diff -Nru a/include/net/protocol.h b/include/net/protocol.h
--- a/include/net/protocol.h	Mon Apr 14 11:25:51 2003
+++ b/include/net/protocol.h	Sat May 10 05:25:34 2003
@@ -80,11 +80,9 @@
 
 extern struct inet_protocol *inet_protocol_base;
 extern struct inet_protocol *inet_protos[MAX_INET_PROTOS];
-extern struct list_head inetsw[SOCK_MAX];
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 extern struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
-extern struct list_head inetsw6[SOCK_MAX];
 #endif
 
 extern int	inet_add_protocol(struct inet_protocol *prot, unsigned char num);
diff -Nru a/include/net/sctp/command.h b/include/net/sctp/command.h
--- a/include/net/sctp/command.h	Tue Mar  4 07:13:48 2003
+++ b/include/net/sctp/command.h	Wed Apr  9 12:24:28 2003
@@ -182,7 +182,7 @@
 /* Create a new sctp_command_sequence.
  * Return NULL if creating a new sequence fails.
  */
-sctp_cmd_seq_t *sctp_new_cmd_seq(int priority);
+sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp);
 
 /* Initialize a block of memory as a command sequence.
  * Return 0 if the initialization fails.
diff -Nru a/include/net/sctp/constants.h b/include/net/sctp/constants.h
--- a/include/net/sctp/constants.h	Tue Mar 25 08:00:39 2003
+++ b/include/net/sctp/constants.h	Fri Apr 18 10:08:58 2003
@@ -6,46 +6,42 @@
  *
  * This file is part of the SCTP kernel reference Implementation
  *
- * This file is part of the implementation of the add-IP extension,
- * based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001,
- * for the SCTP kernel reference Implementation.
- *
- * The SCTP reference implementation  is free software;
+ * The SCTP reference implementation 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.
  *
- * the SCTP reference implementation  is distributed in the hope that it
- * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * The SCTP reference implementation is distributed in the hope that it
+ * will be useful, but WITHOUT ANY WARRANTY; without even the implied
  *                 ************************
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * 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 GNU CC; see the file COPYING.  If not, write to
  * the Free Software Foundation, 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  *
- * Please send any bug reports or fixes you make to one of the following email
- * addresses:
- *
- * La Monte H.P. Yarroll <piggy@acm.org>
- * Karl Knutson <karl@athena.chicago.il.us>
- * Randall Stewart <randall@stewart.chicago.il.us>
- * Ken Morneau <kmorneau@cisco.com>
- * Qiaobing Xie <qxie1@motorola.com>
- * Xingang Guo <xingang.guo@intel.com>
- * Sridhar Samudrala <samudrala@us.ibm.com>
- * Daisy Chang <daisyc@us.ibm.com>
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ *    http://www.sf.net/projects/lksctp
+ *
+ * Written or modified by:
+ *   La Monte H.P. Yarroll <piggy@acm.org>
+ *   Karl Knutson          <karl@athena.chicago.il.us>
+ *   Randall Stewart       <randall@stewart.chicago.il.us>
+ *   Ken Morneau           <kmorneau@cisco.com>
+ *   Qiaobing Xie          <qxie1@motorola.com>
+ *   Xingang Guo           <xingang.guo@intel.com>
+ *   Sridhar Samudrala     <samudrala@us.ibm.com>
+ *   Daisy Chang           <daisyc@us.ibm.com>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
- *
- * There are still LOTS of bugs in this code... I always run on the motto
- * "it is a wonder any code ever works :)"
- *
- *
  */
 
 #ifndef __sctp_constants_h__
@@ -220,7 +216,7 @@
  * - A socket in SCTP_SS_LISTENING state indicates that it is willing to
  *   accept new associations, but cannot initiate the creation of new ones.
  * - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single 
- *   association in ESTABLISHED state.
+ *   association.
  */
 typedef enum {
 	SCTP_SS_CLOSED         = TCP_CLOSE,
@@ -336,9 +332,17 @@
 
 #define SCTP_SIGNATURE_SIZE 20	        /* size of a SLA-1 signature */
 
-#define SCTP_COOKIE_MULTIPLE 64 /* Pad out our cookie to make our hash
+#define SCTP_COOKIE_MULTIPLE 32 /* Pad out our cookie to make our hash
 				 * functions simpler to write.
 				 */
+
+#if defined (CONFIG_SCTP_HMAC_MD5)
+#define SCTP_COOKIE_HMAC_ALG "md5"
+#elif defined (CONFIG_SCTP_HMAC_SHA1)
+#define SCTP_COOKIE_HMAC_ALG "sha1"
+#else
+#define SCTP_COOKIE_HMAC_ALG NULL
+#endif
 
 /* These return values describe the success or failure of a number of
  * routines which form the lower interface to SCTP_outqueue.
diff -Nru a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
--- a/include/net/sctp/sctp.h	Fri Apr  4 16:56:28 2003
+++ b/include/net/sctp/sctp.h	Wed Apr 23 08:47:03 2003
@@ -125,65 +125,61 @@
 extern struct sock *sctp_get_ctl_sock(void);
 extern int sctp_copy_local_addr_list(struct sctp_protocol  *,
 				     struct sctp_bind_addr *,
-				     sctp_scope_t, int priority, int flags);
+				     sctp_scope_t, int gfp, int flags);
 extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
 extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
 
 /*
  * sctp/socket.c
  */
-extern int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
-extern int sctp_inet_listen(struct socket *sock, int backlog);
-extern void sctp_write_space(struct sock *sk);
-extern unsigned int sctp_poll(struct file *file, struct socket *sock,
+int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb);
+int sctp_inet_listen(struct socket *sock, int backlog);
+void sctp_write_space(struct sock *sk);
+unsigned int sctp_poll(struct file *file, struct socket *sock,
 		poll_table *wait);
 
 /*
  * sctp/primitive.c
  */
-extern int sctp_primitive_ASSOCIATE(sctp_association_t *, void *arg);
-extern int sctp_primitive_SHUTDOWN(sctp_association_t *, void *arg);
-extern int sctp_primitive_ABORT(sctp_association_t *, void *arg);
-extern int sctp_primitive_SEND(sctp_association_t *, void *arg);
-extern int sctp_primitive_REQUESTHEARTBEAT(sctp_association_t *, void *arg);
+int sctp_primitive_ASSOCIATE(struct sctp_association *, void *arg);
+int sctp_primitive_SHUTDOWN(struct sctp_association *, void *arg);
+int sctp_primitive_ABORT(struct sctp_association *, void *arg);
+int sctp_primitive_SEND(struct sctp_association *, void *arg);
+int sctp_primitive_REQUESTHEARTBEAT(struct sctp_association *, void *arg);
 
 /*
  * sctp/crc32c.c
  */
-extern __u32 sctp_start_cksum(__u8 *ptr, __u16 count);
-extern __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum);
-extern __u32 sctp_end_cksum(__u32 cksum);
+__u32 sctp_start_cksum(__u8 *ptr, __u16 count);
+__u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 cksum);
+__u32 sctp_end_cksum(__u32 cksum);
+__u32 sctp_update_copy_cksum(__u8 *, __u8 *, __u16 count, __u32 cksum);
 
 /*
  * sctp/input.c
  */
-extern int sctp_rcv(struct sk_buff *skb);
-extern void sctp_v4_err(struct sk_buff *skb, u32 info);
-extern void sctp_hash_established(sctp_association_t *);
-extern void __sctp_hash_established(sctp_association_t *);
-extern void sctp_unhash_established(sctp_association_t *);
-extern void __sctp_unhash_established(sctp_association_t *);
-extern void sctp_hash_endpoint(sctp_endpoint_t *);
-extern void __sctp_hash_endpoint(sctp_endpoint_t *);
-extern void sctp_unhash_endpoint(sctp_endpoint_t *);
-extern void __sctp_unhash_endpoint(sctp_endpoint_t *);
-extern sctp_association_t *__sctp_lookup_association(const union sctp_addr *,
-						     const union sctp_addr *,
-						     struct sctp_transport **);
-extern struct sock *sctp_err_lookup(int family, struct sk_buff *,
-				    struct sctphdr *, struct sctp_endpoint **, 
-				    struct sctp_association **, 
-				    struct sctp_transport **);
-extern void sctp_err_finish(struct sock *, struct sctp_endpoint *, 
+int sctp_rcv(struct sk_buff *skb);
+void sctp_v4_err(struct sk_buff *skb, u32 info);
+void sctp_hash_established(struct sctp_association *);
+void __sctp_hash_established(struct sctp_association *);
+void sctp_unhash_established(struct sctp_association *);
+void __sctp_unhash_established(struct sctp_association *);
+void sctp_hash_endpoint(struct sctp_endpoint *);
+void __sctp_hash_endpoint(struct sctp_endpoint *);
+void sctp_unhash_endpoint(struct sctp_endpoint *);
+void __sctp_unhash_endpoint(struct sctp_endpoint *);
+struct sctp_association *__sctp_lookup_association(
+	const union sctp_addr *,
+	const union sctp_addr *,
+	struct sctp_transport **);
+struct sock *sctp_err_lookup(int family, struct sk_buff *,
+			     struct sctphdr *, struct sctp_endpoint **,
+			     struct sctp_association **,
+			     struct sctp_transport **);
+void sctp_err_finish(struct sock *, struct sctp_endpoint *,
 			    struct sctp_association *);
-extern void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
-				  struct sctp_transport *t, __u32 pmtu);
-/*
- * sctp/hashdriver.c
- */
-extern void sctp_hash_digest(const char *secret, const int secret_len,
-			     const char *text, const int text_len,
-			     __u8 *digest);
+void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
+			   struct sctp_transport *t, __u32 pmtu);
 
 /*
  *  Section:  Macros, externs, and inlines
@@ -281,6 +277,7 @@
 extern atomic_t sctp_dbg_objcnt_bind_addr;
 extern atomic_t sctp_dbg_objcnt_addr;
 extern atomic_t sctp_dbg_objcnt_ssnmap;
+extern atomic_t sctp_dbg_objcnt_datamsg;
 
 /* Macros to atomically increment/decrement objcnt counters.  */
 #define SCTP_DBG_OBJCNT_INC(name) \
@@ -296,8 +293,8 @@
 #define SCTP_DBG_OBJCNT_ENTRY(name) \
 {.label= #name, .counter= &sctp_dbg_objcnt_## name}
 
-extern void sctp_dbg_objcnt_init(void);
-extern void sctp_dbg_objcnt_exit(void);
+void sctp_dbg_objcnt_init(void);
+void sctp_dbg_objcnt_exit(void);
 
 #else
 
@@ -310,8 +307,8 @@
 #endif /* CONFIG_SCTP_DBG_OBJCOUNT */
 
 #if defined CONFIG_SYSCTL
-extern void sctp_sysctl_register(void);
-extern void sctp_sysctl_unregister(void);
+void sctp_sysctl_register(void);
+void sctp_sysctl_unregister(void);
 #else
 static inline void sctp_sysctl_register(void) { return; }
 static inline void sctp_sysctl_unregister(void) { return; }
@@ -322,9 +319,9 @@
 
 #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
 
-extern int sctp_v6_init(void);
-extern void sctp_v6_exit(void);
-extern void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+int sctp_v6_init(void);
+void sctp_v6_exit(void);
+void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 			int type, int code, int offset, __u32 info);
 
 #else /* #ifdef defined(CONFIG_IPV6) */
@@ -334,15 +331,26 @@
 
 #endif /* #if defined(CONFIG_IPV6) */
 
+/* Some wrappers, in case crypto not available. */
+#if defined (CONFIG_CRYPTO_HMAC)
+#define sctp_crypto_alloc_tfm crypto_alloc_tfm
+#define sctp_crypto_free_tfm crypto_free_tfm
+#define sctp_crypto_hmac crypto_hmac
+#else
+#define sctp_crypto_alloc_tfm(x...) NULL
+#define sctp_crypto_free_tfm(x...)
+#define sctp_crypto_hmac(x...)
+#endif
+
+
 /* Map an association to an assoc_id. */
-static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc)
+static inline sctp_assoc_t sctp_assoc2id(const struct sctp_association *asoc)
 {
 	return (sctp_assoc_t) asoc;
 }
 
-
 /* Look up the association by its id.  */
-sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id);
+struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id);
 
 
 /* A macro to walk a list of skbs.  */
@@ -422,12 +430,16 @@
 }
 
 /* Break down data chunks at this point.  */
-static inline int sctp_frag_point(int pmtu)
+static inline int sctp_frag_point(const struct sctp_opt *sp, int pmtu)
 {
-	pmtu -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
-	pmtu -= sizeof(struct sctp_sack_chunk);
+	int frag = pmtu;
+	frag -= SCTP_IP_OVERHEAD + sizeof(struct sctp_data_chunk);
+	frag -= sizeof(struct sctp_sack_chunk);
 
-	return pmtu;
+	if (sp->user_frag)
+		frag = min_t(int, frag, sp->user_frag);
+
+	return frag;
 }
 
 /* Walk through a list of TLV parameters.  Don't trust the
@@ -475,7 +487,7 @@
 
 extern struct proto sctp_prot;
 extern struct proc_dir_entry *proc_net_sctp;
-extern void sctp_put_port(struct sock *sk);
+void sctp_put_port(struct sock *sk);
 
 /* Static inline functions. */
 
@@ -501,10 +513,10 @@
 /* Perform some sanity checks. */
 static inline int sctp_sanity_check(void)
 {
-	SCTP_ASSERT(sizeof(struct sctp_ulpevent) <= 
+	SCTP_ASSERT(sizeof(struct sctp_ulpevent) <=
 		    sizeof(((struct sk_buff *)0)->cb),
 		    "SCTP: ulpevent does not fit in skb!\n", return 0);
-	
+
 	return 1;
 }
 
@@ -565,5 +577,27 @@
 #endif /* CONFIG_IPV6 */
 
 #define sctp_sk(__sk) (&((struct sctp_sock *)__sk)->sctp)
+
+/* Is a socket of this style? */
+#define sctp_style(sk, style) __sctp_style((sk), (SCTP_SOCKET_##style))
+int static inline __sctp_style(const struct sock *sk, sctp_socket_type_t style)
+{
+	return sctp_sk(sk)->type == style;
+}
+
+/* Is the association in this state? */
+#define sctp_state(asoc, state) __sctp_state((asoc), (SCTP_STATE_##state))
+int static inline __sctp_state(const struct sctp_association *asoc, 
+			       sctp_state_t state)
+{
+	return asoc->state == state;
+}
+
+/* Is the socket in this state? */
+#define sctp_sstate(sk, state) __sctp_sstate((sk), (SCTP_SS_##state))
+int static inline __sctp_sstate(const struct sock *sk, sctp_sock_state_t state)
+{
+	return sk->state == state;
+}
 
 #endif /* __net_sctp_h__ */
diff -Nru a/include/net/sctp/sm.h b/include/net/sctp/sm.h
--- a/include/net/sctp/sm.h	Fri Mar 28 12:49:33 2003
+++ b/include/net/sctp/sm.h	Mon Apr 21 10:26:19 2003
@@ -6,10 +6,6 @@
  *
  * This file is part of the SCTP kernel reference Implementation
  *
- * This file is part of the implementation of the add-IP extension,
- * based on <draft-ietf-tsvwg-addip-sctp-02.txt> June 29, 2001,
- * for the SCTP kernel reference Implementation.
- *
  * These are definitions needed by the state machine.
  *
  * The SCTP reference implementation is free software;
@@ -50,7 +46,6 @@
  * be incorporated into the next SCTP release.
  */
 
-
 #include <linux/types.h>
 #include <linux/compiler.h>
 #include <linux/slab.h>
@@ -81,8 +76,8 @@
 	int action;
 } sctp_sm_command_t;
 
-typedef sctp_disposition_t (sctp_state_fn_t) (const sctp_endpoint_t *,
-					      const sctp_association_t *,
+typedef sctp_disposition_t (sctp_state_fn_t) (const struct sctp_endpoint *,
+					      const struct sctp_association *,
 					      const sctp_subtype_t type,
 					      void *arg,
 					      sctp_cmd_seq_t *);
@@ -209,109 +204,104 @@
 void sctp_populate_tie_tags(__u8 *cookie, __u32 curTag, __u32 hisTag);
 
 /* Prototypes for chunk-building functions.  */
-sctp_chunk_t *sctp_make_init(const sctp_association_t *,
-			     const sctp_bind_addr_t *,
-			     int priority, int vparam_len);
-sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *,
-				 const sctp_chunk_t *,
-				 const int priority,
+struct sctp_chunk *sctp_make_init(const struct sctp_association *,
+			     const struct sctp_bind_addr *,
+			     int gfp, int vparam_len);
+struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *,
+				 const struct sctp_chunk *,
+				 const int gfp,
 				 const int unkparam_len);
-sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *,
-				    const sctp_chunk_t *);
-sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *,
-				   const sctp_chunk_t *);
-sctp_chunk_t *sctp_make_cwr(const sctp_association_t *,
+struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *,
+				    const struct sctp_chunk *);
+struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *,
+				   const struct sctp_chunk *);
+struct sctp_chunk *sctp_make_cwr(const struct sctp_association *,
 				 const __u32 lowest_tsn,
-				 const sctp_chunk_t *);
-sctp_chunk_t *sctp_make_datafrag(sctp_association_t *,
+				 const struct sctp_chunk *);
+struct sctp_chunk *sctp_make_datafrag(struct sctp_association *,
 				 const struct sctp_sndrcvinfo *sinfo,
 				 int len, const __u8 *data,
 				 __u8 flags, __u16 ssn);
-sctp_chunk_t * sctp_make_datafrag_empty(sctp_association_t *,
+struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *,
 					const struct sctp_sndrcvinfo *sinfo,
 					int len, const __u8 flags,
 					__u16 ssn);
-sctp_chunk_t *sctp_make_data(sctp_association_t *,
+struct sctp_chunk *sctp_make_data(struct sctp_association *,
 			     const struct sctp_sndrcvinfo *sinfo,
 			     int len, const __u8 *data);
-sctp_chunk_t *sctp_make_data_empty(sctp_association_t *,
+struct sctp_chunk *sctp_make_data_empty(struct sctp_association *,
 				   const struct sctp_sndrcvinfo *, int len);
-sctp_chunk_t *sctp_make_ecne(const sctp_association_t *,
+struct sctp_chunk *sctp_make_ecne(const struct sctp_association *,
 				  const __u32);
-sctp_chunk_t *sctp_make_sack(const sctp_association_t *);
-sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc);
-sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc,
-					  const sctp_chunk_t *);
-sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *,
-					  const sctp_chunk_t *);
-void sctp_init_cause(sctp_chunk_t *, __u16 cause, const void *, size_t);
-sctp_chunk_t *sctp_make_abort(const sctp_association_t *,
-			      const sctp_chunk_t *,
+struct sctp_chunk *sctp_make_sack(const struct sctp_association *);
+struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc);
+struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
+					  const struct sctp_chunk *);
+struct sctp_chunk *sctp_make_shutdown_complete(const struct sctp_association *,
+					  const struct sctp_chunk *);
+void sctp_init_cause(struct sctp_chunk *, __u16 cause, const void *, size_t);
+struct sctp_chunk *sctp_make_abort(const struct sctp_association *,
+			      const struct sctp_chunk *,
 			      const size_t hint);
-sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *,
-				      const sctp_chunk_t *,
+struct sctp_chunk *sctp_make_abort_no_data(const struct sctp_association *,
+				      const struct sctp_chunk *,
 				      __u32 tsn);
-sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *,
-				   const sctp_chunk_t *,
+struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *,
+				   const struct sctp_chunk *,
 				   const struct msghdr *);
-sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *,
+struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *,
 				  const struct sctp_transport *,
 				  const void *payload,
 				  const size_t paylen);
-sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *,
-				      const sctp_chunk_t *,
+struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *,
+				      const struct sctp_chunk *,
 				      const void *payload,
 				      const size_t paylen);
-sctp_chunk_t *sctp_make_op_error(const sctp_association_t *,
-				 const sctp_chunk_t *chunk,
+struct sctp_chunk *sctp_make_op_error(const struct sctp_association *,
+				 const struct sctp_chunk *chunk,
 				 __u16 cause_code,
 				 const void *payload,
 				 size_t paylen);
-void sctp_chunk_assign_tsn(sctp_chunk_t *);
-void sctp_chunk_assign_ssn(sctp_chunk_t *);
-int sctp_datachunks_from_user(sctp_association_t *,
-			      const struct sctp_sndrcvinfo *,
-			      struct msghdr *, int len,
-			      struct sk_buff_head *);
-
+void sctp_chunk_assign_tsn(struct sctp_chunk *);
+void sctp_chunk_assign_ssn(struct sctp_chunk *);
 
 /* Prototypes for statetable processing. */
 
 int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
 	       sctp_state_t state,
-               sctp_endpoint_t *,
-               sctp_association_t *asoc,
+               struct sctp_endpoint *,
+               struct sctp_association *asoc,
                void *event_arg,
-               int priority);
+               int gfp);
 
 int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
 		      sctp_state_t state,
-                      sctp_endpoint_t *,
-                      sctp_association_t *asoc,
+                      struct sctp_endpoint *,
+                      struct sctp_association *asoc,
                       void *event_arg,
                       sctp_disposition_t status,
 		      sctp_cmd_seq_t *commands,
-                      int priority);
+                      int gfp);
 
 /* 2nd level prototypes */
 int
 sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
 		     sctp_state_t state,
-		     sctp_endpoint_t *ep,
-		     sctp_association_t *asoc,
+		     struct sctp_endpoint *ep,
+		     struct sctp_association *asoc,
 		     void *event_arg,
 		     sctp_disposition_t status,
 		     sctp_cmd_seq_t *retval,
-		     int priority);
+		     int gfp);
 
 
-int sctp_gen_sack(sctp_association_t *, int force, sctp_cmd_seq_t *);
-void sctp_do_TSNdup(sctp_association_t *, sctp_chunk_t *, long gap);
+int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *);
+void sctp_do_TSNdup(struct sctp_association *, struct sctp_chunk *, long gap);
 
 void sctp_generate_t3_rtx_event(unsigned long peer);
 void sctp_generate_heartbeat_event(unsigned long peer);
 
-sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *);
+sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *);
 struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *,
 				       const struct sctp_association *,
 				       struct sctp_chunk *chunk,
@@ -325,21 +315,21 @@
 sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *,
 		 const struct sctp_chunk *, int *cookie_len,
 		 const __u8 *, int addrs_len);
-sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *,
-				       const sctp_association_t *,
-				       sctp_chunk_t *, int priority, int *err,
-				       sctp_chunk_t **err_chk_p);
-int sctp_addip_addr_config(sctp_association_t *, sctp_param_t,
+struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *,
+				       const struct sctp_association *,
+				       struct sctp_chunk *, int gfp, int *err,
+				       struct sctp_chunk **err_chk_p);
+int sctp_addip_addr_config(struct sctp_association *, sctp_param_t,
 			   struct sockaddr_storage*, int);
-void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
-				const sctp_association_t *asoc,
-				const sctp_chunk_t *chunk,
+void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+				const struct sctp_association *asoc,
+				const struct sctp_chunk *chunk,
 				sctp_cmd_seq_t *commands,
-				sctp_chunk_t *err_chunk);
+				struct sctp_chunk *err_chunk);
 
 /* 3rd level prototypes */
-__u32 sctp_generate_tag(const sctp_endpoint_t *);
-__u32 sctp_generate_tsn(const sctp_endpoint_t *);
+__u32 sctp_generate_tag(const struct sctp_endpoint *);
+__u32 sctp_generate_tsn(const struct sctp_endpoint *);
 
 /* 4th level prototypes */
 void sctp_param2sockaddr(union sctp_addr *addr, sctp_addr_param_t *,
@@ -361,7 +351,7 @@
 
 
 /* Get the size of a DATA chunk payload. */
-static inline __u16 sctp_data_size(sctp_chunk_t *chunk)
+static inline __u16 sctp_data_size(struct sctp_chunk *chunk)
 {
 	__u16 size;
 
@@ -449,8 +439,8 @@
  * tag and the T bit is set in the Chunk Flags.
  */
 static inline int
-sctp_vtag_verify_either(const sctp_chunk_t *chunk,
-			const sctp_association_t *asoc)
+sctp_vtag_verify_either(const struct sctp_chunk *chunk,
+			const struct sctp_association *asoc)
 {
         /* RFC 2960 Section 8.5.1, sctpimpguide-06 Section 2.13.2
 	 *
diff -Nru a/include/net/sctp/structs.h b/include/net/sctp/structs.h
--- a/include/net/sctp/structs.h	Fri Mar 28 12:49:33 2003
+++ b/include/net/sctp/structs.h	Mon May  5 15:42:16 2003
@@ -70,7 +70,6 @@
 	struct sockaddr sa;
 };
 
-
 /* Forward declarations for data structures. */
 struct sctp_protocol;
 struct sctp_endpoint;
@@ -83,14 +82,9 @@
 struct sctp_bind_addr;
 struct sctp_ulpq;
 struct sctp_opt;
-struct sctp_endpoint_common;
+struct sctp_ep_common;
 struct sctp_ssnmap;
 
-typedef struct sctp_endpoint sctp_endpoint_t;
-typedef struct sctp_association sctp_association_t;
-typedef struct sctp_chunk sctp_chunk_t;
-typedef struct sctp_bind_addr sctp_bind_addr_t;
-typedef struct sctp_endpoint_common sctp_endpoint_common_t;
 
 #include <net/sctp/tsnmap.h>
 #include <net/sctp/ulpevent.h>
@@ -114,7 +108,7 @@
 /* Used for hashing all associations.  */
 typedef struct sctp_hashbucket {
 	rwlock_t	lock;
-	sctp_endpoint_common_t  *chain;
+	struct sctp_ep_common  *chain;
 } sctp_hashbucket_t __attribute__((__aligned__(8)));
 
 
@@ -235,7 +229,9 @@
 					 int saddr);
 	void            (*from_sk)      (union sctp_addr *,
 					 struct sock *sk);
-	void            (*to_sk)        (union sctp_addr *,
+	void            (*to_sk_saddr)  (union sctp_addr *,
+					 struct sock *sk);
+	void            (*to_sk_daddr)  (union sctp_addr *,
 					 struct sock *sk);
 	int             (*addr_valid)   (union sctp_addr *);
 	sctp_scope_t    (*scope) (union sctp_addr *);
@@ -243,6 +239,7 @@
 	int             (*is_any)       (const union sctp_addr *);
 	int             (*available)    (const union sctp_addr *);
 	int             (*skb_iif)      (const struct sk_buff *sk);
+	int             (*is_ce)        (const struct sk_buff *sk); 
 	__u16		net_header_len;
 	int		sockaddr_len;
 	sa_family_t	sa_family;
@@ -283,8 +280,11 @@
 	/* PF_ family specific functions.  */
 	struct sctp_pf *pf;
 
+	/* Access to HMAC transform. */
+	struct crypto_tfm *hmac;
+
 	/* What is our base endpointer? */
-	sctp_endpoint_t *ep;
+	struct sctp_endpoint *ep;
 
 	/* Various Socket Options.  */
 	__u16 default_stream;
@@ -293,10 +293,12 @@
 	struct sctp_rtoinfo rtoinfo;
 	struct sctp_paddrparams paddrparam;
 	struct sctp_event_subscribe subscribe;
+	int user_frag;
 	__u32 autoclose;
 	__u8 nodelay;
 	__u8 disable_fragments;
 	__u8 pd_mode;
+	__u8 v4mapped;
 
 	/* Receive to here while partial delivery is in effect. */
 	struct sk_buff_head pd_lobby;
@@ -448,6 +450,37 @@
 	return stream->ssn[id]++;
 }
 
+/* Structure to track chunk fragments that have been acked, but peer
+ * fragments of the same message have not.
+ */
+struct sctp_datamsg {
+	/* Chunks waiting to be submitted to lower layer. */
+	struct list_head chunks;
+	/* Chunks that have been transmitted. */
+	struct list_head track;
+	/* Reference counting. */
+	atomic_t refcnt;
+	/* When is this message no longer interesting to the peer? */
+	unsigned long expires_at; 
+	/* Did the messenge fail to send? */
+	int send_error;
+	char send_failed;
+	/* Control whether fragments from this message can expire. */
+	char can_expire;
+};
+
+struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
+					    struct sctp_sndrcvinfo *,
+					    struct msghdr *, int len);
+struct sctp_datamsg *sctp_datamsg_new(int gfp);
+void sctp_datamsg_put(struct sctp_datamsg *);
+void sctp_datamsg_hold(struct sctp_datamsg *);
+void sctp_datamsg_free(struct sctp_datamsg *);
+void sctp_datamsg_track(struct sctp_chunk *);
+void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *);
+void sctp_datamsg_fail(struct sctp_chunk *, int error);
+int sctp_datamsg_expires(struct sctp_chunk *);
+
 
 /* RFC2960 1.4 Key Terms
  *
@@ -462,9 +495,10 @@
 	 * three elements of struct sk_buff.  This allows us to reuse
 	 * all the skb_* queue management functions.
 	 */
-	sctp_chunk_t *next;
-	sctp_chunk_t *prev;
+	struct sctp_chunk *next;
+	struct sctp_chunk *prev;
 	struct sk_buff_head *list;
+	atomic_t refcnt;
 
 	/* This is our link to the per-transport transmitted list.  */
 	struct list_head transmitted_list;
@@ -514,43 +548,52 @@
 	struct sctp_association *asoc;
 
 	/* What endpoint received this chunk? */
-	sctp_endpoint_common_t *rcvr;
+	struct sctp_ep_common *rcvr;
 
 	/* We fill this in if we are calculating RTT. */
 	unsigned long sent_at;
 
-	__u8 rtt_in_progress;  /* Is this chunk used for RTT calculation? */
-	__u8 num_times_sent;   /* How man times did we send this? */
-	__u8 has_tsn;          /* Does this chunk have a TSN yet? */
-	__u8 has_ssn;          /* Does this chunk have a SSN yet? */
-	__u8 singleton;        /* Was this the only chunk in the packet? */
-	__u8 end_of_packet;    /* Was this the last chunk in the packet? */
-	__u8 ecn_ce_done;      /* Have we processed the ECN CE bit? */
-	__u8 pdiscard;	  /* Discard the whole packet now? */
-	__u8 tsn_gap_acked;	  /* Is this chunk acked by a GAP ACK? */
-	__u8 fast_retransmit;    /* Is this chunk fast retransmitted? */
-	__u8 tsn_missing_report; /* Data chunk missing counter. */
-
 	/* What is the origin IP address for this chunk?  */
 	union sctp_addr source;
 	/* Destination address for this chunk. */
 	union sctp_addr dest;
 
+	/* For outbound message, track all fragments for SEND_FAILED. */
+	struct sctp_datamsg *msg;
+
 	/* For an inbound chunk, this tells us where it came from.
 	 * For an outbound chunk, it tells us where we'd like it to
 	 * go.  It is NULL if we have no preference.
 	 */
 	struct sctp_transport *transport;
+
+	__u8 rtt_in_progress;	/* Is this chunk used for RTT calculation? */
+	__u8 resent;		/* Has this chunk ever been retransmitted. */
+	__u8 has_tsn;		/* Does this chunk have a TSN yet? */
+	__u8 has_ssn;		/* Does this chunk have a SSN yet? */
+	__u8 singleton;		/* Was this the only chunk in the packet? */
+	__u8 end_of_packet;	/* Was this the last chunk in the packet? */
+	__u8 ecn_ce_done;	/* Have we processed the ECN CE bit? */
+	__u8 pdiscard;		/* Discard the whole packet now? */
+	__u8 tsn_gap_acked;	/* Is this chunk acked by a GAP ACK? */
+	__u8 fast_retransmit;	 /* Is this chunk fast retransmitted? */
+	__u8 tsn_missing_report; /* Data chunk missing counter. */
 };
 
-sctp_chunk_t *sctp_make_chunk(const struct sctp_association *, __u8 type,
-			      __u8 flags, int size);
-void sctp_free_chunk(sctp_chunk_t *);
-void  *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data);
-sctp_chunk_t *sctp_chunkify(struct sk_buff *, const struct sctp_association *,
-			    struct sock *);
-void sctp_init_addrs(sctp_chunk_t *, union sctp_addr *, union sctp_addr *);
-const union sctp_addr *sctp_source(const sctp_chunk_t *chunk);
+void sctp_chunk_hold(struct sctp_chunk *);
+void sctp_chunk_put(struct sctp_chunk *);
+int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
+			  struct iovec *data);
+struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type,
+				   __u8 flags, int size);
+void sctp_chunk_free(struct sctp_chunk *);
+void  *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
+struct sctp_chunk *sctp_chunkify(struct sk_buff *,
+				 const struct sctp_association *,
+				 struct sock *);
+void sctp_init_addrs(struct sctp_chunk *, union sctp_addr *,
+		     union sctp_addr *);
+const union sctp_addr *sctp_source(const struct sctp_chunk *chunk);
 
 /* This is a structure for holding either an IPv6 or an IPv4 address.  */
 /* sin_family -- AF_INET or AF_INET6
@@ -562,7 +605,7 @@
 	union sctp_addr a;
 };
 
-typedef sctp_chunk_t *(sctp_packet_phandler_t)(struct sctp_association *);
+typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *);
 
 /* This structure holds lists of chunks as we are assembling for
  * transmission.
@@ -619,7 +662,7 @@
 	 int ecn_capable,
 	 sctp_packet_phandler_t *get_prepend_chunk);
 typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *,
-                                               sctp_chunk_t *);
+                                               struct sctp_chunk *);
 typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *);
 
 sctp_outq_ohandler_init_t    sctp_packet_init;
@@ -697,7 +740,6 @@
          */
 	int rto_pending;
 
-
 	/*
 	 * These are the congestion stats.
 	 */
@@ -771,9 +813,6 @@
 	 */
 	int max_retrans;
 
-	/* We use this name for debugging output... */
-	char *debug_name;
-
 	/* Per         : A timer used by each destination.
 	 * Destination :
 	 * Timer       :
@@ -799,6 +838,35 @@
 	struct list_head send_ready;
 
 	int malloced; /* Is this structure kfree()able? */
+
+	/* State information saved for SFR_CACC algorithm. The key
+	 * idea in SFR_CACC is to maintain state at the sender on a
+	 * per-destination basis when a changeover happens.
+	 * 	char changeover_active;
+	 * 	char cycling_changeover;
+	 * 	__u32 next_tsn_at_change;
+	 * 	char cacc_saw_newack;
+	 */
+	struct {
+		/* An unsigned integer, which stores the next TSN to be
+		 * used by the sender, at the moment of changeover.
+		 */
+		__u32 next_tsn_at_change;
+
+		/* A flag which indicates the occurrence of a changeover */
+		char changeover_active;
+
+		/* A glag which indicates whether the change of primary is
+		 * the first switch to this destination address during an
+		 * active switch.
+		 */
+		char cycling_changeover;
+
+		/* A temporary flag, which is used during the processing of
+		 * a SACK to estimate the causative TSN(s)'s group.
+		 */
+		char cacc_saw_newack;
+	} cacc;
 };
 
 struct sctp_transport *sctp_transport_new(const union sctp_addr *, int);
@@ -831,7 +899,7 @@
 	/* This is the packet which is currently off the in queue and is
 	 * being worked on through the inbound chunk processing.
 	 */
-	sctp_chunk_t *in_progress;
+	struct sctp_chunk *in_progress;
 
 	/* This is the delayed task to finish delivering inbound
 	 * messages.
@@ -844,7 +912,7 @@
 struct sctp_inq *sctp_inq_new(void);
 void sctp_inq_init(struct sctp_inq *);
 void sctp_inq_free(struct sctp_inq *);
-void sctp_inq_push(struct sctp_inq *, sctp_chunk_t *packet);
+void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet);
 struct sctp_chunk *sctp_inq_pop(struct sctp_inq *);
 void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *);
 
@@ -904,18 +972,21 @@
 	/* How many unackd bytes do we have in-flight?  */
 	__u32 outstanding_bytes;
 
+	/* Corked? */
+	char cork;
+
 	/* Is this structure empty?  */
-	int empty;
+	char empty;
 
 	/* Are we kfree()able? */
-	int malloced;
+	char malloced;
 };
 
 struct sctp_outq *sctp_outq_new(struct sctp_association *);
 void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
 void sctp_outq_teardown(struct sctp_outq *);
 void sctp_outq_free(struct sctp_outq*);
-int sctp_outq_tail(struct sctp_outq *, sctp_chunk_t *chunk);
+int sctp_outq_tail(struct sctp_outq *, struct sctp_chunk *chunk);
 int sctp_outq_flush(struct sctp_outq *, int);
 int sctp_outq_sack(struct sctp_outq *, sctp_sackhdr_t *);
 int sctp_outq_is_empty(const struct sctp_outq *);
@@ -926,10 +997,16 @@
 				  sctp_outq_ohandler_t build,
 				  sctp_outq_ohandler_force_t force);
 void sctp_outq_restart(struct sctp_outq *);
+
 void sctp_retransmit(struct sctp_outq *, struct sctp_transport *,
 		     sctp_retransmit_reason_t);
 void sctp_retransmit_mark(struct sctp_outq *, struct sctp_transport *, __u8);
-
+int sctp_outq_uncork(struct sctp_outq *);
+/* Uncork and flush an outqueue.  */
+static inline void sctp_outq_cork(struct sctp_outq *q)
+{
+	q->cork = 1;
+}
 
 /* These bind address data fields common between endpoints and associations */
 struct sctp_bind_addr {
@@ -952,15 +1029,16 @@
 	int malloced;        /* Are we kfree()able?  */
 };
 
-sctp_bind_addr_t *sctp_bind_addr_new(int gfp_mask);
-void sctp_bind_addr_init(sctp_bind_addr_t *, __u16 port);
-void sctp_bind_addr_free(sctp_bind_addr_t *);
-int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
+struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask);
+void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
+void sctp_bind_addr_free(struct sctp_bind_addr *);
+int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
+			const struct sctp_bind_addr *src,
 			sctp_scope_t scope, int gfp,int flags);
-int sctp_add_bind_addr(sctp_bind_addr_t *, union sctp_addr *,
+int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *,
 		       int gfp);
-int sctp_del_bind_addr(sctp_bind_addr_t *, union sctp_addr *);
-int sctp_bind_addr_match(sctp_bind_addr_t *, const union sctp_addr *,
+int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *);
+int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *,
 			 struct sctp_opt *);
 union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
 					 int *addrs_len, int gfp);
@@ -973,7 +1051,7 @@
 int sctp_addr_is_valid(const union sctp_addr *addr);
 
 
-/* What type of sctp_endpoint_common?  */
+/* What type of endpoint?  */
 typedef enum {
 	SCTP_EP_TYPE_SOCKET,
 	SCTP_EP_TYPE_ASSOCIATION,
@@ -995,10 +1073,10 @@
  *
  */
 
-struct sctp_endpoint_common {
+struct sctp_ep_common {
 	/* Fields to help us manage our entries in the hash tables. */
-	sctp_endpoint_common_t *next;
-	sctp_endpoint_common_t **pprev;
+	struct sctp_ep_common *next;
+	struct sctp_ep_common **pprev;
 	int hashent;
 
 	/* Runtime type information.  What kind of endpoint is this? */
@@ -1024,7 +1102,7 @@
 	 * bind_addr.port is our shared port number.
 	 * bind_addr.address_list is our set of local IP addresses.
 	 */
-	sctp_bind_addr_t bind_addr;
+	struct sctp_bind_addr bind_addr;
 
 	/* Protection during address list comparisons. */
 	rwlock_t   addr_lock;
@@ -1052,12 +1130,7 @@
 
 struct sctp_endpoint {
 	/* Common substructure for endpoint and association. */
-	sctp_endpoint_common_t base;
-
-	/* These are the system-wide defaults and other stuff which is
-	 * endpoint-independent.
-	 */
-	struct sctp_protocol *proto;
+	struct sctp_ep_common base;
 
 	/* Associations: A list of current associations and mappings
 	 *            to the data consumers for each association. This
@@ -1092,28 +1165,29 @@
 };
 
 /* Recover the outter endpoint structure. */
-static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base)
+static inline struct sctp_endpoint *sctp_ep(struct sctp_ep_common *base)
 {
-	sctp_endpoint_t *ep;
+	struct sctp_endpoint *ep;
 
-	ep = container_of(base, sctp_endpoint_t, base);
+	ep = container_of(base, struct sctp_endpoint, base);
 	return ep;
 }
 
 /* These are function signatures for manipulating endpoints.  */
-sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *, struct sock *, int);
-sctp_endpoint_t *sctp_endpoint_init(struct sctp_endpoint *,
-				    struct sctp_protocol *,
-				    struct sock *, int gfp);
-void sctp_endpoint_free(sctp_endpoint_t *);
-void sctp_endpoint_put(sctp_endpoint_t *);
-void sctp_endpoint_hold(sctp_endpoint_t *);
-void sctp_endpoint_add_asoc(sctp_endpoint_t *, struct sctp_association *asoc);
-struct sctp_association *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep,
-					       const union sctp_addr *paddr,
-					       struct sctp_transport **);
-int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *);
-sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *,
+struct sctp_endpoint *sctp_endpoint_new(struct sock *, int);
+struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *,
+					 struct sock *, int gfp);
+void sctp_endpoint_free(struct sctp_endpoint *);
+void sctp_endpoint_put(struct sctp_endpoint *);
+void sctp_endpoint_hold(struct sctp_endpoint *);
+void sctp_endpoint_add_asoc(struct sctp_endpoint *, struct sctp_association *);
+struct sctp_association *sctp_endpoint_lookup_assoc(
+	const struct sctp_endpoint *ep,
+	const union sctp_addr *paddr,
+	struct sctp_transport **);
+int sctp_endpoint_is_peeled_off(struct sctp_endpoint *,
+				const union sctp_addr *);
+struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *,
 					const union sctp_addr *);
 int sctp_has_association(const union sctp_addr *laddr,
 			 const union sctp_addr *paddr);
@@ -1126,8 +1200,8 @@
 		      sctp_init_chunk_t *init, int gfp);
 int sctp_process_param(struct sctp_association *, union sctp_params param,
 		       const union sctp_addr *from, int gfp);
-__u32 sctp_generate_tag(const sctp_endpoint_t *);
-__u32 sctp_generate_tsn(const sctp_endpoint_t *);
+__u32 sctp_generate_tag(const struct sctp_endpoint *);
+__u32 sctp_generate_tsn(const struct sctp_endpoint *);
 
 
 /* RFC2960
@@ -1150,7 +1224,7 @@
 	 * In this context, it represents the associations's view
 	 * of the local endpoint of the association.
 	 */
-	sctp_endpoint_common_t base;
+	struct sctp_ep_common base;
 
 	/* Associations on the same socket. */
 	struct list_head asocs;
@@ -1162,7 +1236,7 @@
 	__u32 eyecatcher;
 
 	/* This is our parent endpoint.  */
-	sctp_endpoint_t *ep;
+	struct sctp_endpoint *ep;
 
 	/* These are those association elements needed in the cookie.  */
 	sctp_cookie_t c;
@@ -1337,7 +1411,6 @@
 	/* The largest timeout or RTO value to use in attempting an INIT */
 	__u16 max_init_timeo;
 
-
 	int timeouts[SCTP_NUM_TIMEOUT_TYPES];
 	struct timer_list timers[SCTP_NUM_TIMEOUT_TYPES];
 
@@ -1438,9 +1511,6 @@
 	 */
 	struct sctp_ulpq ulpq;
 
-	/* Need to send an ECNE Chunk? */
-	int need_ecne;
-
 	/* Last TSN that caused an ECNE Chunk to be sent.  */
 	__u32 last_ecne_tsn;
 
@@ -1453,9 +1523,6 @@
 	/* Number of seconds of idle time before an association is closed.  */
 	__u32 autoclose;
 
-	/* Name for debugging output... */
-	char *debug_name;
-
 	/* These are to support
 	 * "SCTP Extensions for Dynamic Reconfiguration of IP Addresses
 	 *  and Enforcement of Flow and Message Limits"
@@ -1463,8 +1530,7 @@
 	 * or "ADDIP" for short.
 	 */
 
-	/* Is the ADDIP extension enabled for this association? */
-	int addip_enable;
+
 
 	/* ADDIP Section 4.1.1 Congestion Control of ASCONF Chunks
 	 *
@@ -1480,7 +1546,7 @@
 	 * [This is our one-and-only-one ASCONF in flight.  If we do
 	 * not have an ASCONF in flight, this is NULL.]
 	 */
-	sctp_chunk_t *addip_last_asconf;
+	struct sctp_chunk *addip_last_asconf;
 
 	/* ADDIP Section 4.2 Upon reception of an ASCONF Chunk.
 	 *
@@ -1495,7 +1561,7 @@
 	 * [This is our saved ASCONF-ACK.  We invalidate it when a new
 	 * ASCONF serial number arrives.]
 	 */
-	sctp_chunk_t *addip_last_asconf_ack;
+	struct sctp_chunk *addip_last_asconf_ack;
 
 	/* These ASCONF chunks are waiting to be sent.
 	 *
@@ -1548,6 +1614,15 @@
 	 * after reaching 4294967295.
 	 */
 	__u32 addip_serial;
+
+	/* Is the ADDIP extension enabled for this association? */
+	char addip_enable;
+
+	/* Need to send an ECNE Chunk? */
+	char need_ecne;
+
+	/* Is it a temporary association? */
+	char temp;
 };
 
 
@@ -1559,7 +1634,7 @@
 };
 
 /* Recover the outter association structure. */
-static inline struct sctp_association *sctp_assoc(sctp_endpoint_common_t *base)
+static inline struct sctp_association *sctp_assoc(struct sctp_ep_common *base)
 {
 	struct sctp_association *asoc;
 
@@ -1571,10 +1646,10 @@
 
 
 struct sctp_association *
-sctp_association_new(const sctp_endpoint_t *, const struct sock *,
+sctp_association_new(const struct sctp_endpoint *, const struct sock *,
 		     sctp_scope_t scope, int gfp);
 struct sctp_association *
-sctp_association_init(struct sctp_association *, const sctp_endpoint_t *,
+sctp_association_init(struct sctp_association *, const struct sctp_endpoint *,
 		      const struct sock *, sctp_scope_t scope,
 		      int gfp);
 void sctp_association_free(struct sctp_association *);
@@ -1614,8 +1689,8 @@
 
 int sctp_cmp_addr_exact(const union sctp_addr *ss1,
 		        const union sctp_addr *ss2);
-sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc);
-sctp_chunk_t *sctp_get_no_prepend(struct sctp_association *asoc);
+struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc);
+struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc);
 
 /* A convenience structure to parse out SCTP specific CMSGs. */
 typedef struct sctp_cmsgs {
diff -Nru a/include/net/sctp/tsnmap.h b/include/net/sctp/tsnmap.h
--- a/include/net/sctp/tsnmap.h	Tue Feb 18 16:21:43 2003
+++ b/include/net/sctp/tsnmap.h	Wed Apr  9 12:24:28 2003
@@ -114,7 +114,7 @@
 };
 
 /* Create a new tsnmap.  */
-struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int priority);
+struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int gfp);
 
 /* Dispose of a tsnmap.  */
 void sctp_tsnmap_free(struct sctp_tsnmap *);
diff -Nru a/include/net/sctp/ulpevent.h b/include/net/sctp/ulpevent.h
--- a/include/net/sctp/ulpevent.h	Fri Mar 28 12:49:33 2003
+++ b/include/net/sctp/ulpevent.h	Wed Apr  9 15:36:41 2003
@@ -10,13 +10,15 @@
  * sctp_ulpevent type is used to carry information from the state machine
  * upwards to the ULP.
  *
- * The SCTP reference implementation  is free software;
+ * This file is part of the SCTP kernel reference Implementation
+ *
+ * The SCTP reference implementation 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.
  *
- * the SCTP reference implementation  is distributed in the hope that it
+ * The SCTP reference implementation 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.
@@ -27,12 +29,17 @@
  * the Free Software Foundation, 59 Temple Place - Suite 330,
  * Boston, MA 02111-1307, USA.
  *
- * Please send any bug reports or fixes you make to one of the
- * following email addresses:
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ *    http://www.sf.net/projects/lksctp
  *
- * Jon Grimm <jgrimm@us.ibm.com>
- * La Monte H.P. Yarroll <piggy@acm.org>
- * Karl Knutson <karl@athena.chicago.il.us>
+ * Written or modified by:
+ *   Jon Grimm             <jgrimm@us.ibm.com>
+ *   La Monte H.P. Yarroll <piggy@acm.org>
+ *   Karl Knutson          <karl@athena.chicago.il.us>
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -64,7 +71,7 @@
 	return (struct sctp_ulpevent *)skb->cb;
 }
 
-struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int priority);
+struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp);
 struct sctp_ulpevent *sctp_ulpevent_init(struct sctp_ulpevent *, int flags);
 void sctp_ulpevent_free(struct sctp_ulpevent *);
 int sctp_ulpevent_is_notification(const struct sctp_ulpevent *);
@@ -76,7 +83,7 @@
 	__u16 error,
 	__u16 outbound,
 	__u16 inbound,
-	int priority);
+	int gfp);
 
 struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
 	const struct sctp_association *asoc,
@@ -84,32 +91,32 @@
 	int flags,
 	int state,
 	int error,
-	int priority);
+	int gfp);
 
 struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
 	const struct sctp_association *asoc,
 	struct sctp_chunk *chunk,
 	__u16 flags,
-	int priority);
+	int gfp);
 struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
 	const struct sctp_association *asoc,
 	struct sctp_chunk *chunk,
 	__u16 flags,
 	__u32 error,
-	int priority);
+	int gfp);
 
 struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
 	const struct sctp_association *asoc,
 	__u16 flags,
-	int priority);
+	int gfp);
 
 struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
 	const struct sctp_association *asoc,
-	__u32 indication, int priority);
+	__u32 indication, int gfp);
 
 struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
 	struct sctp_chunk *chunk,
-	int priority);
+	int gfp);
 
 void sctp_ulpevent_read_sndrcvinfo(const struct sctp_ulpevent *event,
 	struct msghdr *);
diff -Nru a/include/net/sctp/ulpqueue.h b/include/net/sctp/ulpqueue.h
--- a/include/net/sctp/ulpqueue.h	Thu Mar  6 13:36:44 2003
+++ b/include/net/sctp/ulpqueue.h	Wed Apr  9 12:24:28 2003
@@ -50,14 +50,15 @@
 struct sctp_ulpq {
 	char malloced;
 	char pd_mode;
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	struct sk_buff_head reasm;
 	struct sk_buff_head lobby;
 };
 
 /* Prototypes. */
-struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority);
-struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *, sctp_association_t *);
+struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp);
+struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *,
+				 struct sctp_association *);
 void sctp_ulpq_free(struct sctp_ulpq *);
 
 /* Add a new DATA chunk for processing. */
diff -Nru a/include/net/sctp/user.h b/include/net/sctp/user.h
--- a/include/net/sctp/user.h	Thu Mar  6 13:36:44 2003
+++ b/include/net/sctp/user.h	Wed Apr 23 08:47:03 2003
@@ -110,6 +110,10 @@
 #define SCTP_GET_LOCAL_ADDRS	SCTP_GET_LOCAL_ADDRS
 	SCTP_NODELAY, 	/* Get/set nodelay option. */
 #define SCTP_NODELAY	SCTP_NODELAY
+	SCTP_I_WANT_MAPPED_V4_ADDR,  /* Turn on/off mapped v4 addresses  */
+#define SCTP_I_WANT_MAPPED_V4_ADDR SCTP_I_WANT_MAPPED_V4_ADDR
+	SCTP_MAXSEG, 	/* Get/set maximum fragment. */
+#define SCTP_MAXSEG 	SCTP_MAXSEG
 };
 
 
diff -Nru a/include/net/sock.h b/include/net/sock.h
--- a/include/net/sock.h	Fri May  2 22:55:11 2003
+++ b/include/net/sock.h	Mon May 19 21:22:22 2003
@@ -95,41 +95,109 @@
 	init_waitqueue_head(&((__sk)->lock.wq)); \
 } while(0)
 
+/**
+  *	struct sock - network layer representation of sockets
+  *	@state - Connection state
+  *	@zapped	- ax25 & ipx means !linked
+  *	@reuse - %SO_REUSEADDR setting
+  *	@shutdown - mask of %SEND_SHUTDOWN and/or %RCV_SHUTDOWN
+  *	@bound_dev_if - bound device index if != 0
+  *	@next - main hash linkage for various protocol lookup tables
+  *	@pprev - main hash linkage for various protocol lookup tables
+  *	@bind_next - main hash linkage for various protocol lookup tables
+  *	@bind_pprev - main hash linkage for various protocol lookup tables
+  *	@refcnt - reference count
+  *	@family - network address family
+  *	@use_write_queue - wheter to call sk->write_space(sk) in sock_wfree
+  *	@userlocks - %SO_SNDBUF and %SO_RCVBUF settings
+  *	@lock -	synchronizer
+  *	@rcvbuf - size of receive buffer in bytes
+  *	@sleep - sock wait queue
+  *	@dst_cache - destination cache
+  *	@dst_lock - destination cache lock
+  *	@policy - flow policy
+  *	@rmem_alloc - receive queue bytes committed
+  *	@receive_queue - incoming packets
+  *	@wmem_alloc - transmit queue bytes committed
+  *	@write_queue - Packet sending queue
+  *	@omem_alloc - "o" is "option" or "other"
+  *	@wmem_queued - persistent queue size
+  *	@forward_alloc - space allocated forward
+  *	@allocation - allocation mode
+  *	@sndbuf - size of send buffer in bytes
+  *	@prev - pointer to previous sock in the list this sock is in
+  *	@flags - %SO_LINGER (l_onoff), %SO_BROADCAST, %SO_KEEPALIVE, %SO_OOBINLINE settings
+  *	@no_check - %SO_NO_CHECK setting, wether or not checkup packets
+  *	@debug - %SO_DEBUG setting
+  *	@rcvtstamp - %SO_TIMESTAMP setting
+  *	@no_largesend - whether to sent large segments or not
+  *	@route_caps - route capabilities (e.g. %NETIF_F_TSO)
+  *	@lingertime - %SO_LINGER l_linger setting
+  *	@hashent - hash entry in several tables (e.g. tcp_ehash)
+  *	@pair - socket pair (e.g. AF_UNIX/unix_peer)
+  *	@backlog - always used with the per-socket spinlock held
+  *	@callback_lock - used with the callbacks in the end of this struct
+  *	@error_queue - rarely used
+  *	@prot - protocol handlers inside a network family
+  *	@err - last error
+  *	@err_soft - errors that don't cause failure but are the cause of a persistent failure not just 'timed out'
+  *	@ack_backlog - current listen backlog
+  *	@max_ack_backlog - listen backlog set in listen()
+  *	@priority - %SO_PRIORITY setting
+  *	@type - socket type (%SOCK_STREAM, etc)
+  *	@localroute - route locally only, %SO_DONTROUTE setting
+  *	@protocol - which protocol this socket belongs in this network family
+  *	@peercred - %SO_PEERCRED setting
+  *	@rcvlowat - %SO_RCVLOWAT setting
+  *	@rcvtimeo - %SO_RCVTIMEO setting
+  *	@sndtimeo - %SO_SNDTIMEO setting
+  *	@filter - socket filtering instructions
+  *	@protinfo - private area, net family specific, when not using slab
+  *	@slab - the slabcache this instance was allocated from
+  *	@timer - sock cleanup timer
+  *	@stamp - time stamp of last packet received
+  *	@socket - Identd and reporting IO signals
+  *	@user_data - RPC layer private data
+  *	@owner - module that owns this socket
+  *	@state_change - callback to indicate change in the state of the sock
+  *	@data_ready - callback to indicate there is data to be processed
+  *	@write_space - callback to indicate there is bf sending space available
+  *	@error_report - callback to indicate errors (e.g. %MSG_ERRQUEUE)
+  *	@backlog_rcv - callback to process the backlog
+  *	@destruct - called at sock freeing time, i.e. when all refcnt == 0
+ */
 struct sock {
 	/* Begin of struct sock/struct tcp_tw_bucket shared layout */
-	volatile unsigned char	state,		/* Connection state */
-				zapped;		/* ax25 & ipx means !linked */
-	unsigned char		reuse;		/* SO_REUSEADDR setting */
+	volatile unsigned char	state,
+				zapped;
+	unsigned char		reuse;
 	unsigned char		shutdown;
-	int			bound_dev_if;	/* Bound device index if != 0 */
-	/* Main hash linkage for various protocol lookup tables. */
+	int			bound_dev_if;
 	struct sock		*next;
 	struct sock		**pprev;
 	struct sock		*bind_next;
 	struct sock		**bind_pprev;
-	atomic_t		refcnt;		/* Reference count			*/
-	unsigned short		family;		/* Address family */
+	atomic_t		refcnt;
+	unsigned short		family;
 	/* End of struct sock/struct tcp_tw_bucket shared layout */
 	unsigned char		use_write_queue;
 	unsigned char		userlocks;
-	socket_lock_t		lock;		/* Synchronizer...			*/
-	int			rcvbuf;		/* Size of receive buffer in bytes	*/
-
-	wait_queue_head_t	*sleep;		/* Sock wait queue			*/
-	struct dst_entry	*dst_cache;	/* Destination cache			*/
+	socket_lock_t		lock;
+	int			rcvbuf;
+	wait_queue_head_t	*sleep;
+	struct dst_entry	*dst_cache;
 	rwlock_t		dst_lock;
 	struct xfrm_policy	*policy[2];
-	atomic_t		rmem_alloc;	/* Receive queue bytes committed	*/
-	struct sk_buff_head	receive_queue;	/* Incoming packets			*/
-	atomic_t		wmem_alloc;	/* Transmit queue bytes committed	*/
-	struct sk_buff_head	write_queue;	/* Packet sending queue			*/
-	atomic_t		omem_alloc;	/* "o" is "option" or "other" */
-	int			wmem_queued;	/* Persistent queue size */
-	int			forward_alloc;	/* Space allocated forward. */
-	unsigned int		allocation;	/* Allocation mode			*/
-	int			sndbuf;		/* Size of send buffer in bytes		*/
+	atomic_t		rmem_alloc;
+	struct sk_buff_head	receive_queue;
+	atomic_t		wmem_alloc;
+	struct sk_buff_head	write_queue;
+	atomic_t		omem_alloc;
+	int			wmem_queued;
+	int			forward_alloc;
+	unsigned int		allocation;
+	int			sndbuf;
 	struct sock		*prev;
-
 	unsigned long 		flags;
 	char		 	no_check;
 	unsigned char		debug;
@@ -137,72 +205,44 @@
 	unsigned char		no_largesend;
 	int			route_caps;
 	unsigned long	        lingertime;
-
 	int			hashent;
 	struct sock		*pair;
-
-	/* The backlog queue is special, it is always used with
+	/*
+	 * The backlog queue is special, it is always used with
 	 * the per-socket spinlock held and requires low latency
-	 * access.  Therefore we special case it's implementation.
+	 * access. Therefore we special case it's implementation.
 	 */
 	struct {
 		struct sk_buff *head;
 		struct sk_buff *tail;
 	} backlog;
-
 	rwlock_t		callback_lock;
-
-	/* Error queue, rarely used. */
 	struct sk_buff_head	error_queue;
-
 	struct proto		*prot;
-
-	int			err, err_soft;	/* Soft holds errors that don't
-						   cause failure but are the cause
-						   of a persistent failure not just
-						   'timed out' */
+	int			err,
+				err_soft;
 	unsigned short		ack_backlog;
 	unsigned short		max_ack_backlog;
 	__u32			priority;
 	unsigned short		type;
-	unsigned char		localroute;	/* Route locally only */
+	unsigned char		localroute;
 	unsigned char		protocol;
 	struct ucred		peercred;
 	int			rcvlowat;
 	long			rcvtimeo;
 	long			sndtimeo;
-
-	/* Socket Filtering Instructions */
 	struct sk_filter      	*filter;
-
-	/* This is where all the private (optional) areas that don't
-	 * overlap will eventually live. 
-	 */
-	void *protinfo;
-
-	/* The slabcache this instance was allocated from, it is sk_cachep for most
-	 * protocols, but a private slab for protocols such as IPv4, IPv6, SPX
-	 * and Unix.
-	 */
-	kmem_cache_t *slab;
-
-	/* This part is used for the timeout functions. */
-	struct timer_list	timer;		/* This is the sock cleanup timer. */
+	void			*protinfo;
+	kmem_cache_t		*slab;
+	struct timer_list	timer;
 	struct timeval		stamp;
-
-	/* Identd and reporting IO signals */
 	struct socket		*socket;
-
-	/* RPC layer private data */
 	void			*user_data;
-  
-	/* Callbacks */
 	struct module		*owner;
 	void			(*state_change)(struct sock *sk);
-	void			(*data_ready)(struct sock *sk,int bytes);
+	void			(*data_ready)(struct sock *sk, int bytes);
 	void			(*write_space)(struct sock *sk);
 	void			(*error_report)(struct sock *sk);
-
   	int			(*backlog_rcv) (struct sock *sk,
 						struct sk_buff *skb);  
 	void                    (*destruct)(struct sock *sk);
@@ -405,12 +445,12 @@
 extern void			sock_rfree(struct sk_buff *skb);
 
 extern int			sock_setsockopt(struct socket *sock, int level,
-						int op, char *optval,
+						int op, char __user *optval,
 						int optlen);
 
 extern int			sock_getsockopt(struct socket *sock, int level,
-						int op, char *optval, 
-						int *optlen);
+						int op, char __user *optval, 
+						int __user *optlen);
 extern struct sk_buff 		*sock_alloc_send_skb(struct sock *sk,
 						     unsigned long size,
 						     int noblock,
diff -Nru a/include/net/tcp.h b/include/net/tcp.h
--- a/include/net/tcp.h	Sat May  3 00:42:29 2003
+++ b/include/net/tcp.h	Wed May 14 20:16:59 2003
@@ -222,7 +222,6 @@
 extern atomic_t tcp_orphan_count;
 extern int tcp_tw_count;
 extern void tcp_time_wait(struct sock *sk, int state, int timeo);
-extern void tcp_timewait_kill(struct tcp_tw_bucket *tw);
 extern void tcp_tw_schedule(struct tcp_tw_bucket *tw, int timeo);
 extern void tcp_tw_deschedule(struct tcp_tw_bucket *tw);
 
@@ -615,19 +614,19 @@
  * and worry about wraparound (automatic with unsigned arithmetic).
  */
 
-extern __inline int before(__u32 seq1, __u32 seq2)
+static inline int before(__u32 seq1, __u32 seq2)
 {
         return (__s32)(seq1-seq2) < 0;
 }
 
-extern __inline int after(__u32 seq1, __u32 seq2)
+static inline int after(__u32 seq1, __u32 seq2)
 {
 	return (__s32)(seq2-seq1) < 0;
 }
 
 
 /* is s2<=s1<=s3 ? */
-extern __inline int between(__u32 seq1, __u32 seq2, __u32 seq3)
+static inline int between(__u32 seq1, __u32 seq2, __u32 seq3)
 {
 	return seq3 - seq2 >= seq1 - seq2;
 }
@@ -643,7 +642,7 @@
 #define TCP_ADD_STATS_BH(field, val)	SNMP_ADD_STATS_BH(tcp_statistics, field, val)
 #define TCP_ADD_STATS_USER(field, val)	SNMP_ADD_STATS_USER(tcp_statistics, field, val)
 
-extern __inline__ void		tcp_put_port(struct sock *sk);
+extern inline void		tcp_put_port(struct sock *sk);
 extern void			tcp_inherit_port(struct sock *sk, struct sock *child);
 
 extern void			tcp_v4_err(struct sk_buff *skb, u32);
diff -Nru a/include/net/xfrm.h b/include/net/xfrm.h
--- a/include/net/xfrm.h	Sun May  4 06:26:55 2003
+++ b/include/net/xfrm.h	Thu May 15 21:05:01 2003
@@ -123,6 +123,12 @@
 	/* Data for encapsulator */
 	struct xfrm_encap_tmpl	*encap;
 
+	/* IPComp needs an IPIP tunnel for handling uncompressed packets */
+	struct xfrm_state	*tunnel;
+
+	/* If a tunnel, number of users + 1 */
+	atomic_t		tunnel_users;
+
 	/* State for replay detection */
 	struct xfrm_replay_state replay;
 
@@ -196,6 +202,8 @@
 extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family);
 extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo);
 
+extern void xfrm_state_delete_tunnel(struct xfrm_state *x);
+
 struct xfrm_decap_state;
 struct xfrm_type
 {
@@ -336,7 +344,7 @@
 
 static inline void xfrm_pol_hold(struct xfrm_policy *policy)
 {
-	if (policy)
+	if (likely(policy != NULL))
 		atomic_inc(&policy->refcnt);
 }
 
@@ -699,6 +707,11 @@
 	return 0;
 }
 
+static inline int xfrm_state_kern(struct xfrm_state *x)
+{
+	return atomic_read(&x->tunnel_users);
+}
+
 /*
  * xfrm algorithm information
  */
@@ -775,7 +788,6 @@
 void xfrm6_policy_init(void);
 struct xfrm_policy *xfrm_policy_alloc(int gfp);
 extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *);
-struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl, unsigned short family);
 int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
 struct xfrm_policy *xfrm_policy_delete(int dir, struct xfrm_selector *sel);
 struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete);
diff -Nru a/include/scsi/scsi.h b/include/scsi/scsi.h
--- a/include/scsi/scsi.h	Thu Jan 23 07:50:27 2003
+++ b/include/scsi/scsi.h	Sun May 11 12:26:03 2003
@@ -111,13 +111,38 @@
 #define SAM_STAT_CHECK_CONDITION 0x02
 #define SAM_STAT_CONDITION_MET   0x04
 #define SAM_STAT_BUSY            0x08
-#define SAM_STAT_IMMEDIATE       0x10
-#define SAM_STAT_IMMEDIATE_CONDITION_MET 0x14
+#define SAM_STAT_INTERMEDIATE    0x10
+#define SAM_STAT_INTERMEDIATE_CONDITION_MET 0x14
 #define SAM_STAT_RESERVATION_CONFLICT 0x18
 #define SAM_STAT_COMMAND_TERMINATED 0x22	/* obsolete in SAM-3 */
 #define SAM_STAT_TASK_SET_FULL   0x28
 #define SAM_STAT_ACA_ACTIVE      0x30
 #define SAM_STAT_TASK_ABORTED    0x40
+
+/** scsi_status_is_good - check the status return.
+ *
+ * @status: the status passed up from the driver (including host and
+ *          driver components)
+ *
+ * This returns true for known good conditions that may be treated as
+ * command completed normally
+ */
+static inline int scsi_status_is_good(int status)
+{
+	/* mask out the relevant bits
+	 *
+	 * FIXME: bit0 is listed as reserved in SCSI-2, but is
+	 * significant in SCSI-3.  For now, we follow the SCSI-2
+	 * behaviour and ignore reserved bits. */
+	
+	status &= 0xfe;
+
+	return ((status == SAM_STAT_GOOD)
+		|| (status == SAM_STAT_INTERMEDIATE)
+		|| (status == SAM_STAT_INTERMEDIATE_CONDITION_MET)
+		/* FIXME: this is obsolete in SAM-3 */
+		|| (status == SAM_STAT_COMMAND_TERMINATED));
+}
 
 /*
  *  Status codes. These are deprecated as they are shifted 1 bit right
diff -Nru a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h
--- a/include/sound/seq_kernel.h	Thu Mar 20 08:41:11 2003
+++ b/include/sound/seq_kernel.h	Tue May 13 14:58:07 2003
@@ -158,7 +158,7 @@
 extern int snd_seq_delete_kernel_client(int client);
 extern int snd_seq_kernel_client_enqueue(int client, snd_seq_event_t *ev, int atomic, int hop);
 extern int snd_seq_kernel_client_dispatch(int client, snd_seq_event_t *ev, int atomic, int hop);
-extern int snd_seq_kernel_client_ctl(int client, unsigned int cmd, void *arg);
+extern int snd_seq_kernel_client_ctl(int client, unsigned int cmd, void __user *arg);
 
 #define SNDRV_SEQ_EXT_MASK	0xc0000000
 #define SNDRV_SEQ_EXT_USRPTR	0x80000000
diff -Nru a/init/Kconfig b/init/Kconfig
--- a/init/Kconfig	Sun Apr 20 12:56:52 2003
+++ b/init/Kconfig	Tue Apr 22 09:33:51 2003
@@ -142,7 +142,7 @@
 	  This option allows you to force a module to unload, even if the
 	  kernel believes it is unsafe: the kernel will remove the module
 	  without waiting for anyone to stop using it (using the -f option to
-	  rmmod).  This is mainly for kernel developers and desparate users.
+	  rmmod).  This is mainly for kernel developers and desperate users.
 	  If unsure, say N.
 
 config OBSOLETE_MODPARM
diff -Nru a/init/main.c b/init/main.c
--- a/init/main.c	Sun Apr 20 09:14:41 2003
+++ b/init/main.c	Wed May  7 21:17:55 2003
@@ -417,7 +417,6 @@
 	 */
 	console_init();
 	profile_init();
-	kmem_cache_init();
 	local_irq_enable();
 	calibrate_delay();
 #ifdef CONFIG_BLK_DEV_INITRD
@@ -430,7 +429,7 @@
 #endif
 	page_address_init();
 	mem_init();
-	kmem_cache_sizes_init();
+	kmem_cache_init();
 	pidmap_init();
 	pgtable_cache_init();
 	pte_chain_init();
diff -Nru a/ipc/msg.c b/ipc/msg.c
--- a/ipc/msg.c	Wed Dec 18 05:36:54 2002
+++ b/ipc/msg.c	Mon May 12 21:23:19 2003
@@ -74,7 +74,7 @@
 #define msg_buildid(id, seq) \
 	ipc_buildid(&msg_ids, id, seq)
 
-static void freeque (int id);
+static void freeque (struct msg_queue *msq, int id);
 static int newque (key_t key, int msgflg);
 #ifdef CONFIG_PROC_FS
 static int sysvipc_msg_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
@@ -272,16 +272,21 @@
 		wake_up_process(msr->r_tsk);
 	}
 }
-
-static void freeque (int id)
+/* 
+ * freeque() wakes up waiters on the sender and receiver waiting queue, 
+ * removes the message queue from message queue ID 
+ * array, and cleans up all the messages associated with this queue.
+ *
+ * msg_ids.sem and the spinlock for this message queue is hold
+ * before freeque() is called. msg_ids.sem remains locked on exit.
+ */
+static void freeque (struct msg_queue *msq, int id)
 {
-	struct msg_queue *msq;
 	struct list_head *tmp;
 
-	msq = msg_rmid(id);
-
 	expunge_all(msq,-EIDRM);
 	ss_wakeup(&msq->q_senders,1);
+	msq = msg_rmid(id);
 	msg_unlock(msq);
 		
 	tmp = msq->q_messages.next;
@@ -574,7 +579,7 @@
 		break;
 	}
 	case IPC_RMID:
-		freeque (msqid); 
+		freeque (msq, msqid); 
 		break;
 	}
 	err = 0;
diff -Nru a/ipc/sem.c b/ipc/sem.c
--- a/ipc/sem.c	Wed Dec 18 05:48:49 2002
+++ b/ipc/sem.c	Mon May 12 21:23:19 2003
@@ -79,7 +79,7 @@
 static struct ipc_ids sem_ids;
 
 static int newary (key_t, int, int);
-static void freeary (int id);
+static void freeary (struct sem_array *sma, int id);
 #ifdef CONFIG_PROC_FS
 static int sysvipc_sem_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
 #endif
@@ -405,16 +405,16 @@
 	return semzcnt;
 }
 
-/* Free a semaphore set. */
-static void freeary (int id)
+/* Free a semaphore set. freeary() is called with sem_ids.sem down and
+ * the spinlock for this semaphore set hold. sem_ids.sem remains locked
+ * on exit.
+ */
+static void freeary (struct sem_array *sma, int id)
 {
-	struct sem_array *sma;
 	struct sem_undo *un;
 	struct sem_queue *q;
 	int size;
 
-	sma = sem_rmid(id);
-
 	/* Invalidate the existing undo structures for this semaphore set.
 	 * (They will be freed without any further action in sem_exit()
 	 * or during the next semop.)
@@ -428,6 +428,9 @@
 		q->prev = NULL;
 		wake_up_process(q->sleeper); /* doesn't sleep */
 	}
+
+	/* Remove the semaphore set from the ID array*/
+	sma = sem_rmid(id);
 	sem_unlock(sma);
 
 	used_sems -= sma->sem_nsems;
@@ -764,7 +767,7 @@
 
 	switch(cmd){
 	case IPC_RMID:
-		freeary(semid);
+		freeary(sma, semid);
 		err = 0;
 		break;
 	case IPC_SET:
diff -Nru a/ipc/shm.c b/ipc/shm.c
--- a/ipc/shm.c	Sat Apr 19 23:22:48 2003
+++ b/ipc/shm.c	Fri May  9 14:23:37 2003
@@ -149,7 +149,7 @@
 
 static int shm_mmap(struct file * file, struct vm_area_struct * vma)
 {
-	UPDATE_ATIME(file->f_dentry->d_inode);
+	update_atime(file->f_dentry->d_inode);
 	vma->vm_ops = &shm_vm_ops;
 	shm_inc(file->f_dentry->d_inode->i_ino);
 	return 0;
@@ -270,7 +270,7 @@
 	return err;
 }
 
-static inline unsigned long copy_shmid_to_user(void *buf, struct shmid64_ds *in, int version)
+static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
 {
 	switch(version) {
 	case IPC_64:
@@ -301,7 +301,7 @@
 	mode_t	mode;
 };	
 
-static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void *buf, int version)
+static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __user *buf, int version)
 {
 	switch(version) {
 	case IPC_64:
@@ -335,7 +335,7 @@
 	}
 }
 
-static inline unsigned long copy_shminfo_to_user(void *buf, struct shminfo64 *in, int version)
+static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version)
 {
 	switch(version) {
 	case IPC_64:
@@ -393,7 +393,7 @@
 	}
 }
 
-asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds *buf)
+asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
 {
 	struct shm_setbuf setbuf;
 	struct shmid_kernel *shp;
@@ -580,7 +580,7 @@
 
 	case IPC_SET:
 	{
-		if(copy_shmid_from_user (&setbuf, buf, version)) {
+		if (copy_shmid_from_user (&setbuf, buf, version)) {
 			err = -EFAULT;
 			goto out;
 		}
@@ -630,8 +630,12 @@
 
 /*
  * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists.
+ *
+ * NOTE! Despite the name, this is NOT a direct system call entrypoint. The
+ * "raddr" thing points to kernel space, and there has to be a wrapper around
+ * this.
  */
-asmlinkage long sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr)
+long sys_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
 {
 	struct shmid_kernel *shp;
 	unsigned long addr;
@@ -745,7 +749,7 @@
  * detach and kill segment if marked destroyed.
  * The work is done in shm_close.
  */
-asmlinkage long sys_shmdt(char *shmaddr)
+asmlinkage long sys_shmdt(char __user *shmaddr)
 {
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma, *next;
diff -Nru a/kernel/cpufreq.c b/kernel/cpufreq.c
--- a/kernel/cpufreq.c	Mon Apr 28 23:50:13 2003
+++ b/kernel/cpufreq.c	Mon May 12 21:23:15 2003
@@ -22,15 +22,18 @@
 #include <linux/spinlock.h>
 #include <linux/device.h>
 #include <linux/slab.h>
+#include <linux/cpu.h>
 
 /**
  * The "cpufreq driver" - the arch- or hardware-dependend low
  * level driver of CPUFreq support, and its locking mutex. 
  * cpu_max_freq is in kHz.
  */
-static struct cpufreq_driver   	*cpufreq_driver;
+struct cpufreq_driver   	*cpufreq_driver;
 static DECLARE_MUTEX            (cpufreq_driver_sem);
 
+/* required for the proc interface, remove when that goes away */
+EXPORT_SYMBOL_GPL(cpufreq_driver);
 
 /**
  * Two notifier lists: the "policy" list is involved in the 
@@ -115,6 +118,7 @@
 extern struct device_class cpu_devclass;
 
 static struct class_interface cpufreq_interface = {
+        .class =	&cpu_class,
         .add =		&cpufreq_add_dev,
         .remove =	&cpufreq_remove_dev,
 };
diff -Nru a/kernel/exec_domain.c b/kernel/exec_domain.c
--- a/kernel/exec_domain.c	Mon Dec 30 09:10:06 2002
+++ b/kernel/exec_domain.c	Sat May 17 12:39:13 2003
@@ -88,11 +88,7 @@
 
 #ifdef CONFIG_KMOD
 	read_unlock(&exec_domains_lock);
-	{
-		char buffer[30];
-		sprintf(buffer, "personality-%ld", pers);
-		request_module(buffer);
-	}
+	request_module("personality-%ld", pers);
 	read_lock(&exec_domains_lock);
 
 	for (ep = exec_domains; ep; ep = ep->next) {
diff -Nru a/kernel/exit.c b/kernel/exit.c
--- a/kernel/exit.c	Thu Apr  3 10:15:23 2003
+++ b/kernel/exit.c	Mon May 12 18:59:24 2003
@@ -756,7 +756,7 @@
 	struct pid_link *link = p->pids + PIDTYPE_TGID;
 	struct list_head *tmp, *head = &link->pidptr->task_list;
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	if (!p->sighand)
 		BUG();
 	if (!spin_is_locked(&p->sighand->siglock) &&
diff -Nru a/kernel/fork.c b/kernel/fork.c
--- a/kernel/fork.c	Mon Apr 21 08:09:25 2003
+++ b/kernel/fork.c	Sun May 18 17:00:00 2003
@@ -379,7 +379,6 @@
 	free_mm(mm);
 	return NULL;
 }
-	
 
 /*
  * Allocate and initialize an mm_struct.
@@ -450,7 +449,7 @@
 		complete(vfork_done);
 	}
 	if (tsk->clear_child_tid && atomic_read(&mm->mm_users) > 1) {
-		u32 * tidptr = tsk->clear_child_tid;
+		u32 __user * tidptr = tsk->clear_child_tid;
 		tsk->clear_child_tid = NULL;
 
 		/*
@@ -543,7 +542,7 @@
 		} else {
 			fs->altrootmnt = NULL;
 			fs->altroot = NULL;
-		}	
+		}
 		read_unlock(&old->lock);
 	}
 	return fs;
@@ -562,14 +561,14 @@
 	}
 	tsk->fs = __copy_fs_struct(current->fs);
 	if (!tsk->fs)
-		return -1;
+		return -ENOMEM;
 	return 0;
 }
 
 static int count_open_files(struct files_struct *files, int size)
 {
 	int i;
-	
+
 	/* Find the last open fd */
 	for (i = size/(8*sizeof(long)); i > 0; ) {
 		if (files->open_fds->fds_bits[--i])
@@ -669,7 +668,7 @@
 	if (newf->max_fdset > open_files) {
 		int left = (newf->max_fdset-open_files)/8;
 		int start = open_files / (8 * sizeof(unsigned long));
-		
+
 		memset(&newf->open_fds->fds_bits[start], 0, left);
 		memset(&newf->close_on_exec->fds_bits[start], 0, left);
 	}
@@ -697,7 +696,7 @@
 	sig = kmem_cache_alloc(sighand_cachep, GFP_KERNEL);
 	tsk->sighand = sig;
 	if (!sig)
-		return -1;
+		return -ENOMEM;
 	spin_lock_init(&sig->siglock);
 	atomic_set(&sig->count, 1);
 	memcpy(sig->action, current->sighand->action, sizeof(sig->action));
@@ -715,7 +714,7 @@
 	sig = kmem_cache_alloc(signal_cachep, GFP_KERNEL);
 	tsk->signal = sig;
 	if (!sig)
-		return -1;
+		return -ENOMEM;
 	atomic_set(&sig->count, 1);
 	sig->group_exit = 0;
 	sig->group_exit_code = 0;
@@ -738,7 +737,7 @@
 	p->flags = new_flags;
 }
 
-asmlinkage long sys_set_tid_address(int *tidptr)
+asmlinkage long sys_set_tid_address(int __user *tidptr)
 {
 	current->clear_child_tid = tidptr;
 
@@ -753,12 +752,12 @@
  * parts of the process environment (as per the clone
  * flags). The actual kick-off is left to the caller.
  */
-static struct task_struct *copy_process(unsigned long clone_flags,
-			    unsigned long stack_start,
-			    struct pt_regs *regs,
-			    unsigned long stack_size,
-			    int *parent_tidptr,
-			    int *child_tidptr)
+struct task_struct *copy_process(unsigned long clone_flags,
+				 unsigned long stack_start,
+				 struct pt_regs *regs,
+				 unsigned long stack_size,
+				 int __user *parent_tidptr,
+				 int __user *child_tidptr)
 {
 	int retval;
 	struct task_struct *p = NULL;
@@ -800,7 +799,7 @@
 	 */
 	if (nr_threads >= max_threads)
 		goto bad_fork_cleanup_count;
-	
+
 	if (!try_module_get(p->thread_info->exec_domain->module))
 		goto bad_fork_cleanup_count;
 
@@ -860,23 +859,22 @@
 	p->security = NULL;
 
 	retval = -ENOMEM;
-	if (security_task_alloc(p))
+	if ((retval = security_task_alloc(p)))
 		goto bad_fork_cleanup;
 	/* copy all the process information */
-	if (copy_semundo(clone_flags, p))
+	if ((retval = copy_semundo(clone_flags, p)))
 		goto bad_fork_cleanup_security;
-	if (copy_files(clone_flags, p))
+	if ((retval = copy_files(clone_flags, p)))
 		goto bad_fork_cleanup_semundo;
-	if (copy_fs(clone_flags, p))
+	if ((retval = copy_fs(clone_flags, p)))
 		goto bad_fork_cleanup_files;
-	if (copy_sighand(clone_flags, p))
+	if ((retval = copy_sighand(clone_flags, p)))
 		goto bad_fork_cleanup_fs;
-	if (copy_signal(clone_flags, p))
+	if ((retval = copy_signal(clone_flags, p)))
 		goto bad_fork_cleanup_sighand;
-	if (copy_mm(clone_flags, p))
+	if ((retval = copy_mm(clone_flags, p)))
 		goto bad_fork_cleanup_signal;
-	retval = copy_namespace(clone_flags, p);
-	if (retval)
+	if ((retval = copy_namespace(clone_flags, p)))
 		goto bad_fork_cleanup_mm;
 	retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
 	if (retval)
@@ -1069,15 +1067,16 @@
  * It copies the process, and if successful kick-starts
  * it and waits for it to finish using the VM if required.
  */
-struct task_struct *do_fork(unsigned long clone_flags,
-			    unsigned long stack_start,
-			    struct pt_regs *regs,
-			    unsigned long stack_size,
-			    int *parent_tidptr,
-			    int *child_tidptr)
+long do_fork(unsigned long clone_flags,
+	      unsigned long stack_start,
+	      struct pt_regs *regs,
+	      unsigned long stack_size,
+	      int __user *parent_tidptr,
+	      int __user *child_tidptr)
 {
 	struct task_struct *p;
 	int trace = 0;
+	long pid;
 
 	if (unlikely(current->ptrace)) {
 		trace = fork_traceflag (clone_flags);
@@ -1086,6 +1085,12 @@
 	}
 
 	p = copy_process(clone_flags, stack_start, regs, stack_size, parent_tidptr, child_tidptr);
+	/*
+	 * Do this prior waking up the new thread - the thread pointer
+	 * might get invalid after that point, if the thread exits quickly.
+	 */
+	pid = IS_ERR(p) ? PTR_ERR(p) : p->pid;
+
 	if (!IS_ERR(p)) {
 		struct completion vfork;
 
@@ -1106,7 +1111,7 @@
 		++total_forks;
 
 		if (unlikely (trace)) {
-			current->ptrace_message = (unsigned long) p->pid;
+			current->ptrace_message = pid;
 			ptrace_notify ((trace << 8) | SIGTRAP);
 		}
 
@@ -1121,7 +1126,7 @@
 			 */
 			set_need_resched();
 	}
-	return p;
+	return pid;
 }
 
 /* SLAB cache for signal_struct structures (tsk->signal) */
diff -Nru a/kernel/intermodule.c b/kernel/intermodule.c
--- a/kernel/intermodule.c	Mon Dec 30 09:10:21 2002
+++ b/kernel/intermodule.c	Sat May 17 12:39:13 2003
@@ -143,7 +143,7 @@
 {
 	const void *result = inter_module_get(im_name);
 	if (!result) {
-		request_module(modname);
+		request_module("%s", modname);
 		result = inter_module_get(im_name);
 	}
 	return(result);
diff -Nru a/kernel/kmod.c b/kernel/kmod.c
--- a/kernel/kmod.c	Mon Feb 24 09:40:34 2003
+++ b/kernel/kmod.c	Mon May 19 18:25:07 2003
@@ -58,11 +58,14 @@
  * If module auto-loading support is disabled then this function
  * becomes a no-operation.
  */
-int request_module(const char *module_name)
+#define MODULENAME_SIZE 32
+int request_module(const char *fmt, ...)
 {
+	va_list args;
+	char module_name[MODULENAME_SIZE];
 	unsigned int max_modprobes;
 	int ret;
-	char *argv[] = { modprobe_path, "--", (char*)module_name, NULL };
+	char *argv[] = { modprobe_path, "--", module_name, NULL };
 	static char *envp[] = { "HOME=/",
 				"TERM=linux",
 				"PATH=/sbin:/usr/sbin:/bin:/usr/bin",
@@ -71,6 +74,12 @@
 #define MAX_KMOD_CONCURRENT 50	/* Completely arbitrary value - KAO */
 	static int kmod_loop_msg;
 
+	va_start(args, fmt);
+	ret = vsnprintf(module_name, MODULENAME_SIZE, fmt, args);
+	va_end(args);
+	if (ret >= MODULENAME_SIZE)
+		return -ENAMETOOLONG;
+
 	/* If modprobe needs a service that is in a module, we get a recursive
 	 * loop.  Limit the number of running kmod threads to max_threads/2 or
 	 * MAX_KMOD_CONCURRENT, whichever is the smaller.  A cleaner method
@@ -80,7 +89,6 @@
 	 * and it is not worth changing the proc code just to handle this case. 
 	 * KAO.
 	 *
-
 	 * "trace the ppid" is simple, but will fail if someone's
 	 * parent exits.  I think this is as good as it gets. --RR
 	 */
@@ -254,22 +262,6 @@
 	}
 out:
 	return sub_info.retval;
-}
-
-/*
- * This is for the serialisation of device probe() functions
- * against device open() functions
- */
-static DECLARE_MUTEX(dev_probe_sem);
-
-void dev_probe_lock(void)
-{
-	down(&dev_probe_sem);
-}
-
-void dev_probe_unlock(void)
-{
-	up(&dev_probe_sem);
 }
 
 EXPORT_SYMBOL(call_usermodehelper);
diff -Nru a/kernel/ksyms.c b/kernel/ksyms.c
--- a/kernel/ksyms.c	Tue Apr 29 14:42:50 2003
+++ b/kernel/ksyms.c	Sat May 17 14:09:36 2003
@@ -40,7 +40,6 @@
 #include <linux/mm.h>
 #include <linux/capability.h>
 #include <linux/highuid.h>
-#include <linux/brlock.h>
 #include <linux/fs.h>
 #include <linux/uio.h>
 #include <linux/tty.h>
@@ -224,6 +223,7 @@
 EXPORT_SYMBOL(generic_cont_expand);
 EXPORT_SYMBOL(cont_prepare_write);
 EXPORT_SYMBOL(generic_commit_write);
+EXPORT_SYMBOL(block_commit_write);
 EXPORT_SYMBOL(block_truncate_page);
 EXPORT_SYMBOL(generic_block_bmap);
 EXPORT_SYMBOL(generic_file_read);
@@ -429,17 +429,6 @@
 #endif
 EXPORT_SYMBOL(mod_timer);
 
-#ifdef CONFIG_SMP
-
-/* Big-Reader lock implementation */
-EXPORT_SYMBOL(__brlock_array);
-#ifndef __BRLOCK_USE_ATOMICS
-EXPORT_SYMBOL(__br_write_locks);
-#endif
-EXPORT_SYMBOL(__br_write_lock);
-EXPORT_SYMBOL(__br_write_unlock);
-#endif
-
 #ifdef HAVE_DISABLE_HLT
 EXPORT_SYMBOL(disable_hlt);
 EXPORT_SYMBOL(enable_hlt);
@@ -459,7 +448,7 @@
 EXPORT_SYMBOL(complete_and_exit);
 EXPORT_SYMBOL(default_wake_function);
 EXPORT_SYMBOL(__wake_up);
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL_GPL(__wake_up_sync); /* internal use only */
 #endif
 EXPORT_SYMBOL(wake_up_process);
@@ -477,10 +466,10 @@
 EXPORT_SYMBOL(set_user_nice);
 EXPORT_SYMBOL(task_nice);
 EXPORT_SYMBOL_GPL(idle_cpu);
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 EXPORT_SYMBOL_GPL(set_cpus_allowed);
 #endif
-#if CONFIG_SMP || CONFIG_PREEMPT
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 EXPORT_SYMBOL(kernel_flag);
 #endif
 EXPORT_SYMBOL(jiffies);
@@ -540,6 +529,7 @@
 EXPORT_SYMBOL(seq_lseek);
 EXPORT_SYMBOL(single_open);
 EXPORT_SYMBOL(single_release);
+EXPORT_SYMBOL(seq_release_private);
 
 /* Program loader interfaces */
 #ifdef CONFIG_MMU
@@ -567,6 +557,8 @@
 EXPORT_SYMBOL(make_bad_inode);
 EXPORT_SYMBOL(is_bad_inode);
 EXPORT_SYMBOL(__inode_dir_notify);
+EXPORT_SYMBOL(generic_osync_inode);
+EXPORT_SYMBOL(remove_suid);
 
 #ifdef CONFIG_UID16
 EXPORT_SYMBOL(overflowuid);
@@ -578,8 +570,6 @@
 /* all busmice */
 EXPORT_SYMBOL(fasync_helper);
 EXPORT_SYMBOL(kill_fasync);
-
-EXPORT_SYMBOL(partition_name);
 
 /* binfmt_aout */
 EXPORT_SYMBOL(get_write_access);
diff -Nru a/kernel/module.c b/kernel/module.c
--- a/kernel/module.c	Wed Apr 30 07:17:38 2003
+++ b/kernel/module.c	Mon May 12 21:23:17 2003
@@ -214,6 +214,8 @@
 	INIT_LIST_HEAD(&mod->modules_which_use_me);
 	for (i = 0; i < NR_CPUS; i++)
 		atomic_set(&mod->ref[i].count, 0);
+	/* Hold reference count during initialization. */
+	atomic_set(&mod->ref[smp_processor_id()].count, 1);
 	/* Backwards compatibility macros put refcount during init. */
 	mod->waiter = current;
 }
@@ -462,6 +464,21 @@
 }
 EXPORT_SYMBOL(cleanup_module);
 
+static void wait_for_zero_refcount(struct module *mod)
+{
+	/* Since we might sleep for some time, drop the semaphore first */
+	up(&module_mutex);
+	for (;;) {
+		DEBUGP("Looking at refcount...\n");
+		set_current_state(TASK_UNINTERRUPTIBLE);
+		if (module_refcount(mod) == 0)
+			break;
+		schedule();
+	}
+	current->state = TASK_RUNNING;
+	down(&module_mutex);
+}
+
 asmlinkage long
 sys_delete_module(const char __user *name_user, unsigned int flags)
 {
@@ -500,16 +517,6 @@
 		goto out;
 	}
 
-	/* Coming up?  Allow force on stuck modules. */
-	if (mod->state == MODULE_STATE_COMING) {
-		forced = try_force(flags);
-		if (!forced) {
-			/* This module can't be removed */
-			ret = -EBUSY;
-			goto out;
-		}
-	}
-
 	/* If it has an init func, it must have an exit func to unload */
 	if ((mod->init != init_module && mod->exit == cleanup_module)
 	    || mod->unsafe) {
@@ -529,35 +536,22 @@
 	/* If it's not unused, quit unless we are told to block. */
 	if ((flags & O_NONBLOCK) && module_refcount(mod) != 0) {
 		forced = try_force(flags);
-		if (!forced)
+		if (!forced) {
 			ret = -EWOULDBLOCK;
-	} else {
-		mod->waiter = current;
-		mod->state = MODULE_STATE_GOING;
+			restart_refcounts();
+			goto out;
+		}
 	}
-	restart_refcounts();
-
-	if (ret != 0)
-		goto out;
-
-	if (forced)
-		goto destroy;
 
-	/* Since we might sleep for some time, drop the semaphore first */
-	up(&module_mutex);
-	for (;;) {
-		DEBUGP("Looking at refcount...\n");
-		set_current_state(TASK_UNINTERRUPTIBLE);
-		if (module_refcount(mod) == 0)
-			break;
-		schedule();
-	}
-	current->state = TASK_RUNNING;
+	/* Mark it as dying. */
+	mod->waiter = current;
+	mod->state = MODULE_STATE_GOING;
+	restart_refcounts();
 
-	DEBUGP("Regrabbing mutex...\n");
-	down(&module_mutex);
+	/* Never wait if forced. */
+	if (!forced && module_refcount(mod) != 0)
+		wait_for_zero_refcount(mod);
 
- destroy:
 	/* Final destruction now noone is using it. */
 	mod->exit();
 	free_module(mod);
@@ -910,6 +904,9 @@
 	list_del(&mod->list);
 	spin_unlock_irq(&modlist_lock);
 
+	/* Arch-specific cleanup. */
+	module_arch_cleanup(mod);
+
 	/* Module unload stuff */
 	module_unload_free(mod);
 
@@ -1276,6 +1273,7 @@
 	mod->module_init = ptr;
 
 	/* Transfer each section which specifies SHF_ALLOC */
+	DEBUGP("final section addresses:\n");
 	for (i = 0; i < hdr->e_shnum; i++) {
 		void *dest;
 
@@ -1293,6 +1291,7 @@
 			       sechdrs[i].sh_size);
 		/* Update sh_addr to point to copy in image. */
 		sechdrs[i].sh_addr = (unsigned long)dest;
+		DEBUGP("\t0x%lx %s\n", sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name);
 	}
 	/* Module has been moved. */
 	mod = (void *)sechdrs[modindex].sh_addr;
@@ -1448,6 +1447,7 @@
 			printk(KERN_ERR "%s: module is now stuck!\n",
 			       mod->name);
 		else {
+			module_put(mod);
 			down(&module_mutex);
 			free_module(mod);
 			up(&module_mutex);
@@ -1458,6 +1458,8 @@
 	/* Now it's a first class citizen! */
 	down(&module_mutex);
 	mod->state = MODULE_STATE_LIVE;
+	/* Drop initial reference. */
+	module_put(mod);
 	module_free(mod, mod->module_init);
 	mod->module_init = NULL;
 	mod->init_size = 0;
diff -Nru a/kernel/panic.c b/kernel/panic.c
--- a/kernel/panic.c	Wed Apr  9 01:01:38 2003
+++ b/kernel/panic.c	Mon May 12 11:11:38 2003
@@ -96,9 +96,8 @@
         disabled_wait(caller);
 #endif
 	local_irq_enable();
-	for(;;) {
-		CHECK_EMERGENCY_SYNC
-	}
+	for (;;)
+		;
 }
 
 /**
@@ -111,7 +110,7 @@
  *	The string is overwritten by the next call to print_taint().
  */
  
-const char *print_tainted()
+const char *print_tainted(void)
 {
 	static char buf[20];
 	if (tainted) {
diff -Nru a/kernel/pid.c b/kernel/pid.c
--- a/kernel/pid.c	Sun Jan  5 21:45:17 2003
+++ b/kernel/pid.c	Mon May 12 21:23:24 2003
@@ -252,6 +252,7 @@
 	attach_pid(thread, PIDTYPE_TGID, thread->tgid);
 	attach_pid(thread, PIDTYPE_PGID, thread->pgrp);
 	attach_pid(thread, PIDTYPE_SID, thread->session);
+	list_add_tail(&thread->tasks, &init_task.tasks);
 
 	attach_pid(leader, PIDTYPE_PID, leader->pid);
 	attach_pid(leader, PIDTYPE_TGID, leader->tgid);
diff -Nru a/kernel/posix-timers.c b/kernel/posix-timers.c
--- a/kernel/posix-timers.c	Sat Apr 19 23:22:26 2003
+++ b/kernel/posix-timers.c	Mon May 12 21:23:04 2003
@@ -357,11 +357,8 @@
 			rtn->tgid != current->tgid))
 		return NULL;
 
-	if ((event->sigev_notify & SIGEV_SIGNAL & MIPS_SIGEV) &&
+	if ((event->sigev_notify & ~SIGEV_NONE & MIPS_SIGEV) &&
 			((unsigned) (event->sigev_signo > SIGRTMAX)))
-		return NULL;
-
-	if (event->sigev_notify & ~(SIGEV_SIGNAL | SIGEV_THREAD_ID))
 		return NULL;
 
 	return rtn;
diff -Nru a/kernel/rcupdate.c b/kernel/rcupdate.c
--- a/kernel/rcupdate.c	Wed Oct 23 09:49:35 2002
+++ b/kernel/rcupdate.c	Wed Apr  2 21:02:38 2003
@@ -121,9 +121,8 @@
 {
 	int cpu = smp_processor_id();
 
-	if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask)) {
+	if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask))
 		return;
-	}
 
 	/* 
 	 * Races with local timer interrupt - in the worst case
@@ -134,23 +133,22 @@
 		RCU_last_qsctr(cpu) = RCU_qsctr(cpu);
 		return;
 	}
-	if (RCU_qsctr(cpu) == RCU_last_qsctr(cpu)) {
+	if (RCU_qsctr(cpu) == RCU_last_qsctr(cpu))
 		return;
-	}
 
 	spin_lock(&rcu_ctrlblk.mutex);
-	if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask)) {
-		spin_unlock(&rcu_ctrlblk.mutex);
-		return;
-	}
+	if (!test_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask))
+		goto out_unlock;
+
 	clear_bit(cpu, &rcu_ctrlblk.rcu_cpu_mask);
 	RCU_last_qsctr(cpu) = RCU_QSCTR_INVALID;
-	if (rcu_ctrlblk.rcu_cpu_mask != 0) {
-		spin_unlock(&rcu_ctrlblk.mutex);
-		return;
-	}
+	if (rcu_ctrlblk.rcu_cpu_mask != 0)
+		goto out_unlock;
+
 	rcu_ctrlblk.curbatch++;
 	rcu_start_batch(rcu_ctrlblk.maxbatch);
+
+out_unlock:
 	spin_unlock(&rcu_ctrlblk.mutex);
 }
 
diff -Nru a/kernel/sched.c b/kernel/sched.c
--- a/kernel/sched.c	Mon Apr 21 12:41:21 2003
+++ b/kernel/sched.c	Sun May 18 17:00:00 2003
@@ -340,10 +340,9 @@
  * Update all the scheduling statistics stuff. (sleep average
  * calculation, priority modifiers, etc.)
  */
-static inline int activate_task(task_t *p, runqueue_t *rq)
+static inline void activate_task(task_t *p, runqueue_t *rq)
 {
 	long sleep_time = jiffies - p->last_run - 1;
-	int requeue_waker = 0;
 
 	if (sleep_time > 0) {
 		int sleep_avg;
@@ -372,8 +371,6 @@
 		}
 	}
 	__activate_task(p, rq);
-
-	return requeue_waker;
 }
 
 /*
@@ -454,27 +451,12 @@
 }
 #endif
 
-/*
- * kick_if_running - kick the remote CPU if the task is running currently.
- *
- * This code is used by the signal code to signal tasks
- * which are in user-mode, as quickly as possible.
- *
- * (Note that we do this lockless - if the task does anything
- * while the message is in flight then it will notice the
- * sigpending condition anyway.)
- */
-void kick_if_running(task_t * p)
-{
-	if ((task_running(task_rq(p), p)) && (task_cpu(p) != smp_processor_id()))
-		resched_task(p);
-}
-
 /***
  * try_to_wake_up - wake up a thread
  * @p: the to-be-woken-up thread
  * @state: the mask of task states that can be woken
  * @sync: do a synchronous wakeup?
+ * @kick: kick the CPU if the task is already running?
  *
  * Put it on the run-queue if it's not already there. The "current"
  * thread is always on the run-queue (except when the actual
@@ -484,10 +466,10 @@
  *
  * returns failure only if the task is already active.
  */
-static int try_to_wake_up(task_t * p, unsigned int state, int sync)
+static int try_to_wake_up(task_t * p, unsigned int state, int sync, int kick)
 {
-	int success = 0, requeue_waker = 0;
 	unsigned long flags;
+	int success = 0;
 	long old_state;
 	runqueue_t *rq;
 
@@ -513,42 +495,34 @@
 			if (sync)
 				__activate_task(p, rq);
 			else {
-				requeue_waker = activate_task(p, rq);
+				activate_task(p, rq);
 				if (p->prio < rq->curr->prio)
 					resched_task(rq->curr);
 			}
 			success = 1;
-		}
+		} else
+			if (unlikely(kick) && task_running(rq, p))
+				resched_task(rq->curr);
 		p->state = TASK_RUNNING;
 	}
 	task_rq_unlock(rq, &flags);
 
-	/*
-	 * We have to do this outside the other spinlock, the two
-	 * runqueues might be different:
-	 */
-	if (requeue_waker) {
-		prio_array_t *array;
-
-		rq = task_rq_lock(current, &flags);
-		array = current->array;
-		dequeue_task(current, array);
-		current->prio = effective_prio(current);
-		enqueue_task(current, array);
-		task_rq_unlock(rq, &flags);
-	}
-
 	return success;
 }
 
 int wake_up_process(task_t * p)
 {
-	return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0);
+	return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0, 0);
+}
+
+int wake_up_process_kick(task_t * p)
+{
+	return try_to_wake_up(p, TASK_STOPPED | TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE, 0, 1);
 }
 
 int wake_up_state(task_t *p, unsigned int state)
 {
-	return try_to_wake_up(p, state, 0);
+	return try_to_wake_up(p, state, 0, 0);
 }
 
 /*
@@ -863,7 +837,7 @@
 
 #endif /* CONFIG_NUMA */
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 
 /*
  * double_lock_balance - lock the busiest runqueue
@@ -1206,7 +1180,7 @@
 	/* Task might have expired already, but not scheduled off yet */
 	if (p->array != rq->active) {
 		set_tsk_need_resched(p);
-		return;
+		goto out;
 	}
 	spin_lock(&rq->lock);
 	/*
@@ -1233,7 +1207,7 @@
 			dequeue_task(p, rq->active);
 			enqueue_task(p, rq->active);
 		}
-		goto out;
+		goto out_unlock;
 	}
 	if (!--p->time_slice) {
 		dequeue_task(p, rq->active);
@@ -1249,8 +1223,9 @@
 		} else
 			enqueue_task(p, rq->active);
 	}
-out:
+out_unlock:
 	spin_unlock(&rq->lock);
+out:
 	rebalance_tick(rq, 0);
 }
 
@@ -1309,7 +1284,7 @@
 	}
 pick_next_task:
 	if (unlikely(!rq->nr_running)) {
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 		load_balance(rq, 1, cpu_to_node_mask(smp_processor_id()));
 		if (rq->nr_running)
 			goto pick_next_task;
@@ -1389,7 +1364,7 @@
 int default_wake_function(wait_queue_t *curr, unsigned mode, int sync)
 {
 	task_t *p = curr->task;
-	return try_to_wake_up(p, mode, sync);
+	return try_to_wake_up(p, mode, sync, 0);
 }
 
 /*
@@ -1440,8 +1415,6 @@
 	__wake_up_common(q, mode, 1, 0);
 }
 
-#if CONFIG_SMP
-
 /**
  * __wake_up - sync- wake up threads blocked on a waitqueue.
  * @q: the waitqueue
@@ -1452,6 +1425,8 @@
  * away soon, so while the target thread will be woken up, it will not
  * be migrated to another CPU - ie. the two threads are 'synchronized'
  * with each other. This can prevent needless bouncing between CPUs.
+ *
+ * On UP it can prevent extra preemption.
  */
 void __wake_up_sync(wait_queue_head_t *q, unsigned int mode, int nr_exclusive)
 {
@@ -1468,8 +1443,6 @@
 	spin_unlock_irqrestore(&q->lock, flags);
 }
 
-#endif
-
 void complete(struct completion *x)
 {
 	unsigned long flags;
@@ -2261,7 +2234,7 @@
 #endif
 }
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 /*
  * This is how migration works:
  *
@@ -2443,7 +2416,7 @@
 
 #endif
 
-#if CONFIG_SMP || CONFIG_PREEMPT
+#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT)
 /*
  * The 'big kernel lock'
  *
diff -Nru a/kernel/signal.c b/kernel/signal.c
--- a/kernel/signal.c	Tue Apr  8 17:13:01 2003
+++ b/kernel/signal.c	Sun May 18 17:00:00 2003
@@ -521,18 +521,6 @@
 	set_tsk_thread_flag(t,TIF_SIGPENDING);
 
 	/*
-	 * If the task is running on a different CPU
-	 * force a reschedule on the other CPU to make
-	 * it notice the new signal quickly.
-	 *
-	 * The code below is a tad loose and might occasionally
-	 * kick the wrong CPU if we catch the process in the
-	 * process of changing - but no harm is done by that
-	 * other than doing an extra (lightweight) IPI interrupt.
-	 */
-	if (t->state == TASK_RUNNING)
-		kick_if_running(t);
-	/*
 	 * If resume is set, we want to wake it up in the TASK_STOPPED case.
 	 * We don't check for TASK_STOPPED because there is a race with it
 	 * executing another processor and just now entering stopped state.
@@ -543,7 +531,7 @@
 	if (resume)
 		mask |= TASK_STOPPED;
 	if (t->state & mask) {
-		wake_up_process(t);
+		wake_up_process_kick(t);
 		return;
 	}
 }
@@ -761,7 +749,7 @@
 
 	if (!irqs_disabled())
 		BUG();
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	if (!spin_is_locked(&t->sighand->siglock))
 		BUG();
 #endif
@@ -846,7 +834,7 @@
 	unsigned int mask;
 	int ret = 0;
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	if (!spin_is_locked(&p->sighand->siglock))
 		BUG();
 #endif
@@ -1146,6 +1134,7 @@
 send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
 {
 	int ret;
+	unsigned long flags;
 
 	/*
 	 * We need the tasklist lock even for the specific
@@ -1154,9 +1143,9 @@
 	 * going away or changing from under us.
 	 */
 	read_lock(&tasklist_lock);  
-	spin_lock_irq(&p->sighand->siglock);
+	spin_lock_irqsave(&p->sighand->siglock, flags);
 	ret = specific_send_sig_info(sig, info, p);
-	spin_unlock_irq(&p->sighand->siglock);
+	spin_unlock_irqrestore(&p->sighand->siglock, flags);
 	read_unlock(&tasklist_lock);
 	return ret;
 }
diff -Nru a/kernel/sysctl.c b/kernel/sysctl.c
--- a/kernel/sysctl.c	Wed Apr  9 20:50:43 2003
+++ b/kernel/sysctl.c	Mon May 12 11:25:49 2003
@@ -103,10 +103,10 @@
 extern int acct_parm[];
 #endif
 
-static int parse_table(int *, int, void *, size_t *, void *, size_t,
+static int parse_table(int __user *, int, void __user *, size_t __user *, void __user *, size_t,
 		       ctl_table *, void **);
 static int proc_doutsstring(ctl_table *table, int write, struct file *filp,
-		  void *buffer, size_t *lenp);
+		  void __user *buffer, size_t *lenp);
 
 static ctl_table root_table[];
 static struct ctl_table_header root_table_header =
@@ -127,8 +127,8 @@
 
 #ifdef CONFIG_PROC_FS
 
-static ssize_t proc_readsys(struct file *, char *, size_t, loff_t *);
-static ssize_t proc_writesys(struct file *, const char *, size_t, loff_t *);
+static ssize_t proc_readsys(struct file *, char __user *, size_t, loff_t *);
+static ssize_t proc_writesys(struct file *, const char __user *, size_t, loff_t *);
 static int proc_sys_permission(struct inode *, int);
 
 struct file_operations proc_sys_file_operations = {
@@ -374,8 +374,8 @@
 #endif
 }
 
-int do_sysctl(int *name, int nlen, void *oldval, size_t *oldlenp,
-	       void *newval, size_t newlen)
+int do_sysctl(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp,
+	       void __user *newval, size_t newlen)
 {
 	struct list_head *tmp;
 
@@ -443,7 +443,7 @@
 	return test_perm(table->mode, op);
 }
 
-static int parse_table(int *name, int nlen,
+static int parse_table(int __user *name, int nlen,
 		       void __user *oldval, size_t __user *oldlenp,
 		       void __user *newval, size_t newlen,
 		       ctl_table *table, void **context)
@@ -484,7 +484,7 @@
 
 /* Perform the actual read/write of a sysctl table entry. */
 int do_sysctl_strategy (ctl_table *table, 
-			int *name, int nlen,
+			int __user *name, int nlen,
 			void __user *oldval, size_t __user *oldlenp,
 			void __user *newval, size_t newlen, void **context)
 {
@@ -721,7 +721,7 @@
 	}
 }
 
-static ssize_t do_rw_proc(int write, struct file * file, char * buf,
+static ssize_t do_rw_proc(int write, struct file * file, char __user * buf,
 			  size_t count, loff_t *ppos)
 {
 	int op;
@@ -752,16 +752,16 @@
 	return res;
 }
 
-static ssize_t proc_readsys(struct file * file, char * buf,
+static ssize_t proc_readsys(struct file * file, char __user * buf,
 			    size_t count, loff_t *ppos)
 {
 	return do_rw_proc(0, file, buf, count, ppos);
 }
 
-static ssize_t proc_writesys(struct file * file, const char * buf,
+static ssize_t proc_writesys(struct file * file, const char __user * buf,
 			     size_t count, loff_t *ppos)
 {
-	return do_rw_proc(1, file, (char *) buf, count, ppos);
+	return do_rw_proc(1, file, (char __user *) buf, count, ppos);
 }
 
 static int proc_sys_permission(struct inode *inode, int op)
@@ -1345,7 +1345,7 @@
  */
 
 /* The generic string strategy routine: */
-int sysctl_string(ctl_table *table, int *name, int nlen,
+int sysctl_string(ctl_table *table, int __user *name, int nlen,
 		  void __user *oldval, size_t __user *oldlenp,
 		  void __user *newval, size_t newlen, void **context)
 {
@@ -1388,9 +1388,9 @@
  * are between the minimum and maximum values given in the arrays
  * table->extra1 and table->extra2, respectively.
  */
-int sysctl_intvec(ctl_table *table, int *name, int nlen,
-		void *oldval, size_t *oldlenp,
-		void *newval, size_t newlen, void **context)
+int sysctl_intvec(ctl_table *table, int __user *name, int nlen,
+		void __user *oldval, size_t __user *oldlenp,
+		void __user *newval, size_t newlen, void **context)
 {
 	int i, *vec, *min, *max;
 	size_t length;
@@ -1423,9 +1423,9 @@
 }
 
 /* Strategy function to convert jiffies to seconds */ 
-int sysctl_jiffies(ctl_table *table, int *name, int nlen,
-		void *oldval, size_t *oldlenp,
-		void *newval, size_t newlen, void **context)
+int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
+		void __user *oldval, size_t __user *oldlenp,
+		void __user *newval, size_t newlen, void **context)
 {
 	if (oldval) {
 		size_t olen;
@@ -1459,47 +1459,47 @@
 	return -ENOSYS;
 }
 
-int sysctl_string(ctl_table *table, int *name, int nlen,
-		  void *oldval, size_t *oldlenp,
-		  void *newval, size_t newlen, void **context)
+int sysctl_string(ctl_table *table, int __user *name, int nlen,
+		  void __user *oldval, size_t __user *oldlenp,
+		  void __user *newval, size_t newlen, void **context)
 {
 	return -ENOSYS;
 }
 
-int sysctl_intvec(ctl_table *table, int *name, int nlen,
-		void *oldval, size_t *oldlenp,
-		void *newval, size_t newlen, void **context)
+int sysctl_intvec(ctl_table *table, int __user *name, int nlen,
+		void __user *oldval, size_t __user *oldlenp,
+		void __user *newval, size_t newlen, void **context)
 {
 	return -ENOSYS;
 }
 
-int sysctl_jiffies(ctl_table *table, int *name, int nlen,
-		void *oldval, size_t *oldlenp,
-		void *newval, size_t newlen, void **context)
+int sysctl_jiffies(ctl_table *table, int __user *name, int nlen,
+		void __user *oldval, size_t __user *oldlenp,
+		void __user *newval, size_t newlen, void **context)
 {
 	return -ENOSYS;
 }
 
 int proc_dostring(ctl_table *table, int write, struct file *filp,
-		  void *buffer, size_t *lenp)
+		  void __user *buffer, size_t *lenp)
 {
 	return -ENOSYS;
 }
 
 int proc_dointvec(ctl_table *table, int write, struct file *filp,
-		  void *buffer, size_t *lenp)
+		  void __user *buffer, size_t *lenp)
 {
 	return -ENOSYS;
 }
 
 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
-			void *buffer, size_t *lenp)
+			void __user *buffer, size_t *lenp)
 {
 	return -ENOSYS;
 }
 
 int proc_dointvec_minmax(ctl_table *table, int write, struct file *filp,
-		    void *buffer, size_t *lenp)
+		    void __user *buffer, size_t *lenp)
 {
 	return -ENOSYS;
 }
@@ -1511,14 +1511,14 @@
 }
 
 int proc_doulongvec_minmax(ctl_table *table, int write, struct file *filp,
-		    void *buffer, size_t *lenp)
+		    void __user *buffer, size_t *lenp)
 {
 	return -ENOSYS;
 }
 
 int proc_doulongvec_ms_jiffies_minmax(ctl_table *table, int write,
 				      struct file *filp,
-				      void *buffer, size_t *lenp)
+				      void __user *buffer, size_t *lenp)
 {
     return -ENOSYS;
 }
diff -Nru a/kernel/timer.c b/kernel/timer.c
--- a/kernel/timer.c	Sat Apr 19 23:22:24 2003
+++ b/kernel/timer.c	Mon May 12 18:59:24 2003
@@ -905,7 +905,7 @@
 	parent = me->group_leader->real_parent;
 	for (;;) {
 		pid = parent->tgid;
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 {
 		struct task_struct *old = parent;
 
diff -Nru a/lib/Makefile b/lib/Makefile
--- a/lib/Makefile	Sat Apr 12 15:37:08 2003
+++ b/lib/Makefile	Mon May 12 13:20:36 2003
@@ -8,7 +8,7 @@
 
 L_TARGET := lib.a
 
-obj-y := errno.o ctype.o string.o vsprintf.o brlock.o cmdline.o \
+obj-y := errno.o ctype.o string.o vsprintf.o cmdline.o \
 	 bust_spinlocks.o rbtree.o radix-tree.o dump_stack.o \
 	 kobject.o idr.o
 
diff -Nru a/lib/brlock.c b/lib/brlock.c
--- a/lib/brlock.c	Wed Oct  9 12:49:56 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,72 +0,0 @@
-/*
- *
- * linux/lib/brlock.c
- *
- * 'Big Reader' read-write spinlocks.  See linux/brlock.h for details.
- *
- * Copyright 2000, Ingo Molnar <mingo@redhat.com>
- * Copyright 2000, David S. Miller <davem@redhat.com>
- */
-
-#include <linux/config.h>
-
-#ifdef CONFIG_SMP
-
-#include <linux/sched.h>
-#include <linux/brlock.h>
-
-#ifdef __BRLOCK_USE_ATOMICS
-
-brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX] =
-   { [0 ... NR_CPUS-1] = { [0 ... __BR_IDX_MAX-1] = RW_LOCK_UNLOCKED } };
-
-void __br_write_lock (enum brlock_indices idx)
-{
-	int i;
-
-	preempt_disable();
-	for (i = 0; i < NR_CPUS; i++)
-		_raw_write_lock(&__brlock_array[i][idx]);
-}
-
-void __br_write_unlock (enum brlock_indices idx)
-{
-	int i;
-
-	for (i = 0; i < NR_CPUS; i++)
-		_raw_write_unlock(&__brlock_array[i][idx]);
-	preempt_enable();
-}
-
-#else /* ! __BRLOCK_USE_ATOMICS */
-
-brlock_read_lock_t __brlock_array[NR_CPUS][__BR_IDX_MAX] =
-   { [0 ... NR_CPUS-1] = { [0 ... __BR_IDX_MAX-1] = 0 } };
-
-struct br_wrlock __br_write_locks[__BR_IDX_MAX] =
-   { [0 ... __BR_IDX_MAX-1] = { SPIN_LOCK_UNLOCKED } };
-
-void __br_write_lock (enum brlock_indices idx)
-{
-	int i;
-
-	preempt_disable();
-again:
-	_raw_spin_lock(&__br_write_locks[idx].lock);
-	for (i = 0; i < NR_CPUS; i++)
-		if (__brlock_array[i][idx] != 0) {
-			_raw_spin_unlock(&__br_write_locks[idx].lock);
-			barrier();
-			cpu_relax();
-			goto again;
-		}
-}
-
-void __br_write_unlock (enum brlock_indices idx)
-{
-	spin_unlock(&__br_write_locks[idx].lock);
-}
-
-#endif /* __BRLOCK_USE_ATOMICS */
-
-#endif /* CONFIG_SMP */
diff -Nru a/lib/inflate.c b/lib/inflate.c
--- a/lib/inflate.c	Mon Feb  4 23:38:17 2002
+++ b/lib/inflate.c	Thu May  8 06:26:47 2003
@@ -271,14 +271,15 @@
 STATIC unsigned hufts;         /* track memory usage */
 
 
-STATIC int huft_build(b, n, s, d, e, t, m)
-unsigned *b;            /* code lengths in bits (all assumed <= BMAX) */
-unsigned n;             /* number of codes (assumed <= N_MAX) */
-unsigned s;             /* number of simple-valued codes (0..s-1) */
-const ush *d;                 /* list of base values for non-simple codes */
-const ush *e;                 /* list of extra bits for non-simple codes */
-struct huft **t;        /* result: starting table */
-int *m;                 /* maximum lookup bits, returns actual */
+STATIC int huft_build(
+	unsigned *b,            /* code lengths in bits (all assumed <= BMAX) */
+	unsigned n,             /* number of codes (assumed <= N_MAX) */
+	unsigned s,             /* number of simple-valued codes (0..s-1) */
+	const ush *d,           /* list of base values for non-simple codes */
+	const ush *e,           /* list of extra bits for non-simple codes */
+	struct huft **t,        /* result: starting table */
+	int *m                  /* maximum lookup bits, returns actual */
+	)
 /* Given a list of code lengths and a maximum table size, make a set of
    tables to decode that set of codes.  Return zero on success, one if
    the given code set is incomplete (the tables are still built in this
@@ -489,8 +490,9 @@
 
 
 
-STATIC int huft_free(t)
-struct huft *t;         /* table to free */
+STATIC int huft_free(
+	struct huft *t         /* table to free */
+	)
 /* Free the malloc'ed tables built by huft_build(), which makes a linked
    list of the tables it made, with the links in a dummy first entry of
    each table. */
@@ -510,9 +512,12 @@
 }
 
 
-STATIC int inflate_codes(tl, td, bl, bd)
-struct huft *tl, *td;   /* literal/length and distance decoder tables */
-int bl, bd;             /* number of bits decoded by tl[] and td[] */
+STATIC int inflate_codes(
+	struct huft *tl,    /* literal/length decoder tables */
+	struct huft *td,    /* distance decoder tables */
+	int bl,             /* number of bits decoded by tl[] */
+	int bd              /* number of bits decoded by td[] */
+	)
 /* inflate (decompress) the codes in a deflated (compressed) block.
    Return an error code or zero if it all goes ok. */
 {
@@ -619,7 +624,7 @@
 
 
 
-STATIC int inflate_stored()
+STATIC int inflate_stored(void)
 /* "decompress" an inflated type 0 (stored) block. */
 {
   unsigned n;           /* number of bytes in block */
@@ -675,7 +680,7 @@
 
 
 
-STATIC int inflate_fixed()
+STATIC int inflate_fixed(void)
 /* decompress an inflated type 1 (fixed Huffman codes) block.  We should
    either replace this with a custom decoder, or at least precompute the
    Huffman tables. */
@@ -729,7 +734,7 @@
 
 
 
-STATIC int inflate_dynamic()
+STATIC int inflate_dynamic(void)
 /* decompress an inflated type 2 (dynamic Huffman codes) block. */
 {
   int i;                /* temporary variables */
@@ -907,8 +912,9 @@
 
 
 
-STATIC int inflate_block(e)
-int *e;                 /* last block flag */
+STATIC int inflate_block(
+	int *e                  /* last block flag */
+	)
 /* decompress an inflated block */
 {
   unsigned t;           /* block type */
@@ -954,7 +960,7 @@
 
 
 
-STATIC int inflate()
+STATIC int inflate(void)
 /* decompress an inflated entry */
 {
   int e;                /* last block flag */
@@ -1009,7 +1015,7 @@
 
 static ulg crc_32_tab[256];
 static ulg crc;		/* initialized in makecrc() so it'll reside in bss */
-#define CRC_VALUE (crc ^ 0xffffffffL)
+#define CRC_VALUE (crc ^ 0xffffffffUL)
 
 /*
  * Code to compute the CRC-32 table. Borrowed from 
@@ -1049,7 +1055,7 @@
   }
 
   /* this is initialized here so this code could reside in ROM */
-  crc = (ulg)0xffffffffL; /* shift register contents */
+  crc = (ulg)0xffffffffUL; /* shift register contents */
 }
 
 /* gzip flag byte */
diff -Nru a/lib/kobject.c b/lib/kobject.c
--- a/lib/kobject.c	Mon Apr 28 22:26:24 2003
+++ b/lib/kobject.c	Mon May 12 15:31:04 2003
@@ -290,7 +290,11 @@
 	if (kobj) {
 		kobject_init(kobj);
 		error = kobject_add(kobj);
-		WARN_ON(error);
+		if (error) {
+			printk("kobject_register failed for %s (%d)\n",
+			       kobj->name,error);
+			dump_stack();
+		}
 	} else
 		error = -EINVAL;
 	return error;
diff -Nru a/mm/bootmem.c b/mm/bootmem.c
--- a/mm/bootmem.c	Thu Apr 10 07:06:54 2003
+++ b/mm/bootmem.c	Mon May 12 14:35:19 2003
@@ -311,7 +311,7 @@
 
 void __init free_bootmem_node (pg_data_t *pgdat, unsigned long physaddr, unsigned long size)
 {
-	return(free_bootmem_core(pgdat->bdata, physaddr, size));
+	free_bootmem_core(pgdat->bdata, physaddr, size);
 }
 
 unsigned long __init free_all_bootmem_node (pg_data_t *pgdat)
@@ -336,7 +336,7 @@
 
 void __init free_bootmem (unsigned long addr, unsigned long size)
 {
-	return(free_bootmem_core(contig_page_data.bdata, addr, size));
+	free_bootmem_core(contig_page_data.bdata, addr, size);
 }
 
 unsigned long __init free_all_bootmem (void)
diff -Nru a/mm/filemap.c b/mm/filemap.c
--- a/mm/filemap.c	Sat Apr 19 23:22:33 2003
+++ b/mm/filemap.c	Mon May 12 14:35:19 2003
@@ -681,7 +681,7 @@
 	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
 	if (cached_page)
 		page_cache_release(cached_page);
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 }
 
 int file_read_actor(read_descriptor_t *desc, struct page *page,
@@ -774,7 +774,7 @@
 			if (retval > 0)
 				*ppos = pos + retval;
 		}
-		UPDATE_ATIME(filp->f_dentry->d_inode);
+		update_atime(filp->f_dentry->d_inode);
 		goto out;
 	}
 
@@ -802,7 +802,7 @@
 }
 
 ssize_t
-generic_file_aio_read(struct kiocb *iocb, char *buf, size_t count, loff_t pos)
+generic_file_aio_read(struct kiocb *iocb, char __user *buf, size_t count, loff_t pos)
 {
 	struct iovec local_iov = { .iov_base = buf, .iov_len = count };
 
@@ -812,7 +812,7 @@
 EXPORT_SYMBOL(generic_file_aio_read);
 
 ssize_t
-generic_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+generic_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
 {
 	struct iovec local_iov = { .iov_base = buf, .iov_len = count };
 	struct kiocb kiocb;
@@ -846,7 +846,7 @@
 }
 
 ssize_t generic_file_sendfile(struct file *in_file, loff_t *ppos,
-			 size_t count, read_actor_t actor, void *target)
+			 size_t count, read_actor_t actor, void __user *target)
 {
 	read_descriptor_t desc;
 
@@ -1259,7 +1259,7 @@
 
 	if (!mapping->a_ops->readpage)
 		return -ENOEXEC;
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 	vma->vm_ops = &generic_file_vm_ops;
 	return 0;
 }
@@ -1412,7 +1412,7 @@
 
 static inline int
 filemap_copy_from_user(struct page *page, unsigned long offset,
-			const char *buf, unsigned bytes)
+			const char __user *buf, unsigned bytes)
 {
 	char *kaddr;
 	int left;
@@ -1437,7 +1437,7 @@
 	int left = 0;
 
 	while (bytes) {
-		char *buf = iov->iov_base + base;
+		char __user *buf = iov->iov_base + base;
 		int copy = min(bytes, iov->iov_len - base);
 		base = 0;
 		if ((left = __copy_from_user(vaddr, buf, copy)))
@@ -1601,7 +1601,7 @@
 	const struct iovec *cur_iov = iov; /* current iovec */
 	size_t		iov_base = 0;	   /* offset in the current iovec */
 	unsigned long	seg;
-	char		*buf;
+	char __user	*buf;
 
 	ocount = 0;
 	for (seg = 0; seg < nr_segs; seg++) {
@@ -1775,13 +1775,13 @@
 	return ret;
 }
 
-ssize_t generic_file_aio_write(struct kiocb *iocb, const char *buf,
+ssize_t generic_file_aio_write(struct kiocb *iocb, const char __user *buf,
 			       size_t count, loff_t pos)
 {
 	struct file *file = iocb->ki_filp;
 	struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
 	ssize_t err;
-	struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count };
+	struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
 
 	BUG_ON(iocb->ki_pos != pos);
 
@@ -1795,12 +1795,12 @@
 EXPORT_SYMBOL(generic_file_aio_write);
 EXPORT_SYMBOL(generic_file_aio_write_nolock);
 
-ssize_t generic_file_write(struct file *file, const char *buf,
+ssize_t generic_file_write(struct file *file, const char __user *buf,
 			   size_t count, loff_t *ppos)
 {
 	struct inode	*inode = file->f_dentry->d_inode->i_mapping->host;
 	ssize_t		err;
-	struct iovec local_iov = { .iov_base = (void *)buf, .iov_len = count };
+	struct iovec local_iov = { .iov_base = (void __user *)buf, .iov_len = count };
 
 	down(&inode->i_sem);
 	err = generic_file_write_nolock(file, &local_iov, 1, ppos);
diff -Nru a/mm/memory.c b/mm/memory.c
--- a/mm/memory.c	Sat May  3 06:15:07 2003
+++ b/mm/memory.c	Sat May 17 14:09:39 2003
@@ -1108,17 +1108,12 @@
 	if (inode->i_size < offset)
 		goto do_expand;
 	inode->i_size = offset;
+	pgoff = (offset + PAGE_SIZE - 1) >> PAGE_SHIFT;
 	down(&mapping->i_shared_sem);
-	if (list_empty(&mapping->i_mmap) && list_empty(&mapping->i_mmap_shared))
-		goto out_unlock;
-
-	pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
-	if (!list_empty(&mapping->i_mmap))
+	if (unlikely(!list_empty(&mapping->i_mmap)))
 		vmtruncate_list(&mapping->i_mmap, pgoff);
-	if (!list_empty(&mapping->i_mmap_shared))
+	if (unlikely(!list_empty(&mapping->i_mmap_shared)))
 		vmtruncate_list(&mapping->i_mmap_shared, pgoff);
-
-out_unlock:
 	up(&mapping->i_shared_sem);
 	truncate_inode_pages(mapping, offset);
 	goto out_truncate;
diff -Nru a/mm/mincore.c b/mm/mincore.c
--- a/mm/mincore.c	Mon Apr 29 15:18:35 2002
+++ b/mm/mincore.c	Mon May 12 14:35:19 2003
@@ -39,7 +39,7 @@
 }
 
 static long mincore_vma(struct vm_area_struct * vma,
-	unsigned long start, unsigned long end, unsigned char * vec)
+	unsigned long start, unsigned long end, unsigned char __user * vec)
 {
 	long error, i, remaining;
 	unsigned char * tmp;
@@ -106,7 +106,7 @@
  *  -EAGAIN - A kernel resource was temporarily unavailable.
  */
 asmlinkage long sys_mincore(unsigned long start, size_t len,
-	unsigned char * vec)
+	unsigned char __user * vec)
 {
 	int index = 0;
 	unsigned long end;
diff -Nru a/mm/mmap.c b/mm/mmap.c
--- a/mm/mmap.c	Wed Apr 23 08:50:32 2003
+++ b/mm/mmap.c	Mon May 12 21:23:18 2003
@@ -471,6 +471,8 @@
 			spin_unlock(lock);
 			if (need_up)
 				up(&inode->i_mapping->i_shared_sem);
+			if (file)
+				fput(file);
 
 			mm->map_count--;
 			kmem_cache_free(vm_area_cachep, next);
@@ -1440,7 +1442,7 @@
 	vm_unacct_memory(nr_accounted);
 	BUG_ON(mm->map_count);	/* This is just debugging */
 	clear_page_tables(tlb, FIRST_USER_PGD_NR, USER_PTRS_PER_PGD);
-	tlb_finish_mmu(tlb, 0, TASK_SIZE);
+	tlb_finish_mmu(tlb, 0, MM_VM_SIZE(mm));
 
 	vma = mm->mmap;
 	mm->mmap = mm->mmap_cache = NULL;
diff -Nru a/mm/page-writeback.c b/mm/page-writeback.c
--- a/mm/page-writeback.c	Sat Apr 19 23:22:32 2003
+++ b/mm/page-writeback.c	Fri May  9 02:51:01 2003
@@ -20,7 +20,6 @@
 #include <linux/pagemap.h>
 #include <linux/writeback.h>
 #include <linux/init.h>
-#include <linux/sysrq.h>
 #include <linux/backing-dev.h>
 #include <linux/blkdev.h>
 #include <linux/mpage.h>
@@ -237,7 +236,6 @@
 		.nonblocking	= 1,
 	};
 
-	CHECK_EMERGENCY_SYNC
 	for ( ; ; ) {
 		struct page_state ps;
 		long background_thresh;
@@ -272,7 +270,7 @@
 		struct page_state ps;
 
 		get_page_state(&ps);
-		nr_pages = ps.nr_dirty;
+		nr_pages = ps.nr_dirty + ps.nr_unstable;
 	}
 	return pdflush_operation(background_writeout, nr_pages);
 }
diff -Nru a/mm/page_alloc.c b/mm/page_alloc.c
--- a/mm/page_alloc.c	Sat Apr 19 23:22:40 2003
+++ b/mm/page_alloc.c	Tue May 13 03:59:33 2003
@@ -336,21 +336,17 @@
 static struct page *__rmqueue(struct zone *zone, unsigned int order)
 {
 	struct free_area * area;
-	unsigned int current_order = order;
-	struct list_head *head, *curr;
+	unsigned int current_order;
 	struct page *page;
 	unsigned int index;
 
-	for (current_order=order; current_order < MAX_ORDER; ++current_order) {
+	for (current_order = order; current_order < MAX_ORDER; ++current_order) {
 		area = zone->free_area + current_order;
-		head = &area->free_list;
-		curr = head->next;
-
 		if (list_empty(&area->free_list))
 			continue;
 
-		page = list_entry(curr, struct page, list);
-		list_del(curr);
+		page = list_entry(area->free_list.next, struct page, list);
+		list_del(&page->list);
 		index = page - zone->zone_mem_map;
 		if (current_order != MAX_ORDER-1)
 			MARK_USED(index, current_order, area);
@@ -537,6 +533,7 @@
 	int i;
 	int cold;
 	int do_retry;
+	struct reclaim_state reclaim_state;
 
 	if (wait)
 		might_sleep();
@@ -608,7 +605,12 @@
 		goto nopage;
 
 	current->flags |= PF_MEMALLOC;
+	reclaim_state.reclaimed_slab = 0;
+	current->reclaim_state = &reclaim_state;
+
 	try_to_free_pages(classzone, gfp_mask, order);
+
+	current->reclaim_state = NULL;
 	current->flags &= ~PF_MEMALLOC;
 
 	/* go through the zonelist yet one more time */
@@ -786,7 +788,7 @@
 	return nr_free_zone_pages(GFP_HIGHUSER & GFP_ZONEMASK);
 }
 
-#if CONFIG_HIGHMEM
+#ifdef CONFIG_HIGHMEM
 unsigned int nr_free_highpages (void)
 {
 	pg_data_t *pgdat;
@@ -1039,7 +1041,7 @@
 
 	local_node = pgdat->node_id;
 	printk("Building zonelist for node : %d\n", local_node);
-	for (i = 0; i <= GFP_ZONEMASK; i++) {
+	for (i = 0; i < MAX_NR_ZONES; i++) {
 		struct zonelist *zonelist;
 
 		zonelist = pgdat->node_zonelists + i;
diff -Nru a/mm/shmem.c b/mm/shmem.c
--- a/mm/shmem.c	Sat Apr 12 16:21:01 2003
+++ b/mm/shmem.c	Mon May 12 14:35:19 2003
@@ -1013,7 +1013,7 @@
 	ops = &shmem_vm_ops;
 	if (!inode->i_sb || !S_ISREG(inode->i_mode))
 		return -EACCES;
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 	vma->vm_ops = ops;
 	return 0;
 }
@@ -1114,7 +1114,7 @@
 }
 
 static ssize_t
-shmem_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
+shmem_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
 {
 	struct inode	*inode = file->f_dentry->d_inode;
 	loff_t		pos;
@@ -1307,10 +1307,10 @@
 	}
 
 	*ppos = ((loff_t) index << PAGE_CACHE_SHIFT) + offset;
-	UPDATE_ATIME(inode);
+	update_atime(inode);
 }
 
-static ssize_t shmem_file_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+static ssize_t shmem_file_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos)
 {
 	read_descriptor_t desc;
 
@@ -1333,7 +1333,7 @@
 }
 
 static ssize_t shmem_file_sendfile(struct file *in_file, loff_t *ppos,
-			 size_t count, read_actor_t actor, void *target)
+			 size_t count, read_actor_t actor, void __user *target)
 {
 	read_descriptor_t desc;
 
@@ -1519,7 +1519,7 @@
 	return 0;
 }
 
-static int shmem_readlink_inline(struct dentry *dentry, char *buffer, int buflen)
+static int shmem_readlink_inline(struct dentry *dentry, char __user *buffer, int buflen)
 {
 	return vfs_readlink(dentry, buffer, buflen, (const char *)SHMEM_I(dentry->d_inode));
 }
@@ -1529,7 +1529,7 @@
 	return vfs_follow_link(nd, (const char *)SHMEM_I(dentry->d_inode));
 }
 
-static int shmem_readlink(struct dentry *dentry, char *buffer, int buflen)
+static int shmem_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 {
 	struct page *page = NULL;
 	int res = shmem_getpage(dentry->d_inode, 0, &page, SGP_READ);
diff -Nru a/mm/slab.c b/mm/slab.c
--- a/mm/slab.c	Thu Apr 10 10:14:16 2003
+++ b/mm/slab.c	Mon May 12 21:22:40 2003
@@ -76,6 +76,7 @@
 #include	<linux/config.h>
 #include	<linux/slab.h>
 #include	<linux/mm.h>
+#include	<linux/swap.h>
 #include	<linux/cache.h>
 #include	<linux/interrupt.h>
 #include	<linux/init.h>
@@ -567,11 +568,40 @@
 	return cachep->array[smp_processor_id()];
 }
 
-/* Initialisation - setup the `cache' cache. */
+/* Initialisation.
+ * Called after the gfp() functions have been enabled, and before smp_init().
+ */
 void __init kmem_cache_init(void)
 {
 	size_t left_over;
+	struct cache_sizes *sizes;
+	struct cache_names *names;
 
+	/*
+	 * Fragmentation resistance on low memory - only use bigger
+	 * page orders on machines with more than 32MB of memory.
+	 */
+	if (num_physpages > (32 << 20) >> PAGE_SHIFT)
+		slab_break_gfp_order = BREAK_GFP_ORDER_HI;
+
+	
+	/* Bootstrap is tricky, because several objects are allocated
+	 * from caches that do not exist yet:
+	 * 1) initialize the cache_cache cache: it contains the kmem_cache_t
+	 *    structures of all caches, except cache_cache itself: cache_cache
+	 *    is statically allocated.
+	 *    Initially an __init data area is used for the head array, it's
+	 *    replaced with a kmalloc allocated array at the end of the bootstrap.
+	 * 2) Create the first kmalloc cache.
+	 *    The kmem_cache_t for the new cache is allocated normally. An __init
+	 *    data area is used for the head array.
+	 * 3) Create the remaining kmalloc caches, with minimally sized head arrays.
+	 * 4) Replace the __init data head arrays for cache_cache and the first
+	 *    kmalloc cache with kmalloc allocated arrays.
+	 * 5) Resize the head arrays of the kmalloc caches to their final sizes.
+	 */
+
+	/* 1) create the cache_cache */
 	init_MUTEX(&cache_chain_sem);
 	INIT_LIST_HEAD(&cache_chain);
 	list_add(&cache_cache.next, &cache_chain);
@@ -585,27 +615,10 @@
 	cache_cache.colour = left_over/cache_cache.colour_off;
 	cache_cache.colour_next = 0;
 
-	/* Register a cpu startup notifier callback
-	 * that initializes ac_data for all new cpus
-	 */
-	register_cpu_notifier(&cpucache_notifier);
-}
-
 
-/* Initialisation - setup remaining internal and general caches.
- * Called after the gfp() functions have been enabled, and before smp_init().
- */
-void __init kmem_cache_sizes_init(void)
-{
-	struct cache_sizes *sizes = malloc_sizes;
-	struct cache_names *names = cache_names;
-
-	/*
-	 * Fragmentation resistance on low memory - only use bigger
-	 * page orders on machines with more than 32MB of memory.
-	 */
-	if (num_physpages > (32 << 20) >> PAGE_SHIFT)
-		slab_break_gfp_order = BREAK_GFP_ORDER_HI;
+	/* 2+3) create the kmalloc caches */
+	sizes = malloc_sizes;
+	names = cache_names;
 
 	while (sizes->cs_size) {
 		/* For performance, all the general caches are L1 aligned.
@@ -634,10 +647,7 @@
 		sizes++;
 		names++;
 	}
-	/*
-	 * The generic caches are running - time to kick out the
-	 * bootstrap cpucaches.
-	 */
+	/* 4) Replace the bootstrap head arrays */
 	{
 		void * ptr;
 		
@@ -656,29 +666,42 @@
 		malloc_sizes[0].cs_cachep->array[smp_processor_id()] = ptr;
 		local_irq_enable();
 	}
+
+	/* 5) resize the head arrays to their final sizes */
+	{
+		kmem_cache_t *cachep;
+		down(&cache_chain_sem);
+		list_for_each_entry(cachep, &cache_chain, next)
+			enable_cpucache(cachep);
+		up(&cache_chain_sem);
+	}
+
+	/* Done! */
+	g_cpucache_up = FULL;
+
+	/* Register a cpu startup notifier callback
+	 * that initializes ac_data for all new cpus
+	 */
+	register_cpu_notifier(&cpucache_notifier);
+	
+
+	/* The reap timers are started later, with a module init call:
+	 * That part of the kernel is not yet operational.
+	 */
 }
 
 int __init cpucache_init(void)
 {
-	kmem_cache_t *cachep;
 	int cpu;
 
-	down(&cache_chain_sem);
-	g_cpucache_up = FULL;
-
-	list_for_each_entry(cachep, &cache_chain, next)
-		enable_cpucache(cachep);
-	
 	/* 
 	 * Register the timers that return unneeded
 	 * pages to gfp.
 	 */
-
 	for (cpu = 0; cpu < NR_CPUS; cpu++) {
 		if (cpu_online(cpu))
 			start_cpu_timer(cpu);
 	}
-	up(&cache_chain_sem);
 
 	return 0;
 }
@@ -712,6 +735,7 @@
 {
 	unsigned long i = (1<<cachep->gfporder);
 	struct page *page = virt_to_page(addr);
+	const unsigned long nr_freed = i;
 
 	/* free_pages() does not clear the type bit - we do that.
 	 * The pages have been unlinked from their cache-slab,
@@ -720,9 +744,11 @@
 	 */
 	while (i--) {
 		ClearPageSlab(page);
-		dec_page_state(nr_slab);
 		page++;
 	}
+	sub_page_state(nr_slab, nr_freed);
+	if (current->reclaim_state)
+		current->reclaim_state->reclaimed_slab += nr_freed;
 	free_pages((unsigned long)addr, cachep->gfporder);
 }
 
@@ -914,12 +940,19 @@
 	}
 
 #if FORCED_DEBUG
-	if ((size < (PAGE_SIZE>>3)) && !(flags & SLAB_MUST_HWCACHE_ALIGN))
-		/*
-		 * do not red zone large object, causes severe
-		 * fragmentation.
-		 */
+	/*
+	 * Enable redzoning and last user accounting, except
+	 * - for caches with forced alignment: redzoning would violate the
+	 *   alignment
+	 * - for caches with large objects, if the increased size would
+	 *   increase the object size above the next power of two: caches
+	 *   with object sizes just above a power of two have a significant
+	 *   amount of internal fragmentation
+	 */
+	if ((size < 4096 || fls(size-1) == fls(size-1+3*BYTES_PER_WORD))
+			&& !(flags & SLAB_MUST_HWCACHE_ALIGN)) {
 		flags |= SLAB_RED_ZONE|SLAB_STORE_USER;
+	}
 	flags |= SLAB_POISON;
 #endif
 #endif
@@ -1756,10 +1789,12 @@
 		slabp = GET_PAGE_SLAB(virt_to_page(objp));
 		list_del(&slabp->list);
 		objnr = (objp - slabp->s_mem) / cachep->objsize;
+		check_slabp(cachep, slabp);
 		slab_bufctl(slabp)[objnr] = slabp->free;
 		slabp->free = objnr;
 		STATS_DEC_ACTIVE(cachep);
 		slabp->inuse--;
+		check_slabp(cachep, slabp);
 
 		/* fixup slab chains */
 		if (slabp->inuse == 0) {
@@ -2413,7 +2448,7 @@
  * @count: data len
  * @data: unused
  */
-ssize_t slabinfo_write(struct file *file, const char *buffer,
+ssize_t slabinfo_write(struct file *file, const char __user *buffer,
 				size_t count, loff_t *ppos)
 {
 	char kbuf[MAX_SLABINFO_WRITE+1], *tmp;
diff -Nru a/mm/swapfile.c b/mm/swapfile.c
--- a/mm/swapfile.c	Sat Apr 19 23:22:46 2003
+++ b/mm/swapfile.c	Mon May 19 09:02:40 2003
@@ -886,6 +886,10 @@
  * requirements, they are simply tossed out - we will never use those blocks
  * for swapping.
  *
+ * For S_ISREG swapfiles we hold i_sem across the life of the swapon.  This
+ * prevents root from shooting her foot off by ftruncating an in-use swapfile,
+ * which will scribble on the fs.
+ *
  * The amount of disk space which a single swap extent represents varies.
  * Typically it is in the 1-4 megabyte range.  So we can have hundreds of
  * extents in the list.  To avoid much list walking, we cache the previous
@@ -1095,6 +1099,8 @@
 		bdev = swap_file->f_dentry->d_inode->i_bdev;
 		set_blocksize(bdev, p->old_block_size);
 		bd_release(bdev);
+	} else {
+		up(&swap_file->f_dentry->d_inode->i_mapping->host->i_sem);
 	}
 	filp_close(swap_file, NULL);
 	err = 0;
@@ -1112,14 +1118,9 @@
 	struct swap_info_struct *ptr = swap_info;
 	int i;
 	loff_t l = *pos;
-	char * page = (char *) __get_free_page(GFP_KERNEL);
 
-	swap->private = page;	/* save for swap_show */
 	swap_list_lock();
 
-	if (!page)
-		return ERR_PTR(-ENOMEM);
-
 	for (i = 0; i < nr_swapfiles; i++, ptr++) {
 		if (!(ptr->flags & SWP_USED) || !ptr->swap_map)
 			continue;
@@ -1148,24 +1149,21 @@
 static void swap_stop(struct seq_file *swap, void *v)
 {
 	swap_list_unlock();
-	free_page((unsigned long) swap->private);
-	swap->private = NULL;
 }
 
 static int swap_show(struct seq_file *swap, void *v)
 {
 	struct swap_info_struct *ptr = v;
 	struct file *file;
-	char *path;
+	int len;
 
 	if (v == swap_info)
 		seq_puts(swap, "Filename\t\t\t\tType\t\tSize\tUsed\tPriority\n");
 
 	file = ptr->swap_file;
-	path = d_path(file->f_dentry, file->f_vfsmnt, swap->private, PAGE_SIZE);
-
-	seq_printf(swap, "%-39s %s\t%d\t%ld\t%d\n",
-		       path,
+	len = seq_path(swap, file->f_vfsmnt, file->f_dentry, " \t\n\\");
+	seq_printf(swap, "%*s %s\t%d\t%ld\t%d\n",
+		       len < 40 ? 40 - len : 1, " ",
 		       S_ISBLK(file->f_dentry->d_inode->i_mode) ?
 				"partition" : "file\t",
 		       ptr->pages << (PAGE_SHIFT - 10),
@@ -1228,6 +1226,8 @@
 	int swapfilesize;
 	unsigned short *swap_map;
 	struct page *page = NULL;
+	struct inode *inode;
+	struct inode *downed_inode = NULL;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -1274,39 +1274,42 @@
 	}
 
 	p->swap_file = swap_file;
+	inode = swap_file->f_dentry->d_inode;
+	mapping = swap_file->f_dentry->d_inode->i_mapping;
+
+	error = -EBUSY;
+	for (i = 0; i < nr_swapfiles; i++) {
+		struct swap_info_struct *q = &swap_info[i];
+
+		if (i == type || !q->swap_file)
+			continue;
+		if (mapping == q->swap_file->f_dentry->d_inode->i_mapping)
+			goto bad_swap;
+	}
 
 	error = -EINVAL;
-	if (S_ISBLK(swap_file->f_dentry->d_inode->i_mode)) {
-		bdev = swap_file->f_dentry->d_inode->i_bdev;
+	if (S_ISBLK(inode->i_mode)) {
+		bdev = inode->i_bdev;
 		error = bd_claim(bdev, sys_swapon);
 		if (error < 0) {
 			bdev = NULL;
 			goto bad_swap;
 		}
 		p->old_block_size = block_size(bdev);
-		error = set_blocksize(swap_file->f_dentry->d_inode->i_bdev,
-				      PAGE_SIZE);
+		error = set_blocksize(inode->i_bdev, PAGE_SIZE);
 		if (error < 0)
 			goto bad_swap;
 		p->bdev = bdev;
-	} else if (S_ISREG(swap_file->f_dentry->d_inode->i_mode)) {
-		p->bdev = swap_file->f_dentry->d_inode->i_sb->s_bdev;
+	} else if (S_ISREG(inode->i_mode)) {
+		p->bdev = inode->i_sb->s_bdev;
+		downed_inode = mapping->host;
+		down(&downed_inode->i_sem);
 	} else {
 		goto bad_swap;
 	}
 
-	mapping = swap_file->f_dentry->d_inode->i_mapping;
 	swapfilesize = mapping->host->i_size >> PAGE_SHIFT;
 
-	error = -EBUSY;
-	for (i = 0 ; i < nr_swapfiles ; i++) {
-		struct swap_info_struct *q = &swap_info[i];
-		if (i == type || !q->swap_file)
-			continue;
-		if (mapping == q->swap_file->f_dentry->d_inode->i_mapping)
-			goto bad_swap;
-	}
-
 	/*
 	 * Read the swap header.
 	 */
@@ -1452,6 +1455,8 @@
 	}
 	if (name)
 		putname(name);
+	if (error && downed_inode)
+		up(&downed_inode->i_sem);
 	return error;
 }
 
diff -Nru a/mm/truncate.c b/mm/truncate.c
--- a/mm/truncate.c	Tue Apr  8 03:16:30 2003
+++ b/mm/truncate.c	Sat May 17 14:09:32 2003
@@ -173,15 +173,13 @@
 		}
 		pagevec_release(&pvec);
 	}
-	if (lstart == 0 && mapping->nrpages)
-		printk("%s: I goofed!\n", __FUNCTION__);
 }
 
 /**
  * invalidate_mapping_pages - Invalidate all the unlocked pages of one inode
- * @inode: the address_space which holds the pages to invalidate
- * @end: the index of the last page to invalidate (inclusive)
- * @nr_pages: defines the pagecache span.  Invalidate up to @start + @nr_pages
+ * @mapping: the address_space which holds the pages to invalidate
+ * @start: the offset 'from' which to invalidate
+ * @end: the offset 'to' which to invalidate (inclusive)
  *
  * This function only removes the unlocked pages, if you want to
  * remove all the pages of one inode, you must call truncate_inode_pages.
diff -Nru a/mm/vmalloc.c b/mm/vmalloc.c
--- a/mm/vmalloc.c	Sat Apr 19 23:22:50 2003
+++ b/mm/vmalloc.c	Mon May 12 21:23:25 2003
@@ -97,8 +97,7 @@
 	do {
 		struct page *page = **pages;
 
-		if (!pte_none(*pte))
-			printk(KERN_ERR "alloc_area_pte: page already exists\n");
+		WARN_ON(!pte_none(*pte));
 		if (!page)
 			return -ENOMEM;
 
@@ -261,6 +260,7 @@
 	return NULL;
 
 found:
+	unmap_vm_area(tmp);
 	*p = tmp->next;
 	write_unlock(&vmlist_lock);
 	return tmp;
@@ -284,8 +284,6 @@
 				addr);
 		return;
 	}
-
-	unmap_vm_area(area);
 	
 	if (deallocate_pages) {
 		int i;
diff -Nru a/mm/vmscan.c b/mm/vmscan.c
--- a/mm/vmscan.c	Wed Apr 23 21:49:44 2003
+++ b/mm/vmscan.c	Wed May  7 21:19:58 2003
@@ -817,12 +817,14 @@
  * excessive rotation of the inactive list, which is _supposed_ to be an LRU,
  * yes?
  */
-int try_to_free_pages(struct zone *classzone,
+int try_to_free_pages(struct zone *cz,
 		unsigned int gfp_mask, unsigned int order)
 {
 	int priority;
+	int ret = 0;
 	const int nr_pages = SWAP_CLUSTER_MAX;
 	int nr_reclaimed = 0;
+	struct reclaim_state *reclaim_state = current->reclaim_state;
 
 	inc_page_state(allocstall);
 
@@ -831,11 +833,12 @@
 		struct page_state ps;
 
 		get_page_state(&ps);
-		nr_reclaimed += shrink_caches(classzone, priority,
-					&total_scanned, gfp_mask,
-					nr_pages, &ps);
-		if (nr_reclaimed >= nr_pages)
-			return 1;
+		nr_reclaimed += shrink_caches(cz, priority, &total_scanned,
+						gfp_mask, nr_pages, &ps);
+		if (nr_reclaimed >= nr_pages) {
+			ret = 1;
+			goto out;
+		}
 		if (!(gfp_mask & __GFP_FS))
 			break;		/* Let the caller handle it */
 		/*
@@ -847,12 +850,18 @@
 
 		/* Take a nap, wait for some writeback to complete */
 		blk_congestion_wait(WRITE, HZ/10);
-		if (classzone - classzone->zone_pgdat->node_zones < ZONE_HIGHMEM)
+		if (cz - cz->zone_pgdat->node_zones < ZONE_HIGHMEM) {
 			shrink_slab(total_scanned, gfp_mask);
+			if (reclaim_state) {
+				nr_reclaimed += reclaim_state->reclaimed_slab;
+				reclaim_state->reclaimed_slab = 0;
+			}
+		}
 	}
 	if ((gfp_mask & __GFP_FS) && !(gfp_mask & __GFP_NORETRY))
 		out_of_memory();
-	return 0;
+out:
+	return ret;
 }
 
 /*
@@ -878,6 +887,7 @@
 	int to_free = nr_pages;
 	int priority;
 	int i;
+	struct reclaim_state *reclaim_state = current->reclaim_state;
 
 	inc_page_state(pageoutrun);
 
@@ -908,8 +918,11 @@
 				max_scan = SWAP_CLUSTER_MAX;
 			to_free -= shrink_zone(zone, max_scan, GFP_KERNEL,
 					to_reclaim, &nr_mapped, ps, priority);
-			if (i < ZONE_HIGHMEM)
+			if (i < ZONE_HIGHMEM) {
+				reclaim_state->reclaimed_slab = 0;
 				shrink_slab(max_scan + nr_mapped, GFP_KERNEL);
+				to_free += reclaim_state->reclaimed_slab;
+			}
 			if (zone->all_unreclaimable)
 				continue;
 			if (zone->pages_scanned > zone->present_pages * 2)
@@ -940,10 +953,14 @@
 	pg_data_t *pgdat = (pg_data_t*)p;
 	struct task_struct *tsk = current;
 	DEFINE_WAIT(wait);
+	struct reclaim_state reclaim_state = {
+		.reclaimed_slab = 0,
+	};
 
 	daemonize("kswapd%d", pgdat->node_id);
 	set_cpus_allowed(tsk, node_to_cpumask(pgdat->node_id));
-	
+	current->reclaim_state = &reclaim_state;
+
 	/*
 	 * Tell the memory management that we're a "memory allocator",
 	 * and that if we need more memory we should get access to it
diff -Nru a/net/8021q/vlan.c b/net/8021q/vlan.c
--- a/net/8021q/vlan.c	Sat May  3 16:59:12 2003
+++ b/net/8021q/vlan.c	Mon May 19 23:22:52 2003
@@ -454,7 +454,7 @@
 	/* set up method calls */
 	new_dev->init = vlan_dev_init;
 	new_dev->destructor = vlan_dev_destruct;
-	new_dev->owner = THIS_MODULE;
+	SET_MODULE_OWNER(new_dev);
 	    
 	/* new_dev->ifindex = 0;  it will be set when added to
 	 * the global list.
diff -Nru a/net/8021q/vlanproc.c b/net/8021q/vlanproc.c
--- a/net/8021q/vlanproc.c	Sun Mar  9 14:00:21 2003
+++ b/net/8021q/vlanproc.c	Sat May 10 11:49:46 2003
@@ -18,6 +18,7 @@
  *****************************************************************************/
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/kernel.h>
@@ -75,6 +76,7 @@
  */
 
 static struct file_operations vlan_fops = {
+	.owner = THIS_MODULE,
 	.read =	vlan_proc_read,
 	.ioctl = NULL, /* vlan_proc_ioctl */
 };
@@ -84,6 +86,7 @@
  */
 
 static struct file_operations vlandev_fops = {
+	.owner = THIS_MODULE,
 	.read =	vlan_proc_read,
 	.ioctl =NULL, /* vlan_proc_ioctl */
 };
diff -Nru a/net/Kconfig b/net/Kconfig
--- a/net/Kconfig	Sun Apr 20 12:56:51 2003
+++ b/net/Kconfig	Thu May 15 21:12:28 2003
@@ -213,7 +213,7 @@
 source "net/sctp/Kconfig"
 
 config ATM
-	bool "Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)"
+	tristate "Asynchronous Transfer Mode (ATM) (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
 	---help---
 	  ATM is a high-speed networking technology for Local Area Networks
@@ -230,7 +230,7 @@
 	  further details.
 
 config ATM_CLIP
-	bool "Classical IP over ATM (EXPERIMENTAL)"
+	tristate "Classical IP over ATM (EXPERIMENTAL)"
 	depends on ATM && INET
 	help
 	  Classical IP over ATM for PVCs and SVCs, supporting InARP and
@@ -265,6 +265,23 @@
 	  bridges and ATM attached hosts establish direct ATM VCs across
 	  subnetwork boundaries. These shortcut connections bypass routers
 	  enhancing overall network performance.
+
+config ATM_BR2684
+	tristate "RFC1483/2684 Bridged protocols"
+	depends on ATM && INET
+	help
+	  ATM PVCs can carry ethernet PDUs according to rfc2684 (formerly 1483)
+	  This device will act like an ethernet from the kernels point of view,
+	  with the traffic being carried by ATM PVCs (currently 1 PVC/device).
+	  This is sometimes used over DSL lines.  If in doubt, say N.
+
+config ATM_BR2684_IPFILTER
+	bool "Per-VC IP filter kludge"
+	depends on ATM_BR2684
+	help
+	  This is an experimental mechanism for users who need to terminating a
+	  large number of IP-only vcc's.  Do not enable this unless you are sure
+	  you know what you are doing.
 
 config VLAN_8021Q
 	tristate "802.1Q VLAN Support"
diff -Nru a/net/appletalk/atalk_proc.c b/net/appletalk/atalk_proc.c
--- a/net/appletalk/atalk_proc.c	Mon Oct  7 20:05:42 2002
+++ b/net/appletalk/atalk_proc.c	Sat May 10 11:46:34 2003
@@ -241,6 +241,7 @@
 }
 
 static struct file_operations atalk_seq_interface_fops = {
+	.owner		= THIS_MODULE,
 	.open		= atalk_seq_interface_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -248,6 +249,7 @@
 };
 
 static struct file_operations atalk_seq_route_fops = {
+	.owner		= THIS_MODULE,
 	.open		= atalk_seq_route_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -255,6 +257,7 @@
 };
 
 static struct file_operations atalk_seq_socket_fops = {
+	.owner		= THIS_MODULE,
 	.open		= atalk_seq_socket_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
diff -Nru a/net/appletalk/ddp.c b/net/appletalk/ddp.c
--- a/net/appletalk/ddp.c	Fri May  2 23:14:23 2003
+++ b/net/appletalk/ddp.c	Mon May 19 23:22:52 2003
@@ -88,7 +88,8 @@
 struct sock *atalk_sockets;
 rwlock_t atalk_sockets_lock = RW_LOCK_UNLOCKED;
 
-extern inline void atalk_insert_socket(struct sock *sk)
+#if 0 /* currently unused -DaveM */
+static inline void atalk_insert_socket(struct sock *sk)
 {
 	write_lock_bh(&atalk_sockets_lock);
 	sk->next = atalk_sockets;
@@ -98,8 +99,9 @@
 	sk->pprev = &atalk_sockets;
 	write_unlock_bh(&atalk_sockets_lock);
 }
+#endif
 
-extern inline void atalk_remove_socket(struct sock *sk)
+static inline void atalk_remove_socket(struct sock *sk)
 {
 	write_lock_bh(&atalk_sockets_lock);
 	if (sk->pprev) {
@@ -198,7 +200,7 @@
 	}
 }
 
-extern inline void atalk_destroy_socket(struct sock *sk)
+static inline void atalk_destroy_socket(struct sock *sk)
 {
 	atalk_remove_socket(sk);
 	skb_queue_purge(&sk->receive_queue);
diff -Nru a/net/atm/Makefile b/net/atm/Makefile
--- a/net/atm/Makefile	Mon Feb  3 14:19:38 2003
+++ b/net/atm/Makefile	Thu May 15 21:12:28 2003
@@ -2,13 +2,16 @@
 # Makefile for the ATM Protocol Families.
 #
 
+atm-y		:= addr.o pvc.o signaling.o svc.o common.o atm_misc.o raw.o resources.o
 mpoa-objs	:= mpc.o mpoa_caches.o mpoa_proc.o
 
-obj-$(CONFIG_ATM) := addr.o pvc.o signaling.o svc.o common.o atm_misc.o raw.o resources.o
-
-obj-$(CONFIG_ATM_CLIP) += clip.o ipcommon.o
-obj-$(CONFIG_NET_SCH_ATM) += ipcommon.o
-obj-$(CONFIG_PROC_FS) += proc.o
+obj-$(CONFIG_ATM) += atm.o
+obj-$(CONFIG_ATM_CLIP) += clip.o
+atm-$(subst m,y,$(CONFIG_ATM_CLIP)) += ipcommon.o
+obj-$(CONFIG_ATM_BR2684) += br2684.o
+atm-$(subst m,y,$(CONFIG_ATM_BR2684)) += ipcommon.o
+atm-$(subst m,y,$CONFIG_NET_SCH_ATM)) += ipcommon.o
+atm-$(CONFIG_PROC_FS) += proc.o
 
 obj-$(CONFIG_ATM_LANE) += lec.o
 obj-$(CONFIG_ATM_MPOA) += mpoa.o
diff -Nru a/net/atm/addr.c b/net/atm/addr.c
--- a/net/atm/addr.c	Mon Feb  4 23:39:14 2002
+++ b/net/atm/addr.c	Thu May 15 17:20:17 2003
@@ -36,14 +36,6 @@
 }
 
 
-/*
- * Avoid modification of any list of local interfaces while reading it
- * (which may involve page faults and therefore rescheduling)
- */
-
-static DECLARE_MUTEX(local_lock);
-extern  spinlock_t atm_dev_lock;
-
 static void notify_sigd(struct atm_dev *dev)
 {
 	struct sockaddr_atmpvc pvc;
@@ -52,46 +44,46 @@
 	sigd_enq(NULL,as_itf_notify,NULL,&pvc,NULL);
 }
 
-/*
- *	This is called from atm_ioctl only. You must hold the lock as a caller
- */
 
 void atm_reset_addr(struct atm_dev *dev)
 {
+	unsigned long flags;
 	struct atm_dev_addr *this;
 
-	down(&local_lock);
+	spin_lock_irqsave(&dev->lock, flags);
 	while (dev->local) {
 		this = dev->local;
 		dev->local = this->next;
 		kfree(this);
 	}
-	up(&local_lock);
+	spin_unlock_irqrestore(&dev->lock, flags);
 	notify_sigd(dev);
 }
 
 
 int atm_add_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
 {
+	unsigned long flags;
 	struct atm_dev_addr **walk;
 	int error;
 
 	error = check_addr(addr);
-	if (error) return error;
-	down(&local_lock);
+	if (error)
+		return error;
+	spin_lock_irqsave(&dev->lock, flags);
 	for (walk = &dev->local; *walk; walk = &(*walk)->next)
 		if (identical(&(*walk)->addr,addr)) {
-			up(&local_lock);
+			spin_unlock_irqrestore(&dev->lock, flags);
 			return -EEXIST;
 		}
-	*walk = kmalloc(sizeof(struct atm_dev_addr),GFP_KERNEL);
+	*walk = kmalloc(sizeof(struct atm_dev_addr), GFP_ATOMIC);
 	if (!*walk) {
-		up(&local_lock);
+		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENOMEM;
 	}
 	(*walk)->addr = *addr;
 	(*walk)->next = NULL;
-	up(&local_lock);
+	spin_unlock_irqrestore(&dev->lock, flags);
 	notify_sigd(dev);
 	return 0;
 }
@@ -99,22 +91,24 @@
 
 int atm_del_addr(struct atm_dev *dev,struct sockaddr_atmsvc *addr)
 {
+	unsigned long flags;
 	struct atm_dev_addr **walk,*this;
 	int error;
 
 	error = check_addr(addr);
-	if (error) return error;
-	down(&local_lock);
+	if (error)
+		return error;
+	spin_lock_irqsave(&dev->lock, flags);
 	for (walk = &dev->local; *walk; walk = &(*walk)->next)
 		if (identical(&(*walk)->addr,addr)) break;
 	if (!*walk) {
-		up(&local_lock);
+		spin_unlock_irqrestore(&dev->lock, flags);
 		return -ENOENT;
 	}
 	this = *walk;
 	*walk = this->next;
 	kfree(this);
-	up(&local_lock);
+	spin_unlock_irqrestore(&dev->lock, flags);
 	notify_sigd(dev);
 	return 0;
 }
@@ -122,24 +116,25 @@
 
 int atm_get_addr(struct atm_dev *dev,struct sockaddr_atmsvc *u_buf,int size)
 {
+	unsigned long flags;
 	struct atm_dev_addr *walk;
 	int total;
 
-	down(&local_lock);
+	spin_lock_irqsave(&dev->lock, flags);
 	total = 0;
 	for (walk = dev->local; walk; walk = walk->next) {
 		total += sizeof(struct sockaddr_atmsvc);
 		if (total > size) {
-			up(&local_lock);
+			spin_unlock_irqrestore(&dev->lock, flags);
 			return -E2BIG;
 		}
 		if (copy_to_user(u_buf,&walk->addr,
 		    sizeof(struct sockaddr_atmsvc))) {
-			up(&local_lock);
+			spin_unlock_irqrestore(&dev->lock, flags);
 			return -EFAULT;
 		}
 		u_buf++;
 	}
-	up(&local_lock);
+	spin_unlock_irqrestore(&dev->lock, flags);
 	return total;
 }
diff -Nru a/net/atm/atm_misc.c b/net/atm/atm_misc.c
--- a/net/atm/atm_misc.c	Sat Mar  8 13:09:15 2003
+++ b/net/atm/atm_misc.c	Thu May 15 17:20:17 2003
@@ -63,13 +63,19 @@
 
 int atm_find_ci(struct atm_vcc *vcc,short *vpi,int *vci)
 {
+	unsigned long flags;
 	static short p = 0; /* poor man's per-device cache */
 	static int c = 0;
 	short old_p;
 	int old_c;
+	int err;
 
-	if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY)
-		return check_ci(vcc,*vpi,*vci);
+	spin_lock_irqsave(&vcc->dev->lock, flags);
+	if (*vpi != ATM_VPI_ANY && *vci != ATM_VCI_ANY) {
+		err = check_ci(vcc,*vpi,*vci);
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+		return err;
+	}
 	/* last scan may have left values out of bounds for current device */
 	if (*vpi != ATM_VPI_ANY) p = *vpi;
 	else if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
@@ -82,6 +88,7 @@
 		if (!check_ci(vcc,p,c)) {
 			*vpi = p;
 			*vci = c;
+			spin_unlock_irqrestore(&vcc->dev->lock, flags);
 			return 0;
 		}
 		if (*vci == ATM_VCI_ANY) {
@@ -96,6 +103,7 @@
 		}
 	}
 	while (old_p != p || old_c != c);
+	spin_unlock_irqrestore(&vcc->dev->lock, flags);
 	return -EADDRINUSE;
 }
 
diff -Nru a/net/atm/br2684.c b/net/atm/br2684.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/atm/br2684.c	Wed May  7 12:30:27 2003
@@ -0,0 +1,804 @@
+/*
+Experimental ethernet netdevice using ATM AAL5 as underlying carrier
+(RFC1483 obsoleted by RFC2684) for Linux 2.4
+Author: Marcell GAL, 2000, XDSL Ltd, Hungary
+*/
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/ip.h>
+#include <asm/uaccess.h>
+#include <net/arp.h>
+
+#include <linux/atmbr2684.h>
+
+#include "ipcommon.h"
+
+/*
+ * Define this to use a version of the code which interacts with the higher
+ * layers in a more intellegent way, by always reserving enough space for
+ * our header at the begining of the packet.  However, there may still be
+ * some problems with programs like tcpdump.  In 2.5 we'll sort out what
+ * we need to do to get this perfect.  For now we just will copy the packet
+ * if we need space for the header
+ */
+/* #define FASTER_VERSION */
+
+#ifdef DEBUG
+#define DPRINTK(format, args...) printk(KERN_DEBUG "br2684: " format, ##args)
+#else
+#define DPRINTK(format, args...)
+#endif
+
+#ifdef SKB_DEBUG
+static void skb_debug(const struct sk_buff *skb)
+{
+#define NUM2PRINT 50
+	char buf[NUM2PRINT * 3 + 1];	/* 3 chars per byte */
+	int i = 0;
+	for (i = 0; i < skb->len && i < NUM2PRINT; i++) {
+		sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
+	}
+	printk(KERN_DEBUG "br2684: skb: %s\n", buf);
+}
+#else
+#define skb_debug(skb)	do {} while (0)
+#endif
+
+static unsigned char llc_oui_pid_pad[] =
+    { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 };
+#define PADLEN	(2)
+
+enum br2684_encaps {
+	e_vc  = BR2684_ENCAPS_VC,
+	e_llc = BR2684_ENCAPS_LLC,
+};
+
+struct br2684_vcc {
+	struct atm_vcc  *atmvcc;
+	struct br2684_dev *brdev;
+	/* keep old push,pop functions for chaining */
+	void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb);
+	/* void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); */
+	enum br2684_encaps encaps;
+	struct list_head brvccs;
+#ifdef CONFIG_ATM_BR2684_IPFILTER
+	struct br2684_filter filter;
+#endif /* CONFIG_ATM_BR2684_IPFILTER */
+#ifndef FASTER_VERSION
+	unsigned copies_needed, copies_failed;
+#endif /* FASTER_VERSION */
+};
+
+struct br2684_dev {
+	struct net_device net_dev;
+	struct list_head br2684_devs;
+	int number;
+	struct list_head brvccs; /* one device <=> one vcc (before xmas) */
+	struct net_device_stats stats;
+	int mac_was_set;
+};
+
+/*
+ * This lock should be held for writing any time the list of devices or
+ * their attached vcc's could be altered.  It should be held for reading
+ * any time these are being queried.  Note that we sometimes need to
+ * do read-locking under interrupt context, so write locking must block
+ * the current CPU's interrupts
+ */
+static rwlock_t devs_lock = RW_LOCK_UNLOCKED;
+
+static LIST_HEAD(br2684_devs);
+
+static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev)
+{
+	return (struct br2684_dev *) ((char *) (net_dev) -
+	    (unsigned long) (&((struct br2684_dev *) 0)->net_dev));
+}
+
+static inline struct br2684_dev *list_entry_brdev(const struct list_head *le)
+{
+	return list_entry(le, struct br2684_dev, br2684_devs);
+}
+
+static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc)
+{
+	return (struct br2684_vcc *) (atmvcc->user_back);
+}
+
+static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le)
+{
+	return list_entry(le, struct br2684_vcc, brvccs);
+}
+
+/* Caller should hold read_lock(&devs_lock) */
+static struct br2684_dev *br2684_find_dev(const struct br2684_if_spec *s)
+{
+	struct list_head *lh;
+	struct br2684_dev *brdev;
+	switch (s->method) {
+	case BR2684_FIND_BYNUM:
+		list_for_each(lh, &br2684_devs) {
+			brdev = list_entry_brdev(lh);
+			if (brdev->number == s->spec.devnum)
+				return brdev;
+		}
+		break;
+	case BR2684_FIND_BYIFNAME:
+		list_for_each(lh, &br2684_devs) {
+			brdev = list_entry_brdev(lh);
+			if (!strncmp(brdev->net_dev.name, s->spec.ifname,
+			    sizeof brdev->net_dev.name))
+				return brdev;
+		}
+		break;
+	}
+	return NULL;
+}
+
+/*
+ * Send a packet out a particular vcc.  Not to useful right now, but paves
+ * the way for multiple vcc's per itf.  Returns true if we can send,
+ * otherwise false
+ */
+static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
+	struct br2684_vcc *brvcc)
+{
+	struct atm_vcc *atmvcc;
+#ifdef FASTER_VERSION
+	if (brvcc->encaps == e_llc)
+		memcpy(skb_push(skb, 8), llc_oui_pid_pad, 8);
+	/* last 2 bytes of llc_oui_pid_pad are managed by header routines;
+	   yes, you got it: 8 + 2 = sizeof(llc_oui_pid_pad)
+	 */
+#else
+	int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2;
+	if (skb_headroom(skb) < minheadroom) {
+		struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom);
+		brvcc->copies_needed++;
+		dev_kfree_skb(skb);
+		if (skb2 == NULL) {
+			brvcc->copies_failed++;
+			return 0;
+		}
+		skb = skb2;
+	}
+	skb_push(skb, minheadroom);
+	if (brvcc->encaps == e_llc)
+		memcpy(skb->data, llc_oui_pid_pad, 10);
+	else
+		memset(skb->data, 0, 2);
+#endif /* FASTER_VERSION */
+	skb_debug(skb);
+
+	ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
+	DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
+	if (!atm_may_send(atmvcc, skb->truesize)) {
+		/* we free this here for now, because we cannot know in a higher 
+			layer whether the skb point it supplied wasn't freed yet.
+			now, it always is.
+		*/
+		dev_kfree_skb(skb);
+		return 0;
+		}
+	atomic_add(skb->truesize, &atmvcc->sk->wmem_alloc);
+	ATM_SKB(skb)->atm_options = atmvcc->atm_options;
+	brdev->stats.tx_packets++;
+	brdev->stats.tx_bytes += skb->len;
+	atmvcc->send(atmvcc, skb);
+	return 1;
+}
+
+static inline struct br2684_vcc *pick_outgoing_vcc(struct sk_buff *skb,
+	struct br2684_dev *brdev)
+{
+	return list_empty(&brdev->brvccs) ? NULL :
+	    list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */
+}
+
+static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct br2684_dev *brdev = BRPRIV(dev);
+	struct br2684_vcc *brvcc;
+
+	DPRINTK("br2684_start_xmit, skb->dst=%p\n", skb->dst);
+	read_lock(&devs_lock);
+	brvcc = pick_outgoing_vcc(skb, brdev);
+	if (brvcc == NULL) {
+		DPRINTK("no vcc attached to dev %s\n", dev->name);
+		brdev->stats.tx_errors++;
+		brdev->stats.tx_carrier_errors++;
+		/* netif_stop_queue(dev); */
+		dev_kfree_skb(skb);
+		read_unlock(&devs_lock);
+		return -EUNATCH;
+	}
+	if (!br2684_xmit_vcc(skb, brdev, brvcc)) {
+		/*
+		 * We should probably use netif_*_queue() here, but that
+		 * involves added complication.  We need to walk before
+		 * we can run
+		 */
+		/* don't free here! this pointer might be no longer valid!
+		dev_kfree_skb(skb);
+		*/
+		brdev->stats.tx_errors++;
+		brdev->stats.tx_fifo_errors++;
+	}
+	read_unlock(&devs_lock);
+	return 0;
+}
+
+static struct net_device_stats *br2684_get_stats(struct net_device *dev)
+{
+	DPRINTK("br2684_get_stats\n");
+	return &BRPRIV(dev)->stats;
+}
+
+#ifdef FASTER_VERSION
+/*
+ * These mirror eth_header and eth_header_cache.  They are not usually
+ * exported for use in modules, so we grab them from net_device
+ * after ether_setup() is done with it.  Bit of a hack.
+ */
+static int (*my_eth_header)(struct sk_buff *, struct net_device *,
+	unsigned short, void *, void *, unsigned);
+static int (*my_eth_header_cache)(struct neighbour *, struct hh_cache *);
+
+static int
+br2684_header(struct sk_buff *skb, struct net_device *dev,
+	      unsigned short type, void *daddr, void *saddr, unsigned len)
+{
+	u16 *pad_before_eth;
+	int t = my_eth_header(skb, dev, type, daddr, saddr, len);
+	if (t > 0) {
+		pad_before_eth = (u16 *) skb_push(skb, 2);
+		*pad_before_eth = 0;
+		return dev->hard_header_len;	/* or return 16; ? */
+	} else
+		return t;
+}
+
+static int
+br2684_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+{
+/* hh_data is 16 bytes long. if encaps is ether-llc we need 24, so
+xmit will add the additional header part in that case */
+	u16 *pad_before_eth = (u16 *)(hh->hh_data);
+	int t = my_eth_header_cache(neigh, hh);
+	DPRINTK("br2684_header_cache, neigh=%p, hh_cache=%p\n", neigh, hh);
+	if (t < 0)
+		return t;
+	else {
+		*pad_before_eth = 0;
+		hh->hh_len = PADLEN + ETH_HLEN;
+	}
+	return 0;
+}
+
+/*
+ * This is similar to eth_type_trans, which cannot be used because of
+ * our dev->hard_header_len
+ */
+static inline unsigned short br_type_trans(struct sk_buff *skb,
+					       struct net_device *dev)
+{
+	struct ethhdr *eth;
+	unsigned char *rawp;
+	eth = skb->mac.ethernet;
+
+	if (*eth->h_dest & 1) {
+		if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
+			skb->pkt_type = PACKET_BROADCAST;
+		else
+			skb->pkt_type = PACKET_MULTICAST;
+	}
+
+	else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
+		skb->pkt_type = PACKET_OTHERHOST;
+
+	if (ntohs(eth->h_proto) >= 1536)
+		return eth->h_proto;
+
+	rawp = skb->data;
+
+	/*
+	 * This is a magic hack to spot IPX packets. Older Novell breaks
+	 * the protocol design and runs IPX over 802.3 without an 802.2 LLC
+	 * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
+	 * won't work for fault tolerant netware but does for the rest.
+	 */
+	if (*(unsigned short *) rawp == 0xFFFF)
+		return htons(ETH_P_802_3);
+
+	/*
+	 * Real 802.2 LLC
+	 */
+	return htons(ETH_P_802_2);
+}
+#endif /* FASTER_VERSION */
+
+/*
+ * We remember when the MAC gets set, so we don't override it later with
+ * the ESI of the ATM card of the first VC
+ */
+static int (*my_eth_mac_addr)(struct net_device *, void *);
+static int br2684_mac_addr(struct net_device *dev, void *p)
+{
+	int err = my_eth_mac_addr(dev, p);
+	if (!err)
+		BRPRIV(dev)->mac_was_set = 1;
+	return err;
+}
+
+#ifdef CONFIG_ATM_BR2684_IPFILTER
+/* this IOCTL is experimental. */
+static int br2684_setfilt(struct atm_vcc *atmvcc, unsigned long arg)
+{
+	struct br2684_vcc *brvcc;
+	struct br2684_filter_set fs;
+
+	if (copy_from_user(&fs, (void *) arg, sizeof fs))
+		return -EFAULT;
+	if (fs.ifspec.method != BR2684_FIND_BYNOTHING) {
+		/*
+		 * This is really a per-vcc thing, but we can also search
+		 * by device
+		 */
+		struct br2684_dev *brdev;
+		read_lock(&devs_lock);
+		brdev = br2684_find_dev(&fs.ifspec);
+		if (brdev == NULL || list_empty(&brdev->brvccs) ||
+		    brdev->brvccs.next != brdev->brvccs.prev)  /* >1 VCC */
+			brvcc = NULL;
+		else
+			brvcc = list_entry_brvcc(brdev->brvccs.next);
+		read_unlock(&devs_lock);
+		if (brvcc == NULL)
+			return -ESRCH;
+	} else
+		brvcc = BR2684_VCC(atmvcc);
+	memcpy(&brvcc->filter, &fs.filter, sizeof(brvcc->filter));
+	return 0;
+}
+
+/* Returns 1 if packet should be dropped */
+static inline int
+packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb)
+{
+	if (brvcc->filter.netmask == 0)
+		return 0;			/* no filter in place */
+	if (type == __constant_htons(ETH_P_IP) &&
+	    (((struct iphdr *) (skb->data))->daddr & brvcc->filter.
+	     netmask) == brvcc->filter.prefix)
+		return 0;
+	if (type == __constant_htons(ETH_P_ARP))
+		return 0;
+	/* TODO: we should probably filter ARPs too.. don't want to have
+	 *   them returning values that don't make sense, or is that ok?
+	 */
+	return 1;		/* drop */
+}
+#endif /* CONFIG_ATM_BR2684_IPFILTER */
+
+static void br2684_close_vcc(struct br2684_vcc *brvcc)
+{
+	DPRINTK("removing VCC %p from dev %p\n", brvcc, brvcc->brdev);
+	write_lock_irq(&devs_lock);
+	list_del(&brvcc->brvccs);
+	write_unlock_irq(&devs_lock);
+	brvcc->atmvcc->user_back = NULL;	/* what about vcc->recvq ??? */
+	brvcc->old_push(brvcc->atmvcc, NULL);	/* pass on the bad news */
+	kfree(brvcc);
+	MOD_DEC_USE_COUNT;
+}
+
+/* when AAL5 PDU comes in: */
+static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
+{
+	struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
+	struct br2684_dev *brdev = brvcc->brdev;
+	int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN;
+
+	DPRINTK("br2684_push\n");
+
+	if (skb == NULL) {	/* skb==NULL means VCC is being destroyed */
+		br2684_close_vcc(brvcc);
+		if (list_empty(&brdev->brvccs)) {
+			read_lock(&devs_lock);
+			list_del(&brdev->br2684_devs);
+			read_unlock(&devs_lock);
+			unregister_netdev(&brdev->net_dev);
+			kfree(brdev);
+		}
+		return;
+	}
+
+	skb_debug(skb);
+	atm_return(atmvcc, skb->truesize);
+	DPRINTK("skb from brdev %p\n", brdev);
+	if (brvcc->encaps == e_llc) {
+		/* let us waste some time for checking the encapsulation.
+		   Note, that only 7 char is checked so frames with a valid FCS
+		   are also accepted (but FCS is not checked of course) */
+		if (memcmp(skb->data, llc_oui_pid_pad, 7)) {
+			brdev->stats.rx_errors++;
+			dev_kfree_skb(skb);
+			return;
+		}
+	} else {
+		plen = PADLEN + ETH_HLEN;	/* pad, dstmac,srcmac, ethtype */
+		/* first 2 chars should be 0 */
+		if (*((u16 *) (skb->data)) != 0) {
+			brdev->stats.rx_errors++;
+			dev_kfree_skb(skb);
+			return;
+		}
+	}
+	if (skb->len < plen) {
+		brdev->stats.rx_errors++;
+		dev_kfree_skb(skb);	/* dev_ not needed? */
+		return;
+	}
+
+#ifdef FASTER_VERSION
+	/* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier,
+	   than should be. What else should I set? */
+	skb_pull(skb, plen);
+	skb->mac.raw = ((char *) (skb->data)) - ETH_HLEN;
+	skb->pkt_type = PACKET_HOST;
+#ifdef CONFIG_BR2684_FAST_TRANS
+	skb->protocol = ((u16 *) skb->data)[-1];
+#else				/* some protocols might require this: */
+	skb->protocol = br_type_trans(skb, &brdev->net_dev);
+#endif /* CONFIG_BR2684_FAST_TRANS */
+#else
+	skb_pull(skb, plen - ETH_HLEN);
+	skb->protocol = eth_type_trans(skb, &brdev->net_dev);
+#endif /* FASTER_VERSION */
+#ifdef CONFIG_ATM_BR2684_IPFILTER
+	if (packet_fails_filter(skb->protocol, brvcc, skb)) {
+		brdev->stats.rx_dropped++;
+		dev_kfree_skb(skb);
+		return;
+	}
+#endif /* CONFIG_ATM_BR2684_IPFILTER */
+	skb->dev = &brdev->net_dev;
+	ATM_SKB(skb)->vcc = atmvcc;	/* needed ? */
+	DPRINTK("received packet's protocol: %x\n", ntohs(skb->protocol));
+	skb_debug(skb);
+	if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */
+		brdev->stats.rx_dropped++;
+		dev_kfree_skb(skb);
+		return;
+	}
+	brdev->stats.rx_packets++;
+	brdev->stats.rx_bytes += skb->len;
+	memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
+	netif_rx(skb);
+}
+
+static int br2684_regvcc(struct atm_vcc *atmvcc, unsigned long arg)
+{
+/* assign a vcc to a dev
+Note: we do not have explicit unassign, but look at _push()
+*/
+	int err;
+	struct br2684_vcc *brvcc;
+	struct sk_buff_head copy;
+	struct sk_buff *skb;
+	struct br2684_dev *brdev;
+	struct atm_backend_br2684 be;
+
+	MOD_INC_USE_COUNT;
+	if (copy_from_user(&be, (void *) arg, sizeof be)) {
+		MOD_DEC_USE_COUNT;
+		return -EFAULT;
+	}
+	write_lock_irq(&devs_lock);
+	brdev = br2684_find_dev(&be.ifspec);
+	if (brdev == NULL) {
+		printk(KERN_ERR
+		    "br2684: tried to attach to non-existant device\n");
+		err = -ENXIO;
+		goto error;
+	}
+	if (atmvcc->push == NULL) {
+		err = -EBADFD;
+		goto error;
+	}
+	if (!list_empty(&brdev->brvccs)) {	/* Only 1 VCC/dev right now */
+		err = -EEXIST;
+		goto error;
+	}
+	if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO ||
+	    be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps !=
+	    BR2684_ENCAPS_VC && be.encaps != BR2684_ENCAPS_LLC) ||
+	    be.min_size != 0) {
+		err = -EINVAL;
+		goto error;
+	}
+	brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL);
+	if (!brvcc) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memset(brvcc, 0, sizeof(struct br2684_vcc));
+	DPRINTK("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps,
+		brvcc);
+	if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) {
+		unsigned char *esi = atmvcc->dev->esi;
+		if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5])
+			memcpy(brdev->net_dev.dev_addr, esi,
+			    brdev->net_dev.addr_len);
+		else
+			brdev->net_dev.dev_addr[2] = 1;
+	}
+	list_add(&brvcc->brvccs, &brdev->brvccs);
+	write_unlock_irq(&devs_lock);
+	brvcc->brdev = brdev;
+	brvcc->atmvcc = atmvcc;
+	atmvcc->user_back = brvcc;
+	brvcc->encaps = (enum br2684_encaps) be.encaps;
+	brvcc->old_push = atmvcc->push;
+	barrier();
+	atmvcc->push = br2684_push;
+	skb_queue_head_init(&copy);
+	skb_migrate(&atmvcc->sk->receive_queue, &copy);
+	while ((skb = skb_dequeue(&copy))) {
+		BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
+		BRPRIV(skb->dev)->stats.rx_packets--;
+		br2684_push(atmvcc, skb);
+	}
+	return 0;
+    error:
+	write_unlock_irq(&devs_lock);
+	MOD_DEC_USE_COUNT;
+	return err;
+}
+
+static int br2684_create(unsigned long arg)
+{
+	int err;
+	struct br2684_dev *brdev;
+	struct atm_newif_br2684 ni;
+
+	DPRINTK("br2684_create\n");
+	/*
+	 * We track module use by vcc's NOT the devices they're on.  We're
+	 * protected here against module death by the kernel_lock, but if
+	 * we need to sleep we should make sure that the module doesn't
+	 * disappear under us.
+	 */
+	MOD_INC_USE_COUNT;
+	if (copy_from_user(&ni, (void *) arg, sizeof ni)) {
+		MOD_DEC_USE_COUNT;
+		return -EFAULT;
+	}
+	if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
+		MOD_DEC_USE_COUNT;
+		return -EINVAL;
+	}
+	if ((brdev = kmalloc(sizeof(struct br2684_dev), GFP_KERNEL)) == NULL) {
+		MOD_DEC_USE_COUNT;
+		return -ENOMEM;
+	}
+	memset(brdev, 0, sizeof(struct br2684_dev));
+	INIT_LIST_HEAD(&brdev->brvccs);
+
+	write_lock_irq(&devs_lock);
+	brdev->number = list_empty(&br2684_devs) ? 1 :
+	    list_entry_brdev(br2684_devs.prev)->number + 1;
+	list_add_tail(&brdev->br2684_devs, &br2684_devs);
+	write_unlock_irq(&devs_lock);
+
+	if (ni.ifname[0] != '\0') {
+		memcpy(brdev->net_dev.name, ni.ifname,
+		    sizeof(brdev->net_dev.name));
+		brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] = '\0';
+	} else
+		sprintf(brdev->net_dev.name, "nas%d", brdev->number);
+	DPRINTK("registered netdev %s\n", brdev->net_dev.name);
+	ether_setup(&brdev->net_dev);
+	brdev->mac_was_set = 0;
+#ifdef FASTER_VERSION
+	my_eth_header = brdev->net_dev.hard_header;
+	brdev->net_dev.hard_header = br2684_header;
+	my_eth_header_cache = brdev->net_dev.hard_header_cache;
+	brdev->net_dev.hard_header_cache = br2684_header_cache;
+	brdev->net_dev.hard_header_len = sizeof(llc_oui_pid_pad) + ETH_HLEN;	/* 10 + 14 */
+#endif
+	my_eth_mac_addr = brdev->net_dev.set_mac_address;
+	brdev->net_dev.set_mac_address = br2684_mac_addr;
+	brdev->net_dev.hard_start_xmit = br2684_start_xmit;
+	brdev->net_dev.get_stats = br2684_get_stats;
+
+	/* open, stop, do_ioctl ? */
+	err = register_netdev(&brdev->net_dev);
+	MOD_DEC_USE_COUNT;
+	if (err < 0) {
+		printk(KERN_ERR "br2684_create: register_netdev failed\n");
+		write_lock_irq(&devs_lock);
+		list_del(&brdev->br2684_devs);
+		write_unlock_irq(&devs_lock);
+		kfree(brdev);
+		return err;
+	}
+	return 0;
+}
+
+/*
+ * This handles ioctls actually performed on our vcc - we must return
+ * -ENOIOCTLCMD for any unrecognized ioctl
+ */
+static int br2684_ioctl(struct atm_vcc *atmvcc, unsigned int cmd,
+	unsigned long arg)
+{
+	int err;
+	switch(cmd) {
+	case ATM_SETBACKEND:
+	case ATM_NEWBACKENDIF: {
+		atm_backend_t b;
+		MOD_INC_USE_COUNT;
+		err = get_user(b, (atm_backend_t *) arg);
+		MOD_DEC_USE_COUNT;
+		if (err)
+			return -EFAULT;
+		if (b != ATM_BACKEND_BR2684)
+			return -ENOIOCTLCMD;
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (cmd == ATM_SETBACKEND)
+			return br2684_regvcc(atmvcc, arg);
+		else
+			return br2684_create(arg);
+		}
+#ifdef CONFIG_ATM_BR2684_IPFILTER
+	case BR2684_SETFILT:
+		if (atmvcc->push != br2684_push)
+			return -ENOIOCTLCMD;
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		MOD_INC_USE_COUNT;
+		err = br2684_setfilt(atmvcc, arg);
+		MOD_DEC_USE_COUNT;
+		return err;
+#endif /* CONFIG_ATM_BR2684_IPFILTER */
+	}
+	return -ENOIOCTLCMD;
+}
+
+/* Never put more than 256 bytes in at once */
+static int br2684_proc_engine(loff_t pos, char *buf)
+{
+	struct list_head *lhd, *lhc;
+	struct br2684_dev *brdev;
+	struct br2684_vcc *brvcc;
+	list_for_each(lhd, &br2684_devs) {
+		brdev = list_entry_brdev(lhd);
+		if (pos-- == 0)
+			return sprintf(buf, "dev %.16s: num=%d, mac=%02X:%02X:"
+			    "%02X:%02X:%02X:%02X (%s)\n", brdev->net_dev.name,
+			    brdev->number,
+			    brdev->net_dev.dev_addr[0],
+			    brdev->net_dev.dev_addr[1],
+			    brdev->net_dev.dev_addr[2],
+			    brdev->net_dev.dev_addr[3],
+			    brdev->net_dev.dev_addr[4],
+			    brdev->net_dev.dev_addr[5],
+			    brdev->mac_was_set ? "set" : "auto");
+		list_for_each(lhc, &brdev->brvccs) {
+			brvcc = list_entry_brvcc(lhc);
+			if (pos-- == 0)
+				return sprintf(buf, "  vcc %d.%d.%d: encaps=%s"
+#ifndef FASTER_VERSION
+				    ", failed copies %u/%u"
+#endif /* FASTER_VERSION */
+				    "\n", brvcc->atmvcc->dev->number,
+				    brvcc->atmvcc->vpi, brvcc->atmvcc->vci,
+				    (brvcc->encaps == e_llc) ? "LLC" : "VC"
+#ifndef FASTER_VERSION
+				    , brvcc->copies_failed
+				    , brvcc->copies_needed
+#endif /* FASTER_VERSION */
+				    );
+#ifdef CONFIG_ATM_BR2684_IPFILTER
+#define b1(var, byte)	((u8 *) &brvcc->filter.var)[byte]
+#define bs(var)		b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3)
+			if (brvcc->filter.netmask != 0 && pos-- == 0)
+				return sprintf(buf, "    filter=%d.%d.%d.%d/"
+				    "%d.%d.%d.%d\n", bs(prefix), bs(netmask));
+#undef bs
+#undef b1
+#endif /* CONFIG_ATM_BR2684_IPFILTER */
+		}
+	}
+	return 0;
+}
+
+static ssize_t br2684_proc_read(struct file *file, char *buf, size_t count,
+	loff_t *pos)
+{
+	unsigned long page;
+	int len = 0, x, left;
+	page = get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	left = PAGE_SIZE - 256;
+	if (count < left)
+		left = count;
+	read_lock(&devs_lock);
+	for (;;) {
+		x = br2684_proc_engine(*pos, &((char *) page)[len]);
+		if (x == 0)
+			break;
+		if (x > left)
+			/*
+			 * This should only happen if the user passed in
+			 * a "count" too small for even one line
+			 */
+			x = -EINVAL;
+		if (x < 0) {
+			len = x;
+			break;
+		}
+		len += x;
+		left -= x;
+		(*pos)++;
+		if (left < 256)
+			break;
+	}
+	read_unlock(&devs_lock);
+	if (len > 0 && copy_to_user(buf, (char *) page, len))
+		len = -EFAULT;
+	free_page(page);
+	return len;
+}
+
+static struct file_operations br2684_proc_operations = {
+	read: br2684_proc_read,
+};
+
+extern struct proc_dir_entry *atm_proc_root;	/* from proc.c */
+
+extern int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long);
+
+/* the following avoids some spurious warnings from the compiler */
+#define UNUSED __attribute__((unused))
+
+static int __init UNUSED br2684_init(void)
+{
+	struct proc_dir_entry *p;
+	if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL)
+		return -ENOMEM;
+	p->proc_fops = &br2684_proc_operations;
+	br2684_ioctl_hook = br2684_ioctl;
+	return 0;
+}
+
+static void __exit UNUSED br2684_exit(void)
+{
+	struct br2684_dev *brdev;
+	br2684_ioctl_hook = NULL;
+	remove_proc_entry("br2684", atm_proc_root);
+	while (!list_empty(&br2684_devs)) {
+		brdev = list_entry_brdev(br2684_devs.next);
+		unregister_netdev(&brdev->net_dev);
+		list_del(&brdev->br2684_devs);
+		kfree(brdev);
+	}
+}
+
+module_init(br2684_init);
+module_exit(br2684_exit);
+
+MODULE_AUTHOR("Marcell GAL");
+MODULE_DESCRIPTION("RFC2684 bridged protocols over ATM/AAL5");
+MODULE_LICENSE("GPL");
diff -Nru a/net/atm/clip.c b/net/atm/clip.c
--- a/net/atm/clip.c	Sat Mar  8 13:09:15 2003
+++ b/net/atm/clip.c	Thu May 15 17:20:17 2003
@@ -7,6 +7,8 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/kernel.h> /* for UINT_MAX */
+#include <linux/module.h>
+#include <linux/init.h>
 #include <linux/netdevice.h>
 #include <linux/skbuff.h>
 #include <linux/wait.h>
@@ -45,6 +47,7 @@
 
 struct net_device *clip_devs = NULL;
 struct atm_vcc *atmarpd = NULL;
+static struct neigh_table clip_tbl;
 static struct timer_list idle_timer;
 static int start_timer = 1;
 
@@ -127,6 +130,8 @@
 			struct atmarp_entry *entry = NEIGH2ENTRY(n);
 			struct clip_vcc *clip_vcc;
 
+			write_lock(&n->lock);
+
 			for (clip_vcc = entry->vccs; clip_vcc;
 			    clip_vcc = clip_vcc->next)
 				if (clip_vcc->idle_timeout &&
@@ -141,6 +146,7 @@
 			if (entry->vccs ||
 			    time_before(jiffies, entry->expires)) {
 				np = &n->next;
+				write_unlock(&n->lock);
 				continue;
 			}
 			if (atomic_read(&n->refcnt) > 1) {
@@ -152,11 +158,13 @@
 				     NULL) 
 					dev_kfree_skb(skb);
 				np = &n->next;
+				write_unlock(&n->lock);
 				continue;
 			}
 			*np = n->next;
 			DPRINTK("expired neigh %p\n",n);
 			n->dead = 1;
+			write_unlock(&n->lock);
 			neigh_release(n);
 		}
 	}
@@ -182,7 +190,7 @@
 }
 
 
-void clip_push(struct atm_vcc *vcc,struct sk_buff *skb)
+static void clip_push(struct atm_vcc *vcc,struct sk_buff *skb)
 {
 	struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
 
@@ -218,6 +226,7 @@
 	clip_vcc->last_use = jiffies;
 	PRIV(skb->dev)->stats.rx_packets++;
 	PRIV(skb->dev)->stats.rx_bytes += skb->len;
+	memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
 	netif_rx(skb);
 }
 
@@ -319,7 +328,7 @@
 }
 
 
-struct neigh_table clip_tbl = {
+static struct neigh_table clip_tbl = {
 	NULL,			/* next */
 	AF_INET,		/* family */
 	sizeof(struct neighbour)+sizeof(struct atmarp_entry), /* entry_size */
@@ -365,7 +374,7 @@
  */
 
 
-int clip_encap(struct atm_vcc *vcc,int mode)
+static int clip_encap(struct atm_vcc *vcc,int mode)
 {
 	CLIP_VCC(vcc)->encap = mode;
 	return 0;
@@ -427,7 +436,6 @@
 		((u16 *) here)[3] = skb->protocol;
 	}
 	atomic_add(skb->truesize,&vcc->sk->wmem_alloc);
-	ATM_SKB(skb)->iovcnt = 0;
 	ATM_SKB(skb)->atm_options = vcc->atm_options;
 	entry->vccs->last_use = jiffies;
 	DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n",skb,vcc,vcc->dev);
@@ -463,7 +471,7 @@
 }
 
 
-int clip_mkip(struct atm_vcc *vcc,int timeout)
+static int clip_mkip(struct atm_vcc *vcc,int timeout)
 {
 	struct clip_vcc *clip_vcc;
 	struct sk_buff_head copy;
@@ -503,7 +511,7 @@
 }
 
 
-int clip_setentry(struct atm_vcc *vcc,u32 ip)
+static int clip_setentry(struct atm_vcc *vcc,u32 ip)
 {
 	struct neighbour *neigh;
 	struct atmarp_entry *entry;
@@ -576,7 +584,7 @@
 }
 
 
-int clip_create(int number)
+static int clip_create(int number)
 {
 	struct net_device *dev;
 	struct clip_priv *clip_priv;
@@ -696,28 +704,24 @@
 		    "pending\n");
 	skb_queue_purge(&vcc->sk->receive_queue);
 	DPRINTK("(done)\n");
+	module_put(THIS_MODULE);
 }
 
 
 static struct atmdev_ops atmarpd_dev_ops = {
-	.close =atmarpd_close,
+	.close = atmarpd_close
 };
 
 
 static struct atm_dev atmarpd_dev = {
-	&atmarpd_dev_ops,
-	NULL,		/* no PHY */
-	"arpd",		/* type */
-	999,		/* dummy device number */
-	NULL,NULL,	/* pretend not to have any VCCs */
-	NULL,NULL,	/* no data */
-	0,		/* no flags */
-	NULL,		/* no local address */
-	{ 0 }		/* no ESI, no statistics */
+	.ops =			&atmarpd_dev_ops,
+	.type =			"arpd",
+	.number = 		999,
+	.lock =			SPIN_LOCK_UNLOCKED
 };
 
 
-int atm_init_atmarp(struct atm_vcc *vcc)
+static int atm_init_atmarp(struct atm_vcc *vcc)
 {
 	struct net_device *dev;
 
@@ -747,10 +751,57 @@
 	return 0;
 }
 
+static struct atm_clip_ops __atm_clip_ops = {
+	.clip_create =		clip_create,
+	.clip_mkip =		clip_mkip,
+	.clip_setentry =	clip_setentry,
+	.clip_encap =		clip_encap,
+	.clip_push =		clip_push,
+	.atm_init_atmarp =	atm_init_atmarp,
+	.owner =		THIS_MODULE
+};
 
-void atm_clip_init(void)
+static int __init atm_clip_init(void)
 {
+	/* we should use neigh_table_init() */
 	clip_tbl.lock = RW_LOCK_UNLOCKED;
 	clip_tbl.kmem_cachep = kmem_cache_create(clip_tbl.id,
 	    clip_tbl.entry_size, 0, SLAB_HWCACHE_ALIGN, NULL, NULL);
+
+	/* so neigh_ifdown() doesn't complain */
+	clip_tbl.proxy_timer.data = 0;
+	clip_tbl.proxy_timer.function = 0;
+	init_timer(&clip_tbl.proxy_timer);
+	skb_queue_head_init(&clip_tbl.proxy_queue);
+
+	clip_tbl_hook = &clip_tbl;
+	atm_clip_ops_set(&__atm_clip_ops);
+
+	return 0;
 }
+
+static void __exit atm_clip_exit(void)
+{
+	struct net_device *dev, *next;
+
+	atm_clip_ops_set(NULL);
+
+	neigh_ifdown(&clip_tbl, NULL);
+	dev = clip_devs;
+	while (dev) {
+		next = PRIV(dev)->next;
+		unregister_netdev(dev);
+		kfree(dev);
+		dev = next;
+	}
+	if (start_timer == 0) del_timer(&idle_timer);
+
+	kmem_cache_destroy(clip_tbl.kmem_cachep);
+
+	clip_tbl_hook = NULL;
+}
+
+module_init(atm_clip_init);
+module_exit(atm_clip_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/net/atm/common.c b/net/atm/common.c
--- a/net/atm/common.c	Thu Apr  3 06:08:19 2003
+++ b/net/atm/common.c	Sun May 18 18:17:23 2003
@@ -20,6 +20,7 @@
 #include <linux/time.h>		/* struct timeval */
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
+#include <linux/init.h>
 #include <net/sock.h>		/* struct sock */
 
 #include <asm/uaccess.h>
@@ -57,11 +58,48 @@
 #endif
 #endif
 
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+#include <net/atmclip.h>
+struct atm_clip_ops *atm_clip_ops;
+static DECLARE_MUTEX(atm_clip_ops_mutex);
+
+void atm_clip_ops_set(struct atm_clip_ops *hook)
+{
+	down(&atm_clip_ops_mutex);
+	atm_clip_ops = hook;
+	up(&atm_clip_ops_mutex);
+}
+
+int try_atm_clip_ops(void)
+{
+	down(&atm_clip_ops_mutex);
+	if (atm_clip_ops && try_module_get(atm_clip_ops->owner)) {
+		up(&atm_clip_ops_mutex);
+		return 1;
+	}
+	up(&atm_clip_ops_mutex);
+	return 0;
+}
+
+#ifdef CONFIG_ATM_CLIP_MODULE
+EXPORT_SYMBOL(atm_clip_ops);
+EXPORT_SYMBOL(try_atm_clip_ops);
+EXPORT_SYMBOL(atm_clip_ops_set);
+#endif
+#endif
+
 #if defined(CONFIG_PPPOATM) || defined(CONFIG_PPPOATM_MODULE)
 int (*pppoatm_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long);
 EXPORT_SYMBOL(pppoatm_ioctl_hook);
 #endif
 
+#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE)
+int (*br2684_ioctl_hook)(struct atm_vcc *, unsigned int, unsigned long);
+#ifdef CONFIG_ATM_BR2684_MODULE
+EXPORT_SYMBOL(br2684_ioctl_hook);
+#endif
+#endif
+
 #include "resources.h"		/* atm_find_dev */
 #include "common.h"		/* prototypes */
 #include "protocols.h"		/* atm_init_<transport> */
@@ -78,7 +116,6 @@
 #define DPRINTK(format,args...)
 #endif
 
-spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
 static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
 {
@@ -91,7 +128,7 @@
 	}
 	while (!(skb = alloc_skb(size,GFP_KERNEL))) schedule();
 	DPRINTK("AlTx %d += %d\n",atomic_read(&vcc->sk->wmem_alloc),skb->truesize);
-	atomic_add(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
+	atomic_add(skb->truesize, &vcc->sk->wmem_alloc);
 	return skb;
 }
 
@@ -107,7 +144,6 @@
 	vcc = atm_sk(sk);
 	memset(&vcc->flags,0,sizeof(vcc->flags));
 	vcc->dev = NULL;
-	vcc->alloc_tx = alloc_tx;
 	vcc->callback = NULL;
 	memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
 	memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
@@ -120,7 +156,6 @@
 	vcc->vpi = vcc->vci = 0; /* no VCI/VPI yet */
 	vcc->atm_options = vcc->aal_options = 0;
 	init_waitqueue_head(&vcc->sleep);
-	skb_queue_head_init(&vcc->listenq);
 	sk->sleep = &vcc->sleep;
 	sock->sk = sk;
 	return 0;
@@ -138,23 +173,19 @@
 		if (vcc->push) vcc->push(vcc,NULL); /* atmarpd has no push */
 		while ((skb = skb_dequeue(&vcc->sk->receive_queue))) {
 			atm_return(vcc,skb->truesize);
-			if (vcc->dev->ops->free_rx_skb)
-				vcc->dev->ops->free_rx_skb(vcc,skb);
-			else kfree_skb(skb);
+			kfree_skb(skb);
 		}
-		spin_lock (&atm_dev_lock);	
-		fops_put (vcc->dev->ops);
+
+		module_put(vcc->dev->ops->owner);
+		atm_dev_release(vcc->dev);
 		if (atomic_read(&vcc->sk->rmem_alloc))
 			printk(KERN_WARNING "atm_release_vcc: strange ... "
 			    "rmem_alloc == %d after closing\n",
 			    atomic_read(&vcc->sk->rmem_alloc));
 		bind_vcc(vcc,NULL);
-	} else
-		spin_lock (&atm_dev_lock);	
+	}
 
 	if (free_sk) free_atm_vcc_sk(sk);
-
-	spin_unlock (&atm_dev_lock);
 }
 
 
@@ -247,11 +278,12 @@
 	    vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
 	DPRINTK("  RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
 	    vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
-	fops_get (dev->ops);
+	if (!try_module_get(dev->ops->owner))
+		return -ENODEV;
 	if (dev->ops->open) {
 		error = dev->ops->open(vcc,vpi,vci);
 		if (error) {
-			fops_put (dev->ops);
+			module_put(dev->ops->owner);
 			bind_vcc(vcc,NULL);
 			return error;
 		}
@@ -265,14 +297,13 @@
 	struct atm_dev *dev;
 	int return_val;
 
-	spin_lock (&atm_dev_lock);
-	dev = atm_find_dev(itf);
+	dev = atm_dev_lookup(itf);
 	if (!dev)
 		return_val =  -ENODEV;
-	else
+	else {
 		return_val = atm_do_connect_dev(vcc,dev,vpi,vci);
-
-	spin_unlock (&atm_dev_lock);
+		if (return_val) atm_dev_release(dev);
+	}
 
 	return return_val;
 }
@@ -303,15 +334,20 @@
 	}
 	else {
 		struct atm_dev *dev = NULL;
-		struct list_head *p;
+		struct list_head *p, *next;
 
-		spin_lock (&atm_dev_lock);
-		list_for_each(p, &atm_devs) {
+		spin_lock(&atm_dev_lock);
+		list_for_each_safe(p, next, &atm_devs) {
 			dev = list_entry(p, struct atm_dev, dev_list);
-			if (!atm_do_connect_dev(vcc,dev,vpi,vci)) break;
+			atm_dev_hold(dev);
+			spin_unlock(&atm_dev_lock);
+			if (!atm_do_connect_dev(vcc,dev,vpi,vci))
+				break;
+			atm_dev_release(dev);
 			dev = NULL;
+			spin_lock(&atm_dev_lock);
 		}
-		spin_unlock (&atm_dev_lock);
+		spin_unlock(&atm_dev_lock);
 		if (!dev) return -ENODEV;
 	}
 	if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
@@ -388,31 +424,8 @@
 		    (unsigned long) buff,eff_len);
 	DPRINTK("RcvM %d -= %d\n",atomic_read(&vcc->sk->rmem_alloc),skb->truesize);
 	atm_return(vcc,skb->truesize);
-	if (ATM_SKB(skb)->iovcnt) { /* @@@ hack */
-		/* iovcnt set, use scatter-gather for receive */
-		int el, cnt;
-		struct iovec *iov = (struct iovec *)skb->data;
-		unsigned char *p = (unsigned char *)buff;
-
-		el = eff_len;
-		error = 0;
-		for (cnt = 0; (cnt < ATM_SKB(skb)->iovcnt) && el; cnt++) {
-/*printk("s-g???: %p -> %p (%d)\n",iov->iov_base,p,iov->iov_len);*/
-			error = copy_to_user(p,iov->iov_base,
-			    (iov->iov_len > el) ? el : iov->iov_len) ?
-			    -EFAULT : 0;
-			if (error) break;
-			p += iov->iov_len;
-			el -= (iov->iov_len > el)?el:iov->iov_len;
-			iov++;
-		}
-		if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb);
-		else vcc->dev->ops->free_rx_skb(vcc, skb);
-		return error ? error : eff_len;
-	}
 	error = copy_to_user(buff,skb->data,eff_len) ? -EFAULT : 0;
-	if (!vcc->dev->ops->free_rx_skb) kfree_skb(skb);
-	else vcc->dev->ops->free_rx_skb(vcc, skb);
+	kfree_skb(skb);
 	return error ? error : eff_len;
 }
 
@@ -444,7 +457,7 @@
 	add_wait_queue(&vcc->sleep,&wait);
 	set_current_state(TASK_INTERRUPTIBLE);
 	error = 0;
-	while (!(skb = vcc->alloc_tx(vcc,eff))) {
+	while (!(skb = alloc_tx(vcc,eff))) {
 		if (m->msg_flags & MSG_DONTWAIT) {
 			error = -EAGAIN;
 			break;
@@ -469,7 +482,6 @@
 	remove_wait_queue(&vcc->sleep,&wait);
 	if (error) return error;
 	skb->dev = NULL; /* for paths shared with net_device interfaces */
-	ATM_SKB(skb)->iovcnt = 0;
 	ATM_SKB(skb)->atm_options = vcc->atm_options;
 	if (copy_from_user(skb_put(skb,size),buff,size)) {
 		kfree_skb(skb);
@@ -489,15 +501,14 @@
 	vcc = ATM_SD(sock);
 	poll_wait(file,&vcc->sleep,wait);
 	mask = 0;
-	if (skb_peek(&vcc->sk->receive_queue) || skb_peek(&vcc->listenq))
+	if (skb_peek(&vcc->sk->receive_queue))
 		mask |= POLLIN | POLLRDNORM;
 	if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
 	    test_bit(ATM_VF_CLOSE,&vcc->flags))
 		mask |= POLLHUP;
 	if (sock->state != SS_CONNECTING) {
 		if (vcc->qos.txtp.traffic_class != ATM_NONE &&
-		    vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc)+
-		    ATM_PDU_OVHD <= vcc->sk->sndbuf)
+		    vcc->qos.txtp.max_sdu+atomic_read(&vcc->sk->wmem_alloc) <= vcc->sk->sndbuf)
 			mask |= POLLOUT | POLLWRNORM;
 	}
 	else if (vcc->reply != WAITING) {
@@ -554,7 +565,6 @@
 	int error,len,size,number, ret_val;
 
 	ret_val = 0;
-	spin_lock (&atm_dev_lock);
 	vcc = ATM_SD(sock);
 	switch (cmd) {
 		case SIOCOUTQ:
@@ -564,7 +574,7 @@
 				goto done;
 			}
 			ret_val =  put_user(vcc->sk->sndbuf-
-			    atomic_read(&vcc->sk->wmem_alloc)-ATM_PDU_OVHD,
+			    atomic_read(&vcc->sk->wmem_alloc),
 			    (int *) arg) ? -EFAULT : 0;
 			goto done;
 		case SIOCINQ:
@@ -592,14 +602,17 @@
 				goto done;
 			}
 			size = 0;
+			spin_lock(&atm_dev_lock);
 			list_for_each(p, &atm_devs)
 				size += sizeof(int);
 			if (size > len) {
+				spin_unlock(&atm_dev_lock);
 				ret_val = -E2BIG;
 				goto done;
 			}
-			tmp_buf = kmalloc(size,GFP_KERNEL);
+			tmp_buf = kmalloc(size, GFP_ATOMIC);
 			if (!tmp_buf) {
+				spin_unlock(&atm_dev_lock);
 				ret_val = -ENOMEM;
 				goto done;
 			}
@@ -608,6 +621,7 @@
 				dev = list_entry(p, struct atm_dev, dev_list);
 				*tmp_p++ = dev->number;
 			}
+			spin_unlock(&atm_dev_lock);
 		        ret_val = ((copy_to_user(buf, tmp_buf, size)) ||
 			    put_user(size, &((struct atm_iobuf *) arg)->length)
 			    ) ? -EFAULT : 0;
@@ -645,39 +659,67 @@
 			if (!error) sock->state = SS_CONNECTED;
 			ret_val = error;
 			goto done;
-#ifdef CONFIG_ATM_CLIP
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 		case SIOCMKCLIP:
-			if (!capable(CAP_NET_ADMIN))
+			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-			else 
-				ret_val = clip_create(arg);
+				goto done;
+			}
+			if (try_atm_clip_ops()) {
+				ret_val = atm_clip_ops->clip_create(arg);
+				module_put(atm_clip_ops->owner);
+			} else
+				ret_val = -ENOSYS;
 			goto done;
 		case ATMARPD_CTRL:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
 				goto done;
 			}
-			error = atm_init_atmarp(vcc);
-			if (!error) sock->state = SS_CONNECTED;
-			ret_val = error;
+#if defined(CONFIG_ATM_CLIP_MODULE)
+			if (!atm_clip_ops)
+				request_module("clip");
+#endif
+			if (try_atm_clip_ops()) {
+				error = atm_clip_ops->atm_init_atmarp(vcc);
+				if (!error)
+					sock->state = SS_CONNECTED;
+				ret_val = error;
+			} else
+				ret_val = -ENOSYS;
 			goto done;
 		case ATMARP_MKIP:
-			if (!capable(CAP_NET_ADMIN)) 
+			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-			else 
-				ret_val = clip_mkip(vcc,arg);
+				goto done;
+			}
+			if (try_atm_clip_ops()) {
+				ret_val = atm_clip_ops->clip_mkip(vcc, arg);
+				module_put(atm_clip_ops->owner);
+			} else
+				ret_val = -ENOSYS;
 			goto done;
 		case ATMARP_SETENTRY:
-			if (!capable(CAP_NET_ADMIN)) 
+			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-			else
-				ret_val = clip_setentry(vcc,arg);
+				goto done;
+			}
+			if (try_atm_clip_ops()) {
+				ret_val = atm_clip_ops->clip_setentry(vcc, arg);
+				module_put(atm_clip_ops->owner);
+			} else
+				ret_val = -ENOSYS;
 			goto done;
 		case ATMARP_ENCAP:
-			if (!capable(CAP_NET_ADMIN)) 
+			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-			else
-				ret_val = clip_encap(vcc,arg);
+				goto done;
+			}
+			if (try_atm_clip_ops()) {
+				ret_val = atm_clip_ops->clip_encap(vcc, arg);
+				module_put(atm_clip_ops->owner);
+			} else
+				ret_val = -ENOSYS;
 			goto done;
 #endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
@@ -785,6 +827,13 @@
 			goto done;
 	}
 #endif
+#if defined(CONFIG_ATM_BR2684) || defined(CONFIG_ATM_BR2684_MODULE)
+	if (br2684_ioctl_hook) {
+		ret_val = br2684_ioctl_hook(vcc, cmd, arg);
+		if (ret_val != -ENOIOCTLCMD)
+			goto done;
+	}
+#endif
 	if (get_user(buf,&((struct atmif_sioc *) arg)->arg)) {
 		ret_val = -EFAULT;
 		goto done;
@@ -797,7 +846,7 @@
 		ret_val = -EFAULT;
 		goto done;
 	}
-	if (!(dev = atm_find_dev(number))) {
+	if (!(dev = atm_dev_lookup(number))) {
 		ret_val = -ENODEV;
 		goto done;
 	}
@@ -808,14 +857,14 @@
 			size = strlen(dev->type)+1;
 			if (copy_to_user(buf,dev->type,size)) {
 				ret_val = -EFAULT;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_GETESI:
 			size = ESI_LEN;
 			if (copy_to_user(buf,dev->esi,size)) {
 				ret_val = -EFAULT;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_SETESI:
@@ -825,7 +874,7 @@
 				for (i = 0; i < ESI_LEN; i++)
 					if (dev->esi[i]) {
 						ret_val = -EEXIST;
-						goto done;
+						goto done_release;
 					}
 			}
 			/* fall through */
@@ -835,20 +884,20 @@
 
 				if (!capable(CAP_NET_ADMIN)) {
 					ret_val = -EPERM;
-					goto done;
+					goto done_release;
 				}
 				if (copy_from_user(esi,buf,ESI_LEN)) {
 					ret_val = -EFAULT;
-					goto done;
+					goto done_release;
 				}
 				memcpy(dev->esi,esi,ESI_LEN);
 				ret_val =  ESI_LEN;
-				goto done;
+				goto done_release;
 			}
 		case ATM_GETSTATZ:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-				goto done;
+				goto done_release;
 			}
 			/* fall through */
 		case ATM_GETSTAT:
@@ -856,27 +905,27 @@
 			error = fetch_stats(dev,buf,cmd == ATM_GETSTATZ);
 			if (error) {
 				ret_val = error;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_GETCIRANGE:
 			size = sizeof(struct atm_cirange);
 			if (copy_to_user(buf,&dev->ci_range,size)) {
 				ret_val = -EFAULT;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_GETLINKRATE:
 			size = sizeof(int);
 			if (copy_to_user(buf,&dev->link_rate,size)) {
 				ret_val = -EFAULT;
-				goto done;
+				goto done_release;
 			}
 			break;
 		case ATM_RSTADDR:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-				goto done;
+				goto done_release;
 			}
 			atm_reset_addr(dev);
 			break;
@@ -884,20 +933,20 @@
 		case ATM_DELADDR:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-				goto done;
+				goto done_release;
 			}
 			{
 				struct sockaddr_atmsvc addr;
 
 				if (copy_from_user(&addr,buf,sizeof(addr))) {
 					ret_val = -EFAULT;
-					goto done;
+					goto done_release;
 				}
 				if (cmd == ATM_ADDADDR)
 					ret_val = atm_add_addr(dev,&addr);
 				else
 					ret_val = atm_del_addr(dev,&addr);
-				goto done;
+				goto done_release;
 			}
 		case ATM_GETADDR:
 			size = atm_get_addr(dev,buf,len);
@@ -908,13 +957,13 @@
 			   write the length" */
 				ret_val = put_user(size,
 						   &((struct atmif_sioc *) arg)->length) ? -EFAULT : 0;
-			goto done;
+			goto done_release;
 		case ATM_SETLOOP:
 			if (__ATM_LM_XTRMT((int) (long) buf) &&
 			    __ATM_LM_XTLOC((int) (long) buf) >
 			    __ATM_LM_XTRMT((int) (long) buf)) {
 				ret_val = -EINVAL;
-				goto done;
+				goto done_release;
 			}
 			/* fall through */
 		case ATM_SETCIRANGE:
@@ -924,18 +973,18 @@
 		case SONET_SETFRAMING:
 			if (!capable(CAP_NET_ADMIN)) {
 				ret_val = -EPERM;
-				goto done;
+				goto done_release;
 			}
 			/* fall through */
 		default:
 			if (!dev->ops->ioctl) {
 				ret_val = -EINVAL;
-				goto done;
+				goto done_release;
 			}
 			size = dev->ops->ioctl(dev,cmd,buf);
 			if (size < 0) {
 				ret_val = (size == -ENOIOCTLCMD ? -EINVAL : size);
-				goto done;
+				goto done_release;
 			}
 	}
 	
@@ -944,9 +993,10 @@
 			-EFAULT : 0;
 	else
 		ret_val = 0;
+done_release:
+	atm_dev_release(dev);
 
- done:
-	spin_unlock (&atm_dev_lock); 
+done:
 	return ret_val;
 }
 
@@ -1161,3 +1211,43 @@
         return;
 }        
 #endif
+
+static int __init atm_init(void)
+{
+	int error;
+
+	if ((error = atmpvc_init()) < 0) {
+		printk(KERN_ERR "atmpvc_init() failed with %d\n", error);
+		goto failure;
+	}
+	if ((error = atmsvc_init()) < 0) {
+		printk(KERN_ERR "atmsvc_init() failed with %d\n", error);
+		goto failure;
+	}
+#ifdef CONFIG_PROC_FS
+        if ((error = atm_proc_init()) < 0) {
+		printk(KERN_ERR "atm_proc_init() failed with %d\n",error);
+		goto failure;
+	}
+#endif
+	return 0;
+
+failure:
+	atmsvc_exit();
+	atmpvc_exit();
+	return error;
+}
+
+static void __exit atm_exit(void)
+{
+#ifdef CONFIG_PROC_FS
+	atm_proc_exit();
+#endif
+	atmsvc_exit();
+	atmpvc_exit();
+}
+
+module_init(atm_init);
+module_exit(atm_exit);
+
+MODULE_LICENSE("GPL");
diff -Nru a/net/atm/common.h b/net/atm/common.h
--- a/net/atm/common.h	Thu Mar  6 11:06:44 2003
+++ b/net/atm/common.h	Thu May 15 21:12:28 2003
@@ -28,7 +28,12 @@
 void atm_release_vcc_sk(struct sock *sk,int free_sk);
 void atm_shutdown_dev(struct atm_dev *dev);
 
+int atmpvc_init(void);
+void atmpvc_exit(void);
+int atmsvc_init(void);
+void atmsvc_exit(void);
 int atm_proc_init(void);
+void atm_proc_exit(void);
 
 /* SVC */
 
diff -Nru a/net/atm/ipcommon.c b/net/atm/ipcommon.c
--- a/net/atm/ipcommon.c	Tue Feb  5 09:40:00 2002
+++ b/net/atm/ipcommon.c	Tue May 13 17:05:28 2003
@@ -67,4 +67,5 @@
 }
 
 
+EXPORT_SYMBOL(llc_oui);
 EXPORT_SYMBOL(skb_migrate);
diff -Nru a/net/atm/lec.c b/net/atm/lec.c
--- a/net/atm/lec.c	Mon Apr 21 20:06:59 2003
+++ b/net/atm/lec.c	Thu May 15 17:20:17 2003
@@ -204,7 +204,6 @@
 	if (atm_may_send(vcc, skb->len)) {
 		atomic_add(skb->truesize, &vcc->sk->wmem_alloc);
 	        ATM_SKB(skb)->vcc = vcc;
-	        ATM_SKB(skb)->iovcnt = 0;
 	        ATM_SKB(skb)->atm_options = vcc->atm_options;
 		priv->stats.tx_packets++;
 		priv->stats.tx_bytes += skb->len;
@@ -302,7 +301,7 @@
 #endif
         min_frame_size = LEC_MINIMUM_8023_SIZE;
         if (skb->len < min_frame_size) {
-                if (skb->truesize < min_frame_size) {
+                if ((skb->len + skb_tailroom(skb)) < min_frame_size) {
                         skb2 = skb_copy_expand(skb, 0,
                             min_frame_size - skb->truesize, GFP_ATOMIC);
                                 dev_kfree_skb(skb);
@@ -399,7 +398,7 @@
         int i;
         char *tmp; /* FIXME */
 
-	atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
+	atomic_sub(skb->truesize, &vcc->sk->wmem_alloc);
         mesg = (struct atmlec_msg *)skb->data;
         tmp = skb->data;
         tmp += sizeof(struct atmlec_msg);
@@ -555,6 +554,7 @@
 	.ops	= &lecdev_ops,
 	.type	= "lec",
 	.number	= 999,	/* dummy device number */
+	.lock	= SPIN_LOCK_UNLOCKED
 };
 
 /*
@@ -715,6 +715,7 @@
                 skb->protocol = eth_type_trans(skb, dev);
                 priv->stats.rx_packets++;
                 priv->stats.rx_bytes += skb->len;
+                memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
                 netif_rx(skb);
         }
 }
diff -Nru a/net/atm/mpc.c b/net/atm/mpc.c
--- a/net/atm/mpc.c	Tue Apr 29 02:29:48 2003
+++ b/net/atm/mpc.c	Thu May 15 17:20:17 2003
@@ -324,7 +324,9 @@
 	return;
 }
 
-static const char * __attribute__ ((unused)) mpoa_device_type_string(char type)
+static const char *mpoa_device_type_string(char type) __attribute__ ((unused));
+
+static const char *mpoa_device_type_string(char type)
 {
 	switch(type) {
 	case NON_MPOA:
@@ -429,7 +431,7 @@
 		if (tlvs == NULL) return;
 	}
 	if (end_of_tlvs - tlvs != 0)
-		printk("mpoa: (%s) lane2_assoc_ind: ignoring %d bytes of trailing TLV carbage\n",
+		printk("mpoa: (%s) lane2_assoc_ind: ignoring %Zd bytes of trailing TLV carbage\n",
 		       dev->name, end_of_tlvs - tlvs);
 	return;
 }
@@ -521,7 +523,6 @@
 	}
 
 	atomic_add(skb->truesize, &entry->shortcut->sk->wmem_alloc);
-	ATM_SKB(skb)->iovcnt = 0; /* just to be safe ... */
 	ATM_SKB(skb)->atm_options = entry->shortcut->atm_options;
 	entry->shortcut->send(entry->shortcut, skb);
 	entry->packets_fwded++;
@@ -730,6 +731,7 @@
 	eg->packets_rcvd++;
 	mpc->eg_ops->put(eg);
 
+	memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
 	netif_rx(new_skb);
 
 	return;
@@ -744,6 +746,7 @@
 	.ops	= &mpc_ops,
 	.type	= "mpc",
 	.number	= 42,
+	.lock	= SPIN_LOCK_UNLOCKED
 	/* members not explicitly initialised will be 0 */
 };
 
@@ -861,7 +864,7 @@
 	
 	struct mpoa_client *mpc = find_mpc_by_vcc(vcc);
 	struct k_message *mesg = (struct k_message*)skb->data;
-	atomic_sub(skb->truesize+ATM_PDU_OVHD, &vcc->sk->wmem_alloc);
+	atomic_sub(skb->truesize, &vcc->sk->wmem_alloc);
 	
 	if (mpc == NULL) {
 		printk("mpoa: msg_from_mpoad: no mpc found\n");
diff -Nru a/net/atm/mpoa_proc.c b/net/atm/mpoa_proc.c
--- a/net/atm/mpoa_proc.c	Mon Oct  7 11:39:20 2002
+++ b/net/atm/mpoa_proc.c	Sat May 10 11:46:34 2003
@@ -42,6 +42,7 @@
  *   Define allowed FILE OPERATIONS
  */
 static struct file_operations mpc_file_operations = {
+	.owner =	THIS_MODULE,
 	.read =		proc_mpc_read,
 	.write =	proc_mpc_write,
 };
diff -Nru a/net/atm/pppoatm.c b/net/atm/pppoatm.c
--- a/net/atm/pppoatm.c	Thu Mar 20 00:45:11 2003
+++ b/net/atm/pppoatm.c	Wed May  7 12:47:28 2003
@@ -232,7 +232,6 @@
 		return 1;
 	}
 	atomic_add(skb->truesize, &ATM_SKB(skb)->vcc->sk->wmem_alloc);
-	ATM_SKB(skb)->iovcnt = 0;
 	ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
 	DPRINTK("(unit %d): atm_skb(%p)->vcc(%p)->dev(%p)\n",
 	    pvcc->chan.unit, skb, ATM_SKB(skb)->vcc,
diff -Nru a/net/atm/proc.c b/net/atm/proc.c
--- a/net/atm/proc.c	Sat Mar  8 13:09:15 2003
+++ b/net/atm/proc.c	Tue May 20 20:28:50 2003
@@ -39,10 +39,9 @@
 #include "common.h" /* atm_proc_init prototype */
 #include "signaling.h" /* to get sigd - ugly too */
 
-#ifdef CONFIG_ATM_CLIP
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 #include <net/atmclip.h>
 #include "ipcommon.h"
-extern void clip_push(struct atm_vcc *vcc,struct sk_buff *skb);
 #endif
 
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
@@ -57,10 +56,12 @@
     loff_t *pos);
 
 static struct file_operations proc_dev_atm_operations = {
+	.owner =	THIS_MODULE,
 	.read =		proc_dev_atm_read,
 };
 
 static struct file_operations proc_spec_atm_operations = {
+	.owner =	THIS_MODULE,
 	.read =		proc_spec_atm_read,
 };
 
@@ -74,7 +75,7 @@
 }
 
 
-static void dev_info(const struct atm_dev *dev,char *buf)
+static void atm_dev_info(const struct atm_dev *dev,char *buf)
 {
 	int off,i;
 
@@ -85,11 +86,12 @@
 	add_stats(buf,"0",&dev->stats.aal0);
 	strcat(buf,"  ");
 	add_stats(buf,"5",&dev->stats.aal5);
+	sprintf(strchr(buf,0), "\t[%d]", atomic_read(&dev->refcnt));
 	strcat(buf,"\n");
 }
 
 
-#ifdef CONFIG_ATM_CLIP
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 
 
 static int svc_addr(char *buf,struct sockaddr_atmsvc *addr)
@@ -162,7 +164,7 @@
 #endif
 
 
-static void pvc_info(struct atm_vcc *vcc,char *buf)
+static void pvc_info(struct atm_vcc *vcc, char *buf, int clip_info)
 {
 	static const char *class_name[] = { "off","UBR","CBR","VBR","ABR" };
 	static const char *aal_name[] = {
@@ -178,16 +180,18 @@
 	    aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr,
 	    class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
 	    class_name[vcc->qos.txtp.traffic_class]);
-#ifdef CONFIG_ATM_CLIP
-	if (vcc->push == clip_push) {
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+	if (clip_info && (vcc->push == atm_clip_ops->clip_push)) {
 		struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
 		struct net_device *dev;
 
 		dev = clip_vcc->entry ? clip_vcc->entry->neigh->dev : NULL;
 		off += sprintf(buf+off,"CLIP, Itf:%s, Encap:",
 		    dev ? dev->name : "none?");
-		if (clip_vcc->encap) off += sprintf(buf+off,"LLC/SNAP");
-		else off += sprintf(buf+off,"None");
+		if (clip_vcc->encap)
+			off += sprintf(buf+off,"LLC/SNAP");
+		else
+			off += sprintf(buf+off,"None");
 	}
 #endif
 	strcpy(buf+off,"\n");
@@ -308,16 +312,19 @@
 
 	if (!pos) {
 		return sprintf(buf,"Itf Type    ESI/\"MAC\"addr "
-		    "AAL(TX,err,RX,err,drop) ...\n");
+		    "AAL(TX,err,RX,err,drop) ...               [refcnt]\n");
 	}
 	left = pos-1;
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
 		if (left-- == 0) {
-			dev_info(dev,buf);
+			atm_dev_info(dev,buf);
+			spin_unlock(&atm_dev_lock);
 			return strlen(buf);
 		}
 	}
+	spin_unlock(&atm_dev_lock);
 	return 0;
 }
 
@@ -328,31 +335,50 @@
 
 static int atm_pvc_info(loff_t pos,char *buf)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct list_head *p;
 	struct atm_vcc *vcc;
-	int left;
+	int left, clip_info = 0;
 
 	if (!pos) {
 		return sprintf(buf,"Itf VPI VCI   AAL RX(PCR,Class) "
 		    "TX(PCR,Class)\n");
 	}
 	left = pos-1;
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+	if (try_atm_clip_ops())
+		clip_info = 1;
+#endif
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
+		spin_lock_irqsave(&dev->lock, flags);
 		for (vcc = dev->vccs; vcc; vcc = vcc->next)
-			if (vcc->sk->family == PF_ATMPVC &&
-			    vcc->dev && !left--) {
-				pvc_info(vcc,buf);
+			if (vcc->sk->family == PF_ATMPVC && vcc->dev && !left--) {
+				pvc_info(vcc,buf,clip_info);
+				spin_unlock_irqrestore(&dev->lock, flags);
+				spin_unlock(&atm_dev_lock);
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+				if (clip_info)
+					module_put(atm_clip_ops->owner);
+#endif
 				return strlen(buf);
 			}
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
+	spin_unlock(&atm_dev_lock);
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+	if (clip_info)
+		module_put(atm_clip_ops->owner);
+#endif
 	return 0;
 }
 
 
 static int atm_vc_info(loff_t pos,char *buf)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct list_head *p;
 	struct atm_vcc *vcc;
@@ -363,19 +389,20 @@
 		    "Address"," Itf VPI VCI   Fam Flags Reply Send buffer"
 		    "     Recv buffer\n");
 	left = pos-1;
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
+		spin_lock_irqsave(&dev->lock, flags);
 		for (vcc = dev->vccs; vcc; vcc = vcc->next)
 			if (!left--) {
 				vc_info(vcc,buf);
+				spin_unlock_irqrestore(&dev->lock, flags);
+				spin_unlock(&atm_dev_lock);
 				return strlen(buf);
 			}
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
-	for (vcc = nodev_vccs; vcc; vcc = vcc->next)
-		if (!left--) {
-			vc_info(vcc,buf);
-			return strlen(buf);
-		}
+	spin_unlock(&atm_dev_lock);
 
 	return 0;
 }
@@ -383,6 +410,7 @@
 
 static int atm_svc_info(loff_t pos,char *buf)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct list_head *p;
 	struct atm_vcc *vcc;
@@ -391,23 +419,25 @@
 	if (!pos)
 		return sprintf(buf,"Itf VPI VCI           State      Remote\n");
 	left = pos-1;
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
+		spin_lock_irqsave(&dev->lock, flags);
 		for (vcc = dev->vccs; vcc; vcc = vcc->next)
 			if (vcc->sk->family == PF_ATMSVC && !left--) {
 				svc_info(vcc,buf);
+				spin_unlock_irqrestore(&dev->lock, flags);
+				spin_unlock(&atm_dev_lock);
 				return strlen(buf);
 			}
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
-	for (vcc = nodev_vccs; vcc; vcc = vcc->next)
-		if (vcc->sk->family == PF_ATMSVC && !left--) {
-			svc_info(vcc,buf);
-			return strlen(buf);
-		}
+	spin_unlock(&atm_dev_lock);
+
 	return 0;
 }
 
-#ifdef CONFIG_ATM_CLIP
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 static int atm_arp_info(loff_t pos,char *buf)
 {
 	struct neighbour *n;
@@ -417,28 +447,33 @@
 		return sprintf(buf,"IPitf TypeEncp Idle IP address      "
 		    "ATM address\n");
 	}
+	if (!try_atm_clip_ops())
+		return 0;
 	count = pos;
-	read_lock_bh(&clip_tbl.lock);
+	read_lock_bh(&clip_tbl_hook->lock);
 	for (i = 0; i <= NEIGH_HASHMASK; i++)
-		for (n = clip_tbl.hash_buckets[i]; n; n = n->next) {
+		for (n = clip_tbl_hook->hash_buckets[i]; n; n = n->next) {
 			struct atmarp_entry *entry = NEIGH2ENTRY(n);
 			struct clip_vcc *vcc;
 
 			if (!entry->vccs) {
 				if (--count) continue;
 				atmarp_info(n->dev,entry,NULL,buf);
-				read_unlock_bh(&clip_tbl.lock);
+				read_unlock_bh(&clip_tbl_hook->lock);
+				module_put(atm_clip_ops->owner);
 				return strlen(buf);
 			}
 			for (vcc = entry->vccs; vcc;
 			    vcc = vcc->next) {
 				if (--count) continue;
 				atmarp_info(n->dev,entry,vcc,buf);
-				read_unlock_bh(&clip_tbl.lock);
+				read_unlock_bh(&clip_tbl_hook->lock);
+				module_put(atm_clip_ops->owner);
 				return strlen(buf);
 			}
 		}
-	read_unlock_bh(&clip_tbl.lock);
+	read_unlock_bh(&clip_tbl_hook->lock);
+	module_put(atm_clip_ops->owner);
 	return 0;
 }
 #endif
@@ -597,12 +632,28 @@
     name->proc_fops = &proc_spec_atm_operations; \
     name->owner = THIS_MODULE
 
+static struct proc_dir_entry *devices = NULL, *pvc = NULL,
+		*svc = NULL, *arp = NULL, *lec = NULL, *vc = NULL;
 
-int __init atm_proc_init(void)
+static void atm_proc_cleanup(void)
 {
-	struct proc_dir_entry *devices = NULL,*pvc = NULL,*svc = NULL;
-	struct proc_dir_entry *arp = NULL,*lec = NULL,*vc = NULL;
+	if (devices)
+		remove_proc_entry("devices",atm_proc_root);
+	if (pvc)
+		remove_proc_entry("pvc",atm_proc_root);
+	if (svc)
+		remove_proc_entry("svc",atm_proc_root);
+	if (arp)
+		remove_proc_entry("arp",atm_proc_root);
+	if (lec)
+		remove_proc_entry("lec",atm_proc_root);
+	if (vc)
+		remove_proc_entry("vc",atm_proc_root);
+	remove_proc_entry("net/atm",NULL);
+}
 
+int __init atm_proc_init(void)
+{
 	atm_proc_root = proc_mkdir("net/atm",NULL);
 	if (!atm_proc_root)
 		return -ENOMEM;
@@ -610,7 +661,7 @@
 	CREATE_ENTRY(pvc);
 	CREATE_ENTRY(svc);
 	CREATE_ENTRY(vc);
-#ifdef CONFIG_ATM_CLIP
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 	CREATE_ENTRY(arp);
 #endif
 #if defined(CONFIG_ATM_LANE) || defined(CONFIG_ATM_LANE_MODULE)
@@ -619,12 +670,11 @@
 	return 0;
 
 cleanup:
-	if (devices) remove_proc_entry("devices",atm_proc_root);
-	if (pvc) remove_proc_entry("pvc",atm_proc_root);
-	if (svc) remove_proc_entry("svc",atm_proc_root);
-	if (arp) remove_proc_entry("arp",atm_proc_root);
-	if (lec) remove_proc_entry("lec",atm_proc_root);
-	if (vc) remove_proc_entry("vc",atm_proc_root);
-	remove_proc_entry("net/atm",NULL);
+	atm_proc_cleanup();
 	return -ENOMEM;
+}
+
+void atm_proc_exit(void)
+{
+	atm_proc_cleanup();
 }
diff -Nru a/net/atm/pvc.c b/net/atm/pvc.c
--- a/net/atm/pvc.c	Thu Apr  3 06:08:19 2003
+++ b/net/atm/pvc.c	Thu May 15 21:54:16 2003
@@ -7,16 +7,12 @@
 #include <linux/net.h>		/* struct socket, struct proto_ops */
 #include <linux/atm.h>		/* ATM stuff */
 #include <linux/atmdev.h>	/* ATM devices */
-#include <linux/atmclip.h>	/* Classical IP over ATM */
 #include <linux/errno.h>	/* error codes */
 #include <linux/kernel.h>	/* printk */
 #include <linux/init.h>
 #include <linux/skbuff.h>
 #include <linux/bitops.h>
 #include <net/sock.h>		/* for sock_no_* */
-#ifdef CONFIG_ATM_CLIP
-#include <net/atmclip.h>
-#endif
 
 #include "resources.h"		/* devs and vccs */
 #include "common.h"		/* common for PVCs and SVCs */
@@ -120,23 +116,12 @@
  */
 
 
-static int __init atmpvc_init(void)
+int __init atmpvc_init(void)
 {
-	int error;
-
-	error = sock_register(&pvc_family_ops);
-	if (error < 0) {
-		printk(KERN_ERR "ATMPVC: can't register (%d)",error);
-		return error;
-	}
-#ifdef CONFIG_ATM_CLIP
-	atm_clip_init();
-#endif
-#ifdef CONFIG_PROC_FS
-	error = atm_proc_init();
-	if (error) printk("atm_proc_init fails with %d\n",error);
-#endif
-	return 0;
+	return sock_register(&pvc_family_ops);
 }
 
-module_init(atmpvc_init);
+void atmpvc_exit(void)
+{
+	sock_unregister(PF_ATMPVC);
+}
diff -Nru a/net/atm/raw.c b/net/atm/raw.c
--- a/net/atm/raw.c	Sat Mar  8 13:09:15 2003
+++ b/net/atm/raw.c	Wed May  7 12:33:34 2003
@@ -37,7 +37,7 @@
 static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
 {
 	DPRINTK("APopR (%d) %d -= %d\n",vcc->vci,vcc->sk->wmem_alloc,skb->truesize);
-	atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
+	atomic_sub(skb->truesize, &vcc->sk->wmem_alloc);
 	dev_kfree_skb_any(skb);
 	wake_up(&vcc->sleep);
 }
diff -Nru a/net/atm/resources.c b/net/atm/resources.c
--- a/net/atm/resources.c	Tue Apr 29 02:29:48 2003
+++ b/net/atm/resources.c	Thu May 15 17:20:17 2003
@@ -27,10 +27,8 @@
 
 
 LIST_HEAD(atm_devs);
-struct atm_vcc *nodev_vccs = NULL;
-extern spinlock_t atm_dev_lock;
+spinlock_t atm_dev_lock = SPIN_LOCK_UNLOCKED;
 
-/* Caller must hold atm_dev_lock. */
 static struct atm_dev *__alloc_atm_dev(const char *type)
 {
 	struct atm_dev *dev;
@@ -42,67 +40,78 @@
 	dev->type = type;
 	dev->signal = ATM_PHY_SIG_UNKNOWN;
 	dev->link_rate = ATM_OC3_PCR;
-	list_add_tail(&dev->dev_list, &atm_devs);
+	spin_lock_init(&dev->lock);
 
 	return dev;
 }
 
-/* Caller must hold atm_dev_lock. */
 static void __free_atm_dev(struct atm_dev *dev)
 {
-	list_del(&dev->dev_list);
 	kfree(dev);
 }
 
-/* Caller must hold atm_dev_lock. */
-struct atm_dev *atm_find_dev(int number)
+static struct atm_dev *__atm_dev_lookup(int number)
 {
 	struct atm_dev *dev;
 	struct list_head *p;
 
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
-		if (dev->ops && dev->number == number)
+		if ((dev->ops) && (dev->number == number)) {
+			atm_dev_hold(dev);
 			return dev;
+		}
 	}
 	return NULL;
 }
 
-
-struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
-				 int number, unsigned long *flags)
+struct atm_dev *atm_dev_lookup(int number)
 {
 	struct atm_dev *dev;
 
 	spin_lock(&atm_dev_lock);
+	dev = __atm_dev_lookup(number);
+	spin_unlock(&atm_dev_lock);
+	return dev;
+}
+
+struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
+				 int number, unsigned long *flags)
+{
+	struct atm_dev *dev, *inuse;
 
 	dev = __alloc_atm_dev(type);
 	if (!dev) {
 		printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
 		    type);
-		goto done;
+		return NULL;
 	}
+	spin_lock(&atm_dev_lock);
 	if (number != -1) {
-		if (atm_find_dev(number)) {
+		if ((inuse = __atm_dev_lookup(number))) {
+			atm_dev_release(inuse);
+			spin_unlock(&atm_dev_lock);
 			__free_atm_dev(dev);
-			dev = NULL;
-			goto done;
+			return NULL;
 		}
 		dev->number = number;
 	} else {
 		dev->number = 0;
-		while (atm_find_dev(dev->number))
+		while ((inuse = __atm_dev_lookup(dev->number))) {
+			atm_dev_release(inuse);
 			dev->number++;
+		}
 	}
-	dev->vccs = dev->last = NULL;
-	dev->dev_data = NULL;
-	barrier();
+
 	dev->ops = ops;
 	if (flags)
 		dev->flags = *flags;
 	else
 		memset(&dev->flags, 0, sizeof(dev->flags));
 	memset(&dev->stats, 0, sizeof(dev->stats));
+	atomic_set(&dev->refcnt, 1);
+	list_add_tail(&dev->dev_list, &atm_devs);
+	spin_unlock(&atm_dev_lock);
 
 #ifdef CONFIG_PROC_FS
 	if (ops->proc_read) {
@@ -110,33 +119,50 @@
 			printk(KERN_ERR "atm_dev_register: "
 			       "atm_proc_dev_register failed for dev %s\n",
 			       type);
+			spin_lock(&atm_dev_lock);
+			list_del(&dev->dev_list);
+			spin_unlock(&atm_dev_lock);
 			__free_atm_dev(dev);
-			dev = NULL;
-			goto done;
+			return NULL;
 		}
 	}
 #endif
 
-done:
-	spin_unlock(&atm_dev_lock);
 	return dev;
 }
 
 
 void atm_dev_deregister(struct atm_dev *dev)
 {
+	unsigned long warning_time;
+
 #ifdef CONFIG_PROC_FS
 	if (dev->ops->proc_read)
 		atm_proc_dev_deregister(dev);
 #endif
 	spin_lock(&atm_dev_lock);
-	__free_atm_dev(dev);
+	list_del(&dev->dev_list);
 	spin_unlock(&atm_dev_lock);
+
+        warning_time = jiffies;
+        while (atomic_read(&dev->refcnt) != 1) {
+                current->state = TASK_INTERRUPTIBLE;
+                schedule_timeout(HZ / 4);
+                current->state = TASK_RUNNING;
+                if ((jiffies - warning_time) > 10 * HZ) {
+                        printk(KERN_EMERG "atm_dev_deregister: waiting for "
+                               "dev %d to become free. Usage count = %d\n",
+                               dev->number, atomic_read(&dev->refcnt));
+                        warning_time = jiffies;
+                }
+        }
+
+	__free_atm_dev(dev);
 }
 
 void shutdown_atm_dev(struct atm_dev *dev)
 {
-	if (dev->vccs) {
+	if (atomic_read(&dev->refcnt) > 1) {
 		set_bit(ATM_DF_CLOSE, &dev->flags);
 		return;
 	}
@@ -161,44 +187,44 @@
 	sock_init_data(NULL, sk);
 	memset(vcc, 0, sizeof(*vcc));
 	vcc->sk = sk;
-	if (nodev_vccs)
-		nodev_vccs->prev = vcc;
-	vcc->prev = NULL;
-	vcc->next = nodev_vccs;
-	nodev_vccs = vcc;
+
 	return sk;
 }
 
 
-static void unlink_vcc(struct atm_vcc *vcc,struct atm_dev *hold_dev)
+static void unlink_vcc(struct atm_vcc *vcc)
 {
-	if (vcc->prev)
-		vcc->prev->next = vcc->next;
-	else if (vcc->dev)
-		vcc->dev->vccs = vcc->next;
-	else
-		nodev_vccs = vcc->next;
-	if (vcc->next)
-		vcc->next->prev = vcc->prev;
-	else if (vcc->dev)
-		vcc->dev->last = vcc->prev;
-	if (vcc->dev && vcc->dev != hold_dev && !vcc->dev->vccs &&
-	    test_bit(ATM_DF_CLOSE,&vcc->dev->flags))
-		shutdown_atm_dev(vcc->dev);
+	unsigned long flags;
+	if (vcc->dev) {
+		spin_lock_irqsave(&vcc->dev->lock, flags);
+		if (vcc->prev)
+			vcc->prev->next = vcc->next;
+		else
+			vcc->dev->vccs = vcc->next;
+
+		if (vcc->next)
+			vcc->next->prev = vcc->prev;
+		else
+			vcc->dev->last = vcc->prev;
+		spin_unlock_irqrestore(&vcc->dev->lock, flags);
+	}
 }
 
 
 void free_atm_vcc_sk(struct sock *sk)
 {
-	unlink_vcc(atm_sk(sk), NULL);
+	unlink_vcc(atm_sk(sk));
 	sk_free(sk);
 }
 
 void bind_vcc(struct atm_vcc *vcc,struct atm_dev *dev)
 {
-	unlink_vcc(vcc,dev);
+	unsigned long flags;
+
+	unlink_vcc(vcc);
 	vcc->dev = dev;
 	if (dev) {
+		spin_lock_irqsave(&dev->lock, flags);
 		vcc->next = NULL;
 		vcc->prev = dev->last;
 		if (dev->vccs)
@@ -206,17 +232,12 @@
 		else
 			dev->vccs = vcc;
 		dev->last = vcc;
-	} else {
-		if (nodev_vccs)
-			nodev_vccs->prev = vcc;
-		vcc->next = nodev_vccs;
-		vcc->prev = NULL;
-		nodev_vccs = vcc;
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
 }
 
 EXPORT_SYMBOL(atm_dev_register);
 EXPORT_SYMBOL(atm_dev_deregister);
-EXPORT_SYMBOL(atm_find_dev);
+EXPORT_SYMBOL(atm_dev_lookup);
 EXPORT_SYMBOL(shutdown_atm_dev);
 EXPORT_SYMBOL(bind_vcc);
diff -Nru a/net/atm/resources.h b/net/atm/resources.h
--- a/net/atm/resources.h	Sat Mar  8 13:09:15 2003
+++ b/net/atm/resources.h	Thu May 15 17:20:17 2003
@@ -11,7 +11,7 @@
 
 
 extern struct list_head atm_devs;
-extern struct atm_vcc *nodev_vccs; /* VCCs not linked to any device */
+extern spinlock_t atm_dev_lock;
 
 
 struct sock *alloc_atm_vcc_sk(int family);
diff -Nru a/net/atm/signaling.c b/net/atm/signaling.c
--- a/net/atm/signaling.c	Sat Mar  8 13:09:15 2003
+++ b/net/atm/signaling.c	Thu May 15 17:20:17 2003
@@ -33,7 +33,6 @@
 struct atm_vcc *sigd = NULL;
 static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
 
-extern spinlock_t atm_dev_lock;
 
 static void sigd_put_skb(struct sk_buff *skb)
 {
@@ -98,7 +97,7 @@
 	struct atm_vcc *session_vcc;
 
 	msg = (struct atmsvc_msg *) skb->data;
-	atomic_sub(skb->truesize+ATM_PDU_OVHD,&vcc->sk->wmem_alloc);
+	atomic_sub(skb->truesize, &vcc->sk->wmem_alloc);
 	DPRINTK("sigd_send %d (0x%lx)\n",(int) msg->type,
 	  (unsigned long) msg->vcc);
 	vcc = *(struct atm_vcc **) &msg->vcc;
@@ -129,12 +128,12 @@
 		case as_indicate:
 			vcc = *(struct atm_vcc **) &msg->listen_vcc;
 			DPRINTK("as_indicate!!!\n");
-			if (!vcc->backlog_quota) {
+			if (vcc->sk->ack_backlog == vcc->sk->max_ack_backlog) {
 				sigd_enq(0,as_reject,vcc,NULL,NULL);
 				return 0;
 			}
-			vcc->backlog_quota--;
-			skb_queue_tail(&vcc->listenq,skb);
+			vcc->sk->ack_backlog++;
+			skb_queue_tail(&vcc->sk->receive_queue,skb);
 			if (vcc->callback) {
 				DPRINTK("waking vcc->sleep 0x%p\n",
 				    &vcc->sleep);
@@ -211,6 +210,7 @@
 
 static void sigd_close(struct atm_vcc *vcc)
 {
+	unsigned long flags;
 	struct atm_dev *dev;
 	struct list_head *p;
 
@@ -219,33 +219,29 @@
 	if (skb_peek(&vcc->sk->receive_queue))
 		printk(KERN_ERR "sigd_close: closing with requests pending\n");
 	skb_queue_purge(&vcc->sk->receive_queue);
-	purge_vccs(nodev_vccs);
 
-	spin_lock (&atm_dev_lock);
+	spin_lock(&atm_dev_lock);
 	list_for_each(p, &atm_devs) {
 		dev = list_entry(p, struct atm_dev, dev_list);
+		spin_lock_irqsave(&dev->lock, flags);
 		purge_vccs(dev->vccs);
+		spin_unlock_irqrestore(&dev->lock, flags);
 	}
-	spin_unlock (&atm_dev_lock);
+	spin_unlock(&atm_dev_lock);
 }
 
 
 static struct atmdev_ops sigd_dev_ops = {
-	.close =sigd_close,
+	.close = sigd_close,
 	.send =	sigd_send
 };
 
 
 static struct atm_dev sigd_dev = {
-	&sigd_dev_ops,
-	NULL,		/* no PHY */
-    	"sig",		/* type */
-	999,		/* dummy device number */
-	NULL,NULL,	/* pretend not to have any VCCs */
-	NULL,NULL,	/* no data */
-	0,		/* no flags */
-	NULL,		/* no local address */
-	{ 0 }		/* no ESI, no statistics */
+	.ops =		&sigd_dev_ops,
+	.type =		"sig",
+	.number =	999,
+	.lock =		SPIN_LOCK_UNLOCKED
 };
 
 
diff -Nru a/net/atm/svc.c b/net/atm/svc.c
--- a/net/atm/svc.c	Thu Apr  3 06:08:19 2003
+++ b/net/atm/svc.c	Thu May 15 21:54:16 2003
@@ -64,8 +64,8 @@
 
 	DPRINTK("svc_disconnect %p\n",vcc);
 	if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
-		sigd_enq(vcc,as_close,NULL,NULL,NULL);
 		add_wait_queue(&vcc->sleep,&wait);
+		sigd_enq(vcc,as_close,NULL,NULL,NULL);
 		while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule();
@@ -74,7 +74,7 @@
 	}
 	/* beware - socket is still in use by atmsigd until the last
 	   as_indicate has been answered */
-	while ((skb = skb_dequeue(&vcc->listenq))) {
+	while ((skb = skb_dequeue(&vcc->sk->receive_queue))) {
 		DPRINTK("LISTEN REL\n");
 		sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);
 		dev_kfree_skb(skb);
@@ -124,8 +124,8 @@
 	if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) return -EBADFD;
 	vcc->local = *addr;
 	vcc->reply = WAITING;
-	sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
 	add_wait_queue(&vcc->sleep,&wait);
+	sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
 	while (vcc->reply == WAITING && sigd) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule();
@@ -169,12 +169,13 @@
 		    !vcc->qos.rxtp.traffic_class) return -EINVAL;
 		vcc->remote = *addr;
 		vcc->reply = WAITING;
+		add_wait_queue(&vcc->sleep,&wait);
 		sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote);
 		if (flags & O_NONBLOCK) {
+			remove_wait_queue(&vcc->sleep,&wait);
 			sock->state = SS_CONNECTING;
 			return -EINPROGRESS;
 		}
-		add_wait_queue(&vcc->sleep,&wait);
 		error = 0;
 		while (vcc->reply == WAITING && sigd) {
 			set_current_state(TASK_INTERRUPTIBLE);
@@ -243,8 +244,8 @@
 	/* let server handle listen on unbound sockets */
 	if (test_bit(ATM_VF_SESSION,&vcc->flags)) return -EINVAL;
 	vcc->reply = WAITING;
-	sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
 	add_wait_queue(&vcc->sleep,&wait);
+	sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
 	while (vcc->reply == WAITING && sigd) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
 		schedule();
@@ -252,7 +253,7 @@
 	remove_wait_queue(&vcc->sleep,&wait);
 	if (!sigd) return -EUNATCH;
 	set_bit(ATM_VF_LISTEN,&vcc->flags);
-	vcc->backlog_quota = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
+	vcc->sk->max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
 	return vcc->reply;
 }
 
@@ -276,7 +277,7 @@
 		DECLARE_WAITQUEUE(wait,current);
 
 		add_wait_queue(&old_vcc->sleep,&wait);
-		while (!(skb = skb_dequeue(&old_vcc->listenq)) && sigd) {
+		while (!(skb = skb_dequeue(&old_vcc->sk->receive_queue)) && sigd) {
 			if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
 			if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) {
 				error = old_vcc->reply;
@@ -305,7 +306,7 @@
 		error = atm_connect(newsock,msg->pvc.sap_addr.itf,
 		    msg->pvc.sap_addr.vpi,msg->pvc.sap_addr.vci);
 		dev_kfree_skb(skb);
-		old_vcc->backlog_quota++;
+		old_vcc->sk->ack_backlog--;
 		if (error) {
 			sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL,
 			    &old_vcc->qos,error);
@@ -313,8 +314,8 @@
 		}
 		/* wait should be short, so we ignore the non-blocking flag */
 		new_vcc->reply = WAITING;
-		sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
 		add_wait_queue(&new_vcc->sleep,&wait);
+		sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
 		while (new_vcc->reply == WAITING && sigd) {
 			set_current_state(TASK_UNINTERRUPTIBLE);
 			schedule();
@@ -347,8 +348,8 @@
 	DECLARE_WAITQUEUE(wait,current);
 
 	vcc->reply = WAITING;
-	sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
 	add_wait_queue(&vcc->sleep,&wait);
+	sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
 	while (vcc->reply == WAITING && !test_bit(ATM_VF_RELEASED,&vcc->flags)
 	    && sigd) {
 		set_current_state(TASK_UNINTERRUPTIBLE);
@@ -438,13 +439,12 @@
  *	Initialize the ATM SVC protocol family
  */
 
-static int __init atmsvc_init(void)
+int __init atmsvc_init(void)
 {
-	if (sock_register(&svc_family_ops) < 0) {
-		printk(KERN_ERR "ATMSVC: can't register");
-		return -1;
-	}
-	return 0;
+	return sock_register(&svc_family_ops);
 }
 
-module_init(atmsvc_init);
+void atmsvc_exit(void)
+{
+	sock_unregister(PF_ATMSVC);
+}
diff -Nru a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
--- a/net/bluetooth/af_bluetooth.c	Sun Apr 27 21:43:01 2003
+++ b/net/bluetooth/af_bluetooth.c	Sat May 17 12:39:13 2003
@@ -92,21 +92,22 @@
 
 static int bt_sock_create(struct socket *sock, int proto)
 {
+	int err = 0;
+
 	if (proto >= BT_MAX_PROTO)
 		return -EINVAL;
 
 #if defined(CONFIG_KMOD)
 	if (!bt_proto[proto]) {
-		char module_name[30];
-		sprintf(module_name, "bt-proto-%d", proto);
-		request_module(module_name);
+		request_module("bt-proto-%d", proto);
 	}
 #endif
-
-	if (!bt_proto[proto])
-		return -ENOENT;
-
-	return bt_proto[proto]->create(sock, proto);
+	err = -EPROTONOSUPPORT;
+	if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) {
+		err = bt_proto[proto]->create(sock, proto);
+		module_put(bt_proto[proto]->owner);
+	}
+	return err; 
 }
 
 struct sock *bt_sock_alloc(struct socket *sock, int proto, int pi_size, int prio)
diff -Nru a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c
--- a/net/bluetooth/bnep/core.c	Tue Apr 29 02:29:48 2003
+++ b/net/bluetooth/bnep/core.c	Thu May  8 16:38:32 2003
@@ -85,14 +85,17 @@
 
 static void __bnep_link_session(struct bnep_session *s)
 {
-	MOD_INC_USE_COUNT;
+	/* It's safe to call __module_get() here because sessions are added
+	   by the socket layer which has to hold the refference to this module.
+	 */
+	__module_get(THIS_MODULE);
 	list_add(&s->list, &bnep_session_list);	
 }
 
 static void __bnep_unlink_session(struct bnep_session *s)
 {
 	list_del(&s->list);
-	MOD_DEC_USE_COUNT;
+	module_put(THIS_MODULE);
 }
 
 static int bnep_send(struct bnep_session *s, void *data, size_t len)
@@ -677,7 +680,9 @@
 
 static int  __init bnep_init_module(void)
 {	
-	char flt[50] = "";	
+	char flt[50] = "";
+
+	l2cap_load();
 
 #ifdef CONFIG_BT_BNEP_PROTO_FILTER
 	strcat(flt, "protocol ");
diff -Nru a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c
--- a/net/bluetooth/bnep/sock.c	Fri May  2 23:13:15 2003
+++ b/net/bluetooth/bnep/sock.c	Thu May  8 16:38:32 2003
@@ -67,8 +67,6 @@
 
 	sock_orphan(sk);
 	sock_put(sk);
-
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -179,13 +177,10 @@
 		return -ENOMEM;
 	sock->ops = &bnep_sock_ops;
 
-	MOD_INC_USE_COUNT;
-
-	sock->state = SS_UNCONNECTED;
+	sock->state  = SS_UNCONNECTED;
 
 	sk->destruct = NULL;
 	sk->protocol = protocol;
-
 	return 0;
 }
 
diff -Nru a/net/bluetooth/hci_proc.c b/net/bluetooth/hci_proc.c
--- a/net/bluetooth/hci_proc.c	Wed Feb 19 21:05:12 2003
+++ b/net/bluetooth/hci_proc.c	Sat May 10 11:46:34 2003
@@ -115,6 +115,7 @@
 }
 
 static struct file_operations inq_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open    = inq_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
diff -Nru a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c
--- a/net/bluetooth/l2cap.c	Fri May  2 23:13:15 2003
+++ b/net/bluetooth/l2cap.c	Mon May 12 12:47:24 2003
@@ -145,8 +145,6 @@
 	conn->chan_list.lock = RW_LOCK_UNLOCKED;
 
 	BT_DBG("hcon %p conn %p", hcon, conn);
-
-	MOD_INC_USE_COUNT;
 	return conn;
 }
 
@@ -173,8 +171,6 @@
 
 	hcon->l2cap_data = NULL;
 	kfree(conn);
-
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -242,8 +238,6 @@
 
 	if (sk->protinfo)
 		kfree(sk->protinfo);
-	
-	MOD_DEC_USE_COUNT;
 }
 
 static void l2cap_sock_cleanup_listen(struct sock *parent)
@@ -356,6 +350,8 @@
 	if (!sk)
 		return NULL;
 
+	sk_set_owner(sk, THIS_MODULE);
+
 	sk->destruct = l2cap_sock_destruct;
 	sk->sndtimeo = L2CAP_CONN_TIMEOUT;
 
@@ -365,8 +361,6 @@
 	l2cap_sock_init_timer(sk);
 
 	bt_sock_link(&l2cap_sk_list, sk);
-
-	MOD_INC_USE_COUNT;
 	return sk;
 }
 
@@ -1319,15 +1313,18 @@
 {
 	struct l2cap_conf_rsp *rsp = data;
 	void *ptr = rsp->data;
+	u16 flags = 0;
 
 	BT_DBG("sk %p complete %d", sk, result ? 1 : 0);
 
 	if (result)
 		*result = l2cap_conf_output(sk, &ptr);
+	else
+		flags = 0x0001;
 
 	rsp->scid   = __cpu_to_le16(l2cap_pi(sk)->dcid);
 	rsp->result = __cpu_to_le16(result ? *result : 0);
-	rsp->flags  = __cpu_to_le16(0);
+	rsp->flags  = __cpu_to_le16(flags);
 
 	return ptr - data;
 }
@@ -1440,7 +1437,7 @@
 	case L2CAP_CR_SUCCESS:
 		sk->state = BT_CONFIG;
 		l2cap_pi(sk)->dcid = dcid;
-		l2cap_pi(sk)->conf_state |= CONF_REQ_SENT;
+		l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
 
 		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
 		break;
@@ -1475,7 +1472,7 @@
 
 	l2cap_parse_conf_req(sk, req->data, cmd->len - sizeof(*req));
 
-	if (flags & 0x01) {
+	if (flags & 0x0001) {
 		/* Incomplete config. Send empty response. */
 		l2cap_send_rsp(conn, cmd->ident, L2CAP_CONF_RSP, l2cap_build_conf_rsp(sk, rsp, NULL), rsp);
 		goto unlock;
@@ -1488,12 +1485,12 @@
 		goto unlock;
 
 	/* Output config done */
-	l2cap_pi(sk)->conf_state |= CONF_OUTPUT_DONE;
+	l2cap_pi(sk)->conf_state |= L2CAP_CONF_OUTPUT_DONE;
 
-	if (l2cap_pi(sk)->conf_state & CONF_INPUT_DONE) {
+	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_INPUT_DONE) {
 		sk->state = BT_CONNECTED;
 		l2cap_chan_ready(sk);
-	} else if (!(l2cap_pi(sk)->conf_state & CONF_REQ_SENT)) {
+	} else if (!(l2cap_pi(sk)->conf_state & L2CAP_CONF_REQ_SENT)) {
 		u8 req[64];
 		l2cap_send_req(conn, L2CAP_CONF_REQ, l2cap_build_conf_req(sk, req), req);
 	}
@@ -1538,9 +1535,9 @@
 		goto done;
 
 	/* Input config done */
-	l2cap_pi(sk)->conf_state |= CONF_INPUT_DONE;
+	l2cap_pi(sk)->conf_state |= L2CAP_CONF_INPUT_DONE;
 
-	if (l2cap_pi(sk)->conf_state & CONF_OUTPUT_DONE) {
+	if (l2cap_pi(sk)->conf_state & L2CAP_CONF_OUTPUT_DONE) {
 		sk->state = BT_CONNECTED;
 		l2cap_chan_ready(sk);
 	}
@@ -1943,21 +1940,27 @@
 		}
 
 		if (skb->len < 2) {
-			BT_ERR("Frame is too small (len %d)", skb->len);
+			BT_ERR("Frame is too short (len %d)", skb->len);
 			goto drop;
 		}
 
 		hdr = (struct l2cap_hdr *) skb->data;
 		len = __le16_to_cpu(hdr->len) + L2CAP_HDR_SIZE;
 
-		BT_DBG("Start: total len %d, frag len %d", len, skb->len);
-
 		if (len == skb->len) {
 			/* Complete frame received */
 			l2cap_recv_frame(conn, skb);
 			return 0;
 		}
 
+		BT_DBG("Start: total len %d, frag len %d", len, skb->len);
+
+		if (skb->len > len) {
+			BT_ERR("Frame is too long (len %d, expected len %d)",
+				skb->len, len);
+			goto drop;
+		}
+
 		/* Allocate skb for the complete frame (with header) */
 		if (!(conn->rx_skb = bt_skb_alloc(len, GFP_ATOMIC)))
 			goto drop;
@@ -1973,7 +1976,7 @@
 		}
 
 		if (skb->len > conn->rx_len) {
-			BT_ERR("Fragment is too large (len %d, expect %d)",
+			BT_ERR("Fragment is too long (len %d, expected %d)",
 					skb->len, conn->rx_len);
 			kfree_skb(conn->rx_skb);
 			conn->rx_skb = NULL;
@@ -2048,6 +2051,7 @@
 }
 
 static struct file_operations l2cap_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open    = l2cap_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
@@ -2133,7 +2137,6 @@
 		return err;
 	}
 
-
 	l2cap_proc_init();
 	
 	BT_INFO("L2CAP ver %s", VERSION);
@@ -2153,6 +2156,15 @@
 	if (hci_unregister_proto(&l2cap_hci_proto))
 		BT_ERR("L2CAP protocol unregistration failed");
 }
+
+void l2cap_load(void)
+{
+	/* Dummy function to trigger automatic L2CAP module loading by 
+	   other modules that use L2CAP sockets but don not use any other
+	   symbols from it. */
+	return;
+}
+EXPORT_SYMBOL(l2cap_load);
 
 module_init(l2cap_init);
 module_exit(l2cap_cleanup);
diff -Nru a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
--- a/net/bluetooth/rfcomm/core.c	Tue Apr 29 02:40:59 2003
+++ b/net/bluetooth/rfcomm/core.c	Mon May 12 12:47:24 2003
@@ -52,7 +52,7 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
-#define VERSION "0.3"
+#define VERSION "1.0"
 
 #ifndef CONFIG_BT_RFCOMM_DEBUG
 #undef  BT_DBG
@@ -203,6 +203,7 @@
 
 	d->state      = BT_OPEN;
 	d->flags      = 0;
+	d->mscex      = 0;
 	d->mtu        = RFCOMM_DEFAULT_MTU;
 	d->v24_sig    = RFCOMM_V24_RTC | RFCOMM_V24_RTR | RFCOMM_V24_DV;
 
@@ -304,10 +305,11 @@
 
 	rfcomm_dlc_clear_state(d);
 
-	d->dlci    = dlci;
-	d->addr    = __addr(s->initiator, dlci);
+	d->dlci     = dlci;
+	d->addr     = __addr(s->initiator, dlci);
+	d->priority = 7;
 
-	d->state   = BT_CONFIG;
+	d->state    = BT_CONFIG;
 	rfcomm_dlc_link(s, d);
 
 	d->mtu     = s->mtu;
@@ -481,9 +483,12 @@
 	list_add(&s->list, &session_list);
 
 	/* Do not increment module usage count for listeting sessions.
-	 * Otherwise we won't be able to unload the module. */
+	 * Otherwise we won't be able to unload the module.
+	 * Non listening session are added either by a socket or a TTYs
+	 * which means that we already hold refcount to this module.
+	 */
 	if (state != BT_LISTEN)
-		MOD_INC_USE_COUNT;
+		__module_get(THIS_MODULE);
 	return s;
 }
 
@@ -502,7 +507,7 @@
 	kfree(s);
 
 	if (state != BT_LISTEN)
-		MOD_DEC_USE_COUNT;
+		module_put(THIS_MODULE);
 }
 
 struct rfcomm_session *rfcomm_session_get(bdaddr_t *src, bdaddr_t *dst)
@@ -741,7 +746,7 @@
 
 	pn = (void *) ptr; ptr += sizeof(*pn);
 	pn->dlci        = d->dlci;
-	pn->priority    = 0;
+	pn->priority    = d->priority;
 	pn->ack_timer   = 0;
 	pn->max_retrans = 0;
 
@@ -1099,8 +1104,6 @@
 			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
 			d->credits = 0;
 		}
-
-		d->mtu = btohs(pn->mtu);
 	} else {
 		if (pn->flow_ctrl == 0xe0) {
 			d->tx_credits = pn->credits;
@@ -1108,10 +1111,12 @@
 			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
 			d->credits = 0;
 		}
-
-		d->mtu = btohs(pn->mtu);
 	}
 
+	d->priority = pn->priority;
+
+	d->mtu = btohs(pn->mtu);
+
 	return 0;
 }
 
@@ -1137,7 +1142,7 @@
 			switch (d->state) {
 			case BT_CONFIG:
 				rfcomm_apply_pn(d, cr, pn);
-				
+
 				d->state = BT_CONNECT;
 				rfcomm_send_sabm(s, d->dlci);
 				break;
@@ -1148,7 +1153,7 @@
 
 		if (!cr)
 			return 0;
-		
+
 		/* PN request for non existing DLC.
 		 * Assume incoming connection. */
 		if (rfcomm_connect_ind(s, channel, &d)) {
@@ -1157,7 +1162,7 @@
 			rfcomm_dlc_link(s, d);
 
 			rfcomm_apply_pn(d, cr, pn);
-			
+
 			d->state = BT_OPEN;
 			rfcomm_send_pn(s, 0, d);
 		} else {
@@ -1229,21 +1234,21 @@
 	if (rpn->param_mask & RFCOMM_RPN_PM_FLOW) {
 		if (rpn->flow_ctrl != RFCOMM_RPN_FLOW_NONE) {
 			BT_DBG("RPN flow ctrl mismatch 0x%x", rpn->flow_ctrl);
-			rpn->flow_ctrl = RFCOMM_RPN_FLOW_NONE;
+			flow_ctrl = RFCOMM_RPN_FLOW_NONE;
 			rpn_mask ^= RFCOMM_RPN_PM_FLOW;
 		}
 	}
 	if (rpn->param_mask & RFCOMM_RPN_PM_XON) {
 		if (rpn->xon_char != RFCOMM_RPN_XON_CHAR) {
 			BT_DBG("RPN XON char mismatch 0x%x", rpn->xon_char);
-			rpn->xon_char = RFCOMM_RPN_XON_CHAR;
+			xon_char = RFCOMM_RPN_XON_CHAR;
 			rpn_mask ^= RFCOMM_RPN_PM_XON;
 		}
 	}
 	if (rpn->param_mask & RFCOMM_RPN_PM_XOFF) {
 		if (rpn->xoff_char != RFCOMM_RPN_XOFF_CHAR) {
 			BT_DBG("RPN XOFF char mismatch 0x%x", rpn->xoff_char);
-			rpn->xoff_char = RFCOMM_RPN_XOFF_CHAR;
+			xoff_char = RFCOMM_RPN_XOFF_CHAR;
 			rpn_mask ^= RFCOMM_RPN_PM_XOFF;
 		}
 	}
@@ -1284,11 +1289,11 @@
 
 	BT_DBG("dlci %d cr %d v24 0x%x", dlci, cr, msc->v24_sig);
 
-	if (!cr)
+	d = rfcomm_dlc_get(s, dlci);
+	if (!d) 
 		return 0;
 
-	d = rfcomm_dlc_get(s, dlci);
-	if (d) {
+	if (cr) {
 		if (msc->v24_sig & RFCOMM_V24_FC && !d->credits)
 			set_bit(RFCOMM_TX_THROTTLED, &d->flags);
 		else
@@ -1300,7 +1305,11 @@
 		rfcomm_dlc_unlock(d);
 		
 		rfcomm_send_msc(s, 0, dlci, msc->v24_sig);
-	}
+
+		d->mscex |= RFCOMM_MSCEX_RX;
+	} else 
+		d->mscex |= RFCOMM_MSCEX_TX;
+
 	return 0;
 }
 
@@ -1524,7 +1533,8 @@
 			continue;
 		}
 
-		if (d->state == BT_CONNECTED || d->state == BT_DISCONN)
+		if ((d->state == BT_CONNECTED || d->state == BT_DISCONN) &&
+				d->mscex == RFCOMM_MSCEX_OK)
 			rfcomm_process_tx(d);
 	}
 }
@@ -1824,6 +1834,7 @@
 }
 
 static struct file_operations rfcomm_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open    = rfcomm_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
@@ -1868,6 +1879,8 @@
 /* ---- Initialization ---- */
 int  __init rfcomm_init(void)
 {
+	l2cap_load();
+
 	kernel_thread(rfcomm_run, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
 
 	BT_INFO("RFCOMM ver %s", VERSION);
diff -Nru a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
--- a/net/bluetooth/rfcomm/sock.c	Fri May  2 23:13:15 2003
+++ b/net/bluetooth/rfcomm/sock.c	Mon May 12 12:47:24 2003
@@ -182,8 +182,6 @@
 
 	if (sk->protinfo)
 		kfree(sk->protinfo);
-	
-	MOD_DEC_USE_COUNT;
 }
 
 static void rfcomm_sock_cleanup_listen(struct sock *parent)
@@ -265,6 +263,8 @@
 	if (!sk)
 		return NULL;
 
+	sk_set_owner(sk, THIS_MODULE);
+
 	d = rfcomm_dlc_alloc(prio);
 	if (!d) {
 		sk_free(sk);
@@ -288,8 +288,6 @@
 	bt_sock_link(&rfcomm_sk_list, sk);
 
 	BT_DBG("sk %p", sk);
-
-	MOD_INC_USE_COUNT;
 	return sk;
 }
 
@@ -821,6 +819,7 @@
 }
 
 static struct file_operations rfcomm_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open    = rfcomm_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
diff -Nru a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c
--- a/net/bluetooth/rfcomm/tty.c	Tue Apr 29 02:40:59 2003
+++ b/net/bluetooth/rfcomm/tty.c	Thu May  8 16:38:33 2003
@@ -99,7 +99,9 @@
 	rfcomm_dlc_put(dlc);
 	kfree(dev);
 
-	MOD_DEC_USE_COUNT;
+	/* It's safe to call module_put() here because socket still 
+	 holds refference to this module. */
+	module_put(THIS_MODULE);
 }
 
 static inline void rfcomm_dev_hold(struct rfcomm_dev *dev)
@@ -211,8 +213,9 @@
 	dev->dlc   = dlc;
 	rfcomm_dlc_unlock(dlc);
 
-	MOD_INC_USE_COUNT;
-	
+	/* It's safe to call __module_get() here because socket already 
+	 holds refference to this module. */
+	__module_get(THIS_MODULE);
 out:
 	write_unlock_bh(&rfcomm_dev_lock);
 
diff -Nru a/net/bluetooth/sco.c b/net/bluetooth/sco.c
--- a/net/bluetooth/sco.c	Fri May  2 23:13:15 2003
+++ b/net/bluetooth/sco.c	Mon May 12 12:47:24 2003
@@ -145,8 +145,6 @@
 		conn->mtu = 60;
 
 	BT_DBG("hcon %p conn %p", hcon, conn);
-
-	MOD_INC_USE_COUNT;
 	return conn;
 }
 
@@ -180,8 +178,6 @@
 
 	hcon->sco_data = NULL;
 	kfree(conn);
-
-	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
@@ -347,8 +343,6 @@
 
 	if (sk->protinfo)
 		kfree(sk->protinfo);
-	
-	MOD_DEC_USE_COUNT;
 }
 
 static void sco_sock_cleanup_listen(struct sock *parent)
@@ -434,6 +428,8 @@
 	if (!sk)
 		return NULL;
 
+	sk_set_owner(sk, THIS_MODULE);
+
 	sk->destruct = sco_sock_destruct;
 	sk->sndtimeo = SCO_CONN_TIMEOUT;
 	sk->state    = BT_OPEN;
@@ -441,8 +437,6 @@
 	sco_sock_init_timer(sk);
 
 	bt_sock_link(&sco_sk_list, sk);
-
-	MOD_INC_USE_COUNT;
 	return sk;
 }
 
@@ -933,6 +927,7 @@
 }
 
 static struct file_operations sco_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open    = sco_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
diff -Nru a/net/bridge/br_device.c b/net/bridge/br_device.c
--- a/net/bridge/br_device.c	Fri Apr 25 22:24:03 2003
+++ b/net/bridge/br_device.c	Mon May 19 18:25:07 2003
@@ -125,7 +125,7 @@
 	dev->open = br_dev_open;
 	dev->set_multicast_list = br_dev_set_multicast_list;
 	dev->destructor = br_dev_destruct;
-	dev->owner = THIS_MODULE;
+	SET_MODULE_OWNER(dev);
 	dev->stop = br_dev_stop;
 	dev->accept_fastpath = br_dev_accept_fastpath;
 	dev->tx_queue_len = 0;
diff -Nru a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
--- a/net/bridge/br_fdb.c	Wed Apr 30 00:58:01 2003
+++ b/net/bridge/br_fdb.c	Mon May 12 13:12:17 2003
@@ -20,25 +20,19 @@
 #include <asm/uaccess.h>
 #include "br_private.h"
 
-static __inline__ unsigned long __timeout(struct net_bridge *br)
+/* if topology_changing then use forward_delay (default 15 sec)
+ * otherwise keep longer (default 5 minutes)
+ */
+static __inline__ unsigned long hold_time(const struct net_bridge *br)
 {
-	unsigned long timeout;
-
-	timeout = jiffies - br->ageing_time;
-	if (br->topology_change)
-		timeout = jiffies - br->forward_delay;
-
-	return timeout;
+	return br->topology_change ? br->forward_delay : br->ageing_time;
 }
 
-static __inline__ int has_expired(struct net_bridge *br,
-				  struct net_bridge_fdb_entry *fdb)
+static __inline__ int has_expired(const struct net_bridge *br,
+				  const struct net_bridge_fdb_entry *fdb)
 {
-	if (!fdb->is_static &&
-	    time_before_eq(fdb->ageing_timer, __timeout(br)))
-		return 1;
-
-	return 0;
+	return !fdb->is_static 
+		&& time_before_eq(fdb->ageing_timer + hold_time(br), jiffies);
 }
 
 static __inline__ void copy_fdb(struct __fdb_entry *ent, 
@@ -52,7 +46,7 @@
 		: ((jiffies - f->ageing_timer) * USER_HZ) / HZ;
 }
 
-static __inline__ int br_mac_hash(unsigned char *mac)
+static __inline__ int br_mac_hash(const unsigned char *mac)
 {
 	unsigned long x;
 
@@ -68,7 +62,14 @@
 	return x & (BR_HASH_SIZE - 1);
 }
 
-void br_fdb_changeaddr(struct net_bridge_port *p, unsigned char *newaddr)
+static __inline__ void fdb_delete(struct net_bridge_fdb_entry *f)
+{
+	hlist_del(&f->hlist);
+	list_del(&f->age_list);
+	br_fdb_put(f);
+}
+
+void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
 {
 	struct net_bridge *br;
 	int i;
@@ -98,25 +99,29 @@
 	write_unlock_bh(&br->hash_lock);
 }
 
-void br_fdb_cleanup(struct net_bridge *br)
+void br_fdb_cleanup(unsigned long _data)
 {
-	int i;
-	unsigned long timeout;
-
-	timeout = __timeout(br);
+	struct net_bridge *br = (struct net_bridge *)_data;
+	struct list_head *l, *n;
+	unsigned long delay;
 
 	write_lock_bh(&br->hash_lock);
-	for (i=0;i<BR_HASH_SIZE;i++) {
-		struct hlist_node *h, *g;
-		
-		hlist_for_each_safe(h, g, &br->hash[i]) {
-			struct net_bridge_fdb_entry *f
-				= hlist_entry(h, struct net_bridge_fdb_entry, hlist);
-			if (!f->is_static &&
-			    time_before_eq(f->ageing_timer, timeout)) {
-				hlist_del(&f->hlist);
-				br_fdb_put(f);
+	delay = hold_time(br);
+
+	list_for_each_safe(l, n, &br->age_list) {
+		struct net_bridge_fdb_entry *f
+			= list_entry(l, struct net_bridge_fdb_entry, age_list);
+		unsigned long expires = f->ageing_timer + delay;
+
+		if (time_before_eq(expires, jiffies)) {
+			if (!f->is_static) {
+				pr_debug("expire age %lu jiffies %lu\n",
+					 f->ageing_timer, jiffies);
+				fdb_delete(f);
 			}
+		} else {
+			mod_timer(&br->gc_timer, expires);
+			break;
 		}
 	}
 	write_unlock_bh(&br->hash_lock);
@@ -134,8 +139,7 @@
 			struct net_bridge_fdb_entry *f
 				= hlist_entry(h, struct net_bridge_fdb_entry, hlist);
 			if (f->dst == p) {
-				hlist_del(&f->hlist);
-				br_fdb_put(f);
+				fdb_delete(f);
 			}
 		}
 	}
@@ -237,55 +241,46 @@
 	return num;
 }
 
-static __inline__ void __fdb_possibly_replace(struct net_bridge_fdb_entry *fdb,
-					      struct net_bridge_port *source,
-					      int is_local)
-{
-	if (!fdb->is_static || is_local) {
-		fdb->dst = source;
-		fdb->is_local = is_local;
-		fdb->is_static = is_local;
-		fdb->ageing_timer = jiffies;
-	}
-}
-
-void br_fdb_insert(struct net_bridge *br,
-		   struct net_bridge_port *source,
-		   unsigned char *addr,
-		   int is_local)
+void br_fdb_insert(struct net_bridge *br, struct net_bridge_port *source,
+		   const unsigned char *addr, int is_local)
 {
 	struct hlist_node *h;
 	struct net_bridge_fdb_entry *fdb;
-	int hash;
-
-	hash = br_mac_hash(addr);
+	int hash = br_mac_hash(addr);
 
 	write_lock_bh(&br->hash_lock);
 	hlist_for_each(h, &br->hash[hash]) {
 		fdb = hlist_entry(h, struct net_bridge_fdb_entry, hlist);
 		if (!fdb->is_local &&
 		    !memcmp(fdb->addr.addr, addr, ETH_ALEN)) {
-			__fdb_possibly_replace(fdb, source, is_local);
-			write_unlock_bh(&br->hash_lock);
-			return;
+			if (likely(!fdb->is_static || is_local)) {
+				/* move to end of age list */
+				list_del(&fdb->age_list);
+				goto update;
+			}
+			goto out;
 		}
-
 	}
 
 	fdb = kmalloc(sizeof(*fdb), GFP_ATOMIC);
-	if (fdb == NULL) {
-		write_unlock_bh(&br->hash_lock);
-		return;
-	}
+	if (fdb == NULL) 
+		goto out;
 
 	memcpy(fdb->addr.addr, addr, ETH_ALEN);
 	atomic_set(&fdb->use_count, 1);
+	hlist_add_head(&fdb->hlist, &br->hash[hash]);
+
+	if (!timer_pending(&br->gc_timer)) {
+		br->gc_timer.expires = jiffies + hold_time(br);
+		add_timer(&br->gc_timer);
+	}
+
+ update:
 	fdb->dst = source;
 	fdb->is_local = is_local;
 	fdb->is_static = is_local;
 	fdb->ageing_timer = jiffies;
-
-	hlist_add_head(&fdb->hlist, &br->hash[hash]);
-
+	list_add_tail(&fdb->age_list, &br->age_list);
+ out:
 	write_unlock_bh(&br->hash_lock);
 }
diff -Nru a/net/bridge/br_if.c b/net/bridge/br_if.c
--- a/net/bridge/br_if.c	Fri Apr 25 22:54:34 2003
+++ b/net/bridge/br_if.c	Mon May 19 23:22:52 2003
@@ -84,8 +84,6 @@
 	memset(br, 0, sizeof(*br));
 	dev = &br->dev;
 
-	init_timer(&br->tick);
-
 	strncpy(dev->name, name, IFNAMSIZ);
 	dev->priv = br;
 	dev->priv_flags = IFF_EBRIDGE;
@@ -109,12 +107,10 @@
 	br->bridge_forward_delay = br->forward_delay = 15 * HZ;
 	br->topology_change = 0;
 	br->topology_change_detected = 0;
-	br_timer_clear(&br->hello_timer);
-	br_timer_clear(&br->tcn_timer);
-	br_timer_clear(&br->topology_change_timer);
-
 	br->ageing_time = 300 * HZ;
-	br->gc_interval = 4 * HZ;
+	INIT_LIST_HEAD(&br->age_list);
+
+	br_stp_timer_init(br);
 
 	return br;
 }
@@ -281,8 +277,7 @@
 	rtnl_lock();
 	for (dev = dev_base; dev; dev = nxt) {
 		nxt = dev->next;
-		if ((dev->priv_flags & IFF_EBRIDGE)
-		    && dev->owner == THIS_MODULE) {
+		if (dev->priv_flags & IFF_EBRIDGE) {
 			pr_debug("cleanup %s\n", dev->name);
 
 			del_ifs((struct net_bridge *) dev->priv);
diff -Nru a/net/bridge/br_input.c b/net/bridge/br_input.c
--- a/net/bridge/br_input.c	Fri Apr 25 22:24:03 2003
+++ b/net/bridge/br_input.c	Wed May 14 13:59:21 2003
@@ -64,7 +64,7 @@
 	smp_read_barrier_depends();
 
 	if (p == NULL || p->state == BR_STATE_DISABLED) {
-		kfree(skb);
+		kfree_skb(skb);
 		goto out;
 	}
 
@@ -142,6 +142,9 @@
 			rcu_read_unlock();
 			return -1;
 		}
+
+		if (!memcmp(p->br->dev.dev_addr, dest, ETH_ALEN))
+			skb->pkt_type = PACKET_HOST;
 
 		NF_HOOK(PF_BRIDGE, NF_BR_PRE_ROUTING, skb, skb->dev, NULL,
 			br_handle_frame_finish);
diff -Nru a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
--- a/net/bridge/br_ioctl.c	Tue Apr 29 02:37:01 2003
+++ b/net/bridge/br_ioctl.c	Mon May 12 13:12:17 2003
@@ -32,9 +32,10 @@
 }
 
 /* Report time remaining in user HZ  */
-static unsigned long timer_residue(const struct br_timer *timer)
+static unsigned long timer_residue(const struct timer_list *timer)
 {
-	return ticks_to_user(timer->running ? (jiffies - timer->expires) : 0);
+	return ticks_to_user(timer_pending(timer) 
+			     ? (timer->expires - jiffies) : 0);
 }
 
 static int br_ioctl_device(struct net_bridge *br,
@@ -87,7 +88,6 @@
 		b.root_port = br->root_port;
 		b.stp_enabled = br->stp_enabled;
 		b.ageing_time = ticks_to_user(br->ageing_time);
-		b.gc_interval = ticks_to_user(br->gc_interval);
 		b.hello_timer_value = timer_residue(&br->hello_timer);
 		b.tcn_timer_value = timer_residue(&br->tcn_timer);
 		b.topology_change_timer_value = timer_residue(&br->topology_change_timer);
@@ -146,8 +146,7 @@
 		br->ageing_time = user_to_ticks(arg0);
 		return 0;
 
-	case BRCTL_SET_GC_INTERVAL:
-		br->gc_interval = user_to_ticks(arg0);
+	case BRCTL_SET_GC_INTERVAL:	 /* no longer used */
 		return 0;
 
 	case BRCTL_GET_PORT_INFO:
diff -Nru a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c
--- a/net/bridge/br_netfilter.c	Tue Apr 29 02:32:55 2003
+++ b/net/bridge/br_netfilter.c	Tue May 20 19:39:24 2003
@@ -620,13 +620,11 @@
 	  .priority = NF_IP_PRI_FIRST, },
 };
 
-#define NUMHOOKS (sizeof(br_nf_ops)/sizeof(br_nf_ops[0]))
-
 int br_netfilter_init(void)
 {
 	int i;
 
-	for (i = 0; i < NUMHOOKS; i++) {
+	for (i = 0; i < ARRAY_SIZE(br_nf_ops); i++) {
 		int ret;
 
 		if ((ret = nf_register_hook(&br_nf_ops[i])) >= 0)
@@ -647,6 +645,6 @@
 {
 	int i;
 
-	for (i = NUMHOOKS - 1; i >= 0; i--)
+	for (i = ARRAY_SIZE(br_nf_ops) - 1; i >= 0; i--)
 		nf_unregister_hook(&br_nf_ops[i]);
 }
diff -Nru a/net/bridge/br_private.h b/net/bridge/br_private.h
--- a/net/bridge/br_private.h	Wed Apr 30 00:58:01 2003
+++ b/net/bridge/br_private.h	Mon May 12 13:12:17 2003
@@ -18,7 +18,6 @@
 #include <linux/netdevice.h>
 #include <linux/miscdevice.h>
 #include <linux/if_bridge.h>
-#include "br_private_timer.h"
 
 #define BR_HASH_BITS 8
 #define BR_HASH_SIZE (1 << BR_HASH_BITS)
@@ -44,10 +43,11 @@
 struct net_bridge_fdb_entry
 {
 	struct hlist_node		hlist;
-	atomic_t			use_count;
-	mac_addr			addr;
 	struct net_bridge_port		*dst;
+	struct list_head		age_list;
+	atomic_t			use_count;
 	unsigned long			ageing_timer;
+	mac_addr			addr;
 	unsigned			is_local:1;
 	unsigned			is_static:1;
 };
@@ -71,10 +71,9 @@
 	unsigned			config_pending:1;
 	int				priority;
 
-	struct br_timer			forward_delay_timer;
-	struct br_timer			hold_timer;
-	struct br_timer			message_age_timer;
-
+	struct timer_list		forward_delay_timer;
+	struct timer_list		hold_timer;
+	struct timer_list		message_age_timer;
 	struct rcu_head			rcu;
 };
 
@@ -86,7 +85,7 @@
 	struct net_device_stats		statistics;
 	rwlock_t			hash_lock;
 	struct hlist_head		hash[BR_HASH_SIZE];
-	struct timer_list		tick;
+	struct list_head		age_list;
 
 	/* STP */
 	bridge_id			designated_root;
@@ -103,13 +102,12 @@
 	unsigned			topology_change:1;
 	unsigned			topology_change_detected:1;
 
-	struct br_timer			hello_timer;
-	struct br_timer			tcn_timer;
-	struct br_timer			topology_change_timer;
-	struct br_timer			gc_timer;
+	struct timer_list		hello_timer;
+	struct timer_list		tcn_timer;
+	struct timer_list		topology_change_timer;
+	struct timer_list		gc_timer;
 
 	int				ageing_time;
-	int				gc_interval;
 };
 
 extern struct notifier_block br_device_notifier;
@@ -128,8 +126,8 @@
 
 /* br_fdb.c */
 extern void br_fdb_changeaddr(struct net_bridge_port *p,
-		       unsigned char *newaddr);
-extern void br_fdb_cleanup(struct net_bridge *br);
+			      const unsigned char *newaddr);
+extern void br_fdb_cleanup(unsigned long arg);
 extern void br_fdb_delete_by_port(struct net_bridge *br,
 			   struct net_bridge_port *p);
 extern struct net_bridge_fdb_entry *br_fdb_get(struct net_bridge *br,
@@ -140,9 +138,9 @@
 			int maxnum,
 			int offset);
 extern void br_fdb_insert(struct net_bridge *br,
-		   struct net_bridge_port *source,
-		   unsigned char *addr,
-		   int is_local);
+			  struct net_bridge_port *source,
+			  const unsigned char *addr,
+			  int is_local);
 
 /* br_forward.c */
 extern void br_deliver(const struct net_bridge_port *to,
@@ -188,10 +186,10 @@
 extern void br_netfilter_fini(void);
 
 /* br_stp.c */
+extern void br_log_state(const struct net_bridge_port *p);
 extern struct net_bridge_port *br_get_port(struct net_bridge *br,
 				    int port_no);
 extern void br_init_port(struct net_bridge_port *p);
-extern port_id br_make_port_id(struct net_bridge_port *p);
 extern void br_become_designated_port(struct net_bridge_port *p);
 
 /* br_stp_if.c */
@@ -209,5 +207,9 @@
 
 /* br_stp_bpdu.c */
 extern void br_stp_handle_bpdu(struct sk_buff *skb);
+
+/* br_stp_timer.c */
+extern void br_stp_timer_init(struct net_bridge *br);
+extern void br_stp_port_timer_init(struct net_bridge_port *p);
 
 #endif
diff -Nru a/net/bridge/br_private_stp.h b/net/bridge/br_private_stp.h
--- a/net/bridge/br_private_stp.h	Tue Apr 29 02:35:32 2003
+++ b/net/bridge/br_private_stp.h	Mon May 12 13:12:17 2003
@@ -47,7 +47,6 @@
 extern void br_port_state_selection(struct net_bridge *);
 extern void br_received_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu);
 extern void br_received_tcn_bpdu(struct net_bridge_port *p);
-extern void br_tick(unsigned long __data);
 extern void br_transmit_config(struct net_bridge_port *p);
 extern void br_transmit_tcn(struct net_bridge *br);
 extern void br_topology_change_detection(struct net_bridge *br);
diff -Nru a/net/bridge/br_private_timer.h b/net/bridge/br_private_timer.h
--- a/net/bridge/br_private_timer.h	Tue Feb  5 09:39:59 2002
+++ /dev/null	Wed Dec 31 16:00:00 1969
@@ -1,54 +0,0 @@
-/*
- *	Linux ethernet bridge
- *
- *	Authors:
- *	Lennert Buytenhek		<buytenh@gnu.org>
- *
- *	$Id: br_private_timer.h,v 1.1 2000/02/18 16:47:13 davem Exp $
- *
- *	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 _BR_PRIVATE_TIMER_H
-#define _BR_PRIVATE_TIMER_H
-
-struct br_timer
-{
-	int running;
-	unsigned long expires;
-};
-
-extern __inline__ void br_timer_clear(struct br_timer *t)
-{
-	t->running = 0;
-}
-
-extern __inline__ unsigned long br_timer_get_residue(struct br_timer *t)
-{
-	if (t->running)
-		return jiffies - t->expires;
-
-	return 0;
-}
-
-extern __inline__ void br_timer_set(struct br_timer *t, unsigned long x)
-{
-	t->expires = x;
-	t->running = 1;
-}
-
-extern __inline__ int br_timer_is_running(struct br_timer *t)
-{
-	return t->running;
-}
-
-extern __inline__ int br_timer_has_expired(struct br_timer *t, unsigned long to)
-{
-	return t->running && time_after_eq(jiffies, t->expires + to);
-}
-
-
-#endif
diff -Nru a/net/bridge/br_stp.c b/net/bridge/br_stp.c
--- a/net/bridge/br_stp.c	Tue Apr 29 02:35:32 2003
+++ b/net/bridge/br_stp.c	Mon May 12 13:12:17 2003
@@ -12,7 +12,6 @@
  *	as published by the Free Software Foundation; either version
  *	2 of the License, or (at your option) any later version.
  */
-
 #include <linux/kernel.h>
 #include <linux/if_bridge.h>
 #include <linux/smp_lock.h>
@@ -20,6 +19,18 @@
 #include "br_private.h"
 #include "br_private_stp.h"
 
+static const char *br_port_state_names[] = {
+	"disabled", "learning", "forwarding", "blocking",
+};
+
+void br_log_state(const struct net_bridge_port *p)
+{
+	pr_info("%s: port %d(%s) entering %s state\n",
+		p->br->dev.name, p->port_no, p->dev->name, 
+		br_port_state_names[p->state]);
+
+}
+
 /* called under bridge lock */
 struct net_bridge_port *br_get_port(struct net_bridge *br, int port_no)
 {
@@ -34,7 +45,8 @@
 }
 
 /* called under bridge lock */
-static int br_should_become_root_port(struct net_bridge_port *p, int root_port)
+static int br_should_become_root_port(const struct net_bridge_port *p, 
+				      int root_port)
 {
 	struct net_bridge *br;
 	struct net_bridge_port *rp;
@@ -116,9 +128,12 @@
 	br->hello_time = br->bridge_hello_time;
 	br->forward_delay = br->bridge_forward_delay;
 	br_topology_change_detection(br);
-	br_timer_clear(&br->tcn_timer);
-	br_config_bpdu_generation(br);
-	br_timer_set(&br->hello_timer, jiffies);
+	del_timer(&br->tcn_timer);
+
+	if (br->dev.flags & IFF_UP) {
+		br_config_bpdu_generation(br);
+		mod_timer(&br->hello_timer, jiffies + br->hello_time);
+	}
 }
 
 /* called under bridge lock */
@@ -127,7 +142,8 @@
 	struct br_config_bpdu bpdu;
 	struct net_bridge *br;
 
-	if (br_timer_is_running(&p->hold_timer)) {
+
+	if (timer_pending(&p->hold_timer)) {
 		p->config_pending = 1;
 		return;
 	}
@@ -142,12 +158,11 @@
 	bpdu.port_id = p->port_id;
 	bpdu.message_age = 0;
 	if (!br_is_root_bridge(br)) {
-		struct net_bridge_port *root;
-		unsigned long age;
+		struct net_bridge_port *root
+			= br_get_port(br, br->root_port);
+		bpdu.max_age = root->message_age_timer.expires - jiffies;
 
-		root = br_get_port(br, br->root_port);
-		age = br_timer_get_residue(&root->message_age_timer) + 1;
-		bpdu.message_age = age;
+		if (bpdu.max_age <= 0) bpdu.max_age = 1;
 	}
 	bpdu.max_age = br->max_age;
 	bpdu.hello_time = br->hello_time;
@@ -157,22 +172,26 @@
 
 	p->topology_change_ack = 0;
 	p->config_pending = 0;
-	br_timer_set(&p->hold_timer, jiffies);
+	
+	mod_timer(&p->hold_timer, jiffies + BR_HOLD_TIME);
 }
 
 /* called under bridge lock */
-static void br_record_config_information(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
+static inline void br_record_config_information(struct net_bridge_port *p, 
+						const struct br_config_bpdu *bpdu)
 {
 	p->designated_root = bpdu->root;
 	p->designated_cost = bpdu->root_path_cost;
 	p->designated_bridge = bpdu->bridge_id;
 	p->designated_port = bpdu->port_id;
 
-	br_timer_set(&p->message_age_timer, jiffies - bpdu->message_age);
+	mod_timer(&p->message_age_timer, jiffies 
+		  + (p->br->max_age - bpdu->message_age));
 }
 
 /* called under bridge lock */
-static void br_record_config_timeout_values(struct net_bridge *br, struct br_config_bpdu *bpdu)
+static inline void br_record_config_timeout_values(struct net_bridge *br, 
+					    const struct br_config_bpdu *bpdu)
 {
 	br->max_age = bpdu->max_age;
 	br->hello_time = bpdu->hello_time;
@@ -187,7 +206,7 @@
 }
 
 /* called under bridge lock */
-static int br_should_become_designated_port(struct net_bridge_port *p)
+static int br_should_become_designated_port(const struct net_bridge_port *p)
 {
 	struct net_bridge *br;
 	int t;
@@ -261,25 +280,28 @@
 }
 
 /* called under bridge lock */
-static void br_topology_change_acknowledged(struct net_bridge *br)
+static inline void br_topology_change_acknowledged(struct net_bridge *br)
 {
 	br->topology_change_detected = 0;
-	br_timer_clear(&br->tcn_timer);
+	del_timer(&br->tcn_timer);
 }
 
 /* called under bridge lock */
 void br_topology_change_detection(struct net_bridge *br)
 {
-	printk(KERN_INFO "%s: topology change detected", br->dev.name);
+	if (!(br->dev.flags & IFF_UP))
+		return;
 
+	pr_info("%s: topology change detected", br->dev.name);
 	if (br_is_root_bridge(br)) {
 		printk(", propagating");
 		br->topology_change = 1;
-		br_timer_set(&br->topology_change_timer, jiffies);
+		mod_timer(&br->topology_change_timer, jiffies
+			  + br->bridge_forward_delay + br->bridge_max_age);
 	} else if (!br->topology_change_detected) {
 		printk(", sending tcn bpdu");
 		br_transmit_tcn(br);
-		br_timer_set(&br->tcn_timer, jiffies);
+		mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time);
 	}
 
 	printk("\n");
@@ -299,7 +321,7 @@
 }
 
 /* called under bridge lock */
-static void br_reply(struct net_bridge_port *p)
+static inline void br_reply(struct net_bridge_port *p)
 {
 	br_transmit_config(p);
 }
@@ -323,6 +345,7 @@
 	p->designated_port = p->port_id;
 }
 
+
 /* called under bridge lock */
 static void br_make_blocking(struct net_bridge_port *p)
 {
@@ -332,11 +355,9 @@
 		    p->state == BR_STATE_LEARNING)
 			br_topology_change_detection(p->br);
 
-		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-		       p->br->dev.name, p->port_no, p->dev->name, "blocking");
-
 		p->state = BR_STATE_BLOCKING;
-		br_timer_clear(&p->forward_delay_timer);
+		br_log_state(p);
+		del_timer(&p->forward_delay_timer);
 	}
 }
 
@@ -345,20 +366,12 @@
 {
 	if (p->state == BR_STATE_BLOCKING) {
 		if (p->br->stp_enabled) {
-			printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-			       p->br->dev.name, p->port_no, p->dev->name,
-			       "listening");
-
 			p->state = BR_STATE_LISTENING;
 		} else {
-			printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-			       p->br->dev.name, p->port_no, p->dev->name,
-			       "learning");
-
 			p->state = BR_STATE_LEARNING;
 		}
-		br_timer_set(&p->forward_delay_timer, jiffies);
-	}
+		br_log_state(p);
+		mod_timer(&p->forward_delay_timer, jiffies + p->br->forward_delay);	}
 }
 
 /* called under bridge lock */
@@ -373,7 +386,7 @@
 				p->topology_change_ack = 0;
 				br_make_forwarding(p);
 			} else if (br_is_designated_port(p)) {
-				br_timer_clear(&p->message_age_timer);
+				del_timer(&p->message_age_timer);
 				br_make_forwarding(p);
 			} else {
 				p->config_pending = 0;
@@ -381,11 +394,12 @@
 				br_make_blocking(p);
 			}
 		}
+
 	}
 }
 
 /* called under bridge lock */
-static void br_topology_change_acknowledge(struct net_bridge_port *p)
+static inline void br_topology_change_acknowledge(struct net_bridge_port *p)
 {
 	p->topology_change_ack = 1;
 	br_transmit_config(p);
@@ -396,20 +410,23 @@
 {
 	struct net_bridge *br;
 	int was_root;
-
+ 
 	br = p->br;
 	was_root = br_is_root_bridge(br);
+
 	if (br_supersedes_port_info(p, bpdu)) {
 		br_record_config_information(p, bpdu);
 		br_configuration_update(br);
 		br_port_state_selection(br);
 
 		if (!br_is_root_bridge(br) && was_root) {
-			br_timer_clear(&br->hello_timer);
+			del_timer(&br->hello_timer);
 			if (br->topology_change_detected) {
-				br_timer_clear(&br->topology_change_timer);
+				del_timer(&br->topology_change_timer);
 				br_transmit_tcn(br);
-				br_timer_set(&br->tcn_timer, jiffies);
+
+				mod_timer(&br->tcn_timer, 
+					  jiffies + br->bridge_hello_time);
 			}
 		}
 
@@ -428,7 +445,7 @@
 void br_received_tcn_bpdu(struct net_bridge_port *p)
 {
 	if (br_is_designated_port(p)) {
-		printk(KERN_INFO "%s: received tcn bpdu on port %i(%s)\n",
+		pr_info("%s: received tcn bpdu on port %i(%s)\n",
 		       p->br->dev.name, p->port_no, p->dev->name);
 
 		br_topology_change_detection(p->br);
diff -Nru a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
--- a/net/bridge/br_stp_if.c	Fri Apr 25 22:24:03 2003
+++ b/net/bridge/br_stp_if.c	Mon May 12 13:12:17 2003
@@ -20,7 +20,7 @@
 #include "br_private.h"
 #include "br_private_stp.h"
 
-__u16 br_make_port_id(struct net_bridge_port *p)
+static inline __u16 br_make_port_id(const struct net_bridge_port *p)
 {
 	return (p->priority << 8) | p->port_no;
 }
@@ -33,33 +33,25 @@
 	p->state = BR_STATE_BLOCKING;
 	p->topology_change_ack = 0;
 	p->config_pending = 0;
-	br_timer_clear(&p->message_age_timer);
-	br_timer_clear(&p->forward_delay_timer);
-	br_timer_clear(&p->hold_timer);
+
+	br_stp_port_timer_init(p);
 }
 
 /* called under bridge lock */
 void br_stp_enable_bridge(struct net_bridge *br)
 {
 	struct net_bridge_port *p;
-	struct timer_list *timer = &br->tick;
 
 	spin_lock_bh(&br->lock);
-	init_timer(timer);
-	timer->data = (unsigned long) br;
-	timer->function = br_tick;
-	timer->expires = jiffies + 1;
-	add_timer(timer);
-
-	br_timer_set(&br->hello_timer, jiffies);
+	br->hello_timer.expires = jiffies + br->hello_time;
+	add_timer(&br->hello_timer);
 	br_config_bpdu_generation(br);
 
 	list_for_each_entry(p, &br->port_list, list) {
 		if (p->dev->flags & IFF_UP)
 			br_stp_enable_port(p);
-	}
 
-	br_timer_set(&br->gc_timer, jiffies);
+	}
 	spin_unlock_bh(&br->lock);
 }
 
@@ -68,22 +60,22 @@
 {
 	struct net_bridge_port *p;
 
-	spin_lock_bh(&br->lock);
-	br->topology_change = 0;
-	br->topology_change_detected = 0;
-	br_timer_clear(&br->hello_timer);
-	br_timer_clear(&br->topology_change_timer);
-	br_timer_clear(&br->tcn_timer);
-	br_timer_clear(&br->gc_timer);
-	br_fdb_cleanup(br);
-
+	spin_lock(&br->lock);
 	list_for_each_entry(p, &br->port_list, list) {
 		if (p->state != BR_STATE_DISABLED)
 			br_stp_disable_port(p);
+
 	}
-	spin_unlock_bh(&br->lock);
 
-	del_timer_sync(&br->tick);
+	br->topology_change = 0;
+	br->topology_change_detected = 0;
+	spin_unlock(&br->lock);
+
+	del_timer_sync(&br->hello_timer);
+	del_timer_sync(&br->topology_change_timer);
+	del_timer_sync(&br->tcn_timer);
+	del_timer_sync(&br->gc_timer);
+
 }
 
 /* called under bridge lock */
@@ -108,10 +100,13 @@
 	p->state = BR_STATE_DISABLED;
 	p->topology_change_ack = 0;
 	p->config_pending = 0;
-	br_timer_clear(&p->message_age_timer);
-	br_timer_clear(&p->forward_delay_timer);
-	br_timer_clear(&p->hold_timer);
+
+	del_timer(&p->message_age_timer);
+	del_timer(&p->forward_delay_timer);
+	del_timer(&p->hold_timer);
+
 	br_configuration_update(br);
+
 	br_port_state_selection(br);
 
 	if (br_is_root_bridge(br) && !wasroot)
diff -Nru a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
--- a/net/bridge/br_stp_timer.c	Fri Apr 25 22:24:03 2003
+++ b/net/bridge/br_stp_timer.c	Mon May 12 13:12:17 2003
@@ -20,51 +20,59 @@
 #include "br_private.h"
 #include "br_private_stp.h"
 
-static void dump_bridge_id(bridge_id *id)
-{
-	printk("%.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x", id->prio[0],
-	       id->prio[1], id->addr[0], id->addr[1], id->addr[2], id->addr[3],
-	       id->addr[4], id->addr[5]);
-}
-
 /* called under bridge lock */
-static int br_is_designated_for_some_port(struct net_bridge *br)
+static int br_is_designated_for_some_port(const struct net_bridge *br)
 {
 	struct net_bridge_port *p;
 
 	list_for_each_entry(p, &br->port_list, list) {
 		if (p->state != BR_STATE_DISABLED &&
-		    !memcmp(&p->designated_bridge, &br->bridge_id, 8))
+		    !memcmp(&p->designated_bridge, &br->bridge_id, 8)) 
 			return 1;
 	}
 
 	return 0;
 }
 
-/* called under bridge lock */
-static void br_hello_timer_expired(struct net_bridge *br)
+static void br_hello_timer_expired(unsigned long arg)
 {
-	br_config_bpdu_generation(br);
-	br_timer_set(&br->hello_timer, jiffies);
+	struct net_bridge *br = (struct net_bridge *)arg;
+	
+	pr_debug("%s: hello timer expired\n", br->dev.name);
+	spin_lock_bh(&br->lock);
+	if (br->dev.flags & IFF_UP) {
+		br_config_bpdu_generation(br);
+
+		br->hello_timer.expires = jiffies + br->hello_time;
+		add_timer(&br->hello_timer);
+	}
+	spin_unlock_bh(&br->lock);
 }
 
-/* called under bridge lock */
-static void br_message_age_timer_expired(struct net_bridge_port *p)
+static void br_message_age_timer_expired(unsigned long arg)
 {
-	struct net_bridge *br;
+	struct net_bridge_port *p = (struct net_bridge_port *) arg;
+	struct net_bridge *br = p->br;
+	const bridge_id *id = &p->designated_bridge;
 	int was_root;
 
-	br = p->br;
-	printk(KERN_INFO "%s: ", br->dev.name);
-	printk("neighbour ");
-	dump_bridge_id(&p->designated_bridge);
-	printk(" lost on port %i(%s)\n", p->port_no, p->dev->name);
+	if (p->state == BR_STATE_DISABLED)
+		return;
+
+	
+	pr_info("%s: neighbor %.2x%.2x.%.2x:%.2x:%.2x:%.2x:%.2x:%.2x lost on port %d(%s)\n",
+		br->dev.name, 
+		id->prio[0], id->prio[1], 
+		id->addr[0], id->addr[1], id->addr[2], 
+		id->addr[3], id->addr[4], id->addr[5],
+		p->port_no, p->dev->name);
 
 	/*
 	 * According to the spec, the message age timer cannot be
 	 * running when we are the root bridge. So..  this was_root
 	 * check is redundant. I'm leaving it in for now, though.
 	 */
+	spin_lock_bh(&br->lock);
 	was_root = br_is_root_bridge(br);
 
 	br_become_designated_port(p);
@@ -72,107 +80,101 @@
 	br_port_state_selection(br);
 	if (br_is_root_bridge(br) && !was_root)
 		br_become_root_bridge(br);
+	spin_unlock_bh(&br->lock);
 }
 
-/* called under bridge lock */
-static void br_forward_delay_timer_expired(struct net_bridge_port *p)
+static void br_forward_delay_timer_expired(unsigned long arg)
 {
-	if (p->state == BR_STATE_LISTENING) {
-		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-		       p->br->dev.name, p->port_no, p->dev->name, "learning");
+	struct net_bridge_port *p = (struct net_bridge_port *) arg;
+	struct net_bridge *br = p->br;
 
+	pr_debug("%s: %d(%s) forward delay timer\n",
+		 br->dev.name, p->port_no, p->dev->name);
+	spin_lock_bh(&br->lock);
+	if (p->state == BR_STATE_LISTENING) {
 		p->state = BR_STATE_LEARNING;
-		br_timer_set(&p->forward_delay_timer, jiffies);
+		p->forward_delay_timer.expires = jiffies + br->forward_delay;
+		add_timer(&p->forward_delay_timer);
 	} else if (p->state == BR_STATE_LEARNING) {
-		printk(KERN_INFO "%s: port %i(%s) entering %s state\n",
-		       p->br->dev.name, p->port_no, p->dev->name, "forwarding");
-
 		p->state = BR_STATE_FORWARDING;
-		if (br_is_designated_for_some_port(p->br))
-			br_topology_change_detection(p->br);
+		if (br_is_designated_for_some_port(br))
+			br_topology_change_detection(br);
 	}
+	br_log_state(p);
+	spin_unlock_bh(&br->lock);
 }
 
-/* called under bridge lock */
-static void br_tcn_timer_expired(struct net_bridge *br)
+static void br_tcn_timer_expired(unsigned long arg)
 {
-	printk(KERN_INFO "%s: retransmitting tcn bpdu\n", br->dev.name);
-	br_transmit_tcn(br);
-	br_timer_set(&br->tcn_timer, jiffies);
+	struct net_bridge *br = (struct net_bridge *) arg;
+
+	pr_debug("%s: tcn timer expired\n", br->dev.name);
+	spin_lock_bh(&br->lock);
+	if (br->dev.flags & IFF_UP) {
+		br_transmit_tcn(br);
+	
+		br->tcn_timer.expires = jiffies + br->bridge_hello_time;
+		add_timer(&br->tcn_timer);
+	}
+	spin_unlock_bh(&br->lock);
 }
 
-/* called under bridge lock */
-static void br_topology_change_timer_expired(struct net_bridge *br)
+static void br_topology_change_timer_expired(unsigned long arg)
 {
+	struct net_bridge *br = (struct net_bridge *) arg;
+
+	pr_debug("%s: topo change timer expired\n", br->dev.name);
+	spin_lock_bh(&br->lock);
 	br->topology_change_detected = 0;
 	br->topology_change = 0;
+	spin_unlock_bh(&br->lock);
 }
 
-/* called under bridge lock */
-static void br_hold_timer_expired(struct net_bridge_port *p)
+static void br_hold_timer_expired(unsigned long arg)
 {
+	struct net_bridge_port *p = (struct net_bridge_port *) arg;
+
+	pr_debug("%s: %d(%s) hold timer expired\n", 
+		 p->br->dev.name,  p->port_no, p->dev->name);
+
+	spin_lock_bh(&p->br->lock);
 	if (p->config_pending)
 		br_transmit_config(p);
+	spin_unlock_bh(&p->br->lock);
 }
 
-/* called under bridge lock */
-static void br_check_port_timers(struct net_bridge_port *p)
+static inline void br_timer_init(struct timer_list *timer,
+			  void (*_function)(unsigned long),
+			  unsigned long _data)
 {
-	if (br_timer_has_expired(&p->message_age_timer, p->br->max_age)) {
-		br_timer_clear(&p->message_age_timer);
-		br_message_age_timer_expired(p);
-	}
-
-	if (br_timer_has_expired(&p->forward_delay_timer, p->br->forward_delay)) {
-		br_timer_clear(&p->forward_delay_timer);
-		br_forward_delay_timer_expired(p);
-	}
-
-	if (br_timer_has_expired(&p->hold_timer, BR_HOLD_TIME)) {
-		br_timer_clear(&p->hold_timer);
-		br_hold_timer_expired(p);
-	}
+	init_timer(timer);
+	timer->function = _function;
+	timer->data = _data;
 }
 
-/* called under bridge lock */
-static void br_check_timers(struct net_bridge *br)
+void br_stp_timer_init(struct net_bridge *br)
 {
-	struct net_bridge_port *p;
+	br_timer_init(&br->hello_timer, br_hello_timer_expired,
+		      (unsigned long) br);
 
-	if (br_timer_has_expired(&br->gc_timer, br->gc_interval)) {
-		br_timer_set(&br->gc_timer, jiffies);
-		br_fdb_cleanup(br);
-	}
+	br_timer_init(&br->tcn_timer, br_tcn_timer_expired, 
+		      (unsigned long) br);
 
-	if (br_timer_has_expired(&br->hello_timer, br->hello_time)) {
-		br_timer_clear(&br->hello_timer);
-		br_hello_timer_expired(br);
-	}
-
-	if (br_timer_has_expired(&br->tcn_timer, br->bridge_hello_time)) {
-		br_timer_clear(&br->tcn_timer);
-		br_tcn_timer_expired(br);
-	}
-
-	if (br_timer_has_expired(&br->topology_change_timer, br->bridge_forward_delay + br->bridge_max_age)) {
-		br_timer_clear(&br->topology_change_timer);
-		br_topology_change_timer_expired(br);
-	}
+	br_timer_init(&br->topology_change_timer,
+		      br_topology_change_timer_expired,
+		      (unsigned long) br);
 
-	list_for_each_entry(p, &br->port_list, list) {
-		if (p->state != BR_STATE_DISABLED)
-			br_check_port_timers(p);
-	}
+	br_timer_init(&br->gc_timer, br_fdb_cleanup, (unsigned long) br);
 }
 
-void br_tick(unsigned long __data)
+void br_stp_port_timer_init(struct net_bridge_port *p)
 {
-	struct net_bridge *br = (struct net_bridge *)__data;
+	br_timer_init(&p->message_age_timer, br_message_age_timer_expired,
+		      (unsigned long) p);
 
-	if (spin_trylock_bh(&br->lock)) {
-		br_check_timers(br);
-		spin_unlock_bh(&br->lock);
-	}
-	br->tick.expires = jiffies + 1;
-	add_timer(&br->tick);
-}
+	br_timer_init(&p->forward_delay_timer, br_forward_delay_timer_expired,
+		      (unsigned long) p);
+		      
+	br_timer_init(&p->hold_timer, br_hold_timer_expired,
+		      (unsigned long) p);
+}	
diff -Nru a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c
--- a/net/bridge/netfilter/ebtable_filter.c	Mon Apr 28 02:27:56 2003
+++ b/net/bridge/netfilter/ebtable_filter.c	Tue May 20 19:39:24 2003
@@ -98,7 +98,7 @@
 	ret = ebt_register_table(&frame_filter);
 	if (ret < 0)
 		return ret;
-	for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(ebt_ops_filter); i++)
 		if ((ret = nf_register_hook(&ebt_ops_filter[i])) < 0)
 			goto cleanup;
 	return ret;
@@ -113,7 +113,7 @@
 {
 	int i;
 
-	for (i = 0; i < sizeof(ebt_ops_filter) / sizeof(ebt_ops_filter[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(ebt_ops_filter); i++)
 		nf_unregister_hook(&ebt_ops_filter[i]);
 	ebt_unregister_table(&frame_filter);
 }
diff -Nru a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c
--- a/net/bridge/netfilter/ebtable_nat.c	Mon Apr 28 02:27:56 2003
+++ b/net/bridge/netfilter/ebtable_nat.c	Tue May 20 19:39:24 2003
@@ -10,6 +10,7 @@
 
 #include <linux/netfilter_bridge/ebtables.h>
 #include <linux/module.h>
+
 #define NAT_VALID_HOOKS ((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT) | \
    (1 << NF_BR_POST_ROUTING))
 
@@ -104,7 +105,7 @@
 	ret = ebt_register_table(&frame_nat);
 	if (ret < 0)
 		return ret;
-	for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(ebt_ops_nat); i++)
 		if ((ret = nf_register_hook(&ebt_ops_nat[i])) < 0)
 			goto cleanup;
 	return ret;
@@ -119,7 +120,7 @@
 {
 	int i;
 
-	for (i = 0; i < sizeof(ebt_ops_nat) / sizeof(ebt_ops_nat[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(ebt_ops_nat); i++)
 		nf_unregister_hook(&ebt_ops_nat[i]);
 	ebt_unregister_table(&frame_nat);
 }
diff -Nru a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c
--- a/net/bridge/netfilter/ebtables.c	Mon Apr 21 20:58:40 2003
+++ b/net/bridge/netfilter/ebtables.c	Sat May 17 12:39:13 2003
@@ -319,10 +319,7 @@
 
 	ret = find_inlist_lock_noload(head, name, error, mutex);
 	if (!ret) {
-		char modulename[EBT_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
-		strcpy(modulename, prefix);
-		strcat(modulename, name);
-		request_module(modulename);
+		request_module("%s%s", prefix, name);
 		ret = find_inlist_lock_noload(head, name, error, mutex);
 	}
 	return ret;
diff -Nru a/net/compat.c b/net/compat.c
--- a/net/compat.c	Mon Mar 31 05:19:22 2003
+++ b/net/compat.c	Mon May 19 23:31:53 2003
@@ -27,8 +27,6 @@
 #include <asm/uaccess.h>
 #include <net/compat.h>
 
-#define AA(__x)		((unsigned long)(__x))
-
 static inline int iov_from_user_compat_to_kern(struct iovec *kiov,
 					  struct compat_iovec *uiov32,
 					  int niov)
@@ -391,34 +389,20 @@
 				char *optval, int optlen)
 {
 	struct compat_sock_fprog *fprog32 = (struct compat_sock_fprog *)optval;
-	struct sock_fprog kfprog;
-	mm_segment_t old_fs;
-	compat_uptr_t uptr;
-	unsigned int fsize;
-	int ret;
+	struct sock_fprog *kfprog = compat_alloc_user_space(sizeof(struct sock_fprog)); 
+	compat_uptr_t ptr;
+	u16 len;
 
 	if (!access_ok(VERIFY_READ, fprog32, sizeof(*fprog32)) ||
-	    __get_user(kfprog.len, &fprog32->len) ||
-	    __get_user(uptr, &fprog32->filter))
-		return -EFAULT;
-
-	fsize = kfprog.len * sizeof(struct sock_filter);
-	kfprog.filter = (struct sock_filter *)kmalloc(fsize, GFP_KERNEL);
-	if (kfprog.filter == NULL)
-		return -ENOMEM;
-	if (copy_from_user(kfprog.filter, compat_ptr(uptr), fsize)) {
-		kfree(kfprog.filter);
+	    !access_ok(VERIFY_WRITE, kfprog, sizeof(struct sock_fprog)) ||
+	    __get_user(len, &fprog32->len) ||
+	    __get_user(ptr, &fprog32->filter) ||
+	    __put_user(len, &kfprog->len) ||
+	    __put_user(compat_ptr(ptr), &kfprog->filter))
 		return -EFAULT;
-	}
-
-	old_fs = get_fs();
-	set_fs(KERNEL_DS);
-	ret = sys_setsockopt(fd, level, optname,
-			     (char *)&kfprog, sizeof(kfprog));
-	set_fs(old_fs);
 
-	kfree(kfprog.filter);
-	return ret;
+	return sys_setsockopt(fd, level, optname, (char *)kfprog, 
+			      sizeof(struct sock_fprog));
 }
 
 static int do_set_icmpv6_filter(int fd, int level, int optname,
diff -Nru a/net/core/Makefile b/net/core/Makefile
--- a/net/core/Makefile	Sun Mar 30 01:45:41 2003
+++ b/net/core/Makefile	Tue May 20 19:59:14 2003
@@ -10,7 +10,8 @@
 endif
 endif
 
-obj-$(CONFIG_NET) += dev.o dev_mcast.o dst.o neighbour.o rtnetlink.o utils.o link_watch.o filter.o
+obj-$(CONFIG_NET) += flow.o dev.o net-sysfs.o dev_mcast.o dst.o neighbour.o \
+		     rtnetlink.o utils.o link_watch.o filter.o
 
 obj-$(CONFIG_NETFILTER) += netfilter.o
 obj-$(CONFIG_NET_DIVERT) += dv.o
diff -Nru a/net/core/dev.c b/net/core/dev.c
--- a/net/core/dev.c	Fri May  2 22:17:22 2003
+++ b/net/core/dev.c	Tue May 20 19:59:14 2003
@@ -90,7 +90,6 @@
 #include <linux/etherdevice.h>
 #include <linux/notifier.h>
 #include <linux/skbuff.h>
-#include <linux/brlock.h>
 #include <net/sock.h>
 #include <linux/rtnetlink.h>
 #include <linux/proc_fs.h>
@@ -132,16 +131,6 @@
 NET_PROFILE_DEFINE(dev_queue_xmit)
 NET_PROFILE_DEFINE(softnet_process)
 
-const char *if_port_text[] = {
-  "unknown",
-  "BNC",
-  "10baseT",
-  "AUI",
-  "100baseT",
-  "100baseTX",
-  "100baseFX"
-};
-
 /*
  *	The list of packet types we will receive (as opposed to discard)
  *	and the routines to invoke.
@@ -170,8 +159,9 @@
  *		86DD	IPv6
  */
 
-static struct packet_type *ptype_base[16];	/* 16 way hashed list */
-static struct packet_type *ptype_all;		/* Taps */
+static spinlock_t ptype_lock = SPIN_LOCK_UNLOCKED;
+static struct list_head ptype_base[16];	/* 16 way hashed list */
+static struct list_head ptype_all;		/* Taps */
 
 #ifdef OFFLINE_SAMPLE
 static void sample_queue(unsigned long dummy);
@@ -179,9 +169,11 @@
 #endif
 
 #ifdef CONFIG_HOTPLUG
-static int net_run_sbin_hotplug(struct net_device *dev, char *action);
+static void net_run_sbin_hotplug(struct net_device *dev, int is_register);
+static void net_run_hotplug_todo(void);
 #else
-#define net_run_sbin_hotplug(dev, action) ({ 0; })
+#define net_run_sbin_hotplug(dev, is_register) do { } while (0)
+#define net_run_hotplug_todo() do { } while (0)
 #endif
 
 /*
@@ -201,7 +193,9 @@
 int netdev_fastroute_obstacles;
 #endif
 
-static struct subsystem net_subsys;
+extern int netdev_sysfs_init(void);
+extern int netdev_register_sysfs(struct net_device *);
+extern void netdev_unregister_sysfs(struct net_device *);
 
 
 /*******************************************************************************
@@ -239,14 +233,17 @@
  *	Add a protocol handler to the networking stack. The passed &packet_type
  *	is linked into kernel lists and may not be freed until it has been
  *	removed from the kernel lists.
+ *
+ *	This call does not sleep therefore it can not 
+ *	guarantee all CPU's that are in middle of receiving packets
+ *	will see the new packet type (until the next received packet).
  */
 
 void dev_add_pack(struct packet_type *pt)
 {
 	int hash;
 
-	br_write_lock_bh(BR_NETPROTO_LOCK);
-
+	spin_lock_bh(&ptype_lock);
 #ifdef CONFIG_NET_FASTROUTE
 	/* Hack to detect packet socket */
 	if (pt->data && (long)(pt->data) != 1) {
@@ -256,52 +253,76 @@
 #endif
 	if (pt->type == htons(ETH_P_ALL)) {
 		netdev_nit++;
-		pt->next  = ptype_all;
-		ptype_all = pt;
+		list_add_rcu(&pt->list, &ptype_all);
 	} else {
 		hash = ntohs(pt->type) & 15;
-		pt->next = ptype_base[hash];
-		ptype_base[hash] = pt;
+		list_add_rcu(&pt->list, &ptype_base[hash]);
 	}
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	spin_unlock_bh(&ptype_lock);
 }
 
 extern void linkwatch_run_queue(void);
 
+
+
 /**
- *	dev_remove_pack	 - remove packet handler
+ *	__dev_remove_pack	 - remove packet handler
  *	@pt: packet type declaration
  *
  *	Remove a protocol handler that was previously added to the kernel
  *	protocol handlers by dev_add_pack(). The passed &packet_type is removed
  *	from the kernel lists and can be freed or reused once this function
- *	returns.
+ *	returns. 
+ *
+ *      The packet type might still be in use by receivers
+ *	and must not be freed until after all the CPU's have gone
+ *	through a quiescent state.
  */
-void dev_remove_pack(struct packet_type *pt)
+void __dev_remove_pack(struct packet_type *pt)
 {
-	struct packet_type **pt1;
+	struct list_head *head;
+	struct packet_type *pt1;
 
-	br_write_lock_bh(BR_NETPROTO_LOCK);
+	spin_lock_bh(&ptype_lock);
 
 	if (pt->type == htons(ETH_P_ALL)) {
 		netdev_nit--;
-		pt1 = &ptype_all;
+		head = &ptype_all;
 	} else
-		pt1 = &ptype_base[ntohs(pt->type) & 15];
+		head = &ptype_base[ntohs(pt->type) & 15];
 
-	for (; *pt1; pt1 = &((*pt1)->next)) {
-		if (pt == *pt1) {
-			*pt1 = pt->next;
+	list_for_each_entry(pt1, head, list) {
+		if (pt == pt1) {
 #ifdef CONFIG_NET_FASTROUTE
 			if (pt->data)
 				netdev_fastroute_obstacles--;
 #endif
+			list_del_rcu(&pt->list);
 			goto out;
 		}
 	}
+
 	printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
 out:
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	spin_unlock_bh(&ptype_lock);
+}
+/**
+ *	dev_remove_pack	 - remove packet handler
+ *	@pt: packet type declaration
+ *
+ *	Remove a protocol handler that was previously added to the kernel
+ *	protocol handlers by dev_add_pack(). The passed &packet_type is removed
+ *	from the kernel lists and can be freed or reused once this function
+ *	returns.
+ *
+ *	This call sleeps to guarantee that no CPU is looking at the packet
+ *	type after return.
+ */
+void dev_remove_pack(struct packet_type *pt)
+{
+	__dev_remove_pack(pt);
+	
+	synchronize_net();
 }
 
 /******************************************************************************
@@ -679,9 +700,6 @@
 	}
 }
 
-
-#ifdef CONFIG_KMOD
-
 /**
  *	dev_load 	- load a network module
  *	@name: name of interface
@@ -694,15 +712,9 @@
 void dev_load(const char *name)
 {
 	if (!dev_get(name) && capable(CAP_SYS_MODULE))
-		request_module(name);
+		request_module("%s", name);
 }
 
-#else
-
-extern inline void dev_load(const char *unused){;}
-
-#endif
-
 static int default_rebuild_header(struct sk_buff *skb)
 {
 	printk(KERN_DEBUG "%s: default_rebuild_header called -- BUG!\n",
@@ -743,17 +755,11 @@
 	/*
 	 *	Call device private open method
 	 */
-	if (try_module_get(dev->owner)) {
-		set_bit(__LINK_STATE_START, &dev->state);
-		if (dev->open) {
-			ret = dev->open(dev);
-			if (ret) {
-				clear_bit(__LINK_STATE_START, &dev->state);
-				module_put(dev->owner);
-			}
-		}
-	} else {
-		ret = -ENODEV;
+	set_bit(__LINK_STATE_START, &dev->state);
+	if (dev->open) {
+		ret = dev->open(dev);
+		if (ret)
+			clear_bit(__LINK_STATE_START, &dev->state);
 	}
 
 	/*
@@ -878,10 +884,6 @@
 	 */
 	notifier_call_chain(&netdev_chain, NETDEV_DOWN, dev);
 
-	/*
-	 * Drop the module refcount
-	 */
-	module_put(dev->owner);
 	return 0;
 }
 
@@ -943,8 +945,8 @@
 	struct packet_type *ptype;
 	do_gettimeofday(&skb->stamp);
 
-	br_read_lock(BR_NETPROTO_LOCK);
-	for (ptype = ptype_all; ptype; ptype = ptype->next) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(ptype, &ptype_all, list) {
 		/* Never send packets back to the socket
 		 * they originated from - MvS (miquels@drinkel.ow.org)
 		 */
@@ -974,7 +976,7 @@
 			ptype->func(skb2, skb->dev, ptype);
 		}
 	}
-	br_read_unlock(BR_NETPROTO_LOCK);
+	rcu_read_unlock();
 }
 
 /* Calculate csum in the case, when packet is misrouted.
@@ -1365,7 +1367,7 @@
 	if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC))
 		goto out_kfree;
 
-#if CONFIG_SMP
+#ifdef CONFIG_SMP
 	/* Old protocols did not depened on BHs different of NET_BH and
 	   TIMER_BH - they need to be fixed for the new assumptions.
 	 */
@@ -1455,15 +1457,20 @@
 
 #endif
 
-#ifdef CONFIG_NET_DIVERT
-static inline int handle_diverter(struct sk_buff *skb)
+static inline int __handle_bridge(struct sk_buff *skb,
+			struct packet_type **pt_prev, int *ret)
 {
-	/* if diversion is supported on device, then divert */
-	if (skb->dev->divert && skb->dev->divert->divert)
-		divert_frame(skb);
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+	if (skb->dev->br_port) {
+		*ret = handle_bridge(skb, *pt_prev);
+		if (br_handle_frame_hook(skb) == 0)
+			return 1;
+
+		*pt_prev = NULL;
+	}
+#endif
 	return 0;
 }
-#endif   /* CONFIG_NET_DIVERT */
 
 int netif_receive_skb(struct sk_buff *skb)
 {
@@ -1488,7 +1495,8 @@
 	skb->h.raw = skb->nh.raw = skb->data;
 
 	pt_prev = NULL;
-	for (ptype = ptype_all; ptype; ptype = ptype->next) {
+	rcu_read_lock();
+	list_for_each_entry_rcu(ptype, &ptype_all, list) {
 		if (!ptype->dev || ptype->dev == skb->dev) {
 			if (pt_prev) {
 				if (!pt_prev->data) {
@@ -1504,24 +1512,12 @@
 		}
 	}
 
-#ifdef CONFIG_NET_DIVERT
-	if (skb->dev->divert && skb->dev->divert->divert)
-		ret = handle_diverter(skb);
-#endif /* CONFIG_NET_DIVERT */
-
-#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
-	if (skb->dev->br_port) {
-		int ret;
+	handle_diverter(skb);
 
-		ret = handle_bridge(skb, pt_prev);
-		if (br_handle_frame_hook(skb) == 0) 
-			return ret;
-
-		pt_prev = NULL;
-	}
-#endif
+	if (__handle_bridge(skb, &pt_prev, &ret))
+		goto out;
 
-	for (ptype = ptype_base[ntohs(type) & 15]; ptype; ptype = ptype->next) {
+	list_for_each_entry_rcu(ptype, &ptype_base[ntohs(type)&15], list) {
 		if (ptype->type == type &&
 		    (!ptype->dev || ptype->dev == skb->dev)) {
 			if (pt_prev) {
@@ -1552,6 +1548,8 @@
 		ret = NET_RX_DROP;
 	}
 
+out:
+	rcu_read_unlock();
 	return ret;
 }
 
@@ -1625,7 +1623,8 @@
 	unsigned long start_time = jiffies;
 	int budget = netdev_max_backlog;
 
-	br_read_lock(BR_NETPROTO_LOCK);
+	
+	preempt_disable();
 	local_irq_disable();
 
 	while (!list_empty(&queue->poll_list)) {
@@ -1654,7 +1653,7 @@
 	}
 out:
 	local_irq_enable();
-	br_read_unlock(BR_NETPROTO_LOCK);
+	preempt_enable();
 	return;
 
 softnet_break:
@@ -1912,6 +1911,7 @@
 }
 
 static struct file_operations dev_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open    = dev_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
@@ -1931,6 +1931,7 @@
 }
 
 static struct file_operations softnet_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open    = softnet_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
@@ -1995,9 +1996,9 @@
 		dev_hold(master);
 	}
 
-	br_write_lock_bh(BR_NETPROTO_LOCK);
 	slave->master = master;
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	
+	synchronize_net();
 
 	if (old)
 		dev_put(old);
@@ -2066,6 +2067,22 @@
 		dev_mc_upload(dev);
 }
 
+unsigned dev_get_flags(const struct net_device *dev)
+{
+	unsigned flags;
+
+	flags = (dev->flags & ~(IFF_PROMISC |
+				IFF_ALLMULTI |
+				IFF_RUNNING)) | 
+		(dev->gflags & (IFF_PROMISC |
+				IFF_ALLMULTI));
+
+	if (netif_running(dev) && netif_carrier_ok(dev))
+		flags |= IFF_RUNNING;
+
+	return flags;
+}
+
 int dev_change_flags(struct net_device *dev, unsigned flags)
 {
 	int ret;
@@ -2128,6 +2145,32 @@
 	return ret;
 }
 
+int dev_set_mtu(struct net_device *dev, int new_mtu)
+{
+	int err;
+
+	if (new_mtu == dev->mtu)
+		return 0;
+
+	/*	MTU must be positive.	 */
+	if (new_mtu < 0)
+		return -EINVAL;
+
+	if (!netif_device_present(dev))
+		return -ENODEV;
+
+	err = 0;
+	if (dev->change_mtu)
+		err = dev->change_mtu(dev, new_mtu);
+	else
+		dev->mtu = new_mtu;
+	if (!err && dev->flags & IFF_UP)
+		notifier_call_chain(&netdev_chain,
+				    NETDEV_CHANGEMTU, dev);
+	return err;
+}
+
+
 /*
  *	Perform the SIOCxIFxxx calls.
  */
@@ -2141,13 +2184,7 @@
 
 	switch (cmd) {
 		case SIOCGIFFLAGS:	/* Get interface flags */
-			ifr->ifr_flags = (dev->flags & ~(IFF_PROMISC |
-							 IFF_ALLMULTI |
-							 IFF_RUNNING)) | 
-					 (dev->gflags & (IFF_PROMISC |
-							 IFF_ALLMULTI));
-			if (netif_running(dev) && netif_carrier_ok(dev))
-				ifr->ifr_flags |= IFF_RUNNING;
+			ifr->ifr_flags = dev_get_flags(dev);
 			return 0;
 
 		case SIOCSIFFLAGS:	/* Set interface flags */
@@ -2167,27 +2204,7 @@
 			return 0;
 
 		case SIOCSIFMTU:	/* Set the MTU of a device */
-			if (ifr->ifr_mtu == dev->mtu)
-				return 0;
-
-			/*
-			 *	MTU must be positive.
-			 */
-			if (ifr->ifr_mtu < 0)
-				return -EINVAL;
-
-			if (!netif_device_present(dev))
-				return -ENODEV;
-
-			err = 0;
-			if (dev->change_mtu)
-				err = dev->change_mtu(dev, ifr->ifr_mtu);
-			else
-				dev->mtu = ifr->ifr_mtu;
-			if (!err && dev->flags & IFF_UP)
-				notifier_call_chain(&netdev_chain,
-						    NETDEV_CHANGEMTU, dev);
-			return err;
+			return dev_set_mtu(dev, ifr->ifr_mtu);
 
 		case SIOCGIFHWADDR:
 			memcpy(ifr->ifr_hwaddr.sa_data, dev->dev_addr,
@@ -2275,6 +2292,7 @@
 				return -EEXIST;
 			memcpy(dev->name, ifr->ifr_newname, IFNAMSIZ);
 			dev->name[IFNAMSIZ - 1] = 0;
+			snprintf(dev->class_dev.class_id, BUS_ID_SIZE, dev->name);
 			notifier_call_chain(&netdev_chain,
 					    NETDEV_CHANGENAME, dev);
 			return 0;
@@ -2401,11 +2419,9 @@
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
 			dev_load(ifr.ifr_name);
-			dev_probe_lock();
 			rtnl_lock();
 			ret = dev_ifsioc(&ifr, cmd);
 			rtnl_unlock();
-			dev_probe_unlock();
 			if (!ret) {
 				if (colon)
 					*colon = ':';
@@ -2442,11 +2458,9 @@
 			if (!capable(CAP_NET_ADMIN))
 				return -EPERM;
 			dev_load(ifr.ifr_name);
-			dev_probe_lock();
 			rtnl_lock();
 			ret = dev_ifsioc(&ifr, cmd);
 			rtnl_unlock();
-			dev_probe_unlock();
 			return ret;
 
 		case SIOCGIFMEM:
@@ -2466,11 +2480,9 @@
 			    (cmd >= SIOCDEVPRIVATE &&
 			     cmd <= SIOCDEVPRIVATE + 15)) {
 				dev_load(ifr.ifr_name);
-				dev_probe_lock();
 				rtnl_lock();
 				ret = dev_ifsioc(&ifr, cmd);
 				rtnl_unlock();
-				dev_probe_unlock();
 				if (!ret && copy_to_user(arg, &ifr,
 							 sizeof(struct ifreq)))
 					ret = -EFAULT;
@@ -2547,6 +2559,7 @@
 	int ret;
 
 	BUG_ON(dev_boot_phase);
+	ASSERT_RTNL();
 
 	spin_lock_init(&dev->queue_lock);
 	spin_lock_init(&dev->xmit_lock);
@@ -2555,11 +2568,9 @@
 	dev->fastpath_lock = RW_LOCK_UNLOCKED;
 #endif
 
-#ifdef CONFIG_NET_DIVERT
 	ret = alloc_divert_blk(dev);
 	if (ret)
 		goto out;
-#endif /* CONFIG_NET_DIVERT */
 
 	dev->iflink = -1;
 
@@ -2578,11 +2589,10 @@
 		if (d == dev || !strcmp(d->name, dev->name))
 			goto out_err;
 	}
-	snprintf(dev->kobj.name,KOBJ_NAME_LEN,dev->name);
-	kobj_set_kset_s(dev,net_subsys);
-	if ((ret = kobject_register(&dev->kobj)))
-		goto out_err;
 	
+	if ((ret = netdev_register_sysfs(dev)))
+	    goto out_err;
+
 	/* Fix illegal SG+CSUM combinations. */
 	if ((dev->features & NETIF_F_SG) &&
 	    !(dev->features & (NETIF_F_IP_CSUM |
@@ -2619,15 +2629,13 @@
 	/* Notify protocols, that a new device appeared. */
 	notifier_call_chain(&netdev_chain, NETDEV_REGISTER, dev);
 
-	net_run_sbin_hotplug(dev, "register");
+	net_run_sbin_hotplug(dev, 1);
 	ret = 0;
 
 out:
 	return ret;
 out_err:
-#ifdef CONFIG_NET_DIVERT
 	free_divert_blk(dev);
-#endif
 	goto out;
 }
 
@@ -2638,7 +2646,7 @@
  *	Destroy and free a dead device. A value of zero is returned on
  *	success.
  */
-int netdev_finish_unregister(struct net_device *dev)
+static int netdev_finish_unregister(struct net_device *dev)
 {
 	BUG_TRAP(!dev->ip_ptr);
 	BUG_TRAP(!dev->ip6_ptr);
@@ -2653,16 +2661,114 @@
 	printk(KERN_DEBUG "netdev_finish_unregister: %s%s.\n", dev->name,
 	       (dev->destructor != NULL)?"":", old style");
 #endif
+
+	/* It must be the very last action, after this 'dev' may point
+	 * to freed up memory.
+	 */
 	if (dev->destructor)
 		dev->destructor(dev);
+
 	return 0;
 }
 
+static void netdev_wait_allrefs(struct net_device *dev)
+{
+	unsigned long rebroadcast_time, warning_time;
+
+	rebroadcast_time = warning_time = jiffies;
+	while (atomic_read(&dev->refcnt) != 0) {
+		if (time_after(jiffies, rebroadcast_time + 1 * HZ)) {
+			rtnl_shlock();
+			rtnl_exlock();
+
+			/* Rebroadcast unregister notification */
+			notifier_call_chain(&netdev_chain,
+					    NETDEV_UNREGISTER, dev);
+
+			if (test_bit(__LINK_STATE_LINKWATCH_PENDING,
+				     &dev->state)) {
+				/* We must not have linkwatch events
+				 * pending on unregister. If this
+				 * happens, we simply run the queue
+				 * unscheduled, resulting in a noop
+				 * for this device.
+				 */
+				linkwatch_run_queue();
+			}
+
+			rtnl_exunlock();
+			rtnl_shunlock();
+
+			rebroadcast_time = jiffies;
+		}
+
+		current->state = TASK_INTERRUPTIBLE;
+		schedule_timeout(HZ / 4);
+		current->state = TASK_RUNNING;
+
+		if (time_after(jiffies, warning_time + 10 * HZ)) {
+			printk(KERN_EMERG "unregister_netdevice: "
+			       "waiting for %s to become free. Usage "
+			       "count = %d\n",
+			       dev->name, atomic_read(&dev->refcnt));
+			warning_time = jiffies;
+		}
+	}
+}
+
+/* The sequence is:
+ *
+ *	rtnl_lock();
+ *	...
+ *	register_netdevice(x1);
+ *	register_netdevice(x2);
+ *	...
+ *	unregister_netdevice(y1);
+ *	unregister_netdevice(y2);
+ *      ...
+ *	rtnl_unlock();
+ *
+ * We are invoked by rtnl_unlock() after it drops the semaphore.
+ * This allows us to deal with two problems:
+ * 1) We can invoke hotplug without deadlocking with linkwatch via
+ *    keventd.
+ * 2) Since we run with the RTNL semaphore not held, we can sleep
+ *    safely in order to wait for the netdev refcnt to drop to zero.
+ */
+static spinlock_t unregister_todo_lock = SPIN_LOCK_UNLOCKED;
+static struct net_device *unregister_todo;
+
+void netdev_run_todo(void)
+{
+	struct net_device *dev;
+
+	net_run_hotplug_todo();
+
+	spin_lock(&unregister_todo_lock);
+	dev = unregister_todo;
+	unregister_todo = NULL;
+	spin_unlock(&unregister_todo_lock);
+
+	while (dev) {
+		struct net_device *next = dev->next;
+
+		dev->next = NULL;
+
+		netdev_wait_allrefs(dev);
+
+		BUG_ON(atomic_read(&dev->refcnt));
+
+		netdev_finish_unregister(dev);
+
+		dev = next;
+	}
+}
+
 /* Synchronize with packet receive processing. */
 void synchronize_net(void) 
 {
-	br_write_lock_bh(BR_NETPROTO_LOCK);
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	might_sleep();
+	synchronize_kernel();
 }
 
 /**
@@ -2680,10 +2786,10 @@
 
 int unregister_netdevice(struct net_device *dev)
 {
-	unsigned long now, warning_time;
 	struct net_device *d, **dp;
 
 	BUG_ON(dev_boot_phase);
+	ASSERT_RTNL();
 
 	/* If device is running, close it first. */
 	if (dev->flags & IFF_UP)
@@ -2716,7 +2822,7 @@
 	/* Shutdown queueing discipline. */
 	dev_shutdown(dev);
 
-	net_run_sbin_hotplug(dev, "unregister");
+	net_run_sbin_hotplug(dev, 0);
 	
 	/* Notify protocols, that we are about to destroy
 	   this device. They should clean all the things.
@@ -2734,81 +2840,15 @@
 	/* Notifier chain MUST detach us from master device. */
 	BUG_TRAP(!dev->master);
 
-#ifdef CONFIG_NET_DIVERT
 	free_divert_blk(dev);
-#endif
-
-	if (dev->destructor != NULL) {
-#ifdef NET_REFCNT_DEBUG
-		if (atomic_read(&dev->refcnt) != 1)
-			printk(KERN_DEBUG "unregister_netdevice: holding %s "
-					  "refcnt=%d\n",
-			       dev->name, atomic_read(&dev->refcnt) - 1);
-#endif
-		goto out;
-	}
 
-	/* Last reference is our one */
-	if (atomic_read(&dev->refcnt) == 1)
-		goto out;
+	netdev_unregister_sysfs(dev);
 
-#ifdef NET_REFCNT_DEBUG
-	printk(KERN_DEBUG "unregister_netdevice: waiting %s refcnt=%d\n",
-	       dev->name, atomic_read(&dev->refcnt));
-#endif
+	spin_lock(&unregister_todo_lock);
+	dev->next = unregister_todo;
+	unregister_todo = dev;
+	spin_unlock(&unregister_todo_lock);
 
-	/* EXPLANATION. If dev->refcnt is not now 1 (our own reference)
-	   it means that someone in the kernel still has a reference
-	   to this device and we cannot release it.
-
-	   "New style" devices have destructors, hence we can return from this
-	   function and destructor will do all the work later. As of kernel
-	   2.4.0 there are very few "New Style" devices.
-
-	   "Old style" devices expect that the device is free of any references
-	   upon exit from this function.
-	   We cannot return from this function until all such references have
-	   fallen away. This is because the caller of this function will
-	   probably immediately kfree(*dev) and then be unloaded via
-	   sys_delete_module.
-
-	   So, we linger until all references fall away.  The duration of the
-	   linger is basically unbounded! It is driven by, for example, the
-	   current setting of sysctl_ipfrag_time.
-
-	   After 1 second, we start to rebroadcast unregister notifications
-	   in hope that careless clients will release the device.
-
-	 */
-
-	now = warning_time = jiffies;
-	while (atomic_read(&dev->refcnt) != 1) {
-		if ((jiffies - now) > 1 * HZ) {
-			/* Rebroadcast unregister notification */
-			notifier_call_chain(&netdev_chain,
-					    NETDEV_UNREGISTER, dev);
-
-			if (test_bit(__LINK_STATE_LINKWATCH_PENDING, &dev->state)) {
-				/* We must not have linkwatch events pending
-				 * on unregister. If this happens, we simply
-				 * run the queue unscheduled, resulting in a
-				 * noop for this device
-				 */
-				linkwatch_run_queue();
-			}
-		}
-		current->state = TASK_INTERRUPTIBLE;
-		schedule_timeout(HZ / 4);
-		current->state = TASK_RUNNING;
-		if ((jiffies - warning_time) > 10 * HZ) {
-			printk(KERN_EMERG "unregister_netdevice: waiting for "
-			       "%s to become free. Usage count = %d\n",
-			       dev->name, atomic_read(&dev->refcnt));
-			warning_time = jiffies;
-		}
-	}
-out:
-	kobject_unregister(&dev->kobj);
 	dev_put(dev);
 	return 0;
 }
@@ -2827,8 +2867,6 @@
 extern void dv_init(void);
 #endif /* CONFIG_NET_DIVERT */
 
-static decl_subsys(net,NULL,NULL);
-
 
 /*
  *       This is called single threaded during boot, so no need
@@ -2844,7 +2882,12 @@
 	if (dev_proc_init())
 		goto out;
 
-	subsystem_register(&net_subsys);
+	if (netdev_sysfs_init())
+		goto out;
+
+	INIT_LIST_HEAD(&ptype_all);
+	for (i = 0; i < 16; i++) 
+		INIT_LIST_HEAD(&ptype_base[i]);
 
 #ifdef CONFIG_NET_DIVERT
 	dv_init();
@@ -2914,7 +2957,8 @@
 		 */
 		netdev_boot_setup_check(dev);
 
-		if (dev->init && dev->init(dev)) {
+		if ( (dev->init && dev->init(dev)) ||
+		     netdev_register_sysfs(dev) ) {
 			/*
 			 * It failed to come up. It will be unhooked later.
 			 * dev_alloc_name can now advance to next suitable
@@ -2974,18 +3018,22 @@
 
 #ifdef CONFIG_HOTPLUG
 
-/* Notify userspace when a netdevice event occurs,
- * by running '/sbin/hotplug net' with certain
- * environment variables set.
- */
+struct net_hotplug_todo {
+	struct net_hotplug_todo	*next;
+	char			ifname[IFNAMSIZ];
+	int			is_register;
+};
+static spinlock_t net_hotplug_list_lock = SPIN_LOCK_UNLOCKED;
+static struct net_hotplug_todo *net_hotplug_list;
 
-static int net_run_sbin_hotplug(struct net_device *dev, char *action)
+static void net_run_hotplug_one(struct net_hotplug_todo *ent)
 {
 	char *argv[3], *envp[5], ifname[12 + IFNAMSIZ], action_str[32];
 	int i;
 
-	sprintf(ifname, "INTERFACE=%s", dev->name);
-	sprintf(action_str, "ACTION=%s", action);
+	sprintf(ifname, "INTERFACE=%s", ent->ifname);
+	sprintf(action_str, "ACTION=%s",
+		(ent->is_register ? "register" : "unregister"));
 
         i = 0;
         argv[i++] = hotplug_path;
@@ -3000,6 +3048,46 @@
 	envp [i++] = action_str;
 	envp [i] = 0;
 
-	return call_usermodehelper(argv [0], argv, envp, 0);
+	call_usermodehelper(argv [0], argv, envp, 0);
+}
+
+static void net_run_hotplug_todo(void)
+{
+	struct net_hotplug_todo *list;
+
+	spin_lock(&net_hotplug_list_lock);
+	list = net_hotplug_list;
+	net_hotplug_list = NULL;
+	spin_unlock(&net_hotplug_list_lock);
+
+	while (list != NULL) {
+		struct net_hotplug_todo *next = list->next;
+
+		net_run_hotplug_one(list);
+
+		kfree(list);
+		list = next;
+	}
+}
+
+/* Notify userspace when a netdevice event occurs,
+ * by running '/sbin/hotplug net' with certain
+ * environment variables set.
+ */
+
+static void net_run_sbin_hotplug(struct net_device *dev, int is_register)
+{
+	struct net_hotplug_todo *ent = kmalloc(sizeof(*ent), GFP_KERNEL);
+
+	if (!ent)
+		return;
+
+	memcpy(ent->ifname, dev->name, IFNAMSIZ);
+	ent->is_register = is_register;
+
+	spin_lock(&net_hotplug_list_lock);
+	ent->next = net_hotplug_list;
+	net_hotplug_list = ent;
+	spin_unlock(&net_hotplug_list_lock);
 }
 #endif
diff -Nru a/net/core/dst.c b/net/core/dst.c
--- a/net/core/dst.c	Sun May  4 06:06:24 2003
+++ b/net/core/dst.c	Mon May 19 18:25:07 2003
@@ -226,7 +226,6 @@
 				   _race_ _condition_.
 				 */
 				if (event!=NETDEV_DOWN &&
-				    dev->destructor == NULL &&
 				    dst->output == dst_blackhole) {
 					dst->dev = &loopback_dev;
 					dev_put(dev);
diff -Nru a/net/core/flow.c b/net/core/flow.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/core/flow.c	Thu May 15 23:24:35 2003
@@ -0,0 +1,254 @@
+/* flow.c: Generic flow cache.
+ *
+ * Copyright (C) 2003 Alexey N. Kuznetsov (kuznet@ms2.inr.ac.ru)
+ * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/jhash.h>
+#include <linux/interrupt.h>
+#include <linux/mm.h>
+#include <linux/random.h>
+#include <linux/init.h>
+#include <net/flow.h>
+#include <asm/atomic.h>
+
+struct flow_cache_entry {
+	struct flow_cache_entry	*next;
+	u16			family;
+	u8			dir;
+	struct flowi		key;
+	u32			genid;
+	void			*object;
+	atomic_t		*object_ref;
+};
+
+atomic_t flow_cache_genid = ATOMIC_INIT(0);
+
+static u32 flow_hash_shift;
+#define flow_hash_size	(1 << flow_hash_shift)
+static struct flow_cache_entry **flow_table;
+static kmem_cache_t *flow_cachep;
+
+static int flow_lwm, flow_hwm;
+
+struct flow_percpu_info {
+	int hash_rnd_recalc;
+	u32 hash_rnd;
+	int count;
+} ____cacheline_aligned;
+static struct flow_percpu_info flow_hash_info[NR_CPUS];
+
+#define flow_hash_rnd_recalc(cpu)	(flow_hash_info[cpu].hash_rnd_recalc)
+#define flow_hash_rnd(cpu)		(flow_hash_info[cpu].hash_rnd)
+#define flow_count(cpu)			(flow_hash_info[cpu].count)
+
+static struct timer_list flow_hash_rnd_timer;
+
+#define FLOW_HASH_RND_PERIOD	(10 * 60 * HZ)
+
+static void flow_cache_new_hashrnd(unsigned long arg)
+{
+	int i;
+
+	for (i = 0; i < NR_CPUS; i++)
+		flow_hash_rnd_recalc(i) = 1;
+
+	flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
+	add_timer(&flow_hash_rnd_timer);
+}
+
+static void __flow_cache_shrink(int cpu, int shrink_to)
+{
+	struct flow_cache_entry *fle, **flp;
+	int i;
+
+	for (i = 0; i < flow_hash_size; i++) {
+		int k = 0;
+
+		flp = &flow_table[cpu*flow_hash_size+i];
+		while ((fle = *flp) != NULL && k < shrink_to) {
+			k++;
+			flp = &fle->next;
+		}
+		while ((fle = *flp) != NULL) {
+			*flp = fle->next;
+			if (fle->object)
+				atomic_dec(fle->object_ref);
+			kmem_cache_free(flow_cachep, fle);
+			flow_count(cpu)--;
+		}
+	}
+}
+
+static void flow_cache_shrink(int cpu)
+{
+	int shrink_to = flow_lwm / flow_hash_size;
+
+	__flow_cache_shrink(cpu, shrink_to);
+}
+
+static void flow_new_hash_rnd(int cpu)
+{
+	get_random_bytes(&flow_hash_rnd(cpu), sizeof(u32));
+	flow_hash_rnd_recalc(cpu) = 0;
+
+	__flow_cache_shrink(cpu, 0);
+}
+
+static u32 flow_hash_code(struct flowi *key, int cpu)
+{
+	u32 *k = (u32 *) key;
+
+	return (jhash2(k, (sizeof(*key) / sizeof(u32)), flow_hash_rnd(cpu)) &
+		(flow_hash_size - 1));
+}
+
+#if (BITS_PER_LONG == 64)
+typedef u64 flow_compare_t;
+#else
+typedef u32 flow_compare_t;
+#endif
+
+extern void flowi_is_missized(void);
+
+/* I hear what you're saying, use memcmp.  But memcmp cannot make
+ * important assumptions that we can here, such as alignment and
+ * constant size.
+ */
+static int flow_key_compare(struct flowi *key1, struct flowi *key2)
+{
+	flow_compare_t *k1, *k1_lim, *k2;
+	const int n_elem = sizeof(struct flowi) / sizeof(flow_compare_t);
+
+	if (sizeof(struct flowi) % sizeof(flow_compare_t))
+		flowi_is_missized();
+
+	k1 = (flow_compare_t *) key1;
+	k1_lim = k1 + n_elem;
+
+	k2 = (flow_compare_t *) key2;
+
+	do {
+		if (*k1++ != *k2++)
+			return 1;
+	} while (k1 < k1_lim);
+
+	return 0;
+}
+
+void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir,
+			flow_resolve_t resolver)
+{
+	struct flow_cache_entry *fle, **head;
+	unsigned int hash;
+	int cpu;
+
+	local_bh_disable();
+	cpu = smp_processor_id();
+	if (flow_hash_rnd_recalc(cpu))
+		flow_new_hash_rnd(cpu);
+	hash = flow_hash_code(key, cpu);
+
+	head = &flow_table[(cpu << flow_hash_shift) + hash];
+	for (fle = *head; fle; fle = fle->next) {
+		if (fle->family == family &&
+		    fle->dir == dir &&
+		    flow_key_compare(key, &fle->key) == 0) {
+			if (fle->genid == atomic_read(&flow_cache_genid)) {
+				void *ret = fle->object;
+
+				if (ret)
+					atomic_inc(fle->object_ref);
+				local_bh_enable();
+
+				return ret;
+			}
+			break;
+		}
+	}
+
+	{
+		void *obj;
+		atomic_t *obj_ref;
+
+		resolver(key, family, dir, &obj, &obj_ref);
+
+		if (fle) {
+			fle->genid = atomic_read(&flow_cache_genid);
+
+			if (fle->object)
+				atomic_dec(fle->object_ref);
+
+			fle->object = obj;
+			fle->object_ref = obj_ref;
+			if (obj)
+				atomic_inc(fle->object_ref);
+		} else {
+			if (flow_count(cpu) > flow_hwm)
+				flow_cache_shrink(cpu);
+
+			fle = kmem_cache_alloc(flow_cachep, SLAB_ATOMIC);
+			if (fle) {
+				fle->next = *head;
+				*head = fle;
+				fle->family = family;
+				fle->dir = dir;
+				memcpy(&fle->key, key, sizeof(*key));
+				fle->genid = atomic_read(&flow_cache_genid);
+				fle->object = obj;
+				fle->object_ref = obj_ref;
+
+				flow_count(cpu)++;
+			}
+		}
+		local_bh_enable();
+
+		return obj;
+	}
+}
+
+static int __init flow_cache_init(void)
+{
+	unsigned long order;
+	int i;
+
+	flow_cachep = kmem_cache_create("flow_cache",
+					sizeof(struct flow_cache_entry),
+					0, SLAB_HWCACHE_ALIGN,
+					NULL, NULL);
+
+	if (!flow_cachep)
+		panic("NET: failed to allocate flow cache slab\n");
+
+	flow_hash_shift = 10;
+	flow_lwm = 2 * flow_hash_size;
+	flow_hwm = 4 * flow_hash_size;
+
+	for (i = 0; i < NR_CPUS; i++)
+		flow_hash_rnd_recalc(i) = 1;
+
+	init_timer(&flow_hash_rnd_timer);
+	flow_hash_rnd_timer.function = flow_cache_new_hashrnd;
+	flow_hash_rnd_timer.expires = jiffies + FLOW_HASH_RND_PERIOD;
+	add_timer(&flow_hash_rnd_timer);
+
+	for (order = 0;
+	     (PAGE_SIZE << order) <
+		     (NR_CPUS*sizeof(struct flow_entry *)*flow_hash_size);
+	     order++)
+		/* NOTHING */;
+
+	flow_table = (struct flow_cache_entry **)
+		__get_free_pages(GFP_ATOMIC, order);
+
+	if (!flow_table)
+		panic("Failed to allocate flow cache hash table\n");
+
+	memset(flow_table, 0, PAGE_SIZE << order);
+
+	return 0;
+}
+
+module_init(flow_cache_init);
diff -Nru a/net/core/link_watch.c b/net/core/link_watch.c
--- a/net/core/link_watch.c	Mon Apr 28 09:27:57 2003
+++ b/net/core/link_watch.c	Mon May 19 23:22:52 2003
@@ -48,7 +48,8 @@
 static struct lw_event singleevent;
 
 /* Must be called with the rtnl semaphore held */
-void linkwatch_run_queue(void) {
+void linkwatch_run_queue(void)
+{
 	LIST_HEAD(head);
 	struct list_head *n, *next;
 
diff -Nru a/net/core/neighbour.c b/net/core/neighbour.c
--- a/net/core/neighbour.c	Mon Apr 28 09:22:24 2003
+++ b/net/core/neighbour.c	Sun May  4 10:30:22 2003
@@ -440,8 +440,8 @@
 
 	if (!neigh->dead) {
 		printk(KERN_WARNING
-		       "Destroying alive neighbour %p from %08lx\n", neigh,
-		       *(((unsigned long *)&neigh) - 1));
+		       "Destroying alive neighbour %p\n", neigh);
+		dump_stack();
 		return;
 	}
 
diff -Nru a/net/core/net-sysfs.c b/net/core/net-sysfs.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/core/net-sysfs.c	Tue May 20 19:59:05 2003
@@ -0,0 +1,344 @@
+/*
+ * net-sysfs.c - network device class and attributes
+ *
+ * Copyright (c) 2003 Stephen Hemminber <shemminger@osdl.org>
+ * 
+ *
+ * TODO:
+ * last_tx
+ * last_rx
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <net/sock.h>
+#include <linux/rtnetlink.h>
+
+const char *if_port_text[] = {
+   [IF_PORT_UNKNOWN] = "unknown",
+   [IF_PORT_10BASE2] = "BNC",
+   [IF_PORT_10BASET] = "10baseT",
+   [IF_PORT_AUI]     = "AUI",
+   [IF_PORT_100BASET] = "100baseT",
+   [IF_PORT_100BASETX] = "100baseTX",
+   [IF_PORT_100BASEFX] = "100baseFX"
+};
+
+#define to_net_dev(class) container_of((class), struct net_device, class_dev)
+
+/* generate a show function for  simple field */
+#define NETDEVICE_SHOW(field, format_string)				\
+static ssize_t show_##field(struct class_device *dev, char *buf)	\
+{									\
+	return sprintf(buf, format_string, to_net_dev(dev)->field);	\
+}
+
+/* generate a store function for a field with locking */
+#define NETDEVICE_STORE(field)						\
+static ssize_t 								\
+store_##field(struct class_device *dev, const char *buf, size_t len)	\
+{									\
+	char *endp;							\
+	long new = simple_strtol(buf, &endp, 16);			\
+									\
+	if (endp == buf || new < 0)					\
+		return -EINVAL;						\
+									\
+	if (!capable(CAP_NET_ADMIN))					\
+		return -EPERM;						\
+									\
+	rtnl_lock();							\
+	to_net_dev(dev)->field = new;					\
+	rtnl_unlock();							\
+	return len;							\
+}
+
+/* generate a read-only network device class attribute */
+#define NETDEVICE_ATTR(field, format_string)				\
+NETDEVICE_SHOW(field, format_string)					\
+static CLASS_DEVICE_ATTR(field, S_IRUGO, show_##field, NULL)		\
+
+NETDEVICE_ATTR(addr_len, "%d\n");
+NETDEVICE_ATTR(iflink, "%d\n");
+NETDEVICE_ATTR(ifindex, "%d\n");
+NETDEVICE_ATTR(features, "%#x\n");
+NETDEVICE_ATTR(type, "%d\n");
+
+/* TODO: only a few devices set this now should fix others. */
+static ssize_t show_port(struct class_device *dev, char *buf)
+{
+	unsigned char port = to_net_dev(dev)->if_port;
+	char *cp = buf;
+
+	cp += sprintf(cp, "%d", port);
+	if (port < ARRAY_SIZE(if_port_text))
+		cp += sprintf(cp, " (%s)", if_port_text[port]);
+	*cp++ ='\n';
+	return cp - buf;
+}
+static CLASS_DEVICE_ATTR(if_port, S_IRUGO, show_port, NULL);
+
+static ssize_t format_addr(char *buf, const unsigned char *addr, int len)
+{
+	int i;
+	char *cp = buf;
+
+	read_lock(&dev_base_lock);
+	for (i = 0; i < len; i++)
+		cp += sprintf(cp, "%02x%c", addr[i],
+			      i == (len - 1) ? '\n' : ':');
+	read_unlock(&dev_base_lock);
+	return cp - buf;
+}
+
+static ssize_t show_address(struct class_device *dev, char *buf)
+{
+	struct net_device *net = to_net_dev(dev);
+	return format_addr(buf, net->dev_addr, net->addr_len);
+}
+
+static ssize_t show_broadcast(struct class_device *dev, char *buf)
+{
+	struct net_device *net = to_net_dev(dev);
+	return format_addr(buf, net->broadcast, net->addr_len);
+}
+
+static CLASS_DEVICE_ATTR(address, S_IRUGO, show_address, NULL);
+static CLASS_DEVICE_ATTR(broadcast, S_IRUGO, show_broadcast, NULL);
+
+/* read-write attributes */
+NETDEVICE_SHOW(mtu, "%d\n");
+
+static ssize_t store_mtu(struct class_device *dev, const char *buf, size_t len)
+{
+	char *endp;
+	int new_mtu;
+	int err;
+
+	new_mtu = simple_strtoul(buf, &endp, 10);
+	if (endp == buf) 
+		return -EINVAL;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	
+	rtnl_lock();
+	err = dev_set_mtu(to_net_dev(dev), new_mtu);
+	rtnl_unlock();
+
+	return err == 0 ? len : err;
+}
+
+static CLASS_DEVICE_ATTR(mtu, S_IRUGO | S_IWUSR, show_mtu, store_mtu);
+
+NETDEVICE_SHOW(flags, "%#x\n");
+
+static ssize_t store_flags(struct class_device *dev, const char *buf, size_t len)
+{
+	unsigned long new_flags;
+	char *endp;
+	int err = 0;
+
+	new_flags = simple_strtoul(buf, &endp, 16);
+	if (endp == buf)
+		return -EINVAL;
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EPERM;
+	
+	rtnl_lock();
+	err = dev_change_flags(to_net_dev(dev), new_flags);
+	rtnl_unlock();
+
+	return err ? err : len;
+}
+
+static CLASS_DEVICE_ATTR(flags, S_IRUGO | S_IWUSR, show_flags, store_flags);
+
+NETDEVICE_SHOW(tx_queue_len, "%lu\n");
+NETDEVICE_STORE(tx_queue_len);
+static CLASS_DEVICE_ATTR(tx_queue_len, S_IRUGO | S_IWUSR, show_tx_queue_len, 
+			 store_tx_queue_len);
+
+static struct class net_class = {
+	.name = "net",
+};
+
+
+static struct class_device_attribute *net_class_attributes[] = {
+	&class_device_attr_ifindex,
+	&class_device_attr_iflink,
+	&class_device_attr_addr_len,
+	&class_device_attr_tx_queue_len,
+	&class_device_attr_features,
+	&class_device_attr_mtu,
+	&class_device_attr_flags,
+	&class_device_attr_if_port,
+	&class_device_attr_type,
+	&class_device_attr_address,
+	&class_device_attr_broadcast,
+	NULL
+};
+
+struct netstat_fs_entry {
+	struct attribute attr;
+	ssize_t (*show)(const struct net_device_stats *, char *);
+	ssize_t (*store)(struct net_device_stats *, const char *, size_t);
+};
+
+static ssize_t net_device_stat_show(unsigned long var, char *buf)
+{
+	return sprintf(buf, "%ld\n", var);
+}
+
+/* generate a read-only statistics attribute */
+#define NETDEVICE_STAT(_NAME)						\
+static ssize_t show_stat_##_NAME(const struct net_device_stats *stats,	\
+				 char *buf)				\
+{									\
+	return net_device_stat_show(stats->_NAME, buf);			\
+}									\
+static struct netstat_fs_entry net_stat_##_NAME  = {		   	\
+	.attr = {.name = __stringify(_NAME), .mode = S_IRUGO },		\
+	.show = show_stat_##_NAME,					\
+}
+
+NETDEVICE_STAT(rx_packets);
+NETDEVICE_STAT(tx_packets);
+NETDEVICE_STAT(rx_bytes);
+NETDEVICE_STAT(tx_bytes);
+NETDEVICE_STAT(rx_errors);
+NETDEVICE_STAT(tx_errors);
+NETDEVICE_STAT(rx_dropped);
+NETDEVICE_STAT(tx_dropped);
+NETDEVICE_STAT(multicast);
+NETDEVICE_STAT(collisions);
+NETDEVICE_STAT(rx_length_errors);
+NETDEVICE_STAT(rx_over_errors);
+NETDEVICE_STAT(rx_crc_errors);
+NETDEVICE_STAT(rx_frame_errors);
+NETDEVICE_STAT(rx_fifo_errors);
+NETDEVICE_STAT(rx_missed_errors);
+NETDEVICE_STAT(tx_aborted_errors);
+NETDEVICE_STAT(tx_carrier_errors);
+NETDEVICE_STAT(tx_fifo_errors);
+NETDEVICE_STAT(tx_heartbeat_errors);
+NETDEVICE_STAT(tx_window_errors);
+NETDEVICE_STAT(rx_compressed);
+NETDEVICE_STAT(tx_compressed);
+
+static struct attribute *default_attrs[] = {
+	&net_stat_rx_packets.attr,
+	&net_stat_tx_packets.attr,
+	&net_stat_rx_bytes.attr,
+	&net_stat_tx_bytes.attr,
+	&net_stat_rx_errors.attr,
+	&net_stat_tx_errors.attr,
+	&net_stat_rx_dropped.attr,
+	&net_stat_tx_dropped.attr,
+	&net_stat_multicast.attr,
+	&net_stat_collisions.attr,
+	&net_stat_rx_length_errors.attr,
+	&net_stat_rx_over_errors.attr,
+	&net_stat_rx_crc_errors.attr,
+	&net_stat_rx_frame_errors.attr,
+	&net_stat_rx_fifo_errors.attr,
+	&net_stat_rx_missed_errors.attr,
+	&net_stat_tx_aborted_errors.attr,
+	&net_stat_tx_carrier_errors.attr,
+	&net_stat_tx_fifo_errors.attr,
+	&net_stat_tx_heartbeat_errors.attr,
+	&net_stat_tx_window_errors.attr,
+	&net_stat_rx_compressed.attr,
+	&net_stat_tx_compressed.attr,
+	NULL
+};
+
+
+static ssize_t
+netstat_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
+{
+	struct netstat_fs_entry *entry
+		= container_of(attr, struct netstat_fs_entry, attr);
+	struct class_device *class_dev
+		= container_of(kobj->parent, struct class_device, kobj);
+	struct net_device *dev
+		= to_net_dev(class_dev);
+	struct net_device_stats *stats 
+		= dev->get_stats ? dev->get_stats(dev) : NULL;
+
+	if (stats && entry->show) 
+		return entry->show(stats, buf);
+	return -EINVAL;
+}
+
+static struct sysfs_ops netstat_sysfs_ops = {
+	.show = netstat_attr_show,
+};
+
+static struct kobj_type netstat_ktype = {
+	.sysfs_ops	= &netstat_sysfs_ops,
+	.default_attrs  = default_attrs,
+};
+
+/* Create sysfs entries for network device. */
+int netdev_register_sysfs(struct net_device *net)
+{
+	struct class_device *class_dev = &(net->class_dev);
+	int i;
+	struct class_device_attribute *attr;
+	int ret;
+
+	memset(class_dev, 0, sizeof(struct class_device)); 
+	class_dev->class = &net_class;
+	class_dev->dev = net->dev;
+	class_dev->class_data = net;
+
+	snprintf(class_dev->class_id, BUS_ID_SIZE, net->name);
+	if ((ret = class_device_register(class_dev)))
+		goto out;
+
+	for (i = 0; (attr = net_class_attributes[i]); i++) {
+		if ((ret = class_device_create_file(class_dev, attr)))
+		    goto out_unreg;
+	}
+
+	if (net->get_stats) {
+		struct kobject *k = &net->stats_kobj;
+
+		memset(k, 0, sizeof(*k));
+		k->parent = kobject_get(&class_dev->kobj);
+		if (!k->parent) {
+			ret = -EBUSY;
+			goto out_unreg;
+		}
+
+		snprintf(k->name, KOBJ_NAME_LEN, "%s", "statistics");
+		k->ktype = &netstat_ktype;
+
+		if((ret = kobject_register(k))) 
+			 goto out_unreg; 
+	}
+
+out:
+	return ret;
+out_unreg:
+	printk(KERN_WARNING "%s: sysfs attribute registration failed %d\n",
+	       net->name, ret);
+	class_device_unregister(class_dev);
+	goto out;
+}
+
+void netdev_unregister_sysfs(struct net_device *net)
+{
+	if (net->get_stats)
+		kobject_del(&net->stats_kobj);
+	class_device_unregister(&net->class_dev);
+}
+
+int netdev_sysfs_init(void)
+{
+	return class_register(&net_class);
+}
diff -Nru a/net/core/netfilter.c b/net/core/netfilter.c
--- a/net/core/netfilter.c	Wed Apr 30 01:32:19 2003
+++ b/net/core/netfilter.c	Sat May 17 22:10:44 2003
@@ -20,6 +20,9 @@
 #include <linux/if.h>
 #include <linux/netdevice.h>
 #include <linux/inetdevice.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
+#include <linux/icmp.h>
 #include <net/sock.h>
 #include <net/route.h>
 #include <linux/ip.h>
@@ -683,7 +686,68 @@
 
 	return err;
 }
+
+int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
+{
+	struct sk_buff *nskb;
+	unsigned int iplen;
+
+	if (writable_len > (*pskb)->len)
+		return 0;
+
+	/* Not exclusive use of packet?  Must copy. */
+	if (skb_shared(*pskb) || skb_cloned(*pskb))
+		goto copy_skb;
+
+	/* Alexey says IP hdr is always modifiable and linear, so ok. */
+	if (writable_len <= (*pskb)->nh.iph->ihl*4)
+		return 1;
+
+	iplen = writable_len - (*pskb)->nh.iph->ihl*4;
+
+	/* DaveM says protocol headers are also modifiable. */
+	switch ((*pskb)->nh.iph->protocol) {
+	case IPPROTO_TCP: {
+		struct tcphdr hdr;
+		if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
+				  &hdr, sizeof(hdr)) != 0)
+			goto copy_skb;
+		if (writable_len <= (*pskb)->nh.iph->ihl*4 + hdr.doff*4)
+			goto pull_skb;
+		goto copy_skb;
+	}
+	case IPPROTO_UDP:
+		if (writable_len<=(*pskb)->nh.iph->ihl*4+sizeof(struct udphdr))
+			goto pull_skb;
+		goto copy_skb;
+	case IPPROTO_ICMP:
+		if (writable_len
+		    <= (*pskb)->nh.iph->ihl*4 + sizeof(struct icmphdr))
+			goto pull_skb;
+		goto copy_skb;
+	/* Insert other cases here as desired */
+	}
+
+copy_skb:
+	nskb = skb_copy(*pskb, GFP_ATOMIC);
+	if (!nskb)
+		return 0;
+	BUG_ON(skb_is_nonlinear(nskb));
+
+	/* Rest of kernel will get very unhappy if we pass it a
+	   suddenly-orphaned skbuff */
+	if ((*pskb)->sk)
+		skb_set_owner_w(nskb, (*pskb)->sk);
+	kfree_skb(*pskb);
+	*pskb = nskb;
+	return 1;
+
+pull_skb:
+	return pskb_may_pull(*pskb, writable_len);
+}
+EXPORT_SYMBOL(skb_ip_make_writable);
 #endif /*CONFIG_INET*/
+
 
 /* This does not belong here, but ipt_REJECT needs it if connection
    tracking in use: without this, connection may not be in hash table,
diff -Nru a/net/core/pktgen.c b/net/core/pktgen.c
--- a/net/core/pktgen.c	Mon Apr 28 09:27:57 2003
+++ b/net/core/pktgen.c	Thu May  8 09:44:17 2003
@@ -226,21 +226,20 @@
 {
 	struct net_device *odev;
 
-	rtnl_lock();
-	odev = __dev_get_by_name(info->outdev);
+	odev = dev_get_by_name(info->outdev);
 	if (!odev) {
 		sprintf(info->result, "No such netdevice: \"%s\"", info->outdev);
-		goto out_unlock;
+		goto out;
 	}
 
 	if (odev->type != ARPHRD_ETHER) {
 		sprintf(info->result, "Not ethernet device: \"%s\"", info->outdev);
-		goto out_unlock;
+		goto out_put;
 	}
 
 	if (!netif_running(odev)) {
 		sprintf(info->result, "Device is down: \"%s\"", info->outdev);
-		goto out_unlock;
+		goto out_put;
 	}
 
 	/* Default to the interface's mac if not explicitly set. */
@@ -257,13 +256,13 @@
 	info->saddr_min = 0;
 	info->saddr_max = 0;
 	if (strlen(info->src_min) == 0) {
-		if (odev->ip_ptr) {
-			struct in_device *in_dev = odev->ip_ptr;
-
+		struct in_device *in_dev = in_dev_get(odev);
+		if (in_dev) {
 			if (in_dev->ifa_list) {
 				info->saddr_min = in_dev->ifa_list->ifa_address;
 				info->saddr_max = info->saddr_min;
 			}
+			in_dev_put(in_dev);
 		}
 	}
 	else {
@@ -282,13 +281,11 @@
 	info->cur_udp_dst = info->udp_dst_min;
 	info->cur_udp_src = info->udp_src_min;
 	
-	atomic_inc(&odev->refcnt);
-	rtnl_unlock();
-
 	return odev;
 
-out_unlock:
-	rtnl_unlock();
+out_put:
+	dev_put(odev);
+out:
 	return NULL;
 }
 
@@ -1258,7 +1255,6 @@
 	}
 
 	if (!strcmp(name, "inject") || !strcmp(name, "start")) {
-		MOD_INC_USE_COUNT;
 		if (info->busy) {
 			strcpy(info->result, "Already running...\n");
 		}
@@ -1268,7 +1264,6 @@
 			inject(info);
 			info->busy = 0;
 		}
-		MOD_DEC_USE_COUNT;
 		return count;
 	}
 
@@ -1337,6 +1332,7 @@
 		pginfos[i].proc_ent->read_proc = proc_read;
 		pginfos[i].proc_ent->write_proc = proc_write;
 		pginfos[i].proc_ent->data = (void*)(long)(i);
+		pginfos[i].proc_ent->owner = THIS_MODULE;
 
 		sprintf(pginfos[i].busy_fname, "net/%s/pg_busy%i",  PG_PROC_DIR, i);
 		pginfos[i].busy_proc_ent = create_proc_entry(pginfos[i].busy_fname, 0, 0);
diff -Nru a/net/core/rtnetlink.c b/net/core/rtnetlink.c
--- a/net/core/rtnetlink.c	Mon Apr 21 19:42:38 2003
+++ b/net/core/rtnetlink.c	Mon May 19 23:22:52 2003
@@ -52,7 +52,7 @@
 
 DECLARE_MUTEX(rtnl_sem);
 
-void rtnl_lock(void)
+void rtnl_lock()
 {
 	rtnl_shlock();
 	rtnl_exlock();
@@ -62,6 +62,8 @@
 {
 	rtnl_exunlock();
 	rtnl_shunlock();
+
+	netdev_run_todo();
 }
 
 int rtattr_parse(struct rtattr *tb[], int maxattr, struct rtattr *rta, int len)
@@ -442,7 +444,7 @@
  * Malformed skbs with wrong lengths of messages are discarded silently.
  */
 
-extern __inline__ int rtnetlink_rcv_skb(struct sk_buff *skb)
+static inline int rtnetlink_rcv_skb(struct sk_buff *skb)
 {
 	int err;
 	struct nlmsghdr * nlh;
@@ -500,6 +502,8 @@
 		}
 
 		up(&rtnl_sem);
+
+		netdev_run_todo();
 	} while (rtnl && rtnl->receive_queue.qlen);
 }
 
diff -Nru a/net/core/skbuff.c b/net/core/skbuff.c
--- a/net/core/skbuff.c	Tue Apr 29 23:44:14 2003
+++ b/net/core/skbuff.c	Wed May  7 01:41:27 2003
@@ -126,9 +126,6 @@
 	struct sk_buff *skb;
 	u8 *data;
 
-	if (gfp_mask & __GFP_WAIT)
-		might_sleep();
-
 	/* Get the HEAD */
 	skb = kmem_cache_alloc(skbuff_head_cache,
 			       gfp_mask & ~__GFP_DMA);
diff -Nru a/net/core/sock.c b/net/core/sock.c
--- a/net/core/sock.c	Fri May  2 22:55:11 2003
+++ b/net/core/sock.c	Tue May 13 13:42:28 2003
@@ -134,7 +134,7 @@
 /* Maximal space eaten by iovec or ancilliary data plus some space */
 int sysctl_optmem_max = sizeof(unsigned long)*(2*UIO_MAXIOV + 512);
 
-static int sock_set_timeout(long *timeo_p, char *optval, int optlen)
+static int sock_set_timeout(long *timeo_p, char __user *optval, int optlen)
 {
 	struct timeval tv;
 
@@ -163,7 +163,7 @@
  */
 
 int sock_setsockopt(struct socket *sock, int level, int optname,
-		    char *optval, int optlen)
+		    char __user *optval, int optlen)
 {
 	struct sock *sk=sock->sk;
 	struct sk_filter *filter;
@@ -188,7 +188,7 @@
   	if(optlen<sizeof(int))
   		return(-EINVAL);
   	
-	if (get_user(val, (int *)optval))
+	if (get_user(val, (int __user *)optval))
 		return -EFAULT;
 	
   	valbool = val?1:0;
@@ -415,7 +415,7 @@
 
 
 int sock_getsockopt(struct socket *sock, int level, int optname,
-		    char *optval, int *optlen)
+		    char __user *optval, int __user *optlen)
 {
 	struct sock *sk = sock->sk;
 	
@@ -548,7 +548,7 @@
 				return -ENOTCONN;
 			if (lv < len)
 				return -EINVAL;
-			if(copy_to_user((void*)optval, address, len))
+			if (copy_to_user(optval, address, len))
 				return -EFAULT;
 			goto lenout;
 		}
@@ -996,7 +996,8 @@
 	msg.msg_controllen = 0;
 	msg.msg_flags = flags;
 
-	iov.iov_base = kaddr + offset;
+	/* This cast is ok because of the "set_fs(KERNEL_DS)" */
+	iov.iov_base = (void __user *) (kaddr + offset);
 	iov.iov_len = size;
 
 	old_fs = get_fs();
diff -Nru a/net/core/wireless.c b/net/core/wireless.c
--- a/net/core/wireless.c	Tue Apr 29 02:29:48 2003
+++ b/net/core/wireless.c	Mon May 12 15:17:08 2003
@@ -2,7 +2,7 @@
  * This file implement the Wireless Extensions APIs.
  *
  * Authors :	Jean Tourrilhes - HPL - <jt@hpl.hp.com>
- * Copyright (c) 1997-2002 Jean Tourrilhes, All Rights Reserved.
+ * Copyright (c) 1997-2003 Jean Tourrilhes, All Rights Reserved.
  *
  * (As all part of the Linux kernel, this file is GPL)
  */
@@ -43,19 +43,26 @@
  *	o Turn on WE_STRICT_WRITE by default + kernel warning
  *	o Fix WE_STRICT_WRITE in ioctl_export_private() (32 => iw_num)
  *	o Fix off-by-one in test (extra_size <= IFNAMSIZ)
+ *
+ * v6 - 9.01.03 - Jean II
+ *	o Add common spy support : iw_handler_set_spy(), wireless_spy_update()
+ *	o Add enhanced spy support : iw_handler_set_thrspy() and event.
+ *	o Add WIRELESS_EXT version display in /proc/net/wireless
  */
 
 /***************************** INCLUDES *****************************/
 
 #include <linux/config.h>		/* Not needed ??? */
+#include <linux/module.h>
 #include <linux/types.h>		/* off_t */
 #include <linux/netdevice.h>		/* struct ifreq, dev_get_by_name() */
 #include <linux/proc_fs.h>
 #include <linux/rtnetlink.h>		/* rtnetlink stuff */
 #include <linux/seq_file.h>
-#include <linux/wireless.h>		/* Pretty obvious */
 #include <linux/init.h>			/* for __init */
+#include <linux/if_arp.h>		/* ARPHRD_ETHER */
 
+#include <linux/wireless.h>		/* Pretty obvious */
 #include <net/iw_handler.h>		/* New driver API */
 
 #include <asm/uaccess.h>		/* copy_to_user() */
@@ -69,6 +76,7 @@
 /* Debugging stuff */
 #undef WE_IOCTL_DEBUG		/* Debug IOCTL API */
 #undef WE_EVENT_DEBUG		/* Debug Event dispatcher */
+#undef WE_SPY_DEBUG		/* Debug enhanced spy support */
 
 /* Options */
 #define WE_EVENT_NETLINK	/* Propagate events using rtnetlink */
@@ -76,7 +84,7 @@
 
 /************************* GLOBAL VARIABLES *************************/
 /*
- * You should not use global variables, because or re-entrancy.
+ * You should not use global variables, because of re-entrancy.
  * On our case, it's only const, so it's OK...
  */
 /*
@@ -152,7 +160,19 @@
 		.header_type	= IW_HEADER_TYPE_POINT,
 		.token_size	= sizeof(struct sockaddr) +
 				  sizeof(struct iw_quality),
-		.max_tokens	= IW_MAX_GET_SPY,
+		.max_tokens	= IW_MAX_SPY,
+	},
+	[SIOCSIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
+	},
+	[SIOCGIWTHRSPY	- SIOCIWFIRST] = {
+		.header_type	= IW_HEADER_TYPE_POINT,
+		.token_size	= sizeof(struct iw_thrspy),
+		.min_tokens	= 1,
+		.max_tokens	= 1,
 	},
 	[SIOCSIWAP	- SIOCIWFIRST] = {
 		.header_type	= IW_HEADER_TYPE_ADDR,
@@ -440,9 +460,10 @@
 {
 	if (v == (void *)1)
 		seq_printf(seq, "Inter-| sta-|   Quality        |   Discarded "
-				"packets               | Missed\n"
+				"packets               | Missed | WE\n"
 				" face | tus | link level noise |  nwid  "
-				"crypt   frag  retry   misc | beacon\n");
+				"crypt   frag  retry   misc | beacon | %d\n",
+			   WIRELESS_EXT);
 	else
 		wireless_seq_printf_stats(seq, v);
 	return 0;
@@ -465,6 +486,7 @@
 }
 
 static struct file_operations wireless_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open    = wireless_seq_open,
 	.read    = seq_read,
 	.llseek  = seq_lseek,
@@ -1098,4 +1120,253 @@
 	kfree(event);
 
 	return;		/* Always success, I guess ;-) */
+}
+
+/********************** ENHANCED IWSPY SUPPORT **********************/
+/*
+ * In the old days, the driver was handling spy support all by itself.
+ * Now, the driver can delegate this task to Wireless Extensions.
+ * It needs to use those standard spy iw_handler in struct iw_handler_def,
+ * push data to us via wireless_spy_update() and include struct iw_spy_data
+ * in its private part (and advertise it in iw_handler_def->spy_offset).
+ * One of the main advantage of centralising spy support here is that
+ * it becomes much easier to improve and extend it without having to touch
+ * the drivers. One example is the addition of the Spy-Threshold events.
+ * Note : IW_WIRELESS_SPY is defined in iw_handler.h
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : set Spy List
+ */
+int iw_handler_set_spy(struct net_device *	dev,
+		       struct iw_request_info *	info,
+		       union iwreq_data *	wrqu,
+		       char *			extra)
+{
+#ifdef IW_WIRELESS_SPY
+	struct iw_spy_data *	spydata = (dev->priv +
+					   dev->wireless_handlers->spy_offset);
+	struct sockaddr *	address = (struct sockaddr *) extra;
+
+	/* Disable spy collection while we copy the addresses.
+	 * As we don't disable interrupts, we need to do this to avoid races.
+	 * As we are the only writer, this is good enough. */
+	spydata->spy_number = 0;
+
+	/* Are there are addresses to copy? */
+	if(wrqu->data.length > 0) {
+		int i;
+
+		/* Copy addresses */
+		for(i = 0; i < wrqu->data.length; i++)
+			memcpy(spydata->spy_address[i], address[i].sa_data,
+			       ETH_ALEN);
+		/* Reset stats */
+		memset(spydata->spy_stat, 0,
+		       sizeof(struct iw_quality) * IW_MAX_SPY);
+
+#ifdef WE_SPY_DEBUG
+		printk(KERN_DEBUG "iw_handler_set_spy() :  offset %ld, spydata %p, num %d\n", dev->wireless_handlers->spy_offset, spydata, wrqu->data.length);
+		for (i = 0; i < wrqu->data.length; i++)
+			printk(KERN_DEBUG
+			       "%02X:%02X:%02X:%02X:%02X:%02X \n",
+			       spydata->spy_address[i][0],
+			       spydata->spy_address[i][1],
+			       spydata->spy_address[i][2],
+			       spydata->spy_address[i][3],
+			       spydata->spy_address[i][4],
+			       spydata->spy_address[i][5]);
+#endif	/* WE_SPY_DEBUG */
+	}
+	/* Enable addresses */
+	spydata->spy_number = wrqu->data.length;
+
+	return 0;
+#else /* IW_WIRELESS_SPY */
+	return -EOPNOTSUPP;
+#endif /* IW_WIRELESS_SPY */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : get Spy List
+ */
+int iw_handler_get_spy(struct net_device *	dev,
+		       struct iw_request_info *	info,
+		       union iwreq_data *	wrqu,
+		       char *			extra)
+{
+#ifdef IW_WIRELESS_SPY
+	struct iw_spy_data *	spydata = (dev->priv +
+					   dev->wireless_handlers->spy_offset);
+	struct sockaddr *	address = (struct sockaddr *) extra;
+	int			i;
+
+	wrqu->data.length = spydata->spy_number;
+
+	/* Copy addresses. */
+	for(i = 0; i < spydata->spy_number; i++) 	{
+		memcpy(address[i].sa_data, spydata->spy_address[i], ETH_ALEN);
+		address[i].sa_family = AF_UNIX;
+	}
+	/* Copy stats to the user buffer (just after). */
+	if(spydata->spy_number > 0)
+		memcpy(extra  + (sizeof(struct sockaddr) *spydata->spy_number),
+		       spydata->spy_stat,
+		       sizeof(struct iw_quality) * spydata->spy_number);
+	/* Reset updated flags. */
+	for(i = 0; i < spydata->spy_number; i++)
+		spydata->spy_stat[i].updated = 0;
+	return 0;
+#else /* IW_WIRELESS_SPY */
+	return -EOPNOTSUPP;
+#endif /* IW_WIRELESS_SPY */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : set spy threshold
+ */
+int iw_handler_set_thrspy(struct net_device *	dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *	wrqu,
+			  char *		extra)
+{
+#ifdef IW_WIRELESS_THRSPY
+	struct iw_spy_data *	spydata = (dev->priv +
+					   dev->wireless_handlers->spy_offset);
+	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
+
+	/* Just do it */
+	memcpy(&(spydata->spy_thr_low), &(threshold->low),
+	       2 * sizeof(struct iw_quality));
+
+	/* Clear flag */
+	memset(spydata->spy_thr_under, '\0', sizeof(spydata->spy_thr_under));
+
+#ifdef WE_SPY_DEBUG
+	printk(KERN_DEBUG "iw_handler_set_thrspy() :  low %d ; high %d\n", spydata->spy_thr_low.level, spydata->spy_thr_high.level);
+#endif	/* WE_SPY_DEBUG */
+
+	return 0;
+#else /* IW_WIRELESS_THRSPY */
+	return -EOPNOTSUPP;
+#endif /* IW_WIRELESS_THRSPY */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Standard Wireless Handler : get spy threshold
+ */
+int iw_handler_get_thrspy(struct net_device *	dev,
+			  struct iw_request_info *info,
+			  union iwreq_data *	wrqu,
+			  char *		extra)
+{
+#ifdef IW_WIRELESS_THRSPY
+	struct iw_spy_data *	spydata = (dev->priv +
+					   dev->wireless_handlers->spy_offset);
+	struct iw_thrspy *	threshold = (struct iw_thrspy *) extra;
+
+	/* Just do it */
+	memcpy(&(threshold->low), &(spydata->spy_thr_low),
+	       2 * sizeof(struct iw_quality));
+
+	return 0;
+#else /* IW_WIRELESS_THRSPY */
+	return -EOPNOTSUPP;
+#endif /* IW_WIRELESS_THRSPY */
+}
+
+#ifdef IW_WIRELESS_THRSPY
+/*------------------------------------------------------------------*/
+/*
+ * Prepare and send a Spy Threshold event
+ */
+static void iw_send_thrspy_event(struct net_device *	dev,
+				 struct iw_spy_data *	spydata,
+				 unsigned char *	address,
+				 struct iw_quality *	wstats)
+{
+	union iwreq_data	wrqu;
+	struct iw_thrspy	threshold;
+
+	/* Init */
+	wrqu.data.length = 1;
+	wrqu.data.flags = 0;
+	/* Copy address */
+	memcpy(threshold.addr.sa_data, address, ETH_ALEN);
+	threshold.addr.sa_family = ARPHRD_ETHER;
+	/* Copy stats */
+	memcpy(&(threshold.qual), wstats, sizeof(struct iw_quality));
+	/* Copy also thresholds */
+	memcpy(&(threshold.low), &(spydata->spy_thr_low),
+	       2 * sizeof(struct iw_quality));
+
+#ifdef WE_SPY_DEBUG
+	printk(KERN_DEBUG "iw_send_thrspy_event() : address %02X:%02X:%02X:%02X:%02X:%02X, level %d, up = %d\n",
+	       threshold.addr.sa_data[0],
+	       threshold.addr.sa_data[1],
+	       threshold.addr.sa_data[2],
+	       threshold.addr.sa_data[3],
+	       threshold.addr.sa_data[4],
+	       threshold.addr.sa_data[5], threshold.qual.level);
+#endif	/* WE_SPY_DEBUG */
+
+	/* Send event to user space */
+	wireless_send_event(dev, SIOCGIWTHRSPY, &wrqu, (char *) &threshold);
+}
+#endif /* IW_WIRELESS_THRSPY */
+
+/* ---------------------------------------------------------------- */
+/*
+ * Call for the driver to update the spy data.
+ * For now, the spy data is a simple array. As the size of the array is
+ * small, this is good enough. If we wanted to support larger number of
+ * spy addresses, we should use something more efficient...
+ */
+void wireless_spy_update(struct net_device *	dev,
+			 unsigned char *	address,
+			 struct iw_quality *	wstats)
+{
+#ifdef IW_WIRELESS_SPY
+	struct iw_spy_data *	spydata = (dev->priv +
+					   dev->wireless_handlers->spy_offset);
+	int			i;
+	int			match = -1;
+
+#ifdef WE_SPY_DEBUG
+	printk(KERN_DEBUG "wireless_spy_update() :  offset %ld, spydata %p, address %02X:%02X:%02X:%02X:%02X:%02X\n", dev->wireless_handlers->spy_offset, spydata, address[0], address[1], address[2], address[3], address[4], address[5]);
+#endif	/* WE_SPY_DEBUG */
+
+	/* Update all records that match */
+	for(i = 0; i < spydata->spy_number; i++)
+		if(!memcmp(address, spydata->spy_address[i], ETH_ALEN)) {
+			memcpy(&(spydata->spy_stat[i]), wstats,
+			       sizeof(struct iw_quality));
+			match = i;
+		}
+#ifdef IW_WIRELESS_THRSPY
+	/* Generate an event if we cross the spy threshold.
+	 * To avoid event storms, we have a simple hysteresis : we generate
+	 * event only when we go under the low threshold or above the
+	 * high threshold. */
+	if(match >= 0) {
+		if(spydata->spy_thr_under[match]) {
+			if(wstats->level > spydata->spy_thr_high.level) {
+				spydata->spy_thr_under[match] = 0;
+				iw_send_thrspy_event(dev, spydata,
+						     address, wstats);
+			}
+		} else {
+			if(wstats->level < spydata->spy_thr_low.level) {
+				spydata->spy_thr_under[match] = 1;
+				iw_send_thrspy_event(dev, spydata,
+						     address, wstats);
+			}
+		}
+	}
+#endif /* IW_WIRELESS_THRSPY */
+#endif /* IW_WIRELESS_SPY */
 }
diff -Nru a/net/decnet/Kconfig b/net/decnet/Kconfig
--- a/net/decnet/Kconfig	Tue Oct 29 17:16:55 2002
+++ b/net/decnet/Kconfig	Sun May  4 12:16:46 2003
@@ -17,11 +17,11 @@
 	depends on DECNET && EXPERIMENTAL
 	---help---
 	  Add support for turning your DECnet Endnode into a level 1 or 2
-	  router.  This is an unfinished option for developers only.  If you
+	  router.  This is an experimental, but functional option.  If you
 	  do say Y here, then make sure that you also say Y to "Kernel/User
 	  network link driver", "Routing messages" and "Network packet
 	  filtering".  The first two are required to allow configuration via
-	  rtnetlink (currently you need Alexey Kuznetsov's iproute2 package
+	  rtnetlink (you will need Alexey Kuznetsov's iproute2 package
 	  from <ftp://ftp.inr.ac.ru/>). The "Network packet filtering" option
 	  will be required for the forthcoming routing daemon to work.
 
@@ -34,4 +34,6 @@
 	  If you say Y here, you will be able to specify different routes for
 	  packets with different FWMARK ("firewalling mark") values
 	  (see ipchains(8), "-m" argument).
+
+source "net/decnet/netfilter/Kconfig"
 
diff -Nru a/net/decnet/Makefile b/net/decnet/Makefile
--- a/net/decnet/Makefile	Sat Dec 14 04:38:56 2002
+++ b/net/decnet/Makefile	Sun May  4 12:16:46 2003
@@ -1,7 +1,10 @@
 
 obj-$(CONFIG_DECNET) += decnet.o
 
-decnet-y := af_decnet.o dn_nsp_in.o dn_nsp_out.o dn_route.o dn_dev.o dn_neigh.o dn_timer.o
+decnet-y := af_decnet.o dn_nsp_in.o dn_nsp_out.o \
+	    dn_route.o dn_dev.o dn_neigh.o dn_timer.o
 decnet-$(CONFIG_DECNET_ROUTER) += dn_fib.o dn_rules.o dn_table.o
-decnet-$(CONFIG_DECNET_FW) += dn_fw.o
 decnet-y += sysctl_net_decnet.o
+
+obj-$(CONFIG_NETFILTER) += netfilter/
+
diff -Nru a/net/decnet/TODO b/net/decnet/TODO
--- a/net/decnet/TODO	Fri Apr 18 10:42:53 2003
+++ b/net/decnet/TODO	Tue May  6 00:58:43 2003
@@ -23,15 +23,9 @@
 
  o check MSG_CTRUNC is set where it should be.
 
- o Start to hack together user level software and add more DECnet support
-   in ifconfig for example. 
-
  o Find all the commonality between DECnet and IPv4 routing code and extract 
    it into a small library of routines. [probably a project for 2.7.xx]
 
- o Add the routing message grabbing netfilter module [written, tested,
-   awaiting merge]
-
  o Add perfect socket hashing - an idea suggested by Paul Koning. Currently
    we have a half-way house scheme which seems to work reasonably well, but
    the full scheme is still worth implementing, its not not top of my list
@@ -44,6 +38,4 @@
  o DECnet sendpages() function
 
  o AIO for DECnet
-
- o Eliminate dn_db->parms.blksize
 
diff -Nru a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
--- a/net/decnet/af_decnet.c	Fri May  2 23:16:03 2003
+++ b/net/decnet/af_decnet.c	Tue May  6 00:58:43 2003
@@ -116,6 +116,7 @@
 #include <linux/inet.h>
 #include <linux/route.h>
 #include <linux/netfilter.h>
+#include <linux/seq_file.h>
 #include <net/sock.h>
 #include <net/tcp.h>
 #include <net/flow.h>
@@ -676,45 +677,6 @@
 }
 
 
-static char *dn_state2asc(unsigned char state)
-{
-	switch(state) {
-		case DN_O:
-			return "OPEN";
-		case DN_CR:
-			return "  CR";
-		case DN_DR:
-			return "  DR";
-		case DN_DRC:
-			return " DRC";
-		case DN_CC:
-			return "  CC";
-		case DN_CI:
-			return "  CI";
-		case DN_NR:
-			return "  NR";
-		case DN_NC:
-			return "  NC";
-		case DN_CD:
-			return "  CD";
-		case DN_RJ:
-			return "  RJ";
-		case DN_RUN:
-			return " RUN";
-		case DN_DI:
-			return "  DI";
-		case DN_DIC:
-			return " DIC";
-		case DN_DN:
-			return "  DN";
-		case DN_CL:
-			return "  CL";
-		case DN_CN:
-			return "  CN";
-	}
-
-	return "????";
-}
 
 static int dn_create(struct socket *sock, int protocol)
 {
@@ -1001,6 +963,7 @@
 	fl.fld_dst = dn_saddr2dn(&scp->peer);
 	fl.fld_src = dn_saddr2dn(&scp->addr);
 	dn_sk_ports_copy(&fl, scp);
+	fl.proto = DNPROTO_NSP;
 	if (dn_route_output_sock(&sk->dst_cache, &fl, sk, flags) < 0)
 		goto out;
 	sk->route_caps = sk->dst_cache->dev->features;
@@ -1964,7 +1927,7 @@
 	unsigned char fctype;
 	long timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);
 
-	if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL))
+	if (flags & ~(MSG_TRYHARD|MSG_OOB|MSG_DONTWAIT|MSG_EOR|MSG_NOSIGNAL|MSG_MORE))
 		return -EOPNOTSUPP;
 
 	if (addr_len && (addr_len != sizeof(struct sockaddr_dn)))
@@ -2143,6 +2106,95 @@
 	.data =		(void*)1,
 };
 
+#ifdef CONFIG_PROC_FS
+struct dn_iter_state {
+	int bucket;
+};
+
+static struct sock *dn_socket_get_first(struct seq_file *seq)
+{
+	struct dn_iter_state *state = seq->private;
+	struct sock *n = NULL;
+
+	for(state->bucket = 0;
+	    state->bucket < DN_SK_HASH_SIZE;
+	    ++state->bucket) {
+		n = dn_sk_hash[state->bucket];
+		if (n)
+			break;
+	}
+
+	return n;
+}
+
+static struct sock *dn_socket_get_next(struct seq_file *seq,
+				       struct sock *n)
+{
+	struct dn_iter_state *state = seq->private;
+
+	n = n->next;
+try_again:
+	if (n)
+		goto out;
+	if (++state->bucket >= DN_SK_HASH_SIZE)
+		goto out;
+	n = dn_sk_hash[state->bucket];
+	goto try_again;
+out:
+	return n;
+}
+
+static struct sock *socket_get_idx(struct seq_file *seq, loff_t *pos)
+{
+	struct sock *sk = dn_socket_get_first(seq);
+
+	if (sk) {
+		while(*pos && (sk = dn_socket_get_next(seq, sk)))
+			--*pos;
+	}
+	return *pos ? NULL : sk;
+}
+
+static void *dn_socket_get_idx(struct seq_file *seq, loff_t pos)
+{
+	void *rc;
+	read_lock_bh(&dn_hash_lock);
+	rc = socket_get_idx(seq, &pos);
+	if (!rc) {
+		read_unlock_bh(&dn_hash_lock);
+	}
+	return rc;
+}
+
+static void *dn_socket_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	return *pos ? dn_socket_get_idx(seq, *pos - 1) : (void*)1;
+}
+
+static void *dn_socket_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	void *rc;
+
+	if (v == (void*)1) {
+		rc = dn_socket_get_idx(seq, 0);
+		goto out;
+	}
+
+	rc = dn_socket_get_next(seq, v);
+	if (rc)
+		goto out;
+	read_unlock_bh(&dn_hash_lock);
+out:
+	++*pos;
+	return rc;
+}
+
+static void dn_socket_seq_stop(struct seq_file *seq, void *v)
+{
+	if (v && v != (void*)1)
+		read_unlock_bh(&dn_hash_lock);
+}
+
 #define IS_NOT_PRINTABLE(x) ((x) < 32 || (x) > 126)
 
 static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf)
@@ -2163,70 +2215,127 @@
     	}
 }
 
-static int dn_get_info(char *buffer, char **start, off_t offset, int length)
+static char *dn_state2asc(unsigned char state)
 {
-	struct sock *sk;
-	struct dn_scp *scp;
-	int len = 0;
-	off_t pos = 0;
-	off_t begin = 0;
+	switch(state) {
+		case DN_O:
+			return "OPEN";
+		case DN_CR:
+			return "  CR";
+		case DN_DR:
+			return "  DR";
+		case DN_DRC:
+			return " DRC";
+		case DN_CC:
+			return "  CC";
+		case DN_CI:
+			return "  CI";
+		case DN_NR:
+			return "  NR";
+		case DN_NC:
+			return "  NC";
+		case DN_CD:
+			return "  CD";
+		case DN_RJ:
+			return "  RJ";
+		case DN_RUN:
+			return " RUN";
+		case DN_DI:
+			return "  DI";
+		case DN_DIC:
+			return " DIC";
+		case DN_DN:
+			return "  DN";
+		case DN_CL:
+			return "  CL";
+		case DN_CN:
+			return "  CN";
+	}
+
+	return "????";
+}
+
+static inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk)
+{
+	struct dn_scp *scp = DN_SK(sk);
 	char buf1[DN_ASCBUF_LEN];
 	char buf2[DN_ASCBUF_LEN];
 	char local_object[DN_MAXOBJL+3];
 	char remote_object[DN_MAXOBJL+3];
-	int i;
 
-	len += sprintf(buffer + len, "Local                                              Remote\n");
+	dn_printable_object(&scp->addr, local_object);
+	dn_printable_object(&scp->peer, remote_object);
 
-	read_lock(&dn_hash_lock);
-	for(i = 0; i < DN_SK_HASH_SIZE; i++) {
-		for(sk = dn_sk_hash[i]; sk != NULL; sk = sk->next) {
-			scp = DN_SK(sk);
-
-			dn_printable_object(&scp->addr, local_object);
-			dn_printable_object(&scp->peer, remote_object);
-
-			len += sprintf(buffer + len,
-					"%6s/%04X %04d:%04d %04d:%04d %01d %-16s %6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
-					dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
-					scp->addrloc,
-					scp->numdat,
-					scp->numoth,
-					scp->ackxmt_dat,
-					scp->ackxmt_oth,
-					scp->flowloc_sw,
-					local_object,
-					dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
-					scp->addrrem,
-					scp->numdat_rcv,
-					scp->numoth_rcv,
-					scp->ackrcv_dat,
-					scp->ackrcv_oth,
-					scp->flowrem_sw,
-					remote_object,
-					dn_state2asc(scp->state),
-					((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
-
-			pos = begin + len;
-			if (pos < offset) {
-				len = 0;
-				begin = pos;
-			}
-			if (pos > (offset + length))
-				break;
-		}
+	seq_printf(seq,
+		   "%6s/%04X %04d:%04d %04d:%04d %01d %-16s "
+		   "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n",
+		   dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1),
+		   scp->addrloc,
+		   scp->numdat,
+		   scp->numoth,
+		   scp->ackxmt_dat,
+		   scp->ackxmt_oth,
+		   scp->flowloc_sw,
+		   local_object,
+		   dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2),
+		   scp->addrrem,
+		   scp->numdat_rcv,
+		   scp->numoth_rcv,
+		   scp->ackrcv_dat,
+		   scp->ackrcv_oth,
+		   scp->flowrem_sw,
+		   remote_object,
+		   dn_state2asc(scp->state),
+		   ((scp->accept_mode == ACC_IMMED) ? "IMMED" : "DEFER"));
+}
+
+static int dn_socket_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == (void*)1) {
+		seq_puts(seq, "Local                                              Remote\n");
+	} else {
+		dn_socket_format_entry(seq, v);
 	}
-	read_unlock(&dn_hash_lock);
+	return 0;
+}
 
-	*start = buffer + (offset - begin);
-	len -= (offset - begin);
+static struct seq_operations dn_socket_seq_ops = {
+	.start	= dn_socket_seq_start,
+	.next	= dn_socket_seq_next,
+	.stop	= dn_socket_seq_stop,
+	.show	= dn_socket_seq_show,
+};
 
-	if (len > length)
-		len = length;
+static int dn_socket_seq_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int rc = -ENOMEM;
+	struct dn_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
 
-	return len;
+	if (!s)
+		goto out;
+
+	rc = seq_open(file, &dn_socket_seq_ops);
+	if (rc)
+		goto out_kfree;
+
+	seq		= file->private_data;
+	seq->private	= s;
+	memset(s, 0, sizeof(*s));
+out:
+	return rc;
+out_kfree:
+	kfree(s);
+	goto out;
 }
 
+static struct file_operations dn_socket_seq_fops = {
+	.open		= dn_socket_seq_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= seq_release_private,
+};
+#endif
 
 static struct net_proto_family	dn_family_ops = {
 	.family =	AF_DECnet,
@@ -2258,13 +2367,11 @@
 void dn_register_sysctl(void);
 void dn_unregister_sysctl(void);
 
-
 MODULE_DESCRIPTION("The Linux DECnet Network Protocol");
 MODULE_AUTHOR("Linux DECnet Project Team");
 MODULE_LICENSE("GPL");
 
-
-static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.67s (C) 1995-2003 Linux DECnet Project Team\n";
+static char banner[] __initdata = KERN_INFO "NET4: DECnet for Linux: V.2.5.68s (C) 1995-2003 Linux DECnet Project Team\n";
 
 static int __init decnet_init(void)
 {
@@ -2281,15 +2388,12 @@
 	dev_add_pack(&dn_dix_packet_type);
 	register_netdevice_notifier(&dn_dev_notifier);
 
-	proc_net_create("decnet", 0, dn_get_info);
+	proc_net_fops_create("decnet", S_IRUGO, &dn_socket_seq_fops);
 
 	dn_neigh_init();
 	dn_dev_init();
 	dn_route_init();
-
-#ifdef CONFIG_DECNET_ROUTER
 	dn_fib_init();
-#endif /* CONFIG_DECNET_ROUTER */
 
 	dn_register_sysctl();
 
@@ -2316,10 +2420,7 @@
 	dn_route_cleanup();
 	dn_dev_cleanup();
 	dn_neigh_cleanup();
-
-#ifdef CONFIG_DECNET_ROUTER
 	dn_fib_cleanup();
-#endif /* CONFIG_DECNET_ROUTER */
 
 	proc_net_remove("decnet");
 
diff -Nru a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
--- a/net/decnet/dn_dev.c	Fri Apr 18 10:42:53 2003
+++ b/net/decnet/dn_dev.c	Tue May 20 19:39:24 2003
@@ -20,6 +20,8 @@
  *          Steve Whitehouse : /proc/sys/net/decnet/conf/<sys>/forwarding
  *          Steve Whitehouse : Removed timer1 - it's a user space issue now
  *         Patrick Caulfield : Fixed router hello message format
+ *          Steve Whitehouse : Got rid of constant sizes for blksize for
+ *                             devices. All mtu based now.
  */
 
 #include <linux/config.h>
@@ -28,6 +30,7 @@
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/timer.h>
 #include <linux/string.h>
 #include <linux/if_arp.h>
@@ -72,16 +75,13 @@
 static int dn_eth_up(struct net_device *);
 static void dn_eth_down(struct net_device *);
 static void dn_send_brd_hello(struct net_device *dev, struct dn_ifaddr *ifa);
-#if 0
 static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa);
-#endif
 
 static struct dn_dev_parms dn_dev_list[] =  {
 {
 	.type =		ARPHRD_ETHER, /* Ethernet */
 	.mode =		DN_DEV_BCAST,
 	.state =	DN_DEV_S_RU,
-	.blksize =	1498,
 	.t2 =		1,
 	.t3 =		10,
 	.name =		"ethernet",
@@ -94,7 +94,6 @@
 	.type =		ARPHRD_IPGRE, /* DECnet tunneled over GRE in IP */
 	.mode =		DN_DEV_BCAST,
 	.state =	DN_DEV_S_RU,
-	.blksize =	1400,
 	.t2 =		1,
 	.t3 =		10,
 	.name =		"ipgre",
@@ -106,7 +105,6 @@
 	.type =		ARPHRD_X25, /* Bog standard X.25 */
 	.mode =		DN_DEV_UCAST,
 	.state =	DN_DEV_S_DS,
-	.blksize =	230,
 	.t2 =		1,
 	.t3 =		120,
 	.name =		"x25",
@@ -119,7 +117,6 @@
 	.type =		ARPHRD_PPP, /* DECnet over PPP */
 	.mode =		DN_DEV_BCAST,
 	.state =	DN_DEV_S_RU,
-	.blksize =	230,
 	.t2 =		1,
 	.t3 =		10,
 	.name =		"ppp",
@@ -127,24 +124,20 @@
 	.timer3 =	dn_send_brd_hello,
 },
 #endif
-#if 0
 {
 	.type =		ARPHRD_DDCMP, /* DECnet over DDCMP */
 	.mode =		DN_DEV_UCAST,
 	.state =	DN_DEV_S_DS,
-	.blksize =	230,
 	.t2 =		1,
 	.t3 =		120,
 	.name =		"ddcmp",
 	.ctl_name =	NET_DECNET_CONF_DDCMP,
 	.timer3 =	dn_send_ptp_hello,
 },
-#endif
 {
 	.type =		ARPHRD_LOOPBACK, /* Loopback interface - always last */
 	.mode =		DN_DEV_BCAST,
 	.state =	DN_DEV_S_RU,
-	.blksize =	1498,
 	.t2 =		1,
 	.t3 =		10,
 	.name =		"loopback",
@@ -254,6 +247,21 @@
 	}, {0}}
 };
 
+static inline __u16 mtu2blksize(struct net_device *dev)
+{
+	u32 blksize = dev->mtu;
+	if (blksize > 0xffff)
+		blksize = 0xffff;
+
+	if (dev->type == ARPHRD_ETHER ||
+	    dev->type == ARPHRD_PPP ||
+	    dev->type == ARPHRD_IPGRE ||
+	    dev->type == ARPHRD_LOOPBACK)
+		blksize -= 2;
+
+	return (__u16)blksize;
+}
+
 static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
 {
 	struct dn_dev_sysctl_table *t;
@@ -265,7 +273,7 @@
 
 	memcpy(t, &dn_dev_sysctl, sizeof(*t));
 
-	for(i = 0; i < (sizeof(t->dn_dev_vars)/sizeof(t->dn_dev_vars[0]) - 1); i++) {
+	for(i = 0; i < ARRAY_SIZE(t->dn_dev_vars) - 1; i++) {
 		long offset = (long)t->dn_dev_vars[i].data;
 		t->dn_dev_vars[i].data = ((char *)parms) + offset;
 		t->dn_dev_vars[i].de = NULL;
@@ -553,7 +561,6 @@
 	struct dn_dev *dn_db;
 	struct net_device *dev;
 	struct dn_ifaddr *ifa = NULL, **ifap = NULL;
-	int exclusive = 0;
 	int ret = 0;
 
 	if (copy_from_user(ifr, arg, DN_IFREQ_SIZE))
@@ -572,13 +579,13 @@
 				return -EACCES;
 			if (sdn->sdn_family != AF_DECnet)
 				return -EINVAL;
-			rtnl_lock();
-			exclusive = 1;
 			break;
 		default:
 			return -EINVAL;
 	}
 
+	rtnl_lock();
+
 	if ((dev = __dev_get_by_name(ifr->ifr_name)) == NULL) {
 		ret = -ENODEV;
 		goto done;
@@ -618,15 +625,13 @@
 			ret = dn_dev_set_ifa(dev, ifa);
 	}
 done:
-	if (exclusive)
-		rtnl_unlock();
+	rtnl_unlock();
 
 	return ret;
 rarok:
 	if (copy_to_user(arg, ifr, DN_IFREQ_SIZE))
-		return -EFAULT;
-
-	return 0;
+		ret = -EFAULT;
+	goto done;
 }
 
 static struct dn_dev *dn_dev_by_index(int ifindex)
@@ -858,7 +863,7 @@
         memcpy(msg->tiver, dn_eco_version, 3);
 	dn_dn2eth(msg->id, ifa->ifa_local);
         msg->iinfo   = DN_RT_INFO_ENDN;
-        msg->blksize = dn_htons(dn_db->parms.blksize);
+        msg->blksize = dn_htons(mtu2blksize(dev));
         msg->area    = 0x00;
         memset(msg->seed, 0, 8);
         memcpy(msg->neighbor, dn_hiord, ETH_ALEN);
@@ -920,10 +925,10 @@
 	unsigned short *pktlen;
 	char *src;
 
-	if (dn_db->parms.blksize < (26 + 7))
+	if (mtu2blksize(dev) < (26 + 7))
 		return;
 
-	n = dn_db->parms.blksize - 26;
+	n = mtu2blksize(dev) - 26;
 	n /= 7;
 
 	if (n > 32)
@@ -946,7 +951,7 @@
 	ptr += ETH_ALEN;
 	*ptr++ = dn_db->parms.forwarding == 1 ? 
 			DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
-	*((unsigned short *)ptr) = dn_htons(dn_db->parms.blksize);
+	*((unsigned short *)ptr) = dn_htons(mtu2blksize(dev));
 	ptr += 2;
 	*ptr++ = dn_db->parms.priority; /* Priority */ 
 	*ptr++ = 0; /* Area: Reserved */
@@ -990,16 +995,13 @@
 		dn_send_router_hello(dev, ifa);
 }
 
-#if 0
 static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 {
 	int tdlen = 16;
 	int size = dev->hard_header_len + 2 + 4 + tdlen;
 	struct sk_buff *skb = dn_alloc_skb(NULL, size, GFP_ATOMIC);
-	struct dn_dev *dn_db = dev->dn_ptr;
 	int i;
 	unsigned char *ptr;
-	struct dn_neigh *dn = (struct dn_neigh *)dn_db->router;
 	char src[ETH_ALEN];
 
 	if (skb == NULL)
@@ -1020,7 +1022,6 @@
 	dn_dn2eth(src, ifa->ifa_local);
 	dn_rt_finish_output(skb, dn_rt_all_rt_mcast, src);
 }
-#endif
 
 static int dn_eth_up(struct net_device *dev)
 {
@@ -1332,6 +1333,63 @@
 
 
 #ifdef CONFIG_PROC_FS
+static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
+{
+	do {
+		dev = dev->next;
+	} while(dev && !dev->dn_ptr);
+
+	return dev;
+}
+
+static struct net_device *dn_dev_get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct net_device *dev;
+
+	dev = dev_base;
+	if (dev && !dev->dn_ptr)
+		dev = dn_dev_get_next(seq, dev);
+	if (pos) {
+		while(dev && (dev = dn_dev_get_next(seq, dev)))
+			--pos;
+	}
+	return dev;
+}
+
+static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	if (*pos) {
+		struct net_device *dev;
+		read_lock(&dev_base_lock);
+		dev = dn_dev_get_idx(seq, *pos - 1);
+		if (dev == NULL)
+			read_unlock(&dev_base_lock);
+		return dev;
+	}
+	return (void*)1;
+}
+
+static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct net_device *dev = v;
+	loff_t one = 1;
+
+	if (v == (void*)1) {
+		dev = dn_dev_seq_start(seq, &one);
+	} else {
+		dev = dn_dev_get_next(seq, dev);
+		if (dev == NULL)
+			read_unlock(&dev_base_lock);
+	}
+	++*pos;
+	return dev;
+}
+
+static void dn_dev_seq_stop(struct seq_file *seq, void *v)
+{
+	if (v && v != (void*)1)
+		read_unlock(&dev_base_lock);
+}
 
 static char *dn_type2asc(char type)
 {
@@ -1347,56 +1405,50 @@
 	return "?";
 }
 
-static int decnet_dev_get_info(char *buffer, char **start, off_t offset, int length)
+static int dn_dev_seq_show(struct seq_file *seq, void *v)
 {
-        struct dn_dev *dn_db;
-	struct net_device *dev;
-        int len = 0;
-        off_t pos = 0;
-        off_t begin = 0;
-	char peer_buf[DN_ASCBUF_LEN];
-	char router_buf[DN_ASCBUF_LEN];
-
-
-        len += sprintf(buffer, "Name     Flags T1   Timer1 T3   Timer3 BlkSize Pri State DevType    Router Peer\n");
-
-	read_lock(&dev_base_lock);
-        for (dev = dev_base; dev; dev = dev->next) {
-		if ((dn_db = (struct dn_dev *)dev->dn_ptr) == NULL)
-			continue;
+	if (v == (void*)1)
+        	seq_puts(seq, "Name     Flags T1   Timer1 T3   Timer3 BlkSize Pri State DevType    Router Peer\n");
+	else {
+		struct net_device *dev = v;
+		char peer_buf[DN_ASCBUF_LEN];
+		char router_buf[DN_ASCBUF_LEN];
+		struct dn_dev *dn_db = dev->dn_ptr;
 
-                len += sprintf(buffer + len, "%-8s %1s     %04u %04u   %04lu %04lu   %04hu    %03d %02x    %-10s %-7s %-7s\n",
+                seq_printf(seq, "%-8s %1s     %04u %04u   %04lu %04lu"
+				"   %04hu    %03d %02x    %-10s %-7s %-7s\n",
                              	dev->name ? dev->name : "???",
                              	dn_type2asc(dn_db->parms.mode),
                              	0, 0,
 				dn_db->t3, dn_db->parms.t3,
-				dn_db->parms.blksize,
+				mtu2blksize(dev),
 				dn_db->parms.priority,
 				dn_db->parms.state, dn_db->parms.name,
 				dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "",
 				dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : "");
+	}
+	return 0;
+}
 
+static struct seq_operations dn_dev_seq_ops = {
+	.start	= dn_dev_seq_start,
+	.next	= dn_dev_seq_next,
+	.stop	= dn_dev_seq_stop,
+	.show	= dn_dev_seq_show,
+};
 
-                pos = begin + len;
-
-                if (pos < offset) {
-                        len   = 0;
-                        begin = pos;
-                }
-                if (pos > offset + length)
-                        break;
-        }
-
-	read_unlock(&dev_base_lock);
-
-        *start = buffer + (offset - begin);
-        len   -= (offset - begin);
-
-        if (len > length) len = length;
-
-        return(len);
+static int dn_dev_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &dn_dev_seq_ops);
 }
 
+static struct file_operations dn_dev_seq_fops = {
+	.open	 = dn_dev_seq_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release,
+};
+
 #endif /* CONFIG_PROC_FS */
 
 static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = 
@@ -1448,9 +1500,7 @@
 
 	rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
 
-#ifdef CONFIG_PROC_FS
-	proc_net_create("decnet_dev", 0, decnet_dev_get_info);
-#endif /* CONFIG_PROC_FS */
+	proc_net_fops_create("decnet_dev", S_IRUGO, &dn_dev_seq_fops);
 
 #ifdef CONFIG_SYSCTL
 	{
diff -Nru a/net/decnet/dn_fib.c b/net/decnet/dn_fib.c
--- a/net/decnet/dn_fib.c	Fri Apr 18 10:42:53 2003
+++ b/net/decnet/dn_fib.c	Wed May  7 13:36:49 2003
@@ -67,18 +67,18 @@
 	int error;
 	u8 scope;
 } dn_fib_props[RTA_MAX+1] = {
-	{ .error = 0, .scope = RT_SCOPE_NOWHERE },	  /* RTN_UNSPEC */
-	{ .error = 0, .scope = RT_SCOPE_UNIVERSE },	  /* RTN_UNICAST */
-	{ .error = 0, .scope = RT_SCOPE_HOST },		  /* RTN_LOCAL */
-	{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },  /* RTN_BROADCAST */
-	{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },  /* RTN_ANYCAST */
-	{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },  /* RTN_MULTICAST */
-	{ .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE }, /* RTN_BLACKHOLE */
-	{ .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },	/* RTN_UNREACHABLE */
-	{ .error = -EACCES, .scope = RT_SCOPE_UNIVERSE }, /* RTN_PROHIBIT */
-	{ .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE }, /* RTN_THROW */
-	{ .error = 0, .scope = RT_SCOPE_NOWHERE },  /* RTN_NAT */
-	{ .error = -EINVAL, .scope = RT_SCOPE_NOWHERE }	  /* RTN_XRESOLVE */
+	[RTN_UNSPEC] =      { .error = 0,       .scope = RT_SCOPE_NOWHERE },
+	[RTN_UNICAST] =     { .error = 0,       .scope = RT_SCOPE_UNIVERSE },
+	[RTN_LOCAL] =       { .error = 0,       .scope = RT_SCOPE_HOST },
+	[RTN_BROADCAST] =   { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+	[RTN_ANYCAST] =     { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+	[RTN_MULTICAST] =   { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
+	[RTN_BLACKHOLE] =   { .error = -EINVAL, .scope = RT_SCOPE_UNIVERSE },
+	[RTN_UNREACHABLE] = { .error = -EHOSTUNREACH, .scope = RT_SCOPE_UNIVERSE },
+	[RTN_PROHIBIT] =    { .error = -EACCES, .scope = RT_SCOPE_UNIVERSE },
+	[RTN_THROW] =       { .error = -EAGAIN, .scope = RT_SCOPE_UNIVERSE },
+	[RTN_NAT] =         { .error = 0,       .scope = RT_SCOPE_NOWHERE },
+	[RTN_XRESOLVE] =    { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
 };
 
 void dn_fib_free_info(struct dn_fib_info *fi)
@@ -218,7 +218,7 @@
 			if (!(dev->flags&IFF_UP))
 				return -ENETDOWN;
 			nh->nh_dev = dev;
-			atomic_inc(&dev->refcnt);
+			dev_hold(dev);
 			nh->nh_scope = RT_SCOPE_LINK;
 			return 0;
 		}
@@ -242,7 +242,7 @@
 		nh->nh_dev = DN_FIB_RES_DEV(res);
 		if (nh->nh_dev == NULL)
 			goto out;
-		atomic_inc(&nh->nh_dev->refcnt);
+		dev_hold(nh->nh_dev);
 		err = -ENETDOWN;
 		if (!(nh->nh_dev->flags & IFF_UP))
 			goto out;
@@ -262,7 +262,7 @@
 		if (!(dev->flags&IFF_UP))
 			return -ENETDOWN;
 		nh->nh_dev = dev;
-		atomic_inc(&nh->nh_dev->refcnt);
+		dev_hold(nh->nh_dev);
 		nh->nh_scope = RT_SCOPE_HOST;
 	}
 
@@ -792,53 +792,12 @@
                 dn_rt_cache_flush(-1);
 }
 
-#ifdef CONFIG_PROC_FS
-
-static int decnet_rt_get_info(char *buffer, char **start, off_t offset, int length)
-{
-        int first = offset / 128;
-        char *ptr = buffer;
-        int count = (length + 127) / 128;
-        int len;
-        int i;
-        struct dn_fib_table *tb;
-
-        *start = buffer + (offset % 128);
-
-        if (--first < 0) {
-                sprintf(buffer, "%-127s\n", "Iface\tDest\tGW  \tFlags\tRefCnt\tUse\tMetric\tMask\t\tMTU\tWindow\tIRTT");
-                --count;
-                ptr += 128;
-                first = 0;
-        }
-
-
-        for(i = RT_MIN_TABLE; (i <= RT_TABLE_MAX) && (count > 0); i++) {
-                if ((tb = dn_fib_get_table(i, 0)) != NULL) {
-                        int n = tb->get_info(tb, ptr, first, count);
-                        count -= n;
-                        ptr += n * 128;
-                }
-        }
-
-        len = ptr - *start;
-        if (len >= length)
-                return length;
-        if (len >= 0)
-                return len;
-
-        return 0;
-}
-#endif /* CONFIG_PROC_FS */
-
 static struct notifier_block dn_fib_dnaddr_notifier = {
 	.notifier_call = dn_fib_dnaddr_event,
 };
 
 void __exit dn_fib_cleanup(void)
 {
-	proc_net_remove("decnet_route");
-
 	dn_fib_table_cleanup();
 	dn_fib_rules_cleanup();
 
@@ -848,10 +807,6 @@
 
 void __init dn_fib_init(void)
 {
-
-#ifdef CONFIG_PROC_FS
-	proc_net_create("decnet_route", 0, decnet_rt_get_info);
-#endif
 
 	dn_fib_table_init();
 	dn_fib_rules_init();
diff -Nru a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
--- a/net/decnet/dn_neigh.c	Fri Apr 18 10:42:53 2003
+++ b/net/decnet/dn_neigh.c	Sat May 10 11:46:35 2003
@@ -202,7 +202,7 @@
 	struct net_device *dev = neigh->dev;
 	char mac_addr[ETH_ALEN];
 
-	dn_dn2eth(mac_addr, rt->rt_saddr);
+	dn_dn2eth(mac_addr, rt->rt_local_src);
 	if (!dev->hard_header || dev->hard_header(skb, dev, ntohs(skb->protocol), neigh->ha, mac_addr, skb->len) >= 0)
 		return neigh->ops->queue_xmit(skb);
 
@@ -692,48 +692,24 @@
 	goto out;
 }
 
-static int dn_seq_release(struct inode *inode, struct file *file)
-{
-	struct seq_file *seq  = (struct seq_file *)file->private_data;
-
-	kfree(seq->private);
-	seq->private = NULL;
-	return seq_release(inode, file);
-}
-
 static struct file_operations dn_neigh_seq_fops = {
+	.owner		= THIS_MODULE,
 	.open		= dn_neigh_seq_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
-	.release	= dn_seq_release,
+	.release	= seq_release_private,
 };
 
-static int __init dn_neigh_proc_init(void)
-{
-	int rc = 0;
-	struct proc_dir_entry *p = create_proc_entry("decnet_neigh", S_IRUGO, proc_net);
-	if (p)
-		p->proc_fops = &dn_neigh_seq_fops;
-	else
-		rc = -ENOMEM;
-	return rc;
-}
-
-#else
-static int __init dn_neigh_proc_init(void)
-{
-	return 0;
-}
 #endif
 
 void __init dn_neigh_init(void)
 {
 	neigh_table_init(&dn_neigh_table);
-
-	dn_neigh_proc_init();
+	proc_net_fops_create("decnet_neigh", S_IRUGO, &dn_neigh_seq_fops);
 }
 
 void __exit dn_neigh_cleanup(void)
 {
+	proc_net_remove("decnet_neigh");
 	neigh_table_clear(&dn_neigh_table);
 }
diff -Nru a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
--- a/net/decnet/dn_nsp_in.c	Fri Apr 18 10:42:53 2003
+++ b/net/decnet/dn_nsp_in.c	Tue May  6 00:58:43 2003
@@ -28,6 +28,7 @@
  *    Steve Whitehouse:  Added backlog congestion level return codes.
  *   Patrick Caulfield:
  *    Steve Whitehouse:  Added flow control support (outbound)
+ *    Steve Whitehouse:  Prepare for nonlinear skbs
  */
 
 /******************************************************************************
@@ -240,7 +241,7 @@
 	cb->info     = msg->info;
 	cb->segsize  = dn_ntohs(msg->segsize);
 
-	if (skb->len < sizeof(*msg))
+	if (!pskb_may_pull(skb, sizeof(*msg)))
 		goto err_out;
 
 	skb_pull(skb, sizeof(*msg));
@@ -721,34 +722,19 @@
 	unsigned char *ptr = (unsigned char *)skb->data;
 	unsigned short reason = NSP_REASON_NL;
 
+	if (!pskb_may_pull(skb, 2))
+		goto free_out;
+
 	skb->h.raw    = skb->data;
 	cb->nsp_flags = *ptr++;
 
 	if (decnet_debug_level & 2)
 		printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags);
 
-	if (skb->len < 2) 
-		goto free_out;
-
 	if (cb->nsp_flags & 0x83) 
 		goto free_out;
 
 	/*
-	 * Returned packets...
-	 * Swap src & dst and look up in the normal way.
-	 */
-	if (cb->rt_flags & DN_RT_F_RTS) {
-		unsigned short tmp = cb->dst_port;
-		cb->dst_port = cb->src_port;
-		cb->src_port = tmp;
-		tmp = cb->dst;
-		cb->dst = cb->src;
-		cb->src = tmp;
-		sk = dn_find_by_skb(skb);
-		goto got_it;
-	}
-
-	/*
 	 * Filter out conninits and useless packet types
 	 */
 	if ((cb->nsp_flags & 0x0c) == 0x08) {
@@ -759,12 +745,14 @@
 				goto free_out;
 			case 0x10:
 			case 0x60:
+				if (unlikely(cb->rt_flags & DN_RT_F_RTS))
+					goto free_out;
 				sk = dn_find_listener(skb, &reason);
 				goto got_it;
 		}
 	}
 
-	if (skb->len < 3)
+	if (!pskb_may_pull(skb, 3))
 		goto free_out;
 
 	/*
@@ -777,13 +765,26 @@
 	/*
 	 * If not a connack, grab the source address too.
 	 */
-	if (skb->len >= 5) {
+	if (pskb_may_pull(skb, 5)) {
 		cb->src_port = *(unsigned short *)ptr;
 		ptr += 2;
 		skb_pull(skb, 5);
 	}
 
 	/*
+	 * Returned packets...
+	 * Swap src & dst and look up in the normal way.
+	 */
+	if (unlikely(cb->rt_flags & DN_RT_F_RTS)) {
+		unsigned short tmp = cb->dst_port;
+		cb->dst_port = cb->src_port;
+		cb->src_port = tmp;
+		tmp = cb->dst;
+		cb->dst = cb->src;
+		cb->src = tmp;
+	}
+
+	/*
 	 * Find the socket to which this skb is destined.
 	 */
 	sk = dn_find_by_skb(skb);
@@ -795,6 +796,15 @@
 		/* Reset backoff */
 		scp->nsp_rxtshift = 0;
 
+		/*
+		 * We linearize everything except data segments here.
+		 */
+		if (cb->nsp_flags & ~0x60) {
+			if (unlikely(skb_is_nonlinear(skb)) &&
+			    skb_linearize(skb, GFP_ATOMIC) != 0)
+				goto free_out;
+		}
+
 		bh_lock_sock(sk);
 		ret = NET_RX_SUCCESS;
 		if (decnet_debug_level & 8)
@@ -835,7 +845,10 @@
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 
 	if (cb->rt_flags & DN_RT_F_RTS) {
-		dn_returned_conn_init(sk, skb);
+		if (cb->nsp_flags == 0x18 || cb->nsp_flags == 0x68)
+			dn_returned_conn_init(sk, skb);
+		else
+			kfree_skb(skb);
 		return NET_RX_SUCCESS;
 	}
 
diff -Nru a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
--- a/net/decnet/dn_nsp_out.c	Tue Apr 29 02:29:48 2003
+++ b/net/decnet/dn_nsp_out.c	Tue May  6 00:58:43 2003
@@ -96,6 +96,7 @@
 	fl.fld_src = dn_saddr2dn(&scp->addr);
 	fl.fld_dst = dn_saddr2dn(&scp->peer);
 	dn_sk_ports_copy(&fl, scp);
+	fl.proto = DNPROTO_NSP;
 	if (dn_route_output_sock(&sk->dst_cache, &fl, sk, 0) == 0) {
 		dst = sk_dst_get(sk);
 		sk->route_caps = dst->dev->features;
@@ -349,8 +350,7 @@
 {
 	unsigned char *ptr = skb_push(skb, len);
 
-	if (len < 5)
-		BUG();
+	BUG_ON(len < 5);
 
 	*ptr++ = msgflag;
 	*((unsigned short *)ptr) = scp->addrrem;
@@ -367,8 +367,7 @@
 	unsigned short ackcrs = scp->numoth_rcv & 0x0FFF;
 	unsigned short *ptr;
 
-	if (hlen < 9)
-		BUG();
+	BUG_ON(hlen < 9);
 
 	scp->ackxmt_dat = acknum;
 	scp->ackxmt_oth = ackcrs;
@@ -485,8 +484,8 @@
 		 * We don't expect to see acknowledgements for packets we
 		 * haven't sent yet.
 		 */
-		if (xmit_count == 0)
-			BUG();
+		WARN_ON(xmit_count == 0);
+
 		/*
 		 * If the packet has only been sent once, we can use it
 		 * to calculate the RTT and also open the window a little
diff -Nru a/net/decnet/dn_route.c b/net/decnet/dn_route.c
--- a/net/decnet/dn_route.c	Sun May  4 06:15:35 2003
+++ b/net/decnet/dn_route.c	Tue May  6 00:58:43 2003
@@ -39,6 +39,7 @@
  *                                 no ref count on net devices.
  *              Steve Whitehouse : RCU for the route cache
  *              Steve Whitehouse : Preparations for the flow cache
+ *              Steve Whitehouse : Prepare for nonlinear skbs
  */
 
 /******************************************************************************
@@ -70,6 +71,7 @@
 #include <net/sock.h>
 #include <linux/mm.h>
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #include <linux/init.h>
 #include <linux/rtnetlink.h>
 #include <linux/string.h>
@@ -97,14 +99,17 @@
 
 static unsigned char dn_hiord_addr[6] = {0xAA,0x00,0x04,0x00,0x00,0x00};
 
-int dn_rt_min_delay = 2*HZ;
-int dn_rt_max_delay = 10*HZ;
-static unsigned long dn_rt_deadline = 0;
+int dn_rt_min_delay = 2 * HZ;
+int dn_rt_max_delay = 10 * HZ;
+int dn_rt_mtu_expires = 10 * 60 * HZ;
+
+static unsigned long dn_rt_deadline;
 
 static int dn_dst_gc(void);
 static struct dst_entry *dn_dst_check(struct dst_entry *, __u32);
 static struct dst_entry *dn_dst_negative_advice(struct dst_entry *);
 static void dn_dst_link_failure(struct sk_buff *);
+static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu);
 static int dn_route_input(struct sk_buff *);
 static void dn_run_flush(unsigned long dummy);
 
@@ -124,6 +129,7 @@
 	.check =		dn_dst_check,
 	.negative_advice =	dn_dst_negative_advice,
 	.link_failure =		dn_dst_link_failure,
+	.update_pmtu =		dn_dst_update_pmtu,
 	.entry_size =		sizeof(struct dn_route),
 	.entries =		ATOMIC_INIT(0),
 };
@@ -210,16 +216,49 @@
 	return 0;
 }
 
+/*
+ * The decnet standards don't impose a particular minimum mtu, what they
+ * do insist on is that the routing layer accepts a datagram of at least
+ * 230 bytes long. Here we have to subtract the routing header length from
+ * 230 to get the minimum acceptable mtu. If there is no neighbour, then we
+ * assume the worst and use a long header size.
+ *
+ * We update both the mtu and the advertised mss (i.e. the segment size we
+ * advertise to the other end).
+ */
+static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
+{
+	u32 min_mtu = 230;
+	struct dn_dev *dn = dst->neighbour ?
+			    (struct dn_dev *)dst->neighbour->dev->dn_ptr : NULL;
+
+	if (dn && dn->use_long == 0)
+		min_mtu -= 6;
+	else
+		min_mtu -= 21;
+
+	if (dst->metrics[RTAX_MTU-1] > mtu && mtu >= min_mtu) {
+		if (!(dst_metric_locked(dst, RTAX_MTU))) {
+			dst->metrics[RTAX_MTU-1] = mtu;
+			dst_set_expires(dst, dn_rt_mtu_expires);
+		}
+		if (!(dst_metric_locked(dst, RTAX_ADVMSS))) {
+			u32 mss = mtu - DN_MAX_NSP_DATA_HEADER;
+			if (dst->metrics[RTAX_ADVMSS-1] > mss)
+				dst->metrics[RTAX_ADVMSS-1] = mss;
+		}
+	}
+}
+
+/* 
+ * When a route has been marked obsolete. (e.g. routing cache flush)
+ */
 static struct dst_entry *dn_dst_check(struct dst_entry *dst, __u32 cookie)
 {
 	dst_release(dst);
 	return NULL;
 }
 
-/*
- * This is called through sendmsg() when you specify MSG_TRYHARD
- * and there is already a route in cache.
- */
 static struct dst_entry *dn_dst_negative_advice(struct dst_entry *dst)
 {
 	dst_release(dst);
@@ -467,7 +506,7 @@
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 	unsigned char *ptr = skb->data;
 
-	if (skb->len < 21) /* 20 for long header, 1 for shortest nsp */
+	if (!pskb_may_pull(skb, 21)) /* 20 for long header, 1 for shortest nsp */
 		goto drop_it;
 
 	skb_pull(skb, 20);
@@ -505,7 +544,7 @@
 	struct dn_skb_cb *cb = DN_SKB_CB(skb);
 	unsigned char *ptr = skb->data;
 
-	if (skb->len < 6) /* 5 for short header + 1 for shortest nsp */
+	if (!pskb_may_pull(skb, 6)) /* 5 for short header + 1 for shortest nsp */
 		goto drop_it;
 
 	skb_pull(skb, 5);
@@ -555,6 +594,9 @@
 	if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
 		goto out;
 
+	if (!pskb_may_pull(skb, 3))
+		goto dump_it;
+
 	skb_pull(skb, 2);
 
 	if (len > skb->len)
@@ -573,6 +615,8 @@
 	 */
 	if (flags & DN_RT_F_PF) {
 		padlen = flags & ~DN_RT_F_PF;
+		if (!pskb_may_pull(skb, padlen + 1))
+			goto dump_it;
 		skb_pull(skb, padlen);
 		flags = *skb->data;
 	}
@@ -594,6 +638,10 @@
 			padlen);
 
         if (flags & DN_RT_PKT_CNTL) {
+		if (unlikely(skb_is_nonlinear(skb)) &&
+		    skb_linearize(skb, GFP_ATOMIC) != 0)
+			goto dump_it;
+
                 switch(flags & DN_RT_CNTL_MSK) {
         	        case DN_RT_PKT_INIT:
 				dn_dev_init_pkt(skb);
@@ -712,7 +760,7 @@
 	 * packets, so we don't need to test for them here.
 	 */
 	cb->rt_flags &= ~DN_RT_F_IE;
-	if (rt->rt_flags | RTCF_DOREDIRECT)
+	if (rt->rt_flags & RTCF_DOREDIRECT)
 		cb->rt_flags |= DN_RT_F_IE;
 
 	return NF_HOOK(PF_DECnet, NF_DN_FORWARD, skb, dev, skb->dev, neigh->output);
@@ -788,8 +836,10 @@
 {
 	__u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2);
 	int match = 16;
-	while(tmp)
-		tmp >>= 1, match--;
+	while(tmp) {
+		tmp >>= 1;
+		match--;
+	}
 	return match;
 }
 
@@ -899,17 +949,19 @@
 	/* No destination? Assume its local */
 	if (!fl.fld_dst) {
 		fl.fld_dst = fl.fld_src;
-#if 0
-		if (!fl.fld_dst)
-			/* grab an address from loopback? */
-#endif
+
 		err = -EADDRNOTAVAIL;
 		if (dev_out)
 			dev_put(dev_out);
-		if (!fl.fld_dst)
-			goto out;
 		dev_out = &loopback_dev;
 		dev_hold(dev_out);
+		if (!fl.fld_dst) {
+			fl.fld_dst =
+			fl.fld_src = dnet_select_source(dev_out, 0,
+						       RT_SCOPE_HOST);
+			if (!fl.fld_dst)
+				goto out;
+		}
 		fl.oif = loopback_dev.ifindex;
 		res.type = RTN_LOCAL;
 		goto make_route;
@@ -1061,6 +1113,7 @@
 	rt->rt_saddr      = fl.fld_src;
 	rt->rt_daddr      = fl.fld_dst;
 	rt->rt_gateway    = gateway ? gateway : fl.fld_dst;
+	rt->rt_local_src  = fl.fld_src;
 
 	rt->rt_dst_map    = fl.fld_dst;
 	rt->rt_src_map    = fl.fld_src;
@@ -1075,14 +1128,14 @@
 	rt->u.dst.input   = dn_rt_bug;
 	rt->rt_flags      = flags;
 	if (flags & RTCF_LOCAL)
-		rt->u.dst.output = dn_nsp_rx;
+		rt->u.dst.input = dn_nsp_rx;
 
-	if (dn_rt_set_next_hop(rt, &res))
+	err = dn_rt_set_next_hop(rt, &res);
+	if (err)
 		goto e_neighbour;
 
 	hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
 	dn_insert_route(rt, hash, (struct dn_route **)pprt);
-	err = 0;
 
 done:
 	if (neigh)
@@ -1175,6 +1228,7 @@
 	unsigned hash;
 	int flags = 0;
 	__u16 gateway = 0;
+	__u16 local_src = 0;
 	struct flowi fl = { .nl_u = { .dn_u = 
 				     { .daddr = cb->dst,
 				       .saddr = cb->src,
@@ -1275,6 +1329,8 @@
 		if (out_dev == in_dev && !(flags & RTCF_NAT))
 			flags |= RTCF_DOREDIRECT;
 
+		local_src = DN_FIB_RES_PREFSRC(res);
+
 	case RTN_BLACKHOLE:
 	case RTN_UNREACHABLE:
 		break;
@@ -1319,6 +1375,8 @@
 	rt->rt_gateway    = fl.fld_dst;
 	if (gateway)
 		rt->rt_gateway = gateway;
+	rt->rt_local_src  = local_src ? local_src : rt->rt_saddr;
+
 	rt->rt_dst_map    = fl.fld_dst;
 	rt->rt_src_map    = fl.fld_src;
 
@@ -1352,12 +1410,12 @@
 	if (rt->u.dst.dev)
 		dev_hold(rt->u.dst.dev);
 
-	if (dn_rt_set_next_hop(rt, &res))
+	err = dn_rt_set_next_hop(rt, &res);
+	if (err)
 		goto e_neighbour;
 
 	hash = dn_hash(rt->fl.fld_src, rt->fl.fld_dst);
 	dn_insert_route(rt, hash, (struct dn_route **)&skb->dst);
-	err = 0;
 
 done:
 	if (neigh)
@@ -1449,7 +1507,7 @@
 	 * they deal only with inputs and not with replies like they do
 	 * currently.
 	 */
-	RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_saddr);
+	RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src);
 	if (rt->rt_daddr != rt->rt_gateway)
 		RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway);
 	if (rtnetlink_put_metrics(skb, rt->u.dst.metrics) < 0)
@@ -1490,6 +1548,7 @@
 	struct flowi fl;
 
 	memset(&fl, 0, sizeof(fl));
+	fl.proto = DNPROTO_NSP;
 
 	skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
 	if (skb == NULL)
@@ -1609,54 +1668,114 @@
 }
 
 #ifdef CONFIG_PROC_FS
+struct dn_rt_cache_iter_state {
+	int bucket;
+};
 
-static int decnet_cache_get_info(char *buffer, char **start, off_t offset, int length)
+static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq)
 {
-        int len = 0;
-        off_t pos = 0;
-        off_t begin = 0;
-	struct dn_route *rt;
-	int i;
-	char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
+	struct dn_route *rt = NULL;
+	struct dn_rt_cache_iter_state *s = seq->private;
 
-	for(i = 0; i <= dn_rt_hash_mask; i++) {
+	for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) {
 		rcu_read_lock();
-		rt = dn_rt_hash_table[i].chain;
-		for(; rt != NULL; rt = rt->u.rt_next) {
-			read_barrier_depends();
-			len += sprintf(buffer + len, "%-8s %-7s %-7s %04d %04d %04d\n",
-					rt->u.dst.dev ? rt->u.dst.dev->name : "*",
-					dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1),
-					dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),
-					atomic_read(&rt->u.dst.__refcnt),
-					rt->u.dst.__use,
-					(int) dst_metric(&rt->u.dst, RTAX_RTT)
-					);
-
+		rt = dn_rt_hash_table[s->bucket].chain;
+		if (rt)
+			break;
+		rcu_read_unlock();
+	}
+	return rt;
+}
 
+static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt)
+{
+	struct dn_rt_cache_iter_state *s = seq->private;
 
-	                pos = begin + len;
-	
-        	        if (pos < offset) {
-                	        len   = 0;
-                        	begin = pos;
-                	}
-              		if (pos > offset + length)
-                	        break;
-		}
+	smp_read_barrier_depends();
+	rt = rt->u.rt_next;
+	while(!rt) {
 		rcu_read_unlock();
-		if (pos > offset + length)
+		if (--s->bucket < 0)
 			break;
+		rcu_read_lock();
+		rt = dn_rt_hash_table[s->bucket].chain;
 	}
+	return rt;
+}
+
+static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	struct dn_route *rt = dn_rt_cache_get_first(seq);
+
+	if (rt) {
+		while(*pos && (rt = dn_rt_cache_get_next(seq, rt)))
+			--*pos;
+	}
+	return *pos ? NULL : rt;
+}
+
+static void *dn_rt_cache_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct dn_route *rt = dn_rt_cache_get_next(seq, v);
+	++*pos;
+	return rt;
+}
 
-        *start = buffer + (offset - begin);
-        len   -= (offset - begin);
+static void dn_rt_cache_seq_stop(struct seq_file *seq, void *v)
+{
+	rcu_read_unlock();
+}
 
-        if (len > length) len = length;
+static int dn_rt_cache_seq_show(struct seq_file *seq, void *v)
+{
+	struct dn_route *rt = v;
+	char buf1[DN_ASCBUF_LEN], buf2[DN_ASCBUF_LEN];
 
-        return(len);
+	seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n",
+			rt->u.dst.dev ? rt->u.dst.dev->name : "*",
+			dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1),
+			dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2),
+			atomic_read(&rt->u.dst.__refcnt),
+			rt->u.dst.__use,
+			(int) dst_metric(&rt->u.dst, RTAX_RTT));
+	return 0;
 } 
 
+static struct seq_operations dn_rt_cache_seq_ops = {
+	.start	= dn_rt_cache_seq_start,
+	.next	= dn_rt_cache_seq_next,
+	.stop	= dn_rt_cache_seq_stop,
+	.show	= dn_rt_cache_seq_show,
+};
+
+static int dn_rt_cache_seq_open(struct inode *inode, struct file *file)
+{
+	struct seq_file *seq;
+	int rc = -ENOMEM;
+	struct dn_rt_cache_iter_state *s = kmalloc(sizeof(*s), GFP_KERNEL);
+
+	if (!s)
+		goto out;
+	rc = seq_open(file, &dn_rt_cache_seq_ops);
+	if (rc)
+		goto out_kfree;
+	seq		= file->private_data;
+	seq->private	= s;
+	memset(s, 0, sizeof(*s));
+out:
+	return rc;
+out_kfree:
+	kfree(s);
+	goto out;
+}
+
+static struct file_operations dn_rt_cache_seq_fops = {
+	.open	 = dn_rt_cache_seq_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release_private,
+};
+
 #endif /* CONFIG_PROC_FS */
 
 void __init dn_route_init(void)
@@ -1714,9 +1833,7 @@
 
         dn_dst_ops.gc_thresh = (dn_rt_hash_mask + 1);
 
-#ifdef CONFIG_PROC_FS
-	proc_net_create("decnet_cache",0,decnet_cache_get_info);
-#endif /* CONFIG_PROC_FS */
+	proc_net_fops_create("decnet_cache", S_IRUGO, &dn_rt_cache_seq_fops);
 }
 
 void __exit dn_route_cleanup(void)
diff -Nru a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
--- a/net/decnet/dn_rules.c	Fri Apr 18 10:42:53 2003
+++ b/net/decnet/dn_rules.c	Thu May  8 09:46:11 2003
@@ -173,9 +173,11 @@
 		memcpy(new_r->r_ifname, RTA_DATA(rta[RTA_IIF-1]), IFNAMSIZ);
 		new_r->r_ifname[IFNAMSIZ-1] = 0;
 		new_r->r_ifindex = -1;
-		dev = __dev_get_by_name(new_r->r_ifname);
-		if (dev)
+		dev = dev_get_by_name(new_r->r_ifname);
+		if (dev) {
 			new_r->r_ifindex = dev->ifindex;
+			dev_put(dev);
+		}
 	}
 
 	rp = &dn_fib_rules;
diff -Nru a/net/decnet/dn_table.c b/net/decnet/dn_table.c
--- a/net/decnet/dn_table.c	Fri Apr 18 10:42:53 2003
+++ b/net/decnet/dn_table.c	Tue May  6 00:58:43 2003
@@ -744,86 +744,6 @@
         return err;
 }
 
-#ifdef CONFIG_PROC_FS
-
-static unsigned dn_fib_flag_trans(int type, int dead, u16 mask, struct dn_fib_info *fi)
-{
-	static unsigned type2flags[RTN_MAX+1] = {
-		0, 0, 0, 0, 0, 0, 0, RTF_REJECT, RTF_REJECT, 0, 0, 0
-	};
-	unsigned flags = type2flags[type];
-
-	if (fi && fi->fib_nh->nh_gw)
-		flags |= RTF_GATEWAY;
-	if (mask == 0xFFFF)
-		flags |= RTF_HOST;
-	if (dead)
-		flags |= RTF_UP;
-	return flags;
-}
-
-static void dn_fib_node_get_info(int type, int dead, struct dn_fib_info *fi, u16 prefix, u16 mask, char *buffer)
-{
-	int len;
-	unsigned flags = dn_fib_flag_trans(type, dead, mask, fi);
-
-	if (fi) {
-		len = sprintf(buffer, "%s\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u",
-				fi->dn_fib_dev ? fi->dn_fib_dev->name : "*", prefix,
-				fi->fib_nh->nh_gw, flags, 0, 0, fi->fib_priority,
-				mask, 0, 0, 0);
-	} else {
-		len = sprintf(buffer, "*\t%04x\t%04x\t%04x\t%d\t%u\t%d\t%04x\t%d\t%u\t%u",
-					prefix, 0,
-					flags, 0, 0, 0,
-					mask, 0, 0, 0);
-	}
-	memset(buffer+len, ' ', 127-len);
-	buffer[127] = '\n';
-}
-
-static int dn_fib_table_get_info(struct dn_fib_table *tb, char *buffer, int first, int count)
-{
-	struct dn_hash *table = (struct dn_hash *)tb->data;
-	struct dn_zone *dz;
-	int pos = 0;
-	int n = 0;
-
-	read_lock(&dn_fib_tables_lock);
-	for(dz = table->dh_zone_list; dz; dz = dz->dz_next) {
-		int i;
-		struct dn_fib_node *f;
-		int maxslot = dz->dz_divisor;
-		struct dn_fib_node **fp = dz->dz_hash;
-
-		if (dz->dz_nent == 0)
-			continue;
-
-		if (pos + dz->dz_nent < first) {
-			pos += dz->dz_nent;
-			continue;
-		}
-
-		for(i = 0; i < maxslot; i++, fp++) {
-			for(f = *fp; f ; f = f->fn_next) {
-				if (++pos <= first)
-					continue;
-				dn_fib_node_get_info(f->fn_type,
-						f->fn_state & DN_S_ZOMBIE,
-						DN_FIB_INFO(f),
-						dz_prefix(f->fn_key, dz),
-						DZ_MASK(dz), buffer);
-				buffer += 128;
-				if (++n >= count)
-					goto out;
-			}
-		}
-	}
-out:
-	read_unlock(&dn_fib_tables_lock);
-	return n;
-}
-#endif /* CONFIG_PROC_FS */
 
 struct dn_fib_table *dn_fib_get_table(int n, int create)
 {
@@ -855,9 +775,6 @@
         t->delete = dn_fib_table_delete;
         t->lookup = dn_fib_table_lookup;
         t->flush  = dn_fib_table_flush;
-#ifdef CONFIG_PROC_FS
-	t->get_info = dn_fib_table_get_info;
-#endif
         t->dump = dn_fib_table_dump;
 	memset(t->data, 0, sizeof(struct dn_hash));
         dn_fib_tables[n] = t;
diff -Nru a/net/decnet/netfilter/Kconfig b/net/decnet/netfilter/Kconfig
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/decnet/netfilter/Kconfig	Sun May  4 12:16:38 2003
@@ -0,0 +1,15 @@
+#
+# DECnet netfilter configuration
+#
+
+menu "DECnet: Netfilter Configuration"
+	depends on DECNET && NETFILTER && EXPERIMENTAL
+
+config DECNET_NF_GRABULATOR
+	tristate "Routing message grabulator (for userland routing daemon)"
+	help
+	  Enable this module if you want to use the userland DECnet routing
+	  daemon. You will also need to enable routing support for DECnet
+	  unless you just want to monitor routing messages from other nodes.
+
+endmenu
diff -Nru a/net/decnet/netfilter/Makefile b/net/decnet/netfilter/Makefile
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/decnet/netfilter/Makefile	Sun May  4 12:16:38 2003
@@ -0,0 +1,6 @@
+#
+# Makefile for DECnet netfilter modules
+#
+
+obj-$(CONFIG_DECNET_NF_GRABULATOR) += dn_rtmsg.o
+
diff -Nru a/net/decnet/netfilter/dn_rtmsg.c b/net/decnet/netfilter/dn_rtmsg.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/decnet/netfilter/dn_rtmsg.c	Wed May 14 13:59:21 2003
@@ -0,0 +1,167 @@
+/*
+ * DECnet       An implementation of the DECnet protocol suite for the LINUX
+ *              operating system.  DECnet is implemented using the  BSD Socket
+ *              interface as the means of communication with the user level.
+ *
+ *              DECnet Routing Message Grabulator
+ *
+ *              (C) 2000 ChyGwyn Limited  -  http://www.chygwyn.com/
+ *              This code may be copied under the GPL v.2 or at your option
+ *              any later version.
+ *
+ * Author:      Steven Whitehouse <steve@chygwyn.com>
+ *
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/netfilter.h>
+#include <linux/spinlock.h>
+#include <linux/netlink.h>
+
+#include <net/sock.h>
+#include <net/flow.h>
+#include <net/dn.h>
+#include <net/dn_route.h>
+
+#include <linux/netfilter_decnet.h>
+
+static struct sock *dnrmg = NULL;
+
+
+static struct sk_buff *dnrmg_build_message(struct sk_buff *rt_skb, int *errp)
+{
+	struct sk_buff *skb = NULL;
+	size_t size;
+	unsigned char *old_tail;
+	struct nlmsghdr *nlh;
+	unsigned char *ptr;
+	struct nf_dn_rtmsg *rtm;
+
+	size = NLMSG_SPACE(rt_skb->len);
+	size += NLMSG_ALIGN(sizeof(struct nf_dn_rtmsg));
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb)
+		goto nlmsg_failure;
+	old_tail = skb->tail;
+	nlh = NLMSG_PUT(skb, 0, 0, 0, size - sizeof(*nlh));
+	rtm = (struct nf_dn_rtmsg *)NLMSG_DATA(nlh);
+	rtm->nfdn_ifindex = rt_skb->dev->ifindex;
+	ptr = NFDN_RTMSG(rtm);
+	memcpy(ptr, rt_skb->data, rt_skb->len);
+	nlh->nlmsg_len = skb->tail - old_tail;
+	return skb;
+
+nlmsg_failure:
+	if (skb)
+		kfree_skb(skb);
+	*errp = -ENOMEM;
+	if (net_ratelimit())
+		printk(KERN_ERR "dn_rtmsg: error creating netlink message\n");
+	return NULL;
+}
+
+static void dnrmg_send_peer(struct sk_buff *skb)
+{
+	struct sk_buff *skb2;
+	int status = 0;
+	int group = 0;
+	unsigned char flags = *skb->data;
+
+	switch(flags & DN_RT_CNTL_MSK) {
+		case DN_RT_PKT_L1RT:
+			group = DNRMG_L1_GROUP;
+			break;
+		case DN_RT_PKT_L2RT:
+			group = DNRMG_L2_GROUP;
+			break;
+		default:
+			return;
+	}
+
+	skb2 = dnrmg_build_message(skb, &status);
+	if (skb2 == NULL)
+		return;
+	NETLINK_CB(skb2).dst_groups = group;
+	netlink_broadcast(dnrmg, skb2, 0, group, GFP_ATOMIC);
+}
+
+
+static unsigned int dnrmg_hook(unsigned int hook,
+			struct sk_buff **pskb,
+			const struct net_device *in,
+			const struct net_device *out,
+			int (*okfn)(struct sk_buff *))
+{
+	dnrmg_send_peer(*pskb);
+	return NF_ACCEPT;
+}
+
+
+#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
+
+static inline void dnrmg_receive_user_skb(struct sk_buff *skb)
+{
+	struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
+
+	if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
+		return;
+
+	if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
+		RCV_SKB_FAIL(-EPERM);
+
+	/* Eventually we might send routing messages too */
+
+	RCV_SKB_FAIL(-EINVAL);
+}
+
+static void dnrmg_receive_user_sk(struct sock *sk, int len)
+{
+	struct sk_buff *skb;
+
+	while((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+		dnrmg_receive_user_skb(skb);
+		kfree_skb(skb);
+	}
+}
+
+static struct nf_hook_ops dnrmg_ops = {
+	.hook		= dnrmg_hook,
+	.pf		= PF_DECnet,
+	.hooknum	= NF_DN_ROUTE,
+	.priority	= NF_DN_PRI_DNRTMSG,
+};
+
+static int __init init(void)
+{
+	int rv = 0;
+
+	dnrmg = netlink_kernel_create(NETLINK_DNRTMSG, dnrmg_receive_user_sk);
+	if (dnrmg == NULL) {
+		printk(KERN_ERR "dn_rtmsg: Cannot create netlink socket");
+		return -ENOMEM;
+	}
+
+	rv = nf_register_hook(&dnrmg_ops);
+	if (rv) {
+		sock_release(dnrmg->socket);
+	}
+
+	return rv;
+}
+
+static void __exit fini(void)
+{
+	nf_unregister_hook(&dnrmg_ops);
+	sock_release(dnrmg->socket);
+}
+
+
+MODULE_DESCRIPTION("DECnet Routing Message Grabulator");
+MODULE_AUTHOR("Steven Whitehouse <steve@chygwyn.com>");
+MODULE_LICENSE("GPL");
+
+module_init(init);
+module_exit(fini);
+
diff -Nru a/net/econet/af_econet.c b/net/econet/af_econet.c
--- a/net/econet/af_econet.c	Fri May  2 23:16:43 2003
+++ b/net/econet/af_econet.c	Wed May  7 13:36:50 2003
@@ -325,7 +325,7 @@
 	{
 		/* Real hardware Econet.  We're not worthy etc. */
 #ifdef CONFIG_ECONET_NATIVE
-		atomic_inc(&dev->refcnt);
+		dev_hold(dev);
 		
 		skb = sock_alloc_send_skb(sk, len+dev->hard_header_len+15, 
 					  msg->msg_flags & MSG_DONTWAIT, &err);
diff -Nru a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
--- a/net/ipv4/af_inet.c	Fri May  2 23:42:59 2003
+++ b/net/ipv4/af_inet.c	Fri May 16 01:07:42 2003
@@ -94,7 +94,6 @@
 #include <linux/inet.h>
 #include <linux/igmp.h>
 #include <linux/netdevice.h>
-#include <linux/brlock.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/arp.h>
@@ -129,7 +128,8 @@
 /* The inetsw table contains everything that inet_create needs to
  * build a new socket.
  */
-struct list_head inetsw[SOCK_MAX];
+static struct list_head inetsw[SOCK_MAX];
+static spinlock_t inetsw_lock = SPIN_LOCK_UNLOCKED;
 
 /* New destruction routine */
 
@@ -337,8 +337,8 @@
 
 	/* Look for the requested type/protocol pair. */
 	answer = NULL;
-	br_read_lock_bh(BR_NETPROTO_LOCK);
-	list_for_each(p, &inetsw[sock->type]) {
+	rcu_read_lock();
+	list_for_each_rcu(p, &inetsw[sock->type]) {
 		answer = list_entry(p, struct inet_protosw, list);
 
 		/* Check the non-wild match. */
@@ -356,7 +356,6 @@
 		}
 		answer = NULL;
 	}
-	br_read_unlock_bh(BR_NETPROTO_LOCK);
 
 	err = -ESOCKTNOSUPPORT;
 	if (!answer)
@@ -373,6 +372,7 @@
 	sk->no_check = answer->no_check;
 	if (INET_PROTOSW_REUSE & answer->flags)
 		sk->reuse = 1;
+	rcu_read_unlock();
 
 	inet = inet_sk(sk);
 
@@ -398,7 +398,7 @@
 	sk->protocol	= protocol;
 	sk->backlog_rcv = sk->prot->backlog_rcv;
 
-	inet->ttl	= sysctl_ip_default_ttl;
+	inet->uc_ttl	= -1;
 	inet->mc_loop	= 1;
 	inet->mc_ttl	= 1;
 	inet->mc_index	= 0;
@@ -427,6 +427,7 @@
 out:
 	return err;
 out_sk_free:
+	rcu_read_unlock();
 	sk_free(sk);
 	goto out;
 }
@@ -926,6 +927,7 @@
 struct net_proto_family inet_family_ops = {
 	.family = PF_INET,
 	.create = inet_create,
+	.owner	= THIS_MODULE,
 };
 
 
@@ -978,7 +980,7 @@
 	int protocol = p->protocol;
 	struct list_head *last_perm;
 
-	br_write_lock_bh(BR_NETPROTO_LOCK);
+	spin_lock_bh(&inetsw_lock);
 
 	if (p->type > SOCK_MAX)
 		goto out_illegal;
@@ -1007,9 +1009,12 @@
 	 * non-permanent entry.  This means that when we remove this entry, the 
 	 * system automatically returns to the old behavior.
 	 */
-	list_add(&p->list, last_perm);
+	list_add_rcu(&p->list, last_perm);
 out:
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	spin_unlock_bh(&inetsw_lock);
+
+	synchronize_net();
+
 	return;
 
 out_permanent:
@@ -1031,9 +1036,11 @@
 		       "Attempt to unregister permanent protocol %d.\n",
 		       p->protocol);
 	} else {
-		br_write_lock_bh(BR_NETPROTO_LOCK);
-		list_del(&p->list);
-		br_write_unlock_bh(BR_NETPROTO_LOCK);
+		spin_lock_bh(&inetsw_lock);
+		list_del_rcu(&p->list);
+		spin_unlock_bh(&inetsw_lock);
+
+		synchronize_net();
 	}
 }
 
diff -Nru a/net/ipv4/arp.c b/net/ipv4/arp.c
--- a/net/ipv4/arp.c	Wed Mar 19 19:34:17 2003
+++ b/net/ipv4/arp.c	Mon May 19 23:22:52 2003
@@ -108,8 +108,9 @@
 #include <net/netrom.h>
 #endif
 #endif
-#ifdef CONFIG_ATM_CLIP
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
 #include <net/atmclip.h>
+struct neigh_table *clip_tbl_hook;
 #endif
 
 #include <asm/system.h>
@@ -443,8 +444,8 @@
 		if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT))
 			nexthop = 0;
 		n = __neigh_lookup_errno(
-#ifdef CONFIG_ATM_CLIP
-		    dev->type == ARPHRD_ATM ? &clip_tbl :
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+		    dev->type == ARPHRD_ATM ? clip_tbl_hook :
 #endif
 		    &arp_tbl, &nexthop, dev);
 		if (IS_ERR(n))
@@ -1384,6 +1385,7 @@
 }
 
 static struct file_operations arp_seq_fops = {
+	.owner		= THIS_MODULE,
 	.open           = arp_seq_open,
 	.read           = seq_read,
 	.llseek         = seq_lseek,
diff -Nru a/net/ipv4/devinet.c b/net/ipv4/devinet.c
--- a/net/ipv4/devinet.c	Thu Apr  3 06:47:45 2003
+++ b/net/ipv4/devinet.c	Tue May 20 19:39:24 2003
@@ -552,7 +552,6 @@
 		goto out;
 	}
 
-	dev_probe_lock();
 	rtnl_lock();
 
 	ret = -ENODEV;
@@ -702,12 +701,10 @@
 	}
 done:
 	rtnl_unlock();
-	dev_probe_unlock();
 out:
 	return ret;
 rarok:
 	rtnl_unlock();
-	dev_probe_unlock();
 	ret = copy_to_user(arg, &ifr, sizeof(struct ifreq)) ? -EFAULT : 0;
 	goto out;
 }
@@ -1065,9 +1062,9 @@
 	return ret;
 }
 
-static int ipv4_doint_and_flush(ctl_table *ctl, int write,
-				struct file* filp, void *buffer,
-				size_t *lenp)
+int ipv4_doint_and_flush(ctl_table *ctl, int write,
+			 struct file* filp, void *buffer,
+			 size_t *lenp)
 {
 	int *valp = ctl->data;
 	int val = *valp;
@@ -1079,10 +1076,10 @@
 	return ret;
 }
 
-static int ipv4_doint_and_flush_strategy(ctl_table *table, int *name, int nlen,
-					 void *oldval, size_t *oldlenp,
-					 void *newval, size_t newlen, 
-					 void **context)
+int ipv4_doint_and_flush_strategy(ctl_table *table, int *name, int nlen,
+				  void *oldval, size_t *oldlenp,
+				  void *newval, size_t newlen, 
+				  void **context)
 {
 	int *valp = table->data;
 	int new;
@@ -1305,9 +1302,7 @@
 	if (!t)
 		return;
 	memcpy(t, &devinet_sysctl, sizeof(*t));
-	for (i = 0;
-	     i < sizeof(t->devinet_vars) / sizeof(t->devinet_vars[0]) - 1;
-	     i++) {
+	for (i = 0; i < ARRAY_SIZE(t->devinet_vars) - 1; i++) {
 		t->devinet_vars[i].data += (char *)p - (char *)&ipv4_devconf;
 		t->devinet_vars[i].de = NULL;
 	}
diff -Nru a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c
--- a/net/ipv4/fib_frontend.c	Sun Oct 13 15:14:24 2002
+++ b/net/ipv4/fib_frontend.c	Mon May 19 23:22:52 2003
@@ -115,9 +115,9 @@
 	if (res.type != RTN_LOCAL)
 		goto out;
 	dev = FIB_RES_DEV(res);
-	if (dev)
-		atomic_inc(&dev->refcnt);
 
+	if (dev)
+		dev_hold(dev);
 out:
 	fib_res_put(&res);
 	return dev;
diff -Nru a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c
--- a/net/ipv4/fib_hash.c	Thu Apr  3 04:42:38 2003
+++ b/net/ipv4/fib_hash.c	Sat May 10 11:46:35 2003
@@ -1065,6 +1065,7 @@
 }
 
 static struct file_operations fib_seq_fops = {
+	.owner		= THIS_MODULE,
 	.open           = fib_seq_open,
 	.read           = seq_read,
 	.llseek         = seq_lseek,
diff -Nru a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c
--- a/net/ipv4/fib_semantics.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv4/fib_semantics.c	Wed May  7 01:38:09 2003
@@ -406,7 +406,7 @@
 			if (!(dev->flags&IFF_UP))
 				return -ENETDOWN;
 			nh->nh_dev = dev;
-			atomic_inc(&dev->refcnt);
+			dev_hold(dev);
 			nh->nh_scope = RT_SCOPE_LINK;
 			return 0;
 		}
@@ -429,7 +429,7 @@
 		nh->nh_oif = FIB_RES_OIF(res);
 		if ((nh->nh_dev = FIB_RES_DEV(res)) == NULL)
 			goto out;
-		atomic_inc(&nh->nh_dev->refcnt);
+		dev_hold(nh->nh_dev);
 		err = -ENETDOWN;
 		if (!(nh->nh_dev->flags & IFF_UP))
 			goto out;
@@ -451,7 +451,7 @@
 			return -ENETDOWN;
 		}
 		nh->nh_dev = in_dev->dev;
-		atomic_inc(&nh->nh_dev->refcnt);
+		dev_hold(nh->nh_dev);
 		nh->nh_scope = RT_SCOPE_HOST;
 		in_dev_put(in_dev);
 	}
diff -Nru a/net/ipv4/icmp.c b/net/ipv4/icmp.c
--- a/net/ipv4/icmp.c	Thu Mar  6 16:30:30 2003
+++ b/net/ipv4/icmp.c	Fri May 16 01:07:42 2003
@@ -185,8 +185,6 @@
 	},
 };
 
-extern int sysctl_ip_default_ttl;
-
 /* Control parameters for ECHO replies. */
 int sysctl_icmp_echo_ignore_all;
 int sysctl_icmp_echo_ignore_broadcasts;
@@ -384,7 +382,6 @@
 	icmp_out_count(icmp_param->data.icmph.type);
 
 	inet->tos = skb->nh.iph->tos;
-	inet->ttl = sysctl_ip_default_ttl;
 	daddr = ipc.addr = rt->rt_src;
 	ipc.opt = NULL;
 	if (icmp_param->replyopts.optlen) {
@@ -539,7 +536,6 @@
 	icmp_param.offset = skb_in->nh.raw - skb_in->data;
 	icmp_out_count(icmp_param.data.icmph.type);
 	inet_sk(icmp_socket->sk)->tos = tos;
-	inet_sk(icmp_socket->sk)->ttl = sysctl_ip_default_ttl;
 	ipc.addr = iph->saddr;
 	ipc.opt = &icmp_param.replyopts;
 	if (icmp_param.replyopts.srr) {
@@ -695,15 +691,12 @@
 	}
 	read_unlock(&raw_v4_lock);
 
-	/*
-	 *	This can't change while we are doing it.
-	 *	Callers have obtained BR_NETPROTO_LOCK so
-	 *	we are OK.
-	 */
-
+	rcu_read_lock();
 	ipprot = inet_protos[hash];
+	smp_read_barrier_depends();
 	if (ipprot && ipprot->err_handler)
 		ipprot->err_handler(skb, info);
+	rcu_read_unlock();
 
 out:
 	return;
@@ -1129,7 +1122,7 @@
 		per_cpu(__icmp_socket, i)->sk->allocation = GFP_ATOMIC;
 		per_cpu(__icmp_socket, i)->sk->sndbuf = SK_WMEM_MAX * 2;
 		inet = inet_sk(per_cpu(__icmp_socket, i)->sk);
-		inet->ttl = MAXTTL;
+		inet->uc_ttl = -1;
 		inet->pmtudisc = IP_PMTUDISC_DONT;
 
 		/* Unhash it so that IP input processing does not even
diff -Nru a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
--- a/net/ipv4/ip_gre.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv4/ip_gre.c	Fri May 16 01:07:42 2003
@@ -860,7 +860,7 @@
 			iph->ttl = ((struct ipv6hdr*)old_iph)->hop_limit;
 #endif
 		else
-			iph->ttl = sysctl_ip_default_ttl;
+			iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT);
 	}
 
 	((u16*)(iph+1))[0] = tunnel->parms.o_flags;
diff -Nru a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
--- a/net/ipv4/ip_input.c	Sun Mar 23 02:21:28 2003
+++ b/net/ipv4/ip_input.c	Sat May 10 05:25:34 2003
@@ -215,6 +215,7 @@
         /* Point into the IP datagram, just past the header. */
         skb->h.raw = skb->data;
 
+	rcu_read_lock();
 	{
 		/* Note: See raw.c and net/raw.h, RAWV4_HTABLE_SIZE==MAX_INET_PROTOS */
 		int protocol = skb->nh.iph->protocol;
@@ -235,10 +236,11 @@
 		if ((ipprot = inet_protos[hash]) != NULL) {
 			int ret;
 
+			smp_read_barrier_depends();
 			if (!ipprot->no_policy &&
 			    !xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
 				kfree_skb(skb);
-				return 0;
+				goto out;
 			}
 			ret = ipprot->handler(skb);
 			if (ret < 0) {
@@ -258,6 +260,8 @@
 			kfree_skb(skb);
 		}
 	}
+ out:
+	rcu_read_unlock();
 
 	return 0;
 }
diff -Nru a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
--- a/net/ipv4/ip_output.c	Wed Apr 30 01:34:47 2003
+++ b/net/ipv4/ip_output.c	Fri May 16 01:07:43 2003
@@ -112,6 +112,15 @@
 	return 0;
 }
 
+static inline int ip_select_ttl(struct inet_opt *inet, struct dst_entry *dst)
+{
+	int ttl = inet->uc_ttl;
+
+	if (ttl < 0)
+		ttl = dst_metric(dst, RTAX_HOPLIMIT);
+	return ttl;
+}
+
 /* 
  *		Add an ip header to a skbuff and send it out.
  *
@@ -136,7 +145,7 @@
 		iph->frag_off = htons(IP_DF);
 	else
 		iph->frag_off = 0;
-	iph->ttl      = inet->ttl;
+	iph->ttl      = ip_select_ttl(inet, &rt->u.dst);
 	iph->daddr    = rt->rt_dst;
 	iph->saddr    = rt->rt_src;
 	iph->protocol = sk->protocol;
@@ -341,7 +350,7 @@
 		iph->frag_off = htons(IP_DF);
 	else
 		iph->frag_off = 0;
-	iph->ttl      = inet->ttl;
+	iph->ttl      = ip_select_ttl(inet, &rt->u.dst);
 	iph->protocol = sk->protocol;
 	iph->saddr    = rt->rt_src;
 	iph->daddr    = rt->rt_dst;
@@ -685,16 +694,6 @@
 	return 0;
 }
 
-static void
-skb_fill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size)
-{
-	skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
-	frag->page = page;
-	frag->page_offset = off;
-	frag->size = size;
-	skb_shinfo(skb)->nr_frags = i+1;
-}
-
 static inline unsigned int
 csum_page(struct page *page, int offset, int copy)
 {
@@ -1130,7 +1129,7 @@
 	if (rt->rt_type == RTN_MULTICAST)
 		ttl = inet->mc_ttl;
 	else
-		ttl = inet->ttl;
+		ttl = ip_select_ttl(inet, &rt->u.dst);
 
 	iph = (struct iphdr *)skb->data;
 	iph->version = 4;
diff -Nru a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
--- a/net/ipv4/ip_sockglue.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv4/ip_sockglue.c	Fri May 16 01:07:43 2003
@@ -501,11 +501,9 @@
 		case IP_TTL:
 			if (optlen<1)
 				goto e_inval;
-			if(val==-1)
-				val = sysctl_ip_default_ttl;
-			if(val<1||val>255)
+			if (val != -1 && (val < 1 || val>255))
 				goto e_inval;
-			inet->ttl = val;
+			inet->uc_ttl = val;
 			break;
 		case IP_HDRINCL:
 			if(sk->type!=SOCK_RAW) {
@@ -911,7 +909,9 @@
 			val = inet->tos;
 			break;
 		case IP_TTL:
-			val = inet->ttl;
+			val = (inet->uc_ttl == -1 ?
+			       sysctl_ip_default_ttl :
+			       inet->uc_ttl);
 			break;
 		case IP_HDRINCL:
 			val = inet->hdrincl;
diff -Nru a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c
--- a/net/ipv4/ipcomp.c	Sun May  4 06:26:55 2003
+++ b/net/ipv4/ipcomp.c	Sat May 17 22:35:07 2003
@@ -1,5 +1,5 @@
 /*
- * IP Payload Compression Protocol (IPComp) - RFC3713.
+ * IP Payload Compression Protocol (IPComp) - RFC3173.
  *
  * Copyright (c) 2003 James Morris <jmorris@intercode.com.au>
  *
@@ -22,20 +22,7 @@
 #include <net/xfrm.h>
 #include <net/icmp.h>
 #include <net/esp.h>
-
-#define IPCOMP_SCRATCH_SIZE	65400
-
-struct ipcomp_hdr {
-	u8 nexthdr;
-	u8 flags;
-	u16 cpi;
-};
-
-struct ipcomp_data {
-	u16 threshold;
-	u8 *scratch;
-	struct crypto_tfm *tfm;
-};
+#include <net/ipcomp.h>
 
 static int ipcomp_decompress(struct xfrm_state *x, struct sk_buff *skb)
 {
@@ -52,7 +39,7 @@
 	if (err)
 		goto out;
 
-	if (dlen < (plen + sizeof(struct ipcomp_hdr))) {
+	if (dlen < (plen + sizeof(struct ip_comp_hdr))) {
 		err = -EINVAL;
 		goto out;
 	}
@@ -93,9 +80,11 @@
 	iph = skb->nh.iph;
 	memcpy(&tmp_iph, iph, iph->ihl * 4);
 	nexthdr = *(u8 *)skb->data;
-	skb_pull(skb, sizeof(struct ipcomp_hdr));
+	skb_pull(skb, sizeof(struct ip_comp_hdr));
+	skb->nh.raw += sizeof(struct ip_comp_hdr);
 	memcpy(skb->nh.raw, &tmp_iph, tmp_iph.iph.ihl * 4);
-	iph->tot_len = htons(ntohs(iph->tot_len) - sizeof(struct ipcomp_hdr));
+	iph = skb->nh.iph;
+	iph->tot_len = htons(ntohs(iph->tot_len) - sizeof(struct ip_comp_hdr));
 	iph->protocol = nexthdr;
 	skb->h.raw = skb->data;
 	err = ipcomp_decompress(x, skb);
@@ -120,7 +109,7 @@
 	if (err)
 		goto out;
 
-	if ((dlen + sizeof(struct ipcomp_hdr)) >= plen) {
+	if ((dlen + sizeof(struct ip_comp_hdr)) >= plen) {
 		err = -EMSGSIZE;
 		goto out;
 	}
@@ -160,12 +149,13 @@
 	struct dst_entry *dst = skb->dst;
 	struct xfrm_state *x = dst->xfrm;
 	struct iphdr *iph, *top_iph;
-	struct ipcomp_hdr *ipch;
+	struct ip_comp_hdr *ipch;
 	struct ipcomp_data *ipcd = x->data;
 	union {
 		struct iphdr	iph;
 		char 		buf[60];
 	} tmp_iph;
+	int hdr_len = 0;
 
 	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) {
 		err = -EINVAL;
@@ -178,7 +168,11 @@
 		goto error;
 
 	/* Don't bother compressing */
-	if (skb->len < ipcd->threshold) {
+	if (!x->props.mode) {
+		iph = skb->nh.iph;
+		hdr_len = iph->ihl * 4;
+	}
+	if ((skb->len - hdr_len) < ipcd->threshold) {
 		if (x->props.mode) {
 			ipcomp_tunnel_encap(x, skb);
 			iph = skb->nh.iph;
@@ -213,13 +207,13 @@
 	/* Install ipcomp header, convert into ipcomp datagram. */
 	iph = skb->nh.iph;
 	memcpy(&tmp_iph, iph, iph->ihl * 4);
-	top_iph = (struct iphdr *)skb_push(skb, sizeof(struct ipcomp_hdr));
+	top_iph = (struct iphdr *)skb_push(skb, sizeof(struct ip_comp_hdr));
 	memcpy(top_iph, &tmp_iph, iph->ihl * 4);
 	iph = top_iph;
 	iph->tot_len = htons(skb->len);
 	iph->protocol = IPPROTO_COMP;
 	iph->check = 0;
-	ipch = (struct ipcomp_hdr *)((char *)iph + iph->ihl * 4);
+	ipch = (struct ip_comp_hdr *)((char *)iph + iph->ihl * 4);
 	ipch->nexthdr = x->props.mode ? IPPROTO_IPIP : tmp_iph.iph.protocol;
 	ipch->flags = 0;
 	ipch->cpi = htons((u16 )ntohl(x->id.spi));
@@ -250,7 +244,7 @@
 {
 	u32 spi;
 	struct iphdr *iph = (struct iphdr *)skb->data;
-	struct ipcomp_hdr *ipch = (struct ipcomp_hdr *)(skb->data+(iph->ihl<<2));
+	struct ip_comp_hdr *ipch = (struct ip_comp_hdr *)(skb->data+(iph->ihl<<2));
 	struct xfrm_state *x;
 
 	if (skb->h.icmph->type != ICMP_DEST_UNREACH ||
@@ -267,6 +261,67 @@
 	xfrm_state_put(x);
 }
 
+/* We always hold one tunnel user reference to indicate a tunnel */ 
+static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x)
+{
+	struct xfrm_state *t;
+	
+	t = xfrm_state_alloc();
+	if (t == NULL)
+		goto out;
+
+	t->id.proto = IPPROTO_IPIP;
+	t->id.spi = x->props.saddr.a4;
+	t->id.daddr.a4 = x->id.daddr.a4;
+	memcpy(&t->sel, &x->sel, sizeof(t->sel));
+	t->props.family = AF_INET;
+	t->props.mode = 1;
+	t->props.saddr.a4 = x->props.saddr.a4;
+	
+	t->type = xfrm_get_type(IPPROTO_IPIP, t->props.family);
+	if (t->type == NULL)
+		goto error;
+		
+	if (t->type->init_state(t, NULL))
+		goto error;
+
+	t->km.state = XFRM_STATE_VALID;
+	atomic_set(&t->tunnel_users, 1);
+out:
+	return t;
+
+error:
+	xfrm_state_put(t);
+	t = NULL;
+	goto out;
+}
+
+/*
+ * Must be protected by xfrm_cfg_sem.  State and tunnel user references are
+ * always incremented on success.
+ */
+static int ipcomp_tunnel_attach(struct xfrm_state *x)
+{
+	int err = 0;
+	struct xfrm_state *t;
+
+	t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr.a4,
+	                      x->props.saddr.a4, IPPROTO_IPIP, AF_INET);
+	if (!t) {
+		t = ipcomp_tunnel_create(x);
+		if (!t) {
+			err = -EINVAL;
+			goto out;
+		}
+		xfrm_state_insert(t);
+		xfrm_state_hold(t);
+	}
+	x->tunnel = t;
+	atomic_inc(&t->tunnel_users);
+out:
+	return err;
+}
+
 static void ipcomp_free_data(struct ipcomp_data *ipcd)
 {
 	if (ipcd->tfm)
@@ -293,7 +348,7 @@
 		goto error;
 
 	memset(ipcd, 0, sizeof(*ipcd));
-	x->props.header_len = sizeof(struct ipcomp_hdr);
+	x->props.header_len = sizeof(struct ip_comp_hdr);
 	if (x->props.mode)
 		x->props.header_len += sizeof(struct iphdr);
 	x->data = ipcd;
@@ -306,6 +361,12 @@
 	if (!ipcd->tfm)
 		goto error;
 
+	if (x->props.mode) {
+		err = ipcomp_tunnel_attach(x);
+		if (err)
+			goto error;
+	}
+
 	calg_desc = xfrm_calg_get_byname(x->calg->alg_name);
 	BUG_ON(!calg_desc);
 	ipcd->threshold = calg_desc->uinfo.comp.threshold;
@@ -364,6 +425,6 @@
 module_exit(ipcomp4_fini);
 
 MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) - RFC3713");
+MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) - RFC3173");
 MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>");
 
diff -Nru a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c
--- a/net/ipv4/netfilter/arp_tables.c	Wed Apr  9 22:08:17 2003
+++ b/net/ipv4/netfilter/arp_tables.c	Sat May 17 12:39:13 2003
@@ -371,11 +371,8 @@
 
 	ret = find_inlist_lock_noload(head, name, error, mutex);
 	if (!ret) {
-		char modulename[ARPT_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
-		strcpy(modulename, prefix);
-		strcat(modulename, name);
-		duprintf("find_inlist: loading `%s'.\n", modulename);
-		request_module(modulename);
+		duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
+		request_module("%s%s", prefix, name);
 		ret = find_inlist_lock_noload(head, name, error, mutex);
 	}
 
diff -Nru a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
--- a/net/ipv4/netfilter/ip_conntrack_core.c	Sat May  3 10:01:19 2003
+++ b/net/ipv4/netfilter/ip_conntrack_core.c	Mon May 12 15:35:45 2003
@@ -1188,12 +1188,9 @@
 	local_bh_enable();
 
 	if (!skb) {
-		if (sk) sock_put(sk);
+		if (sk)
+			sock_put(sk);
 		return skb;
-	} else if (skb_is_nonlinear(skb) && skb_linearize(skb, GFP_ATOMIC) != 0) {
-		kfree_skb(skb);
-		if (sk) sock_put(sk);
-		return NULL;
 	}
 
 	if (sk) {
diff -Nru a/net/ipv4/netfilter/ip_conntrack_ftp.c b/net/ipv4/netfilter/ip_conntrack_ftp.c
--- a/net/ipv4/netfilter/ip_conntrack_ftp.c	Sun Apr 27 19:03:40 2003
+++ b/net/ipv4/netfilter/ip_conntrack_ftp.c	Tue May 20 19:39:24 2003
@@ -301,7 +301,7 @@
 	array[2] = (ntohl(ct->tuplehash[dir].tuple.src.ip) >> 8) & 0xFF;
 	array[3] = ntohl(ct->tuplehash[dir].tuple.src.ip) & 0xFF;
 
-	for (i = 0; i < sizeof(search) / sizeof(search[0]); i++) {
+	for (i = 0; i < ARRAY_SIZE(search); i++) {
 		if (search[i].dir != dir) continue;
 
 		found = find_pattern(ftp_buffer, skb->len - dataoff,
diff -Nru a/net/ipv4/netfilter/ip_fw_compat.c b/net/ipv4/netfilter/ip_fw_compat.c
--- a/net/ipv4/netfilter/ip_fw_compat.c	Mon Apr 28 02:27:56 2003
+++ b/net/ipv4/netfilter/ip_fw_compat.c	Tue May 13 13:25:32 2003
@@ -15,34 +15,10 @@
 #include <linux/netfilter_ipv4/compat_firewall.h>
 #include <linux/netfilter_ipv4/ip_conntrack.h>
 #include <linux/netfilter_ipv4/ip_conntrack_core.h>
+#include "ip_fw_compat.h"
 
 static struct firewall_ops *fwops;
 
-/* From ip_fw_compat_redir.c */
-extern unsigned int
-do_redirect(struct sk_buff *skb,
-	    const struct net_device *dev,
-	    u_int16_t redirpt);
-
-extern void
-check_for_redirect(struct sk_buff *skb);
-
-extern void
-check_for_unredirect(struct sk_buff *skb);
-
-/* From ip_fw_compat_masq.c */
-extern unsigned int
-do_masquerade(struct sk_buff **pskb, const struct net_device *dev);
-
-extern unsigned int
-check_for_masq_error(struct sk_buff *pskb);
-
-extern unsigned int
-check_for_demasq(struct sk_buff **pskb);
-
-extern int __init masq_init(void);
-extern void masq_cleanup(void);
-
 /* They call these; we do what they want. */
 int register_firewall(int pf, struct firewall_ops *fw)
 {
@@ -75,31 +51,17 @@
 	int ret = FW_BLOCK;
 	u_int16_t redirpt;
 
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	/* Assume worse case: any hook could change packet */
 	(*pskb)->nfcache |= NFC_UNKNOWN | NFC_ALTERED;
 	if ((*pskb)->ip_summed == CHECKSUM_HW)
 		(*pskb)->ip_summed = CHECKSUM_NONE;
 
-	/* Firewall rules can alter TOS: raw socket (tcpdump) may have
-           clone of incoming skb: don't disturb it --RR */
-	if (skb_cloned(*pskb) && !(*pskb)->sk) {
-		struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
-		if (!nskb)
-			return NF_DROP;
-		kfree_skb(*pskb);
-		*pskb = nskb;
-	}
-
 	switch (hooknum) {
 	case NF_IP_PRE_ROUTING:
 		if (fwops->fw_acct_in)
 			fwops->fw_acct_in(fwops, PF_INET,
 					  (struct net_device *)in,
-					  (*pskb)->nh.raw, &redirpt, pskb);
+					  &redirpt, pskb);
 
 		if ((*pskb)->nh.iph->frag_off & htons(IP_MF|IP_OFFSET)) {
 			*pskb = ip_ct_gather_frags(*pskb);
@@ -109,7 +71,7 @@
 		}
 
 		ret = fwops->fw_input(fwops, PF_INET, (struct net_device *)in,
-				      (*pskb)->nh.raw, &redirpt, pskb);
+				      &redirpt, pskb);
 		break;
 
 	case NF_IP_FORWARD:
@@ -119,18 +81,18 @@
 			ret = FW_ACCEPT;
 		else ret = fwops->fw_forward(fwops, PF_INET,
 					     (struct net_device *)out,
-					     (*pskb)->nh.raw, &redirpt, pskb);
+					     &redirpt, pskb);
 		break;
 
 	case NF_IP_POST_ROUTING:
 		ret = fwops->fw_output(fwops, PF_INET,
 				       (struct net_device *)out,
-				       (*pskb)->nh.raw, &redirpt, pskb);
+				       &redirpt, pskb);
 		if (ret == FW_ACCEPT || ret == FW_SKIP) {
 			if (fwops->fw_acct_out)
 				fwops->fw_acct_out(fwops, PF_INET,
 						   (struct net_device *)out,
-						   (*pskb)->nh.raw, &redirpt,
+						   &redirpt,
 						   pskb);
 
 			/* ip_conntrack_confirm return NF_DROP or NF_ACCEPT */
@@ -167,7 +129,7 @@
 			/* Handle ICMP errors from client here */
 			if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP
 			    && (*pskb)->nfct)
-				check_for_masq_error(*pskb);
+				check_for_masq_error(pskb);
 		}
 		return NF_ACCEPT;
 
@@ -193,10 +155,6 @@
 			       const struct net_device *out,
 			       int (*okfn)(struct sk_buff *))
 {
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	return ip_conntrack_confirm(*pskb);
 }
 
diff -Nru a/net/ipv4/netfilter/ip_fw_compat.h b/net/ipv4/netfilter/ip_fw_compat.h
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv4/netfilter/ip_fw_compat.h	Sun May 11 22:11:59 2003
@@ -0,0 +1,28 @@
+#ifndef _LINUX_IP_FW_COMPAT_H
+#define _LINUX_IP_FW_COMPAT_H
+
+/* From ip_fw_compat_redir.c */
+extern unsigned int
+do_redirect(struct sk_buff *skb,
+	    const struct net_device *dev,
+	    u_int16_t redirpt);
+
+extern void
+check_for_redirect(struct sk_buff *skb);
+
+extern void
+check_for_unredirect(struct sk_buff *skb);
+
+/* From ip_fw_compat_masq.c */
+extern unsigned int
+do_masquerade(struct sk_buff **pskb, const struct net_device *dev);
+
+extern void check_for_masq_error(struct sk_buff **pskb);
+
+extern unsigned int
+check_for_demasq(struct sk_buff **pskb);
+
+extern int __init masq_init(void);
+extern void masq_cleanup(void);
+
+#endif /* _LINUX_IP_FW_COMPAT_H */
diff -Nru a/net/ipv4/netfilter/ip_fw_compat_masq.c b/net/ipv4/netfilter/ip_fw_compat_masq.c
--- a/net/ipv4/netfilter/ip_fw_compat_masq.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv4/netfilter/ip_fw_compat_masq.c	Sun May 11 22:12:07 2003
@@ -25,6 +25,7 @@
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_core.h>
 #include <linux/netfilter_ipv4/listhelp.h>
+#include "ip_fw_compat.h"
 
 #if 0
 #define DEBUGP printk
@@ -35,16 +36,15 @@
 unsigned int
 do_masquerade(struct sk_buff **pskb, const struct net_device *dev)
 {
-	struct iphdr *iph = (*pskb)->nh.iph;
 	struct ip_nat_info *info;
 	enum ip_conntrack_info ctinfo;
 	struct ip_conntrack *ct;
 	unsigned int ret;
 
 	/* Sorry, only ICMP, TCP and UDP. */
-	if (iph->protocol != IPPROTO_ICMP
-	    && iph->protocol != IPPROTO_TCP
-	    && iph->protocol != IPPROTO_UDP)
+	if ((*pskb)->nh.iph->protocol != IPPROTO_ICMP
+	    && (*pskb)->nh.iph->protocol != IPPROTO_TCP
+	    && (*pskb)->nh.iph->protocol != IPPROTO_UDP)
 		return NF_DROP;
 
 	/* Feed it to connection tracking; in fact we're in NF_IP_FORWARD,
@@ -68,7 +68,7 @@
 	/* Setup the masquerade, if not already */
 	if (!info->initialized) {
 		u_int32_t newsrc;
-		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->daddr } } };
+		struct flowi fl = { .nl_u = { .ip4_u = { .daddr = (*pskb)->nh.iph->daddr } } };
 		struct rtable *rt;
 		struct ip_nat_multi_range range;
 
@@ -103,19 +103,19 @@
 }
 
 void
-check_for_masq_error(struct sk_buff *skb)
+check_for_masq_error(struct sk_buff **pskb)
 {
 	enum ip_conntrack_info ctinfo;
 	struct ip_conntrack *ct;
 
-	ct = ip_conntrack_get(skb, &ctinfo);
+	ct = ip_conntrack_get(*pskb, &ctinfo);
 	/* Wouldn't be here if not tracked already => masq'ed ICMP
            ping or error related to masq'd connection */
 	IP_NF_ASSERT(ct);
 	if (ctinfo == IP_CT_RELATED) {
-		icmp_reply_translation(skb, ct, NF_IP_PRE_ROUTING,
+		icmp_reply_translation(pskb, ct, NF_IP_PRE_ROUTING,
 				       CTINFO2DIR(ctinfo));
-		icmp_reply_translation(skb, ct, NF_IP_POST_ROUTING,
+		icmp_reply_translation(pskb, ct, NF_IP_POST_ROUTING,
 				       CTINFO2DIR(ctinfo));
 	}
 }
@@ -124,19 +124,18 @@
 check_for_demasq(struct sk_buff **pskb)
 {
 	struct ip_conntrack_tuple tuple;
-	struct iphdr *iph = (*pskb)->nh.iph;
 	struct ip_conntrack_protocol *protocol;
 	struct ip_conntrack_tuple_hash *h;
 	enum ip_conntrack_info ctinfo;
 	struct ip_conntrack *ct;
 	int ret;
 
-	protocol = ip_ct_find_proto(iph->protocol);
+	protocol = ip_ct_find_proto((*pskb)->nh.iph->protocol);
 
 	/* We don't feed packets to conntrack system unless we know
            they're part of an connection already established by an
            explicit masq command. */
-	switch (iph->protocol) {
+	switch ((*pskb)->nh.iph->protocol) {
 	case IPPROTO_ICMP:
 		/* ICMP errors. */
 		ct = icmp_error_track(*pskb, &ctinfo, NF_IP_PRE_ROUTING);
@@ -146,16 +145,10 @@
 			   server here (== DNAT).  Do SNAT icmp manips
 			   in POST_ROUTING handling. */
 			if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
-				/* FIXME: Remove once NAT handled non-linear.
-				 */
-				if (skb_is_nonlinear(*pskb)
-				    && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-					return NF_DROP;
-
-				icmp_reply_translation(*pskb, ct,
+				icmp_reply_translation(pskb, ct,
 						       NF_IP_PRE_ROUTING,
 						       CTINFO2DIR(ctinfo));
-				icmp_reply_translation(*pskb, ct,
+				icmp_reply_translation(pskb, ct,
 						       NF_IP_POST_ROUTING,
 						       CTINFO2DIR(ctinfo));
 			}
@@ -166,7 +159,7 @@
 	case IPPROTO_UDP:
 		IP_NF_ASSERT(((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) == 0);
 
-		if (!get_tuple(iph, *pskb, iph->ihl*4, &tuple, protocol)) {
+		if (!get_tuple((*pskb)->nh.iph, *pskb, (*pskb)->nh.iph->ihl*4, &tuple, protocol)) {
 			if (net_ratelimit())
 				printk("ip_fw_compat_masq: Can't get tuple\n");
 			return NF_ACCEPT;
diff -Nru a/net/ipv4/netfilter/ip_fw_compat_redir.c b/net/ipv4/netfilter/ip_fw_compat_redir.c
--- a/net/ipv4/netfilter/ip_fw_compat_redir.c	Wed Feb 13 16:36:31 2002
+++ b/net/ipv4/netfilter/ip_fw_compat_redir.c	Sun May 11 22:12:07 2003
@@ -28,6 +28,7 @@
 #define ASSERT_WRITE_LOCK(x) MUST_BE_LOCKED(&redir_lock)
 
 #include <linux/netfilter_ipv4/listhelp.h>
+#include "ip_fw_compat.h"
 
 #if 0
 #define DEBUGP printk
diff -Nru a/net/ipv4/netfilter/ip_nat_core.c b/net/ipv4/netfilter/ip_nat_core.c
--- a/net/ipv4/netfilter/ip_nat_core.c	Tue Apr 15 21:55:20 2003
+++ b/net/ipv4/netfilter/ip_nat_core.c	Sat May 17 15:37:25 2003
@@ -13,6 +13,8 @@
 #include <net/icmp.h>
 #include <net/ip.h>
 #include <net/tcp.h>  /* For tcp_prot in getorigdst */
+#include <linux/icmp.h>
+#include <linux/udp.h>
 
 #define ASSERT_READ_LOCK(x) MUST_BE_READ_LOCKED(&ip_nat_lock)
 #define ASSERT_WRITE_LOCK(x) MUST_BE_WRITE_LOCKED(&ip_nat_lock)
@@ -698,14 +700,29 @@
 	list_prepend(&byipsproto[ipsprotohash], &info->byipsproto);
 }
 
-static void
-manip_pkt(u_int16_t proto, struct iphdr *iph, size_t len,
+/* Returns true if succeeded. */
+static int
+manip_pkt(u_int16_t proto,
+	  struct sk_buff **pskb,
+	  unsigned int iphdroff,
 	  const struct ip_conntrack_manip *manip,
-	  enum ip_nat_manip_type maniptype,
-	  __u32 *nfcache)
+	  enum ip_nat_manip_type maniptype)
 {
-	*nfcache |= NFC_ALTERED;
-	find_nat_proto(proto)->manip_pkt(iph, len, manip, maniptype);
+	struct iphdr *iph;
+
+	(*pskb)->nfcache |= NFC_ALTERED;
+	if (!skb_ip_make_writable(pskb, iphdroff+sizeof(iph)))
+		return 0;
+
+	iph = (void *)(*pskb)->data + iphdroff;
+
+	/* Manipulate protcol part. */
+	if (!find_nat_proto(proto)->manip_pkt(pskb,
+					      iphdroff + iph->ihl*4,
+					      manip, maniptype))
+		return 0;
+
+	iph = (void *)(*pskb)->data + iphdroff;
 
 	if (maniptype == IP_NAT_MANIP_SRC) {
 		iph->check = ip_nat_cheat_check(~iph->saddr, manip->ip,
@@ -716,17 +733,7 @@
 						iph->check);
 		iph->daddr = manip->ip;
 	}
-#if 0
-	if (ip_fast_csum((u8 *)iph, iph->ihl) != 0)
-		DEBUGP("IP: checksum on packet bad.\n");
-
-	if (proto == IPPROTO_TCP) {
-		void *th = (u_int32_t *)iph + iph->ihl;
-		if (tcp_v4_check(th, len - 4*iph->ihl, iph->saddr, iph->daddr,
-				 csum_partial((char *)th, len-4*iph->ihl, 0)))
-			DEBUGP("TCP: checksum on packet bad\n");
-	}
-#endif
+	return 1;
 }
 
 static inline int exp_for_packet(struct ip_conntrack_expect *exp,
@@ -754,25 +761,13 @@
 	unsigned int i;
 	struct ip_nat_helper *helper;
 	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
-	int is_tcp = (*pskb)->nh.iph->protocol == IPPROTO_TCP;
+	int proto = (*pskb)->nh.iph->protocol;
 
 	/* Need nat lock to protect against modification, but neither
 	   conntrack (referenced) and helper (deleted with
 	   synchronize_bh()) can vanish. */
 	READ_LOCK(&ip_nat_lock);
 	for (i = 0; i < info->num_manips; i++) {
-		/* raw socket (tcpdump) may have clone of incoming
-                   skb: don't disturb it --RR */
-		if (skb_cloned(*pskb) && !(*pskb)->sk) {
-			struct sk_buff *nskb = skb_copy(*pskb, GFP_ATOMIC);
-			if (!nskb) {
-				READ_UNLOCK(&ip_nat_lock);
-				return NF_DROP;
-			}
-			kfree_skb(*pskb);
-			*pskb = nskb;
-		}
-
 		if (info->manips[i].direction == dir
 		    && info->manips[i].hooknum == hooknum) {
 			DEBUGP("Mangling %p: %s to %u.%u.%u.%u %u\n",
@@ -781,12 +776,12 @@
 			       ? "SRC" : "DST",
 			       NIPQUAD(info->manips[i].manip.ip),
 			       htons(info->manips[i].manip.u.all));
-			manip_pkt((*pskb)->nh.iph->protocol,
-				  (*pskb)->nh.iph,
-				  (*pskb)->len,
-				  &info->manips[i].manip,
-				  info->manips[i].maniptype,
-				  &(*pskb)->nfcache);
+			if (!manip_pkt(proto, pskb, 0,
+				       &info->manips[i].manip,
+				       info->manips[i].maniptype)) {
+				READ_UNLOCK(&ip_nat_lock);
+				return NF_DROP;
+			}
 		}
 	}
 	helper = info->helper;
@@ -839,12 +834,14 @@
 		
 		/* Adjust sequence number only once per packet 
 		 * (helper is called at all hooks) */
-		if (is_tcp && (hooknum == NF_IP_POST_ROUTING
-			       || hooknum == NF_IP_LOCAL_IN)) {
+		if (proto == IPPROTO_TCP
+		    && (hooknum == NF_IP_POST_ROUTING
+			|| hooknum == NF_IP_LOCAL_IN)) {
 			DEBUGP("ip_nat_core: adjusting sequence number\n");
 			/* future: put this in a l4-proto specific function,
 			 * and call this function here. */
-			ip_nat_seq_adjust(*pskb, ct, ctinfo);
+			if (!ip_nat_seq_adjust(pskb, ct, ctinfo))
+				ret = NF_DROP;
 		}
 
 		return ret;
@@ -855,39 +852,54 @@
 	/* not reached */
 }
 
-unsigned int
-icmp_reply_translation(struct sk_buff *skb,
+int
+icmp_reply_translation(struct sk_buff **pskb,
 		       struct ip_conntrack *conntrack,
 		       unsigned int hooknum,
 		       int dir)
 {
-	struct iphdr *iph = skb->nh.iph;
-	struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
-	struct iphdr *inner = (struct iphdr *)(hdr + 1);
-	size_t datalen = skb->len - ((void *)inner - (void *)iph);
+	struct {
+		struct icmphdr icmp;
+		struct iphdr ip;
+	} *inside;
 	unsigned int i;
 	struct ip_nat_info *info = &conntrack->nat.info;
+	int hdrlen;
+
+	if (!skb_ip_make_writable(pskb,(*pskb)->nh.iph->ihl*4+sizeof(*inside)))
+		return 0;
+	inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
+
+	/* We're actually going to mangle it beyond trivial checksum
+	   adjustment, so make sure the current checksum is correct. */
+	if ((*pskb)->ip_summed != CHECKSUM_UNNECESSARY) {
+		hdrlen = (*pskb)->nh.iph->ihl * 4;
+		if ((u16)csum_fold(skb_checksum(*pskb, hdrlen,
+						(*pskb)->len - hdrlen, 0)))
+			return 0;
+	}
 
-	IP_NF_ASSERT(skb->len >= iph->ihl*4 + sizeof(struct icmphdr));
 	/* Must be RELATED */
-	IP_NF_ASSERT(skb->nfct - (struct ip_conntrack *)skb->nfct->master
+	IP_NF_ASSERT((*pskb)->nfct
+		     - (struct ip_conntrack *)(*pskb)->nfct->master
 		     == IP_CT_RELATED
-		     || skb->nfct - (struct ip_conntrack *)skb->nfct->master
+		     || (*pskb)->nfct
+		     - (struct ip_conntrack *)(*pskb)->nfct->master
 		     == IP_CT_RELATED+IP_CT_IS_REPLY);
 
 	/* Redirects on non-null nats must be dropped, else they'll
            start talking to each other without our translation, and be
            confused... --RR */
-	if (hdr->type == ICMP_REDIRECT) {
+	if (inside->icmp.type == ICMP_REDIRECT) {
 		/* Don't care about races here. */
 		if (info->initialized
 		    != ((1 << IP_NAT_MANIP_SRC) | (1 << IP_NAT_MANIP_DST))
 		    || info->num_manips != 0)
-			return NF_DROP;
+			return 0;
 	}
 
 	DEBUGP("icmp_reply_translation: translating error %p hook %u dir %s\n",
-	       skb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
+	       *pskb, hooknum, dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY");
 	/* Note: May not be from a NAT'd host, but probably safest to
 	   do translation always as if it came from the host itself
 	   (even though a "host unreachable" coming from the host
@@ -918,11 +930,13 @@
 			       ? "DST" : "SRC",
 			       NIPQUAD(info->manips[i].manip.ip),
 			       ntohs(info->manips[i].manip.u.udp.port));
-			manip_pkt(inner->protocol, inner,
-				  skb->len - ((void *)inner - (void *)iph),
-				  &info->manips[i].manip,
-				  !info->manips[i].maniptype,
-				  &skb->nfcache);
+			if (!manip_pkt(inside->ip.protocol, pskb,
+				       (*pskb)->nh.iph->ihl*4
+				       + sizeof(inside->icmp),
+				       &info->manips[i].manip,
+				       !info->manips[i].maniptype))
+				goto unlock_fail;
+
 			/* Outer packet needs to have IP header NATed like
 	                   it's a reply. */
 
@@ -932,22 +946,27 @@
 			       info->manips[i].maniptype == IP_NAT_MANIP_SRC
 			       ? "SRC" : "DST",
 			       NIPQUAD(info->manips[i].manip.ip));
-			manip_pkt(0, iph, skb->len,
-				  &info->manips[i].manip,
-				  info->manips[i].maniptype,
-				  &skb->nfcache);
+			if (!manip_pkt(0, pskb, 0,
+				       &info->manips[i].manip,
+				       info->manips[i].maniptype))
+				goto unlock_fail;
 		}
 	}
 	READ_UNLOCK(&ip_nat_lock);
 
-	/* Since we mangled inside ICMP packet, recalculate its
-	   checksum from scratch.  (Hence the handling of incorrect
-	   checksums in conntrack, so we don't accidentally fix one.)  */
-	hdr->checksum = 0;
-	hdr->checksum = ip_compute_csum((unsigned char *)hdr,
-					sizeof(*hdr) + datalen);
+	hdrlen = (*pskb)->nh.iph->ihl * 4;
 
-	return NF_ACCEPT;
+	inside = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
+
+	inside->icmp.checksum = 0;
+	inside->icmp.checksum = csum_fold(skb_checksum(*pskb, hdrlen,
+						       (*pskb)->len - hdrlen,
+						       0));
+	return 1;
+
+ unlock_fail:
+	READ_UNLOCK(&ip_nat_lock);
+	return 0;
 }
 
 int __init ip_nat_init(void)
diff -Nru a/net/ipv4/netfilter/ip_nat_helper.c b/net/ipv4/netfilter/ip_nat_helper.c
--- a/net/ipv4/netfilter/ip_nat_helper.c	Thu Apr  3 04:47:05 2003
+++ b/net/ipv4/netfilter/ip_nat_helper.c	Sat May 17 12:39:13 2003
@@ -46,14 +46,14 @@
 #endif
 
 DECLARE_LOCK(ip_nat_seqofs_lock);
-			 
-static inline int 
-ip_nat_resize_packet(struct sk_buff **skb,
-		     struct ip_conntrack *ct, 
-		     enum ip_conntrack_info ctinfo,
-		     int new_size)
+
+/* Setup TCP sequence correction given this change at this sequence */
+static inline void 
+adjust_tcp_sequence(u32 seq,
+		    int sizediff,
+		    struct ip_conntrack *ct, 
+		    enum ip_conntrack_info ctinfo)
 {
-	struct iphdr *iph;
 	int dir;
 	struct ip_nat_seq *this_way, *other_way;
 
@@ -65,52 +65,89 @@
 	this_way = &ct->nat.info.seq[dir];
 	other_way = &ct->nat.info.seq[!dir];
 
-	if (new_size > (*skb)->len + skb_tailroom(*skb)) {
-		struct sk_buff *newskb;
-		newskb = skb_copy_expand(*skb, skb_headroom(*skb),
-					 new_size - (*skb)->len,
-					 GFP_ATOMIC);
-
-		if (!newskb) {
-			printk("ip_nat_resize_packet: oom\n");
-			return 0;
-		} else {
-			kfree_skb(*skb);
-			*skb = newskb;
-		}
+	DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
+	DUMP_OFFSET(this_way);
+
+	LOCK_BH(&ip_nat_seqofs_lock);
+
+	/* SYN adjust. If it's uninitialized, of this is after last
+	 * correction, record it: we don't handle more than one
+	 * adjustment in the window, but do deal with common case of a
+	 * retransmit */
+	if (this_way->offset_before == this_way->offset_after
+	    || before(this_way->correction_pos, seq)) {
+		    this_way->correction_pos = seq;
+		    this_way->offset_before = this_way->offset_after;
+		    this_way->offset_after += sizediff;
 	}
+	UNLOCK_BH(&ip_nat_seqofs_lock);
 
-	iph = (*skb)->nh.iph;
-	if (iph->protocol == IPPROTO_TCP) {
-		struct tcphdr *tcph = (void *)iph + iph->ihl*4;
-
-		DEBUGP("ip_nat_resize_packet: Seq_offset before: ");
-		DUMP_OFFSET(this_way);
-
-		LOCK_BH(&ip_nat_seqofs_lock);
-
-		/* SYN adjust. If it's uninitialized, of this is after last 
-		 * correction, record it: we don't handle more than one 
-		 * adjustment in the window, but do deal with common case of a 
-		 * retransmit */
-		if (this_way->offset_before == this_way->offset_after
-		    || before(this_way->correction_pos, ntohl(tcph->seq))) {
-			this_way->correction_pos = ntohl(tcph->seq);
-			this_way->offset_before = this_way->offset_after;
-			this_way->offset_after = (int32_t)
-				this_way->offset_before + new_size -
-				(*skb)->len;
-		}
+	DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
+	DUMP_OFFSET(this_way);
+}
+
+/* Frobs data inside this packet, which is linear. */
+static void mangle_contents(struct sk_buff *skb,
+			    unsigned int dataoff,
+			    unsigned int match_offset,
+			    unsigned int match_len,
+			    const char *rep_buffer,
+			    unsigned int rep_len)
+{
+	unsigned char *data;
 
-		UNLOCK_BH(&ip_nat_seqofs_lock);
+	BUG_ON(skb_is_nonlinear(skb));
+	data = (unsigned char *)skb->nh.iph + dataoff;
 
-		DEBUGP("ip_nat_resize_packet: Seq_offset after: ");
-		DUMP_OFFSET(this_way);
+	/* move post-replacement */
+	memmove(data + match_offset + rep_len,
+		data + match_offset + match_len,
+		skb->tail - (data + match_offset + match_len));
+
+	/* insert data from buffer */
+	memcpy(data + match_offset, rep_buffer, rep_len);
+
+	/* update skb info */
+	if (rep_len > match_len) {
+		DEBUGP("ip_nat_mangle_packet: Extending packet by "
+			"%u from %u bytes\n", rep_len - match_len,
+		       skb->len);
+		skb_put(skb, rep_len - match_len);
+	} else {
+		DEBUGP("ip_nat_mangle_packet: Shrinking packet from "
+			"%u from %u bytes\n", match_len - rep_len,
+		       skb->len);
+		__skb_trim(skb, skb->len + rep_len - match_len);
 	}
-	
-	return 1;
+
+	/* fix IP hdr checksum information */
+	skb->nh.iph->tot_len = htons(skb->len);
+	ip_send_check(skb->nh.iph);
+	skb->csum = csum_partial(data, skb->len - dataoff, 0);
 }
 
+/* Unusual, but possible case. */
+static int enlarge_skb(struct sk_buff **pskb, unsigned int extra)
+{
+	struct sk_buff *nskb;
+
+	if ((*pskb)->len + extra > 65535)
+		return 0;
+
+	nskb = skb_copy_expand(*pskb, skb_headroom(*pskb), extra, GFP_ATOMIC);
+	if (!nskb)
+		return 0;
+
+	/* Transfer socket to new skb. */
+	if ((*pskb)->sk)
+		skb_set_owner_w(nskb, (*pskb)->sk);
+#ifdef CONFIG_NETFILTER_DEBUG
+	nskb->nf_debug = (*pskb)->nf_debug;
+#endif
+	kfree_skb(*pskb);
+	*pskb = nskb;
+	return 1;
+}
 
 /* Generic function for mangling variable-length address changes inside
  * NATed TCP connections (like the PORT XXX,XXX,XXX,XXX,XXX,XXX
@@ -121,91 +158,41 @@
  *
  * */
 int 
-ip_nat_mangle_tcp_packet(struct sk_buff **skb,
+ip_nat_mangle_tcp_packet(struct sk_buff **pskb,
 			 struct ip_conntrack *ct,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned int match_offset,
 			 unsigned int match_len,
-			 char *rep_buffer,
+			 const char *rep_buffer,
 			 unsigned int rep_len)
 {
-	struct iphdr *iph = (*skb)->nh.iph;
+	struct iphdr *iph;
 	struct tcphdr *tcph;
-	unsigned char *data;
-	u_int32_t tcplen, newlen, newtcplen;
 
-	tcplen = (*skb)->len - iph->ihl*4;
-	newtcplen = tcplen - match_len + rep_len;
-	newlen = iph->ihl*4 + newtcplen;
-
-	if (newlen > 65535) {
-		if (net_ratelimit())
-			printk("ip_nat_mangle_tcp_packet: nat'ed packet "
-				"exceeds maximum packet size\n");
+	if (!skb_ip_make_writable(pskb, (*pskb)->len))
 		return 0;
-	}
 
-	if ((*skb)->len != newlen) {
-		if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) {
-			printk("resize_packet failed!!\n");
-			return 0;
-		}
-	}
+	if (rep_len > match_len
+	    && rep_len - match_len > skb_tailroom(*pskb)
+	    && !enlarge_skb(pskb, rep_len - match_len))
+		return 0;
 
-	/* Alexey says: if a hook changes _data_ ... it can break
-	   original packet sitting in tcp queue and this is fatal */
-	if (skb_cloned(*skb)) {
-		struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
-		if (!nskb) {
-			if (net_ratelimit())
-				printk("Out of memory cloning TCP packet\n");
-			return 0;
-		}
-		/* Rest of kernel will get very unhappy if we pass it
-		   a suddenly-orphaned skbuff */
-		if ((*skb)->sk)
-			skb_set_owner_w(nskb, (*skb)->sk);
-		kfree_skb(*skb);
-		*skb = nskb;
-	}
+	SKB_LINEAR_ASSERT(*pskb);
 
-	/* skb may be copied !! */
-	iph = (*skb)->nh.iph;
+	iph = (*pskb)->nh.iph;
 	tcph = (void *)iph + iph->ihl*4;
-	data = (void *)tcph + tcph->doff*4;
-
-	if (rep_len != match_len)
-		/* move post-replacement */
-		memmove(data + match_offset + rep_len,
-			data + match_offset + match_len,
-			(*skb)->tail - (data + match_offset + match_len));
-
-	/* insert data from buffer */
-	memcpy(data + match_offset, rep_buffer, rep_len);
-
-	/* update skb info */
-	if (newlen > (*skb)->len) {
-		DEBUGP("ip_nat_mangle_tcp_packet: Extending packet by "
-			"%u to %u bytes\n", newlen - (*skb)->len, newlen);
-		skb_put(*skb, newlen - (*skb)->len);
-	} else {
-		DEBUGP("ip_nat_mangle_tcp_packet: Shrinking packet from "
-			"%u to %u bytes\n", (*skb)->len, newlen);
-		skb_trim(*skb, newlen);
-	}
 
-	/* fix checksum information */
-
-	iph->tot_len = htons(newlen);
-	(*skb)->csum = csum_partial((char *)tcph + tcph->doff*4,
-				    newtcplen - tcph->doff*4, 0);
+	mangle_contents(*pskb, iph->ihl*4 + tcph->doff*4,
+			match_offset, match_len, rep_buffer, rep_len);
 
 	tcph->check = 0;
-	tcph->check = tcp_v4_check(tcph, newtcplen, iph->saddr, iph->daddr,
+	tcph->check = tcp_v4_check(tcph, (*pskb)->len - iph->ihl*4,
+				   iph->saddr, iph->daddr,
 				   csum_partial((char *)tcph, tcph->doff*4,
-					   (*skb)->csum));
-	ip_send_check(iph);
-
+						(*pskb)->csum));
+	adjust_tcp_sequence(ntohl(tcph->seq),
+			    (int)match_len - (int)rep_len,
+			    ct, ctinfo);
 	return 1;
 }
 			
@@ -220,219 +207,164 @@
  *       should be fairly easy to do.
  */
 int 
-ip_nat_mangle_udp_packet(struct sk_buff **skb,
+ip_nat_mangle_udp_packet(struct sk_buff **pskb,
 			 struct ip_conntrack *ct,
 			 enum ip_conntrack_info ctinfo,
 			 unsigned int match_offset,
 			 unsigned int match_len,
-			 char *rep_buffer,
+			 const char *rep_buffer,
 			 unsigned int rep_len)
 {
-	struct iphdr *iph = (*skb)->nh.iph;
-	struct udphdr *udph = (void *)iph + iph->ihl * 4;
-	unsigned char *data;
-	u_int32_t udplen, newlen, newudplen;
+	struct iphdr *iph;
+	struct udphdr *udph;
+	int need_csum = ((*pskb)->csum != 0);
 
-	udplen = (*skb)->len - iph->ihl*4;
-	newudplen = udplen - match_len + rep_len;
-	newlen = iph->ihl*4 + newudplen;
-
-	if (newlen > 65535) {
-		if (net_ratelimit())
-			printk("ip_nat_mangle_udp_packet: nat'ed packet "
-				"exceeds maximum packet size\n");
+	if (!skb_ip_make_writable(pskb, (*pskb)->len))
 		return 0;
-	}
 
-	if ((*skb)->len != newlen) {
-		if (!ip_nat_resize_packet(skb, ct, ctinfo, newlen)) {
-			printk("resize_packet failed!!\n");
-			return 0;
-		}
-	}
-
-	/* Alexey says: if a hook changes _data_ ... it can break
-	   original packet sitting in tcp queue and this is fatal */
-	if (skb_cloned(*skb)) {
-		struct sk_buff *nskb = skb_copy(*skb, GFP_ATOMIC);
-		if (!nskb) {
-			if (net_ratelimit())
-				printk("Out of memory cloning TCP packet\n");
-			return 0;
-		}
-		/* Rest of kernel will get very unhappy if we pass it
-		   a suddenly-orphaned skbuff */
-		if ((*skb)->sk)
-			skb_set_owner_w(nskb, (*skb)->sk);
-		kfree_skb(*skb);
-		*skb = nskb;
-	}
+	if (rep_len > match_len
+	    && rep_len - match_len > skb_tailroom(*pskb)
+	    && !enlarge_skb(pskb, rep_len - match_len))
+		return 0;
 
-	/* skb may be copied !! */
-	iph = (*skb)->nh.iph;
+	iph = (*pskb)->nh.iph;
 	udph = (void *)iph + iph->ihl*4;
-	data = (void *)udph + sizeof(struct udphdr);
+	mangle_contents(*pskb, iph->ihl*4 + sizeof(*udph),
+			match_offset, match_len, rep_buffer, rep_len);
 
-	if (rep_len != match_len)
-		/* move post-replacement */
-		memmove(data + match_offset + rep_len,
-			data + match_offset + match_len,
-			(*skb)->tail - (data + match_offset + match_len));
-
-	/* insert data from buffer */
-	memcpy(data + match_offset, rep_buffer, rep_len);
-
-	/* update skb info */
-	if (newlen > (*skb)->len) {
-		DEBUGP("ip_nat_mangle_udp_packet: Extending packet by "
-			"%u to %u bytes\n", newlen - (*skb)->len, newlen);
-		skb_put(*skb, newlen - (*skb)->len);
-	} else {
-		DEBUGP("ip_nat_mangle_udp_packet: Shrinking packet from "
-			"%u to %u bytes\n", (*skb)->len, newlen);
-		skb_trim(*skb, newlen);
-	}
-
-	/* update the length of the UDP and IP packets to the new values*/
-	udph->len = htons((*skb)->len - iph->ihl*4);
-	iph->tot_len = htons(newlen);
+	/* update the length of the UDP packet */
+	udph->len = htons((*pskb)->len - iph->ihl*4);
 
 	/* fix udp checksum if udp checksum was previously calculated */
-	if ((*skb)->csum != 0) {
-		(*skb)->csum = csum_partial((char *)udph +
-					    sizeof(struct udphdr),
-					    newudplen - sizeof(struct udphdr),
-					    0);
-
+	if (need_csum) {
 		udph->check = 0;
-		udph->check = csum_tcpudp_magic(iph->saddr, iph->daddr,
-						newudplen, IPPROTO_UDP,
-						csum_partial((char *)udph,
+		udph->check
+			= csum_tcpudp_magic(iph->saddr, iph->daddr,
+					    (*pskb)->len - iph->ihl*4,
+					    IPPROTO_UDP,
+					    csum_partial((char *)udph,
 							 sizeof(struct udphdr),
-							(*skb)->csum));
-	}
-
-	ip_send_check(iph);
-
+							 (*pskb)->csum));
+	} else
+		(*pskb)->csum = 0;
 	return 1;
 }
 
 /* Adjust one found SACK option including checksum correction */
 static void
-sack_adjust(struct tcphdr *tcph, 
-	    unsigned char *ptr, 
+sack_adjust(struct sk_buff *skb,
+	    struct tcphdr *tcph, 
+	    unsigned int sackoff,
+	    unsigned int sackend,
 	    struct ip_nat_seq *natseq)
 {
-	struct tcp_sack_block *sp = (struct tcp_sack_block *)(ptr+2);
-	int num_sacks = (ptr[1] - TCPOLEN_SACK_BASE)>>3;
-	int i;
-
-	for (i = 0; i < num_sacks; i++, sp++) {
+	while (sackoff < sackend) {
+		struct tcp_sack_block *sack;
 		u_int32_t new_start_seq, new_end_seq;
 
-		if (after(ntohl(sp->start_seq) - natseq->offset_before,
+		sack = (void *)skb->data + sackoff;
+		if (after(ntohl(sack->start_seq) - natseq->offset_before,
 			  natseq->correction_pos))
-			new_start_seq = ntohl(sp->start_seq) 
+			new_start_seq = ntohl(sack->start_seq) 
 					- natseq->offset_after;
 		else
-			new_start_seq = ntohl(sp->start_seq) 
+			new_start_seq = ntohl(sack->start_seq) 
 					- natseq->offset_before;
 		new_start_seq = htonl(new_start_seq);
 
-		if (after(ntohl(sp->end_seq) - natseq->offset_before,
+		if (after(ntohl(sack->end_seq) - natseq->offset_before,
 			  natseq->correction_pos))
-			new_end_seq = ntohl(sp->end_seq)
+			new_end_seq = ntohl(sack->end_seq)
 				      - natseq->offset_after;
 		else
-			new_end_seq = ntohl(sp->end_seq)
+			new_end_seq = ntohl(sack->end_seq)
 				      - natseq->offset_before;
 		new_end_seq = htonl(new_end_seq);
 
 		DEBUGP("sack_adjust: start_seq: %d->%d, end_seq: %d->%d\n",
-			ntohl(sp->start_seq), new_start_seq,
-			ntohl(sp->end_seq), new_end_seq);
+			ntohl(sack->start_seq), new_start_seq,
+			ntohl(sack->end_seq), new_end_seq);
 
 		tcph->check = 
-			ip_nat_cheat_check(~sp->start_seq, new_start_seq,
-					   ip_nat_cheat_check(~sp->end_seq, 
+			ip_nat_cheat_check(~sack->start_seq, new_start_seq,
+					   ip_nat_cheat_check(~sack->end_seq, 
 						   	      new_end_seq,
 							      tcph->check));
-
-		sp->start_seq = new_start_seq;
-		sp->end_seq = new_end_seq;
+		sack->start_seq = new_start_seq;
+		sack->end_seq = new_end_seq;
+		sackoff += sizeof(*sack);
 	}
 }
-			
 
-/* TCP SACK sequence number adjustment, return 0 if sack found and adjusted */
-static inline int
-ip_nat_sack_adjust(struct sk_buff *skb,
-			struct ip_conntrack *ct,
-			enum ip_conntrack_info ctinfo)
+/* TCP SACK sequence number adjustment */
+static inline unsigned int
+ip_nat_sack_adjust(struct sk_buff **pskb,
+		   struct tcphdr *tcph,
+		   struct ip_conntrack *ct,
+		   enum ip_conntrack_info ctinfo)
 {
-	struct iphdr *iph;
-	struct tcphdr *tcph;
-	unsigned char *ptr;
-	int length, dir, sack_adjusted = 0;
+	unsigned int dir, optoff, optend;
 
-	iph = skb->nh.iph;
-	tcph = (void *)iph + iph->ihl*4;
-	length = (tcph->doff*4)-sizeof(struct tcphdr);
-	ptr = (unsigned char *)(tcph+1);
+	optoff = (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr);
+	optend = (*pskb)->nh.iph->ihl*4 + tcph->doff*4;
+
+	if (!skb_ip_make_writable(pskb, optend))
+		return 0;
 
 	dir = CTINFO2DIR(ctinfo);
 
-	while (length > 0) {
-		int opcode = *ptr++;
-		int opsize;
+	while (optoff < optend) {
+		/* Usually: option, length. */
+		unsigned char *op = (*pskb)->data + optoff;
 
-		switch (opcode) {
+		switch (op[0]) {
 		case TCPOPT_EOL:
-			return !sack_adjusted;
+			return 1;
 		case TCPOPT_NOP:
-			length--;
+			optoff++;
 			continue;
 		default:
-			opsize = *ptr++;
-			if (opsize > length) /* no partial opts */
-				return !sack_adjusted;
-			if (opcode == TCPOPT_SACK) {
-				/* found SACK */
-				if((opsize >= (TCPOLEN_SACK_BASE
-					       +TCPOLEN_SACK_PERBLOCK)) &&
-				   !((opsize - TCPOLEN_SACK_BASE)
-				     % TCPOLEN_SACK_PERBLOCK))
-					sack_adjust(tcph, ptr-2,
-						    &ct->nat.info.seq[!dir]);
-				
-				sack_adjusted = 1;
-			}
-			ptr += opsize-2;
-			length -= opsize;
+			/* no partial options */
+			if (optoff + 1 == optend
+			    || optoff + op[1] > optend
+			    || op[1] < 2)
+				return 0;
+			if (op[0] == TCPOPT_SACK
+			    && op[1] >= 2+TCPOLEN_SACK_PERBLOCK
+			    && ((op[1] - 2) % TCPOLEN_SACK_PERBLOCK) == 0)
+				sack_adjust(*pskb, tcph, optoff+2,
+					    optoff+op[1],
+					    &ct->nat.info.seq[!dir]);
+			optoff += op[1];
 		}
 	}
-	return !sack_adjusted;
+	return 1;
 }
 
-/* TCP sequence number adjustment */
-int 
-ip_nat_seq_adjust(struct sk_buff *skb, 
+/* TCP sequence number adjustment.  Returns true or false.  */
+int
+ip_nat_seq_adjust(struct sk_buff **pskb, 
 		  struct ip_conntrack *ct, 
 		  enum ip_conntrack_info ctinfo)
 {
-	struct iphdr *iph;
 	struct tcphdr *tcph;
 	int dir, newseq, newack;
 	struct ip_nat_seq *this_way, *other_way;	
-	
-	iph = skb->nh.iph;
-	tcph = (void *)iph + iph->ihl*4;
 
 	dir = CTINFO2DIR(ctinfo);
 
 	this_way = &ct->nat.info.seq[dir];
 	other_way = &ct->nat.info.seq[!dir];
-	
+
+	/* No adjustments to make?  Very common case. */
+	if (!this_way->offset_before && !this_way->offset_after
+	    && !other_way->offset_before && !other_way->offset_after)
+		return 1;
+
+	if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(*tcph)))
+		return 0;
+
+	tcph = (void *)(*pskb)->data + (*pskb)->nh.iph->ihl*4;
 	if (after(ntohl(tcph->seq), this_way->correction_pos))
 		newseq = ntohl(tcph->seq) + this_way->offset_after;
 	else
@@ -458,9 +390,7 @@
 	tcph->seq = newseq;
 	tcph->ack_seq = newack;
 
-	ip_nat_sack_adjust(skb, ct, ctinfo);
-
-	return 0;
+	return ip_nat_sack_adjust(pskb, tcph, ct, ctinfo);
 }
 
 static inline int
@@ -496,7 +426,7 @@
 			tmp += 6;
 			sprintf(name, "ip_conntrack%s", tmp);
 #ifdef CONFIG_KMOD
-			if (!request_module(name)
+			if (!request_module("ip_conntrack%s", tmp)
 			    && (ct_helper = ip_ct_find_helper(&me->tuple))) {
 				if (!try_module_get(ct_helper->me))
 					return -EBUSY;
diff -Nru a/net/ipv4/netfilter/ip_nat_proto_icmp.c b/net/ipv4/netfilter/ip_nat_proto_icmp.c
--- a/net/ipv4/netfilter/ip_nat_proto_icmp.c	Tue Feb  5 09:39:58 2002
+++ b/net/ipv4/netfilter/ip_nat_proto_icmp.c	Tue May  6 02:06:09 2003
@@ -6,6 +6,7 @@
 #include <linux/if.h>
 
 #include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 
@@ -42,17 +43,24 @@
 	return 0;
 }
 
-static void
-icmp_manip_pkt(struct iphdr *iph, size_t len,
+static int
+icmp_manip_pkt(struct sk_buff **pskb,
+	       unsigned int hdroff,
 	       const struct ip_conntrack_manip *manip,
 	       enum ip_nat_manip_type maniptype)
 {
-	struct icmphdr *hdr = (struct icmphdr *)((u_int32_t *)iph + iph->ihl);
+	struct icmphdr *hdr;
+
+	if (!skb_ip_make_writable(pskb, hdroff + sizeof(*hdr)))
+		return 0;
+
+	hdr = (void *)(*pskb)->data + hdroff;
 
 	hdr->checksum = ip_nat_cheat_check(hdr->un.echo.id ^ 0xFFFF,
-					   manip->u.icmp.id,
-					   hdr->checksum);
+					    manip->u.icmp.id,
+					    hdr->checksum);
 	hdr->un.echo.id = manip->u.icmp.id;
+	return 1;
 }
 
 static unsigned int
diff -Nru a/net/ipv4/netfilter/ip_nat_proto_tcp.c b/net/ipv4/netfilter/ip_nat_proto_tcp.c
--- a/net/ipv4/netfilter/ip_nat_proto_tcp.c	Tue Mar 26 15:16:27 2002
+++ b/net/ipv4/netfilter/ip_nat_proto_tcp.c	Tue May  6 01:04:01 2003
@@ -7,6 +7,7 @@
 #include <linux/netfilter_ipv4/ip_nat.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
 
 static int
 tcp_in_range(const struct ip_conntrack_tuple *tuple,
@@ -73,36 +74,49 @@
 	return 0;
 }
 
-static void
-tcp_manip_pkt(struct iphdr *iph, size_t len,
+static int
+tcp_manip_pkt(struct sk_buff **pskb,
+	      unsigned int hdroff,
 	      const struct ip_conntrack_manip *manip,
 	      enum ip_nat_manip_type maniptype)
 {
-	struct tcphdr *hdr = (struct tcphdr *)((u_int32_t *)iph + iph->ihl);
+	struct tcphdr *hdr;
 	u_int32_t oldip;
-	u_int16_t *portptr;
+	u_int16_t *portptr, oldport;
+	int hdrsize = 8; /* TCP connection tracking guarantees this much */
+
+	/* this could be a inner header returned in icmp packet; in such
+	   cases we cannot update the checksum field since it is outside of
+	   the 8 bytes of transport layer headers we are guaranteed */
+	if ((*pskb)->len >= hdroff + sizeof(struct tcphdr))
+		hdrsize = sizeof(struct tcphdr);
+
+	if (!skb_ip_make_writable(pskb, hdroff + hdrsize))
+		return 0;
+
+	hdr = (void *)(*pskb)->data + hdroff;
 
 	if (maniptype == IP_NAT_MANIP_SRC) {
 		/* Get rid of src ip and src pt */
-		oldip = iph->saddr;
+		oldip = (*pskb)->nh.iph->saddr;
 		portptr = &hdr->source;
 	} else {
 		/* Get rid of dst ip and dst pt */
-		oldip = iph->daddr;
+		oldip = (*pskb)->nh.iph->daddr;
 		portptr = &hdr->dest;
 	}
 
-	/* this could be a inner header returned in icmp packet; in such
-	   cases we cannot update the checksum field since it is outside of
-	   the 8 bytes of transport layer headers we are guaranteed */
-	if(((void *)&hdr->check + sizeof(hdr->check) - (void *)iph) <= len) {
-		hdr->check = ip_nat_cheat_check(~oldip, manip->ip,
-					ip_nat_cheat_check(*portptr ^ 0xFFFF,
+	oldport = *portptr;
+	*portptr = manip->u.tcp.port;
+
+	if (hdrsize < sizeof(*hdr))
+		return 1;
+
+	hdr->check = ip_nat_cheat_check(~oldip, manip->ip,
+					ip_nat_cheat_check(oldport ^ 0xFFFF,
 							   manip->u.tcp.port,
 							   hdr->check));
-	}
-
-	*portptr = manip->u.tcp.port;
+	return 1;
 }
 
 static unsigned int
diff -Nru a/net/ipv4/netfilter/ip_nat_proto_udp.c b/net/ipv4/netfilter/ip_nat_proto_udp.c
--- a/net/ipv4/netfilter/ip_nat_proto_udp.c	Tue Feb  5 09:39:58 2002
+++ b/net/ipv4/netfilter/ip_nat_proto_udp.c	Tue May  6 02:06:09 2003
@@ -6,6 +6,7 @@
 #include <linux/if.h>
 
 #include <linux/netfilter_ipv4/ip_nat.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
 #include <linux/netfilter_ipv4/ip_nat_rule.h>
 #include <linux/netfilter_ipv4/ip_nat_protocol.h>
 
@@ -72,22 +73,27 @@
 	return 0;
 }
 
-static void
-udp_manip_pkt(struct iphdr *iph, size_t len,
+static int
+udp_manip_pkt(struct sk_buff **pskb,
+	      unsigned int hdroff,
 	      const struct ip_conntrack_manip *manip,
 	      enum ip_nat_manip_type maniptype)
 {
-	struct udphdr *hdr = (struct udphdr *)((u_int32_t *)iph + iph->ihl);
+	struct udphdr *hdr;
 	u_int32_t oldip;
 	u_int16_t *portptr;
 
+	if (!skb_ip_make_writable(pskb, hdroff + sizeof(hdr)))
+		return 0;
+
+	hdr = (void *)(*pskb)->data + hdroff;
 	if (maniptype == IP_NAT_MANIP_SRC) {
 		/* Get rid of src ip and src pt */
-		oldip = iph->saddr;
+		oldip = (*pskb)->nh.iph->saddr;
 		portptr = &hdr->source;
 	} else {
 		/* Get rid of dst ip and dst pt */
-		oldip = iph->daddr;
+		oldip = (*pskb)->nh.iph->daddr;
 		portptr = &hdr->dest;
 	}
 	if (hdr->check) /* 0 is a special case meaning no checksum */
@@ -96,6 +102,7 @@
 							   manip->u.udp.port,
 							   hdr->check));
 	*portptr = manip->u.udp.port;
+	return 1;
 }
 
 static unsigned int
diff -Nru a/net/ipv4/netfilter/ip_nat_proto_unknown.c b/net/ipv4/netfilter/ip_nat_proto_unknown.c
--- a/net/ipv4/netfilter/ip_nat_proto_unknown.c	Tue Mar 26 15:16:27 2002
+++ b/net/ipv4/netfilter/ip_nat_proto_unknown.c	Tue May  6 01:04:01 2003
@@ -29,12 +29,13 @@
 	return 0;
 }
 
-static void
-unknown_manip_pkt(struct iphdr *iph, size_t len,
+static int
+unknown_manip_pkt(struct sk_buff **pskb,
+		  unsigned int hdroff,
 		  const struct ip_conntrack_manip *manip,
 		  enum ip_nat_manip_type maniptype)
 {
-	return;
+	return 1;
 }
 
 static unsigned int
diff -Nru a/net/ipv4/netfilter/ip_nat_standalone.c b/net/ipv4/netfilter/ip_nat_standalone.c
--- a/net/ipv4/netfilter/ip_nat_standalone.c	Mon Apr 28 02:27:56 2003
+++ b/net/ipv4/netfilter/ip_nat_standalone.c	Sat May 17 22:10:44 2003
@@ -71,10 +71,6 @@
 	/* maniptype == SRC for postrouting. */
 	enum ip_nat_manip_type maniptype = HOOK2MANIP(hooknum);
 
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	/* We never see fragments: conntrack defrags on pre-routing
 	   and local-out, and ip_nat_out protects post-routing. */
 	IP_NF_ASSERT(!((*pskb)->nh.iph->frag_off
@@ -95,12 +91,14 @@
 		/* Exception: ICMP redirect to new connection (not in
                    hash table yet).  We must not let this through, in
                    case we're doing NAT to the same network. */
-		struct iphdr *iph = (*pskb)->nh.iph;
-		struct icmphdr *hdr = (struct icmphdr *)
-			((u_int32_t *)iph + iph->ihl);
-		if (iph->protocol == IPPROTO_ICMP
-		    && hdr->type == ICMP_REDIRECT)
-			return NF_DROP;
+		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
+			struct icmphdr hdr;
+
+			if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
+					  &hdr, sizeof(hdr)) == 0
+			    && hdr.type == ICMP_REDIRECT)
+				return NF_DROP;
+		}
 		return NF_ACCEPT;
 	}
 
@@ -108,8 +106,11 @@
 	case IP_CT_RELATED:
 	case IP_CT_RELATED+IP_CT_IS_REPLY:
 		if ((*pskb)->nh.iph->protocol == IPPROTO_ICMP) {
-			return icmp_reply_translation(*pskb, ct, hooknum,
-						      CTINFO2DIR(ctinfo));
+			if (!icmp_reply_translation(pskb, ct, hooknum,
+						    CTINFO2DIR(ctinfo)))
+				return NF_DROP;
+			else
+				return NF_ACCEPT;
 		}
 		/* Fall thru... (Only ICMPs can be IP_CT_IS_REPLY) */
 	case IP_CT_NEW:
@@ -174,10 +175,6 @@
 	   const struct net_device *out,
 	   int (*okfn)(struct sk_buff *))
 {
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
-
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
 	    || (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
@@ -212,10 +209,6 @@
 {
 	u_int32_t saddr, daddr;
 	unsigned int ret;
-
-	/* FIXME: Push down to extensions --RR */
-	if (skb_is_nonlinear(*pskb) && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-		return NF_DROP;
 
 	/* root is playing with raw sockets. */
 	if ((*pskb)->len < sizeof(struct iphdr)
diff -Nru a/net/ipv4/netfilter/ip_nat_tftp.c b/net/ipv4/netfilter/ip_nat_tftp.c
--- a/net/ipv4/netfilter/ip_nat_tftp.c	Tue Apr 15 21:55:20 2003
+++ b/net/ipv4/netfilter/ip_nat_tftp.c	Tue May  6 01:04:01 2003
@@ -57,9 +57,7 @@
 	      struct sk_buff **pskb)
 {
 	int dir = CTINFO2DIR(ctinfo);
-	struct iphdr *iph = (*pskb)->nh.iph;
-	struct udphdr *udph = (void *)iph + iph->ihl * 4;
-	struct tftphdr *tftph = (void *)udph + 8;
+	struct tftphdr tftph;
 	struct ip_conntrack_tuple repl;
 
 	if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL)
@@ -71,7 +69,11 @@
 		return NF_ACCEPT;
 	}
 
-	switch (ntohs(tftph->opcode)) {
+	if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4+sizeof(struct udphdr),
+			  &tftph, sizeof(tftph)) != 0)
+		return NF_DROP;
+
+	switch (ntohs(tftph.opcode)) {
 	/* RRQ and WRQ works the same way */
 	case TFTP_OPCODE_READ:
 	case TFTP_OPCODE_WRITE:
@@ -104,8 +106,10 @@
 #if 0
 	const struct ip_conntrack_tuple *repl =
 			&master->tuplehash[IP_CT_DIR_REPLY].tuple;
-	struct iphdr *iph = (*pskb)->nh.iph;
-	struct udphdr *udph = (void *)iph + iph->ihl*4;
+	struct udphdr udph;
+
+	if (skb_copy_bits(*pskb,(*pskb)->nh.iph->ihl*4,&udph,sizeof(udph))!=0)
+		return NF_DROP;
 #endif
 
 	IP_NF_ASSERT(info);
@@ -119,8 +123,8 @@
 		mr.range[0].min_ip = mr.range[0].max_ip = orig->dst.ip; 
 		DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
 			"newsrc: %u.%u.%u.%u\n",
-                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
-			NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
+                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph.source),
+ 			NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph.dest),
 			NIPQUAD(orig->dst.ip));
 	} else {
 		mr.range[0].min_ip = mr.range[0].max_ip = orig->src.ip;
@@ -130,8 +134,8 @@
 
 		DEBUGP("orig: %u.%u.%u.%u:%u <-> %u.%u.%u.%u:%u "
 			"newdst: %u.%u.%u.%u:%u\n",
-                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph->source),
-                        NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph->dest),
+                        NIPQUAD((*pskb)->nh.iph->saddr), ntohs(udph.source),
+                        NIPQUAD((*pskb)->nh.iph->daddr), ntohs(udph.dest),
                         NIPQUAD(orig->src.ip), ntohs(orig->src.u.udp.port));
 	}
 
diff -Nru a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
--- a/net/ipv4/netfilter/ip_tables.c	Wed Apr  9 22:08:17 2003
+++ b/net/ipv4/netfilter/ip_tables.c	Sat May 17 12:39:13 2003
@@ -454,11 +454,8 @@
 
 	ret = find_inlist_lock_noload(head, name, error, mutex);
 	if (!ret) {
-		char modulename[IPT_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
-		strcpy(modulename, prefix);
-		strcat(modulename, name);
-		duprintf("find_inlist: loading `%s'.\n", modulename);
-		request_module(modulename);
+		duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
+		request_module("%s%s", prefix, name);
 		ret = find_inlist_lock_noload(head, name, error, mutex);
 	}
 
diff -Nru a/net/ipv4/netfilter/ipchains_core.c b/net/ipv4/netfilter/ipchains_core.c
--- a/net/ipv4/netfilter/ipchains_core.c	Mon Mar  3 01:06:54 2003
+++ b/net/ipv4/netfilter/ipchains_core.c	Tue May 13 13:25:32 2003
@@ -94,6 +94,7 @@
 #include <linux/netfilter.h>
 #include <linux/netfilter_ipv4/compat_firewall.h>
 #include <linux/netfilter_ipv4/ipchains_core.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
 
 #include <net/checksum.h>
 #include <linux/proc_fs.h>
@@ -280,11 +281,13 @@
 /* Returns whether matches rule or not. */
 static int ip_rule_match(struct ip_fwkernel *f,
 			 const char *ifname,
-			 struct iphdr *ip,
+			 struct sk_buff **pskb,
 			 char tcpsyn,
 			 __u16 src_port, __u16 dst_port,
 			 char isfrag)
 {
+	struct iphdr *ip = (*pskb)->nh.iph;
+
 #define FWINV(bool,invflg) ((bool) ^ !!(f->ipfw.fw_invflg & invflg))
 	/*
 	 *	This is a bit simpler as we don't have to walk
@@ -401,7 +404,7 @@
  * VERY ugly piece of code which actually
  * makes kernel printf for matching packets...
  */
-static void dump_packet(const struct iphdr *ip,
+static void dump_packet(struct sk_buff **pskb,
 			const char *ifname,
 			struct ip_fwkernel *f,
 			const ip_chainlabel chainlabel,
@@ -410,7 +413,7 @@
 			unsigned int count,
 			int syn)
 {
-	__u32 *opt = (__u32 *) (ip + 1);
+	__u32 *opt = (__u32 *) ((*pskb)->nh.iph + 1);
 	int opti;
 
 	if (f) {
@@ -422,13 +425,18 @@
 
 	printk("%s PROTO=%d %u.%u.%u.%u:%hu %u.%u.%u.%u:%hu"
 	       " L=%hu S=0x%2.2hX I=%hu F=0x%4.4hX T=%hu",
-	       ifname, ip->protocol, NIPQUAD(ip->saddr),
-	       src_port, NIPQUAD(ip->daddr),
+	       ifname, (*pskb)->nh.iph->protocol,
+	       NIPQUAD((*pskb)->nh.iph->saddr),
+	       src_port,
+	       NIPQUAD((*pskb)->nh.iph->daddr),
 	       dst_port,
-	       ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
-	       ntohs(ip->frag_off), ip->ttl);
+	       ntohs((*pskb)->nh.iph->tot_len),
+	       (*pskb)->nh.iph->tos,
+	       ntohs((*pskb)->nh.iph->id),
+	       ntohs((*pskb)->nh.iph->frag_off),
+	       (*pskb)->nh.iph->ttl);
 
-	for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
+	for (opti = 0; opti < ((*pskb)->nh.iph->ihl - sizeof(struct iphdr) / 4); opti++)
 		printk(" O=0x%8.8X", *opt++);
 	printk(" %s(#%d)\n", syn ? "SYN " : /* "PENANCE" */ "", count);
 }
@@ -509,34 +517,35 @@
 
 static inline int
 ip_fw_domatch(struct ip_fwkernel *f,
-	      struct iphdr *ip,
 	      const char *rif,
 	      const ip_chainlabel label,
-	      struct sk_buff *skb,
+	      struct sk_buff **pskb,
 	      unsigned int slot,
 	      __u16 src_port, __u16 dst_port,
 	      unsigned int count,
-	      int tcpsyn)
+	      int tcpsyn,
+	      unsigned char *tos)
 {
-	f->counters[slot].bcnt+=ntohs(ip->tot_len);
+	f->counters[slot].bcnt+=ntohs((*pskb)->nh.iph->tot_len);
 	f->counters[slot].pcnt++;
 	if (f->ipfw.fw_flg & IP_FW_F_PRN) {
-		dump_packet(ip,rif,f,label,src_port,dst_port,count,tcpsyn);
+		dump_packet(pskb,rif,f,label,src_port,dst_port,count,tcpsyn);
 	}
-	ip->tos = (ip->tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor;
+
+	*tos = (*tos & f->ipfw.fw_tosand) ^ f->ipfw.fw_tosxor;
 
 /* This functionality is useless in stock 2.0.x series, but we don't
  * discard the mark thing altogether, to avoid breaking ipchains (and,
  * more importantly, the ipfwadm wrapper) --PR */
 	if (f->ipfw.fw_flg & IP_FW_F_MARKABS) {
-		skb->nfmark = f->ipfw.fw_mark;
+		(*pskb)->nfmark = f->ipfw.fw_mark;
 	} else {
-		skb->nfmark += f->ipfw.fw_mark;
+		(*pskb)->nfmark += f->ipfw.fw_mark;
 	}
 	if (f->ipfw.fw_flg & IP_FW_F_NETLINK) {
 #if defined(CONFIG_NETLINK_DEV) || defined(CONFIG_NETLINK_DEV_MODULE)
-		size_t len = min_t(unsigned int, f->ipfw.fw_outputsize, ntohs(ip->tot_len))
-			+ sizeof(__u32) + sizeof(skb->nfmark) + IFNAMSIZ;
+		size_t len = min_t(unsigned int, f->ipfw.fw_outputsize, ntohs((*pskb)->nh.iph->tot_len))
+			+ sizeof(__u32) + sizeof((*pskb)->nfmark) + IFNAMSIZ;
 		struct sk_buff *outskb=alloc_skb(len, GFP_ATOMIC);
 
 		duprintf("Sending packet out NETLINK (length = %u).\n",
@@ -545,10 +554,13 @@
 			/* Prepend length, mark & interface */
 			skb_put(outskb, len);
 			*((__u32 *)outskb->data) = (__u32)len;
-			*((__u32 *)(outskb->data+sizeof(__u32))) = skb->nfmark;
+			*((__u32 *)(outskb->data+sizeof(__u32))) =
+				(*pskb)->nfmark;
 			strcpy(outskb->data+sizeof(__u32)*2, rif);
-			memcpy(outskb->data+sizeof(__u32)*2+IFNAMSIZ, ip,
-			       len-(sizeof(__u32)*2+IFNAMSIZ));
+			skb_copy_bits(*pskb,
+				((char *)(*pskb)->nh.iph - (char *)(*pskb)->data),
+				outskb->data+sizeof(__u32)*2+IFNAMSIZ,
+				len-(sizeof(__u32)*2+IFNAMSIZ));
 			netlink_broadcast(ipfwsk, outskb, 0, ~0, GFP_ATOMIC);
 		}
 		else {
@@ -571,22 +583,18 @@
  *	user checking mode (counters are not updated, TOS & mark not done).
  */
 static int
-ip_fw_check(struct iphdr *ip,
-	    const char *rif,
+ip_fw_check(const char *rif,
 	    __u16 *redirport,
 	    struct ip_chain *chain,
-	    struct sk_buff *skb,
+	    struct sk_buff **pskb,
 	    unsigned int slot,
 	    int testing)
 {
-	struct tcphdr		*tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
-	struct udphdr		*udp=(struct udphdr *)((__u32 *)ip+ip->ihl);
-	struct icmphdr		*icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl);
 	__u32			src, dst;
 	__u16			src_port = 0xFFFF, dst_port = 0xFFFF;
 	char			tcpsyn=0;
 	__u16			offset;
-	unsigned char		oldtos;
+	unsigned char		tos;
 	struct ip_fwkernel	*f;
 	int			ret = FW_SKIP+2;
 	unsigned int		count;
@@ -598,7 +606,7 @@
 	 * rule is also a fragment-specific rule, non-fragments won't
 	 * match it. */
 
-	offset = ntohs(ip->frag_off) & IP_OFFSET;
+	offset = ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET;
 
 	/*
 	 *	Don't allow a fragment of TCP 8 bytes in. Nobody
@@ -606,10 +614,10 @@
 	 *	in by doing a flag overwrite to pass the direction
 	 *	checks.
 	 */
-	if (offset == 1 && ip->protocol == IPPROTO_TCP)	{
+	if (offset == 1 && (*pskb)->nh.iph->protocol == IPPROTO_TCP) {
 		if (!testing && net_ratelimit()) {
 			printk("Suspect TCP fragment.\n");
-			dump_packet(ip,rif,NULL,NULL,0,0,0,0);
+			dump_packet(pskb,rif,NULL,NULL,0,0,0,0);
 		}
 		return FW_BLOCK;
 	}
@@ -621,7 +629,7 @@
 	 */
 	if (offset == 0) {
 		unsigned int size_req;
-		switch (ip->protocol) {
+		switch ((*pskb)->nh.iph->protocol) {
 		case IPPROTO_TCP:
 			/* Don't care about things past flags word */
 			size_req = 16;
@@ -640,18 +648,19 @@
 		 * used to rewrite port information, and thus should
 		 * be blocked.
 		 */
-		if (ntohs(ip->tot_len) < (ip->ihl<<2)+size_req) {
+		if (ntohs((*pskb)->nh.iph->tot_len) <
+		    ((*pskb)->nh.iph->ihl<<2)+size_req) {
 			if (!testing && net_ratelimit()) {
 				printk("Suspect short first fragment.\n");
-				dump_packet(ip,rif,NULL,NULL,0,0,0,0);
+				dump_packet(pskb,rif,NULL,NULL,0,0,0,0);
 			}
 			return FW_BLOCK;
 		}
 	}
 
-	src = ip->saddr;
-	dst = ip->daddr;
-	oldtos = ip->tos;
+	src = (*pskb)->nh.iph->saddr;
+	dst = (*pskb)->nh.iph->daddr;
+	tos = (*pskb)->nh.iph->tos;
 
 	/*
 	 *	If we got interface from which packet came
@@ -662,47 +671,68 @@
 	 */
 
 	dprintf("Packet ");
-	switch(ip->protocol)
-	{
+	switch ((*pskb)->nh.iph->protocol) {
 		case IPPROTO_TCP:
 			dprintf("TCP ");
 			if (!offset) {
-				src_port=ntohs(tcp->source);
-				dst_port=ntohs(tcp->dest);
+				struct tcphdr tcph;
+
+				if (skb_copy_bits(*pskb,
+						  (*pskb)->nh.iph->ihl * 4,
+						  &tcph, sizeof(tcph)))
+					return FW_BLOCK;
+
+				src_port = ntohs(tcph.source);
+				dst_port = ntohs(tcph.dest);
 
 				/* Connection initilisation can only
 				 * be made when the syn bit is set and
 				 * neither of the ack or reset is
 				 * set. */
-				if(tcp->syn && !(tcp->ack || tcp->rst))
-					tcpsyn=1;
+				if (tcph.syn && !(tcph.ack || tcph.rst))
+					tcpsyn = 1;
 			}
 			break;
 		case IPPROTO_UDP:
 			dprintf("UDP ");
 			if (!offset) {
-				src_port=ntohs(udp->source);
-				dst_port=ntohs(udp->dest);
+				struct udphdr udph;
+
+				if (skb_copy_bits(*pskb,
+						  (*pskb)->nh.iph->ihl * 4,
+						  &udph, sizeof(udph)))
+					return FW_BLOCK;
+
+				src_port = ntohs(udph.source);
+				dst_port = ntohs(udph.dest);
 			}
 			break;
 		case IPPROTO_ICMP:
 			if (!offset) {
-				src_port=(__u16)icmp->type;
-				dst_port=(__u16)icmp->code;
+				struct icmphdr icmph;
+
+				if (skb_copy_bits(*pskb,
+						  (*pskb)->nh.iph->ihl * 4,
+						  &icmph, sizeof(icmph)))
+					return FW_BLOCK;
+
+				src_port = (__u16) icmph.type;
+				dst_port = (__u16) icmph.code;
 			}
 			dprintf("ICMP ");
 			break;
 		default:
-			dprintf("p=%d ",ip->protocol);
+			dprintf("p=%d ", (*pskb)->nh.iph->protocol);
 			break;
 	}
 #ifdef DEBUG_IP_FIREWALL
-	print_ip(ip->saddr);
+	print_ip((*pskb)->nh.iph->saddr);
 
 	if (offset)
 		dprintf(":fragment (%i) ", ((int)offset)<<2);
-	else if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP
-		 || ip->protocol==IPPROTO_ICMP)
+	else if ((*pskb)->nh.iph->protocol == IPPROTO_TCP ||
+		 (*pskb)->nh.iph->protocol == IPPROTO_UDP ||
+		 (*pskb)->nh.iph->protocol == IPPROTO_ICMP)
 		dprintf(":%hu:%hu", src_port, dst_port);
 	dprintf("\n");
 #endif
@@ -715,13 +745,14 @@
 		count = 0;
 		for (; f; f = f->next) {
 			count++;
-			if (ip_rule_match(f,rif,ip,
-					  tcpsyn,src_port,dst_port,offset)) {
+			if (ip_rule_match(f, rif, pskb,
+					  tcpsyn, src_port, dst_port,
+					  offset)) {
 				if (!testing
-				    && !ip_fw_domatch(f, ip, rif, chain->label,
-						      skb, slot,
+				    && !ip_fw_domatch(f, rif, chain->label,
+						      pskb, slot,
 						      src_port, dst_port,
-						      count, tcpsyn)) {
+						      count, tcpsyn, &tos)) {
 					ret = FW_BLOCK;
 					cleanup(chain, 0, slot);
 					goto out;
@@ -780,7 +811,7 @@
 				if (!testing) {
 					chain->reent[slot].counters.pcnt++;
 					chain->reent[slot].counters.bcnt
-						+= ntohs(ip->tot_len);
+						+= ntohs((*pskb)->nh.iph->tot_len);
 				}
 			}
 		}
@@ -790,10 +821,16 @@
 	if (!testing) FWC_READ_UNLOCK(&ip_fw_lock);
 
 	/* Recalculate checksum if not going to reject, and TOS changed. */
-	if (ip->tos != oldtos
+	if ((*pskb)->nh.iph->tos != tos
 	    && ret != FW_REJECT && ret != FW_BLOCK
-	    && !testing)
-		ip_send_check(ip);
+	    && !testing) {
+		if (!skb_ip_make_writable(pskb, offsetof(struct iphdr, tos)+1))
+			ret = FW_BLOCK;
+		else {
+			(*pskb)->nh.iph->tos = tos;
+			ip_send_check((*pskb)->nh.iph);
+		}
+	}
 
 	if (ret == FW_REDIRECT && redirport) {
 		if ((*redirport = htons(f->ipfw.fw_redirpt)) == 0) {
@@ -839,7 +876,9 @@
 			i->branch->refcount--;
 		kfree(i);
 		i = tmp;
-		MOD_DEC_USE_COUNT;
+		/* We will block in cleanup's unregister sockopt if unloaded,
+		   so this is safe. */
+		module_put(THIS_MODULE);
 	}
 	return 0;
 }
@@ -870,6 +909,11 @@
 	struct ip_fwkernel *i;
 
 	FWC_HAVE_LOCK(fwc_wlocks);
+
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	/* Special case if no rules already present */
 	if (chainptr->chain == NULL) {
 
@@ -886,7 +930,6 @@
 	if (rule->branch) rule->branch->refcount++;
 
 append_successful:
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -900,6 +943,11 @@
 	struct ip_fwkernel *f = chainptr->chain;
 
 	FWC_HAVE_LOCK(fwc_wlocks);
+
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	/* special case if the position is number 1 */
 	if (position == 1) {
 		frwl->next = chainptr->chain;
@@ -917,7 +965,6 @@
 	f->next = frwl;
 
 insert_successful:
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -952,7 +999,9 @@
 		kfree(tmp);
 	}
 
-	MOD_DEC_USE_COUNT;
+	/* We will block in cleanup's unregister sockopt if unloaded,
+	   so this is safe. */
+	module_put(THIS_MODULE);
 	return 0;
 }
 
@@ -1059,7 +1108,9 @@
 		else
 			chainptr->chain = ftmp->next;
 		kfree(ftmp);
-		MOD_DEC_USE_COUNT;
+		/* We will block in cleanup's unregister sockopt if unloaded,
+		   so this is safe. */
+		module_put(THIS_MODULE);
 		break;
 	}
 
@@ -1101,7 +1152,9 @@
 	tmp->next = tmp2->next;
 	kfree(tmp2);
 
-	MOD_DEC_USE_COUNT;
+	/* We will block in cleanup's unregister sockopt if unloaded,
+	   so this is safe. */
+	module_put(THIS_MODULE);
 	return 0;
 }
 
@@ -1149,12 +1202,15 @@
 	if (strcmp(tmp->label,label) == 0)
 		return EEXIST;
 
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	tmp->next = ip_init_chain(label, 0, FW_SKIP); /* refcount is
 					      * zero since this is a
 					      * user defined chain *
 					      * and therefore can be
 					      * deleted */
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
@@ -1330,18 +1386,40 @@
 		if ((chain = find_label(new->fwt_label)) == NULL)
 			ret = ENOENT;
 		else {
+			struct sk_buff *tmp_skb;
+			int hdrlen;
+
+			hdrlen = sizeof(struct ip_fwpkt) -
+				sizeof(struct in_addr) -
+				IFNAMSIZ;
+
 			ip = &(new->fwt_packet.fwp_iph);
 
-			if (ip->ihl != sizeof(struct iphdr) / sizeof(int)) {
-			    duprintf("ip_fw_ctl: ip->ihl=%d, want %d\n",
-				     ip->ihl,
-				     sizeof(struct iphdr) / sizeof(int));
-			    ret = EINVAL;
-			}
-			else {
-				ret = ip_fw_check(ip, new->fwt_packet.fwp_vianame,
+			/* Fix this one up by hand, who knows how many
+			 * tools will break if we start to barf on this.
+			 */
+			if (ntohs(ip->tot_len) > hdrlen)
+				ip->tot_len = htons(hdrlen);
+
+			if (ip->ihl != sizeof(struct iphdr) / sizeof(u32)) {
+				duprintf("ip_fw_ctl: ip->ihl=%d, want %d\n",
+					 ip->ihl,
+					 sizeof(struct iphdr) / sizeof(u32));
+				ret = EINVAL;
+			} else if ((tmp_skb = alloc_skb(hdrlen,
+							GFP_ATOMIC)) == NULL) {
+				duprintf("ip_fw_ctl: tmp_skb alloc failure\n");
+				ret = EFAULT;
+			} else {
+				skb_reserve(tmp_skb, hdrlen);
+				skb_push(tmp_skb, hdrlen);
+				memcpy(tmp_skb->data, ip, hdrlen);
+				tmp_skb->nh.raw =
+					(unsigned char *) tmp_skb->data;
+				ret = ip_fw_check(new->fwt_packet.fwp_vianame,
 						  NULL, chain,
-						  NULL, SLOT_NUMBER(), 1);
+						  &tmp_skb, SLOT_NUMBER(), 1);
+				kfree_skb(tmp_skb);
 				switch (ret) {
 				case FW_ACCEPT:
 					ret = 0; break;
@@ -1671,41 +1749,37 @@
  *	Interface to the generic firewall chains.
  */
 int ipfw_input_check(struct firewall_ops *this, int pf,
-		     struct net_device *dev, void *phdr, void *arg,
+		     struct net_device *dev, void *arg,
 		     struct sk_buff **pskb)
 {
-	return ip_fw_check(phdr, dev->name,
-			   arg, IP_FW_INPUT_CHAIN, *pskb, SLOT_NUMBER(), 0);
+	return ip_fw_check(dev->name,
+			   arg, IP_FW_INPUT_CHAIN, pskb, SLOT_NUMBER(), 0);
 }
 
 int ipfw_output_check(struct firewall_ops *this, int pf,
-		      struct net_device *dev, void *phdr, void *arg,
+		      struct net_device *dev, void *arg,
 		      struct sk_buff **pskb)
 {
 	/* Locally generated bogus packets by root. <SIGH>. */
-	if (((struct iphdr *)phdr)->ihl * 4 < sizeof(struct iphdr)
-	    || (*pskb)->len < sizeof(struct iphdr))
+	if ((*pskb)->len < sizeof(struct iphdr) ||
+	    (*pskb)->nh.iph->ihl * 4 < sizeof(struct iphdr))
 		return FW_ACCEPT;
-	return ip_fw_check(phdr, dev->name,
-			   arg, IP_FW_OUTPUT_CHAIN, *pskb, SLOT_NUMBER(), 0);
+	return ip_fw_check(dev->name,
+			   arg, IP_FW_OUTPUT_CHAIN, pskb, SLOT_NUMBER(), 0);
 }
 
 int ipfw_forward_check(struct firewall_ops *this, int pf,
-		       struct net_device *dev, void *phdr, void *arg,
+		       struct net_device *dev, void *arg,
 		       struct sk_buff **pskb)
 {
-	return ip_fw_check(phdr, dev->name,
-			   arg, IP_FW_FORWARD_CHAIN, *pskb, SLOT_NUMBER(), 0);
+	return ip_fw_check(dev->name,
+			   arg, IP_FW_FORWARD_CHAIN, pskb, SLOT_NUMBER(), 0);
 }
 
-struct firewall_ops ipfw_ops=
-{
-	NULL,
-	ipfw_forward_check,
-	ipfw_input_check,
-	ipfw_output_check,
-	NULL,
-	NULL
+struct firewall_ops ipfw_ops = {
+	.fw_forward	=	ipfw_forward_check,
+	.fw_input	=	ipfw_input_check,
+	.fw_output	=	ipfw_output_check,
 };
 
 int ipfw_init_or_cleanup(int init)
diff -Nru a/net/ipv4/netfilter/ipfwadm_core.c b/net/ipv4/netfilter/ipfwadm_core.c
--- a/net/ipv4/netfilter/ipfwadm_core.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv4/netfilter/ipfwadm_core.c	Tue May 13 13:25:32 2003
@@ -126,6 +126,7 @@
 #include <linux/netfilter_ipv4/ipfwadm_core.h>
 #include <linux/netfilter_ipv4/compat_firewall.h>
 #include <linux/netfilter_ipv4/lockhelp.h>
+#include <linux/netfilter_ipv4/ip_nat_core.h>
 
 #include <net/checksum.h>
 #include <linux/proc_fs.h>
@@ -259,18 +260,18 @@
 	}
 }
 
-static void print_packet(struct iphdr *ip,
+static void print_packet(struct sk_buff **pskb,
 			 u16 src_port, u16 dst_port, u16 icmp_type,
 			 char *chain, char *rule, char *devname)
 {
-	__u32 *opt = (__u32 *) (ip + 1);
+	__u32 *opt = (__u32 *) ((*pskb)->nh.iph + 1);
 	int opti;
-	__u16 foff = ntohs(ip->frag_off);
+	__u16 foff = ntohs((*pskb)->nh.iph->frag_off);
+	int protocol = (*pskb)->nh.iph->protocol;
 
 	printk(KERN_INFO "IP %s %s%s", chain, rule, devname);
 
-	switch(ip->protocol)
-	{
+	switch (protocol) {
 	case IPPROTO_TCP:
 		printk(" TCP ");
 		break;
@@ -281,22 +282,28 @@
 		printk(" ICMP/%d ", icmp_type);
 		break;
 	default:
-		printk(" PROTO=%d ", ip->protocol);
+		printk(" PROTO=%d ", protocol);
 		break;
-	}
-	print_ip(ip->saddr);
-	if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
+	};
+
+	print_ip((*pskb)->nh.iph->saddr);
+	if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP)
 		printk(":%hu", src_port);
 	printk(" ");
-	print_ip(ip->daddr);
-	if(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP)
+	print_ip((*pskb)->nh.iph->daddr);
+	if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP)
 		printk(":%hu", dst_port);
 	printk(" L=%hu S=0x%2.2hX I=%hu FO=0x%4.4hX T=%hu",
-	       ntohs(ip->tot_len), ip->tos, ntohs(ip->id),
-	       foff & IP_OFFSET, ip->ttl);
-	if (foff & IP_DF) printk(" DF=1");
-	if (foff & IP_MF) printk(" MF=1");
-	for (opti = 0; opti < (ip->ihl - sizeof(struct iphdr) / 4); opti++)
+	       ntohs((*pskb)->nh.iph->tot_len),
+	       (*pskb)->nh.iph->tos,
+	       ntohs((*pskb)->nh.iph->id),
+	       foff & IP_OFFSET,
+	       (*pskb)->nh.iph->ttl);
+	if (foff & IP_DF)
+		printk(" DF=1");
+	if (foff & IP_MF)
+		printk(" MF=1");
+	for (opti = 0; opti < ((*pskb)->nh.iph->ihl - sizeof(struct iphdr) / 4); opti++)
 		printk(" O=0x%8.8X", *opt++);
 	printk("\n");
 }
@@ -314,13 +321,11 @@
  */
 
 
-int ip_fw_chk(struct iphdr *ip, struct net_device *rif, __u16 *redirport,
+int ip_fw_chk(struct sk_buff **pskb,
+	      struct net_device *rif, __u16 *redirport,
 	      struct ip_fw *chain, int policy, int mode)
 {
 	struct ip_fw *f;
-	struct tcphdr		*tcp=(struct tcphdr *)((__u32 *)ip+ip->ihl);
-	struct udphdr		*udp=(struct udphdr *)((__u32 *)ip+ip->ihl);
-	struct icmphdr		*icmp=(struct icmphdr *)((__u32 *)ip+ip->ihl);
 	__u32			src, dst;
 	__u16			src_port=0xFFFF, dst_port=0xFFFF, icmp_type=0xFF;
 	unsigned short		f_prt=0, prt;
@@ -328,6 +333,7 @@
 	unsigned short		offset;
 	int			answer;
 	unsigned char		tosand, tosxor;
+	int			protocol;
 
 	/*
 	 *	If the chain is empty follow policy. The BSD one
@@ -335,9 +341,6 @@
 	 *	flushing and rebuilding the tables.
 	 */
 
-	src = ip->saddr;
-	dst = ip->daddr;
-
 	/*
 	 *	This way we handle fragmented packets.
 	 *	we ignore all fragments but the first one
@@ -352,7 +355,8 @@
 	 *	of system.
 	 */
 
-	offset = ntohs(ip->frag_off) & IP_OFFSET;
+	offset = ntohs((*pskb)->nh.iph->frag_off) & IP_OFFSET;
+	protocol = (*pskb)->nh.iph->protocol;
 
 	/*
 	 *	Don't allow a fragment of TCP 8 bytes in. Nobody
@@ -361,19 +365,21 @@
 	 *	checks.
 	 */
 
-	if (offset == 1 && ip->protocol == IPPROTO_TCP)
+	if (offset == 1 && protocol == IPPROTO_TCP)
 		return FW_BLOCK;
 
 	if (offset!=0 && !(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)) &&
-		(ip->protocol == IPPROTO_TCP || ip->protocol == IPPROTO_UDP ||
-			ip->protocol == IPPROTO_ICMP))
+		(protocol == IPPROTO_TCP ||
+		 protocol == IPPROTO_UDP ||
+		 protocol == IPPROTO_ICMP))
 		return FW_ACCEPT;
 
 	/*
 	 *	 Header fragment for TCP is too small to check the bits.
 	 */
 
-	if(ip->protocol==IPPROTO_TCP && (ip->ihl<<2)+16 > ntohs(ip->tot_len))
+	if (protocol == IPPROTO_TCP &&
+	    ((*pskb)->nh.iph->ihl<<2)+16 > ntohs((*pskb)->nh.iph->tot_len))
 		return FW_BLOCK;
 
 	/*
@@ -382,11 +388,13 @@
 	 *	But only too short for a packet with ports...
 	 */
 
-	else if((ntohs(ip->tot_len)<8+(ip->ihl<<2))&&(ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP))
+	else if ((ntohs((*pskb)->nh.iph->tot_len) <
+		  8 + ((*pskb)->nh.iph->ihl << 2)) &&
+		 (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP))
 		return FW_BLOCK;
 
-	src = ip->saddr;
-	dst = ip->daddr;
+	src = (*pskb)->nh.iph->saddr;
+	dst = (*pskb)->nh.iph->daddr;
 
 	/*
 	 *	If we got interface from which packet came
@@ -397,54 +405,76 @@
 	 */
 
 	dprintf1("Packet ");
-	switch(ip->protocol)
-	{
+	switch (protocol) {
 		case IPPROTO_TCP:
 			dprintf1("TCP ");
 			/* ports stay 0xFFFF if it is not the first fragment */
 			if (!offset) {
-				src_port=ntohs(tcp->source);
-				dst_port=ntohs(tcp->dest);
-				if(!tcp->ack && !tcp->rst)
+				struct tcphdr tcph;
+
+				if (skb_copy_bits(*pskb,
+						  (*pskb)->nh.iph->ihl * 4,
+						  &tcph, sizeof(tcph)))
+					return FW_BLOCK;
+
+				src_port = ntohs(tcph.source);
+				dst_port = ntohs(tcph.dest);
+
+				if(!tcph.ack && !tcph.rst)
 					/* We do NOT have ACK, value TRUE */
-					notcpack=1;
-				if(!tcp->syn || !notcpack)
+					notcpack = 1;
+				if(!tcph.syn || !notcpack)
 					/* We do NOT have SYN, value TRUE */
-					notcpsyn=1;
+					notcpsyn = 1;
 			}
-			prt=IP_FW_F_TCP;
+			prt = IP_FW_F_TCP;
 			break;
 		case IPPROTO_UDP:
 			dprintf1("UDP ");
 			/* ports stay 0xFFFF if it is not the first fragment */
 			if (!offset) {
-				src_port=ntohs(udp->source);
-				dst_port=ntohs(udp->dest);
+				struct udphdr udph;
+
+				if (skb_copy_bits(*pskb,
+						  (*pskb)->nh.iph->ihl * 4,
+						  &udph, sizeof(udph)))
+					return FW_BLOCK;
+
+				src_port = ntohs(udph.source);
+				dst_port = ntohs(udph.dest);
 			}
-			prt=IP_FW_F_UDP;
+			prt = IP_FW_F_UDP;
 			break;
 		case IPPROTO_ICMP:
 			/* icmp_type stays 255 if it is not the first fragment */
-			if (!offset)
-				icmp_type=(__u16)(icmp->type);
-			dprintf2("ICMP:%d ",icmp_type);
-			prt=IP_FW_F_ICMP;
+			if (!offset) {
+				struct icmphdr icmph;
+
+				if (skb_copy_bits(*pskb,
+						  (*pskb)->nh.iph->ihl * 4,
+						  &icmph, sizeof(icmph)))
+					return FW_BLOCK;
+
+				icmp_type = (__u16) icmph.type;
+			}
+			dprintf2("ICMP:%d ", icmp_type);
+			prt = IP_FW_F_ICMP;
 			break;
 		default:
-			dprintf2("p=%d ",ip->protocol);
-			prt=IP_FW_F_ALL;
+			dprintf2("p=%d ", protocol);
+			prt = IP_FW_F_ALL;
 			break;
 	}
 #ifdef DEBUG_IP_FIREWALL
-	dprint_ip(ip->saddr);
+	dprint_ip(src);
 
-	if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
+	if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP)
 		/* This will print 65535 when it is not the first fragment! */
 		dprintf2(":%d ", src_port);
-	dprint_ip(ip->daddr);
-	if (ip->protocol==IPPROTO_TCP || ip->protocol==IPPROTO_UDP)
+	dprint_ip(dst);
+	if (protocol == IPPROTO_TCP || protocol == IPPROTO_UDP)
 		/* This will print 65535 when it is not the first fragment! */
-		dprintf2(":%d ",dst_port);
+		dprintf2(":%d ", dst_port);
 	dprintf1("\n");
 #endif
 
@@ -453,8 +483,7 @@
 	else
 		WRITE_LOCK(&ip_fw_lock);
 	
-	for (f=chain;f;f=f->fw_next)
-	{
+	for (f = chain; f; f = f->fw_next) {
 		/*
 		 *	This is a bit simpler as we don't have to walk
 		 *	an interface chain as you do in BSD - same logic
@@ -474,14 +503,14 @@
 		 */
 		match = 0x00;
 
-		if ((src&f->fw_smsk.s_addr)==f->fw_src.s_addr
-		&&  (dst&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
+		if ((src & f->fw_smsk.s_addr) == f->fw_src.s_addr &&
+		    (dst & f->fw_dmsk.s_addr) == f->fw_dst.s_addr)
 			/* normal direction */
 			match |= 0x01;
 
 		if ((f->fw_flg & IP_FW_F_BIDIR) &&
-		    (dst&f->fw_smsk.s_addr)==f->fw_src.s_addr
-		&&  (src&f->fw_dmsk.s_addr)==f->fw_dst.s_addr)
+		    (dst & f->fw_smsk.s_addr) == f->fw_src.s_addr &&
+		    (src & f->fw_dmsk.s_addr) == f->fw_dst.s_addr)
 			/* reverse direction */
 			match |= 0x02;
 
@@ -491,9 +520,8 @@
 		/*
 		 *	Look for a VIA device match
 		 */
-		if(f->fw_viadev)
-		{
-			if(rif!=f->fw_viadev)
+		if (f->fw_viadev) {
+			if (rif != f->fw_viadev)
 				continue;	/* Mismatch */
 		}
 
@@ -560,14 +588,13 @@
 		 	continue;
 
 		f_prt=f->fw_flg&IP_FW_F_KIND;
-		if (f_prt!=IP_FW_F_ALL)
-		{
+		if (f_prt != IP_FW_F_ALL) {
 			/*
 			 *	Specific firewall - packet's protocol
 			 *	must match firewall's.
 			 */
 
-			if(prt!=f_prt)
+			if (prt != f_prt)
 				continue;
 
 			if((prt==IP_FW_F_ICMP &&
@@ -592,14 +619,14 @@
 		{
 			char buf[16];
 
-			print_packet(ip, src_port, dst_port, icmp_type,
+			print_packet(pskb, src_port, dst_port, icmp_type,
 				     chain_name(chain, mode),
 				     rule_name(f, mode, buf),
 				     rif ? rif->name : "-");
 		}
 #endif
 		if (mode != IP_FW_MODE_CHK) {
-			f->fw_bcnt+=ntohs(ip->tot_len);
+			f->fw_bcnt += ntohs((*pskb)->nh.iph->tot_len);
 			f->fw_pcnt++;
 		}
 		if (!(mode & (IP_FW_MODE_ACCT_IN|IP_FW_MODE_ACCT_OUT)))
@@ -614,23 +641,30 @@
 		 * of firewall.
 		 */
 
-		if (f!=NULL) {
-			policy=f->fw_flg;
-			tosand=f->fw_tosand;
-			tosxor=f->fw_tosxor;
+		if (f != NULL) {
+			policy = f->fw_flg;
+			tosand = f->fw_tosand;
+			tosxor = f->fw_tosxor;
 		} else {
-			tosand=0xFF;
-			tosxor=0x00;
+			tosand = 0xFF;
+			tosxor = 0x00;
 		}
 
-		if (policy&IP_FW_F_ACCEPT) {
+		if (policy & IP_FW_F_ACCEPT) {
 			/* Adjust priority and recompute checksum */
-			__u8 old_tos = ip->tos;
-			ip->tos = (old_tos & tosand) ^ tosxor;
-			if (ip->tos != old_tos)
-		 		ip_send_check(ip);
+			__u8 tos = (*pskb)->nh.iph->tos;
+
+			if (((tos & tosand) ^ tosxor) != tos) {
+				if (!skb_ip_make_writable(pskb,
+					  offsetof(struct iphdr, tos)+1))
+					goto drop_it;
+
+				(*pskb)->nh.iph->tos = (tos & tosand) ^ tosxor;
+		 		ip_send_check((*pskb)->nh.iph);
+			}
+
 #ifdef CONFIG_IP_TRANSPARENT_PROXY
-			if (policy&IP_FW_F_REDIR) {
+			if (policy & IP_FW_F_REDIR) {
 				if (redirport)
 					if ((*redirport = htons(f->fw_pts[f->fw_nsp+f->fw_ndp])) == 0) {
 						/* Wildcard redirection.
@@ -643,30 +677,36 @@
 			} else
 #endif
 #ifdef CONFIG_IP_MASQUERADE
-			if (policy&IP_FW_F_MASQ)
+			if (policy & IP_FW_F_MASQ)
 				answer = FW_MASQUERADE;
 			else
 #endif
 				answer = FW_ACCEPT;
 
-		} else if(policy&IP_FW_F_ICMPRPL)
+		} else if (policy & IP_FW_F_ICMPRPL)
 			answer = FW_REJECT;
-		else
+		else {
+		drop_it:
 			answer = FW_BLOCK;
+		}
 
 #ifdef CONFIG_IP_FIREWALL_NETLINK
-		if((policy&IP_FW_F_PRN) && (answer == FW_REJECT || answer == FW_BLOCK))
+		if ((policy & IP_FW_F_PRN) && (answer == FW_REJECT || answer == FW_BLOCK))
 		{
-			struct sk_buff *skb=alloc_skb(128, (mode == IP_FW_MODE_CHK) ?
-							GFP_KERNEL : GFP_ATOMIC);
-			if(skb)
-			{
+			struct sk_buff *skb = alloc_skb(128,
+					(mode == IP_FW_MODE_CHK) ?
+					GFP_KERNEL : GFP_ATOMIC);
+			if (skb) {
 				int len = min_t(unsigned int,
-					      128, ntohs(ip->tot_len));
+					128,
+					ntohs((*pskb)->nh.iph->tot_len));
 
-				skb_put(skb,len);
-				memcpy(skb->data,ip,len);
-				if(netlink_post(NETLINK_FIREWALL, skb))
+				skb_put(skb, len);
+				skb_copy_bits(*pskb,
+					((char *)(*pskb)->nh.iph -
+					 (char *)(*pskb)->data),
+					skb->data, len);
+				if (netlink_post(NETLINK_FIREWALL, skb))
 					kfree_skb(skb);
 			}
 		}
@@ -706,8 +746,13 @@
 		struct ip_fw *ftmp;
 		ftmp = *chainptr;
 		*chainptr = ftmp->fw_next;
+		if (ftmp->fw_viadev
+		    && ftmp->fw_viadev != (struct net_device *)-1)
+			dev_put(ftmp->fw_viadev);
 		kfree(ftmp);
-		MOD_DEC_USE_COUNT;
+		/* We will block in cleanup's unregister sockopt if unloaded,
+		   so this is safe. */
+		module_put(THIS_MODULE);
 	}
 	WRITE_UNLOCK(&ip_fw_lock);
 }
@@ -718,6 +763,10 @@
 {
 	struct ip_fw *ftmp;
 
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL );
 	if ( ftmp == NULL )
 	{
@@ -748,7 +797,6 @@
 	ftmp->fw_next = *chainptr;
        	*chainptr=ftmp;
 	WRITE_UNLOCK(&ip_fw_lock);
-	MOD_INC_USE_COUNT;
 	return(0);
 }
 
@@ -758,6 +806,10 @@
 	struct ip_fw *chtmp=NULL;
 	struct ip_fw *volatile chtmp_prev=NULL;
 
+	/* Are we unloading now?  We will block on nf_unregister_sockopt */
+	if (!try_module_get(THIS_MODULE))
+		return ENOPROTOOPT;
+
 	ftmp = kmalloc( sizeof(struct ip_fw), GFP_KERNEL );
 	if ( ftmp == NULL )
 	{
@@ -796,7 +848,6 @@
 	else
         	*chainptr=ftmp;
 	WRITE_UNLOCK(&ip_fw_lock);
-	MOD_INC_USE_COUNT;
 	return(0);
 }
 
@@ -848,6 +899,9 @@
 		if(matches)
 		{
 			was_found=1;
+			if (ftmp->fw_viadev
+			    && ftmp->fw_viadev != (struct net_device *)-1)
+				dev_put(ftmp->fw_viadev);
 			if (ltmp)
 			{
 				ltmp->fw_next=ftmp->fw_next;
@@ -869,7 +923,9 @@
 	}
 	WRITE_UNLOCK(&ip_fw_lock);
 	if (was_found) {
-		MOD_DEC_USE_COUNT;
+		/* We will block in cleanup's unregister sockopt if unloaded,
+		   so this is safe. */
+		module_put(THIS_MODULE);
 		return 0;
 	} else
 		return(EINVAL);
@@ -1025,9 +1081,15 @@
 
 	if ( cmd == IP_FW_CHECK )
 	{
+		struct sk_buff *tmp_skb;
 		struct net_device *viadev;
 		struct ip_fwpkt *ipfwp;
 		struct iphdr *ip;
+		int hdrlen, ret;
+
+		hdrlen = sizeof(struct ip_fwpkt) -
+			sizeof(struct in_addr) -
+			IFNAMSIZ;
 
 		if ( len != sizeof(struct ip_fwpkt) )
 		{
@@ -1051,12 +1113,34 @@
 			printk("ip_fw_ctl: ip->ihl=%d, want %d\n",ip->ihl,
 					sizeof(struct iphdr)/sizeof(int));
 #endif
+			dev_put(viadev);
 			return(EINVAL);
 		}
 
-		switch (ip_fw_chk(ip, viadev, NULL, *chains[fwtype],
-				*policies[fwtype], IP_FW_MODE_CHK))
-		{
+		/* Fix this one up by hand, who knows how many
+		 * tools will break if we start to barf on this.
+		 */
+		if (ntohs(ip->tot_len) > hdrlen)
+			ip->tot_len = htons(hdrlen);
+
+		if ((tmp_skb = alloc_skb(hdrlen, GFP_ATOMIC)) == NULL) {
+#ifdef DEBUG_IP_FIREWALL
+			printk("ip_fw_ctl: tmp_skb alloc failure\n");
+#endif
+			dev_put(viadev);
+			return(EFAULT);
+		}
+		skb_reserve(tmp_skb, hdrlen);
+		skb_push(tmp_skb, hdrlen);
+		memcpy(tmp_skb->data, ip, hdrlen);
+
+		ret = ip_fw_chk(&tmp_skb, viadev, NULL, *chains[fwtype],
+				*policies[fwtype], IP_FW_MODE_CHK);
+
+		kfree_skb(tmp_skb);
+		dev_put(viadev);
+
+		switch (ret) {
 			case FW_ACCEPT:
 				return(0);
 	    		case FW_REDIRECT:
@@ -1232,55 +1316,50 @@
  */
 
 int ipfw_input_check(struct firewall_ops *this, int pf,
-		     struct net_device *dev, void *phdr, void *arg,
+		     struct net_device *dev, void *arg,
 		     struct sk_buff **pskb)
 {
-	return ip_fw_chk(phdr, dev, arg, ip_fw_in_chain, ip_fw_in_policy,
+	return ip_fw_chk(pskb, dev, arg, ip_fw_in_chain, ip_fw_in_policy,
 			 IP_FW_MODE_FW);
 }
 
 int ipfw_output_check(struct firewall_ops *this, int pf,
-		      struct net_device *dev, void *phdr, void *arg,
+		      struct net_device *dev, void *arg,
 		      struct sk_buff **pskb)
 {
-	return ip_fw_chk(phdr, dev, arg, ip_fw_out_chain, ip_fw_out_policy,
+	return ip_fw_chk(pskb, dev, arg, ip_fw_out_chain, ip_fw_out_policy,
 			 IP_FW_MODE_FW);
 }
 
 int ipfw_forward_check(struct firewall_ops *this, int pf,
-		       struct net_device *dev, void *phdr, void *arg,
+		       struct net_device *dev, void *arg,
 		       struct sk_buff **pskb)
 {
-	return ip_fw_chk(phdr, dev, arg, ip_fw_fwd_chain, ip_fw_fwd_policy,
+	return ip_fw_chk(pskb, dev, arg, ip_fw_fwd_chain, ip_fw_fwd_policy,
 			 IP_FW_MODE_FW);
 }
 
 #ifdef CONFIG_IP_ACCT
 int ipfw_acct_in(struct firewall_ops *this, int pf, struct net_device *dev,
-		 void *phdr, void *arg, struct sk_buff **pskb)
+		 void *arg, struct sk_buff **pskb)
 {
-	return ip_fw_chk(phdr,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN);
+	return ip_fw_chk(pskb,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN);
 }
 
 int ipfw_acct_out(struct firewall_ops *this, int pf, struct net_device *dev,
-		  void *phdr, void *arg, struct sk_buff **pskb)
+		  void *arg, struct sk_buff **pskb)
 {
-	return ip_fw_chk(phdr,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT);
+	return ip_fw_chk(pskb,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT);
 }
 #endif
 
-struct firewall_ops ipfw_ops=
-{
-	NULL,
-	ipfw_forward_check,
-	ipfw_input_check,
-	ipfw_output_check,
+struct firewall_ops ipfw_ops = {
+	.fw_forward	=	ipfw_forward_check,
+	.fw_input	=	ipfw_input_check,
+	.fw_output	=	ipfw_output_check,
 #ifdef CONFIG_IP_ACCT
-	ipfw_acct_in,
-	ipfw_acct_out
-#else
-	NULL,
-	NULL
+	.fw_acct_in	=	ipfw_acct_in,
+	.fw_acct_out	=	ipfw_acct_out,
 #endif
 };
 
@@ -1301,23 +1380,29 @@
 		for (chn = 0; chn < IP_FW_CHAINS; chn++)
 			for (fw = *chains[chn]; fw; fw = fw->fw_next)
 				if ((fw->fw_vianame)[0] && !strncmp(devname,
-						fw->fw_vianame, IFNAMSIZ))
+					    fw->fw_vianame, IFNAMSIZ)) {
+					dev_hold(dev);
 					fw->fw_viadev = dev;
+				}
 	} else if (event == NETDEV_DOWN) {
 		for (chn = 0; chn < IP_FW_CHAINS; chn++)
 			for (fw = *chains[chn]; fw; fw = fw->fw_next)
 				/* we could compare just the pointers ... */
 				if ((fw->fw_vianame)[0] && !strncmp(devname,
-						fw->fw_vianame, IFNAMSIZ))
+						    fw->fw_vianame, IFNAMSIZ)){
+					if (fw->fw_viadev
+					    && fw->fw_viadev != (struct net_device *)-1)
+						dev_put(fw->fw_viadev);
 					fw->fw_viadev = (struct net_device*)-1;
+				}
 	}
 
 	WRITE_UNLOCK(&ip_fw_lock);
 	return NOTIFY_DONE;
 }
 
-static struct notifier_block ipfw_dev_notifier={
-	.notifier_call	= ipfw_device_event,
+static struct notifier_block ipfw_dev_notifier = {
+	.notifier_call	=	ipfw_device_event,
 };
 
 #endif
diff -Nru a/net/ipv4/proc.c b/net/ipv4/proc.c
--- a/net/ipv4/proc.c	Mon Apr  7 22:07:27 2003
+++ b/net/ipv4/proc.c	Fri May 16 01:07:43 2003
@@ -80,6 +80,7 @@
 }
 
 static struct file_operations sockstat_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open	 = sockstat_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
@@ -110,7 +111,6 @@
  */
 static int snmp_seq_show(struct seq_file *seq, void *v)
 {
-	extern int sysctl_ip_default_ttl;
 	int i;
 
 	seq_printf(seq, "Ip: Forwarding DefaultTTL InReceives InHdrErrors "
@@ -171,6 +171,7 @@
 }
 
 static struct file_operations snmp_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open	 = snmp_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
@@ -227,6 +228,7 @@
 }
 
 static struct file_operations netstat_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open	 = netstat_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
diff -Nru a/net/ipv4/protocol.c b/net/ipv4/protocol.c
--- a/net/ipv4/protocol.c	Tue Oct  8 16:44:52 2002
+++ b/net/ipv4/protocol.c	Sun May 11 13:53:56 2003
@@ -37,7 +37,6 @@
 #include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/timer.h>
-#include <linux/brlock.h>
 #include <net/ip.h>
 #include <net/protocol.h>
 #include <net/tcp.h>
@@ -49,6 +48,7 @@
 #include <linux/igmp.h>
 
 struct inet_protocol *inet_protos[MAX_INET_PROTOS];
+static spinlock_t inet_proto_lock = SPIN_LOCK_UNLOCKED;
 
 /*
  *	Add a protocol handler to the hash tables
@@ -60,16 +60,14 @@
 
 	hash = protocol & (MAX_INET_PROTOS - 1);
 
-	br_write_lock_bh(BR_NETPROTO_LOCK);
-
+	spin_lock_bh(&inet_proto_lock);
 	if (inet_protos[hash]) {
 		ret = -1;
 	} else {
 		inet_protos[hash] = prot;
 		ret = 0;
 	}
-
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	spin_unlock_bh(&inet_proto_lock);
 
 	return ret;
 }
@@ -84,16 +82,16 @@
 
 	hash = protocol & (MAX_INET_PROTOS - 1);
 
-	br_write_lock_bh(BR_NETPROTO_LOCK);
-
+	spin_lock_bh(&inet_proto_lock);
 	if (inet_protos[hash] == prot) {
 		inet_protos[hash] = NULL;
 		ret = 0;
 	} else {
 		ret = -1;
 	}
+	spin_unlock_bh(&inet_proto_lock);
 
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	synchronize_net();
 
 	return ret;
 }
diff -Nru a/net/ipv4/raw.c b/net/ipv4/raw.c
--- a/net/ipv4/raw.c	Sun Mar 23 02:21:28 2003
+++ b/net/ipv4/raw.c	Sat May 10 11:46:35 2003
@@ -807,6 +807,7 @@
 }
 
 static struct file_operations raw_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open	 = raw_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
diff -Nru a/net/ipv4/route.c b/net/ipv4/route.c
--- a/net/ipv4/route.c	Sun May  4 06:01:10 2003
+++ b/net/ipv4/route.c	Tue May 20 19:39:24 2003
@@ -382,6 +382,7 @@
 }
 
 static struct file_operations rt_cache_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open	 = rt_cache_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
@@ -431,16 +432,17 @@
 		rth->u.dst.expires;
 }
 
-static int rt_may_expire(struct rtable *rth, int tmo1, int tmo2)
+static int rt_may_expire(struct rtable *rth, unsigned long tmo1, unsigned long tmo2)
 {
-	int age;
+	unsigned long age;
 	int ret = 0;
 
 	if (atomic_read(&rth->u.dst.__refcnt))
 		goto out;
 
 	ret = 1;
-	if (rth->u.dst.expires && (long)(rth->u.dst.expires - jiffies) <= 0)
+	if (rth->u.dst.expires &&
+	    time_after_eq(jiffies, rth->u.dst.expires))
 		goto out;
 
 	age = jiffies - rth->u.dst.lastuse;
@@ -462,7 +464,7 @@
 
 	for (t = ip_rt_gc_interval << rt_hash_log; t >= 0;
 	     t -= ip_rt_gc_timeout) {
-		unsigned tmo = ip_rt_gc_timeout;
+		unsigned long tmo = ip_rt_gc_timeout;
 
 		i = (i + 1) & rt_hash_mask;
 		rthp = &rt_hash_table[i].chain;
@@ -471,7 +473,7 @@
 		while ((rth = *rthp) != NULL) {
 			if (rth->u.dst.expires) {
 				/* Entry is expired even if it is in use */
-				if ((long)(now - rth->u.dst.expires) <= 0) {
+				if (time_before_eq(now, rth->u.dst.expires)) {
 					tmo >>= 1;
 					rthp = &rth->u.rt_next;
 					continue;
@@ -489,7 +491,7 @@
 		spin_unlock(&rt_hash_table[i].lock);
 
 		/* Fallback loop breaker. */
-		if ((jiffies - now) > 0)
+		if (time_after(jiffies, now))
 			break;
 	}
 	rover = i;
@@ -591,7 +593,7 @@
 
 static int rt_garbage_collect(void)
 {
-	static unsigned expire = RT_GC_TIMEOUT;
+	static unsigned long expire = RT_GC_TIMEOUT;
 	static unsigned long last_gc;
 	static int rover;
 	static int equilibrium;
@@ -643,7 +645,7 @@
 		int i, k;
 
 		for (i = rt_hash_mask, k = rover; i >= 0; i--) {
-			unsigned tmo = expire;
+			unsigned long tmo = expire;
 
 			k = (k + 1) & rt_hash_mask;
 			rthp = &rt_hash_table[k].chain;
@@ -689,7 +691,7 @@
 
 		if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
 			goto out;
-	} while (!in_softirq() && jiffies - now < 1);
+	} while (!in_softirq() && time_before_eq(jiffies, now));
 
 	if (atomic_read(&ipv4_dst_ops.entries) < ip_rt_max_size)
 		goto out;
@@ -956,12 +958,15 @@
  				INIT_RCU_HEAD(&rt->u.dst.rcu_head);
 				rt->u.dst.__use		= 1;
 				atomic_set(&rt->u.dst.__refcnt, 1);
+				rt->u.dst.child		= NULL;
 				if (rt->u.dst.dev)
 					dev_hold(rt->u.dst.dev);
+				rt->u.dst.obsolete	= 0;
 				rt->u.dst.lastuse	= jiffies;
+				rt->u.dst.path		= &rt->u.dst;
 				rt->u.dst.neighbour	= NULL;
 				rt->u.dst.hh		= NULL;
-				rt->u.dst.obsolete	= 0;
+				rt->u.dst.xfrm		= NULL;
 
 				rt->rt_flags		|= RTCF_REDIRECTED;
 
@@ -1067,7 +1072,7 @@
 	/* No redirected packets during ip_rt_redirect_silence;
 	 * reset the algorithm.
 	 */
-	if (jiffies - rt->u.dst.rate_last > ip_rt_redirect_silence)
+	if (time_after(jiffies, rt->u.dst.rate_last + ip_rt_redirect_silence))
 		rt->u.dst.rate_tokens = 0;
 
 	/* Too many ignored redirects; do not send anything
@@ -1081,8 +1086,9 @@
 	/* Check for load limit; set rate_last to the latest sent
 	 * redirect.
 	 */
-	if (jiffies - rt->u.dst.rate_last >
-	    (ip_rt_redirect_load << rt->u.dst.rate_tokens)) {
+	if (time_after(jiffies,
+		       (rt->u.dst.rate_last +
+			(ip_rt_redirect_load << rt->u.dst.rate_tokens)))) {
 		icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, rt->rt_gateway);
 		rt->u.dst.rate_last = jiffies;
 		++rt->u.dst.rate_tokens;
@@ -1147,7 +1153,7 @@
 {
 	int i;
 	
-	for (i = 0; i < sizeof(mtu_plateau) / sizeof(mtu_plateau[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(mtu_plateau); i++)
 		if (old_mtu > mtu_plateau[i])
 			return mtu_plateau[i];
 	return 68;
@@ -1314,6 +1320,9 @@
 			rt->rt_gateway = FIB_RES_GW(*res);
 		memcpy(rt->u.dst.metrics, fi->fib_metrics,
 		       sizeof(rt->u.dst.metrics));
+		if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0)
+			rt->u.dst.metrics[RTAX_HOPLIMIT-1] =
+				sysctl_ip_default_ttl;
 		if (fi->fib_mtu == 0) {
 			rt->u.dst.metrics[RTAX_MTU-1] = rt->u.dst.dev->mtu;
 			if (rt->u.dst.metrics[RTAX_LOCK-1] & (1 << RTAX_MTU) &&
diff -Nru a/net/ipv4/syncookies.c b/net/ipv4/syncookies.c
--- a/net/ipv4/syncookies.c	Fri May  2 23:42:59 2003
+++ b/net/ipv4/syncookies.c	Tue May 20 19:39:24 2003
@@ -17,6 +17,7 @@
 #include <linux/tcp.h>
 #include <linux/slab.h>
 #include <linux/random.h>
+#include <linux/kernel.h>
 #include <net/tcp.h>
 
 extern int sysctl_tcp_syncookies;
@@ -38,7 +39,7 @@
 	(__u16)-1
 };
 /* The number doesn't include the -1 terminator */
-#define NUM_MSS (sizeof(msstab)/sizeof(msstab[0]) - 1)
+#define NUM_MSS (ARRAY_SIZE(msstab) - 1)
 
 /*
  * Generate a syncookie.  mssp points to the mss, which is returned
diff -Nru a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
--- a/net/ipv4/sysctl_net_ipv4.c	Tue Mar 25 22:47:43 2003
+++ b/net/ipv4/sysctl_net_ipv4.c	Sat May 17 23:02:40 2003
@@ -160,7 +160,8 @@
  		.data		= &sysctl_ip_default_ttl,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= &proc_dointvec
+		.proc_handler	= &ipv4_doint_and_flush,
+		.strategy	= &ipv4_doint_and_flush_strategy,
 	},
         {
 		.ctl_name	= NET_IPV4_AUTOCONFIG,
diff -Nru a/net/ipv4/tcp.c b/net/ipv4/tcp.c
--- a/net/ipv4/tcp.c	Sat May  3 00:42:29 2003
+++ b/net/ipv4/tcp.c	Wed May 14 20:16:59 2003
@@ -2101,7 +2101,7 @@
 
 /* These states need RST on ABORT according to RFC793 */
 
-extern __inline__ int tcp_need_reset(int state)
+static inline int tcp_need_reset(int state)
 {
 	return (1 << state) &
 	       (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_FIN_WAIT1 |
@@ -2140,17 +2140,8 @@
 
 	inet->dport = 0;
 
-	if (!(sk->userlocks & SOCK_BINDADDR_LOCK)) {
-		inet->rcv_saddr = inet->saddr = 0;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-		if (sk->family == PF_INET6) {
-			struct ipv6_pinfo *np = inet6_sk(sk);
-
-			memset(&np->saddr, 0, 16);
-			memset(&np->rcv_saddr, 0, 16);
-		}
-#endif
-	}
+	if (!(sk->userlocks & SOCK_BINDADDR_LOCK))
+		inet_reset_saddr(sk);
 
 	sk->shutdown = 0;
 	__clear_bit(SOCK_DONE, &sk->flags);
diff -Nru a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c
--- a/net/ipv4/tcp_diag.c	Fri Oct  4 17:44:25 2002
+++ b/net/ipv4/tcp_diag.c	Tue May 20 19:34:42 2003
@@ -88,8 +88,10 @@
 		r->tcpdiag_inode = 0;
 #ifdef CONFIG_IPV6
 		if (r->tcpdiag_family == AF_INET6) {
-			memcpy(r->id.tcpdiag_src, &tw->v6_rcv_saddr, 16);
-			memcpy(r->id.tcpdiag_dst, &tw->v6_daddr, 16);
+			ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src,
+				       &tw->v6_rcv_saddr);
+			ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_dst,
+				       &tw->v6_daddr);
 		}
 #endif
 		nlh->nlmsg_len = skb->tail - b;
@@ -105,8 +107,10 @@
 	if (r->tcpdiag_family == AF_INET6) {
 		struct ipv6_pinfo *np = inet6_sk(sk);
 
-		memcpy(r->id.tcpdiag_src, &np->rcv_saddr, 16);
-		memcpy(r->id.tcpdiag_dst, &np->daddr, 16);
+		ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_src,
+			       &np->rcv_saddr);
+		ipv6_addr_copy((struct in6_addr *)r->id.tcpdiag_dst,
+			       &np->daddr);
 	}
 #endif
 
@@ -599,7 +603,7 @@
 }
 
 
-extern __inline__ void tcpdiag_rcv_skb(struct sk_buff *skb)
+static inline void tcpdiag_rcv_skb(struct sk_buff *skb)
 {
 	int err;
 	struct nlmsghdr * nlh;
@@ -609,7 +613,7 @@
 		if (nlh->nlmsg_len < sizeof(*nlh) || skb->len < nlh->nlmsg_len)
 			return;
 		err = tcpdiag_rcv_msg(skb, nlh);
-		if (err) 
+		if (err || nlh->nlmsg_flags & NLM_F_ACK) 
 			netlink_ack(skb, nlh, err);
 	}
 }
diff -Nru a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
--- a/net/ipv4/tcp_ipv4.c	Sat May  3 10:01:19 2003
+++ b/net/ipv4/tcp_ipv4.c	Fri May 16 01:07:42 2003
@@ -74,7 +74,6 @@
 #include <linux/seq_file.h>
 
 extern int sysctl_ip_dynaddr;
-extern int sysctl_ip_default_ttl;
 int sysctl_tcp_tw_reuse;
 int sysctl_tcp_low_latency;
 
@@ -171,7 +170,7 @@
 	spin_unlock(&head->lock);
 }
 
-__inline__ void tcp_inherit_port(struct sock *sk, struct sock *child)
+inline void tcp_inherit_port(struct sock *sk, struct sock *child)
 {
 	local_bh_disable();
 	__tcp_inherit_port(sk, child);
@@ -316,7 +315,7 @@
 	spin_unlock(&head->lock);
 }
 
-__inline__ void tcp_put_port(struct sock *sk)
+inline void tcp_put_port(struct sock *sk)
 {
 	local_bh_disable();
 	__tcp_put_port(sk);
@@ -458,8 +457,8 @@
 }
 
 /* Optimize the common listener case. */
-__inline__ struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum,
-					       int dif)
+inline struct sock *tcp_v4_lookup_listener(u32 daddr, unsigned short hnum,
+					   int dif)
 {
 	struct sock *sk;
 
@@ -529,8 +528,8 @@
 	return sk ? : tcp_v4_lookup_listener(daddr, hnum, dif);
 }
 
-__inline__ struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr,
-				      u16 dport, int dif)
+inline struct sock *tcp_v4_lookup(u32 saddr, u16 sport, u32 daddr,
+				  u16 dport, int dif)
 {
 	struct sock *sk;
 
@@ -633,7 +632,6 @@
 	} else if (tw) {
 		/* Silly. Should hash-dance instead... */
 		tcp_tw_deschedule(tw);
-		tcp_timewait_kill(tw);
 		NET_INC_STATS_BH(TimeWaitRecycled);
 
 		tcp_tw_put(tw);
@@ -737,7 +735,6 @@
 
  		if (tw) {
  			tcp_tw_deschedule(tw);
- 			tcp_timewait_kill(tw);
  			tcp_tw_put(tw);
  		}
 
@@ -1215,7 +1212,6 @@
 				      sizeof(struct tcphdr), IPPROTO_TCP, 0);
 	arg.csumoffset = offsetof(struct tcphdr, check) / 2;
 
-	inet_sk(tcp_socket->sk)->ttl = sysctl_ip_default_ttl;
 	ip_send_reply(tcp_socket->sk, skb, &arg, sizeof rth);
 
 	TCP_INC_STATS_BH(TcpOutSegs);
@@ -1853,7 +1849,6 @@
 							  tcp_v4_iif(skb));
 		if (sk2) {
 			tcp_tw_deschedule((struct tcp_tw_bucket *)sk);
-			tcp_timewait_kill((struct tcp_tw_bucket *)sk);
 			tcp_tw_put((struct tcp_tw_bucket *)sk);
 			sk = sk2;
 			goto process;
@@ -2569,6 +2564,7 @@
 }
 
 static struct file_operations tcp_seq_fops = {
+	.owner		=	THIS_MODULE,
 	.open		=	tcp_seq_open,
 	.read		=	seq_read,
 	.llseek		=	seq_lseek,
@@ -2621,7 +2617,7 @@
 	if (err < 0)
 		panic("Failed to create the TCP control socket.\n");
 	tcp_socket->sk->allocation   = GFP_ATOMIC;
-	inet_sk(tcp_socket->sk)->ttl = MAXTTL;
+	inet_sk(tcp_socket->sk)->uc_ttl = -1;
 
 	/* Unhash it so that IP input processing does not even
 	 * see it, we do not wish this socket to see incoming
diff -Nru a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
--- a/net/ipv4/tcp_minisocks.c	Fri May  2 23:42:59 2003
+++ b/net/ipv4/tcp_minisocks.c	Tue May 13 21:23:49 2003
@@ -54,7 +54,7 @@
 
 
 /* Must be called with locally disabled BHs. */
-void tcp_timewait_kill(struct tcp_tw_bucket *tw)
+static void tcp_timewait_kill(struct tcp_tw_bucket *tw)
 {
 	struct tcp_ehash_bucket *ehead;
 	struct tcp_bind_hashbucket *bhead;
@@ -166,7 +166,6 @@
 		if (!th->fin || TCP_SKB_CB(skb)->end_seq != tw->rcv_nxt+1) {
 kill_with_rst:
 			tcp_tw_deschedule(tw);
-			tcp_timewait_kill(tw);
 			tcp_tw_put(tw);
 			return TCP_TW_RST;
 		}
@@ -223,7 +222,6 @@
 			if (sysctl_tcp_rfc1337 == 0) {
 kill:
 				tcp_tw_deschedule(tw);
-				tcp_timewait_kill(tw);
 				tcp_tw_put(tw);
 				return TCP_TW_SUCCESS;
 			}
@@ -381,10 +379,8 @@
 		if(tw->family == PF_INET6) {
 			struct ipv6_pinfo *np = inet6_sk(sk);
 
-			memcpy(&tw->v6_daddr, &np->daddr,
-			       sizeof(struct in6_addr));
-			memcpy(&tw->v6_rcv_saddr, &np->rcv_saddr,
-			       sizeof(struct in6_addr));
+			ipv6_addr_copy(&tw->v6_daddr, &np->daddr);
+			ipv6_addr_copy(&tw->v6_rcv_saddr, &np->rcv_saddr);
 		}
 #endif
 		/* Linkage updates. */
@@ -444,6 +440,8 @@
 
 	while((tw = tcp_tw_death_row[tcp_tw_death_row_slot]) != NULL) {
 		tcp_tw_death_row[tcp_tw_death_row_slot] = tw->next_death;
+		if (tw->next_death)
+			tw->next_death->pprev_death = tw->pprev_death;
 		tw->pprev_death = NULL;
 		spin_unlock(&tw_death_lock);
 
@@ -484,6 +482,7 @@
 			del_timer(&tcp_tw_timer);
 	}
 	spin_unlock(&tw_death_lock);
+	tcp_timewait_kill(tw);
 }
 
 /* Short-time timewait calendar */
@@ -758,6 +757,7 @@
 			tcp_reset_keepalive_timer(newsk, keepalive_time_when(newtp));
 		newsk->socket = NULL;
 		newsk->sleep = NULL;
+		newsk->owner = NULL;
 
 		newtp->tstamp_ok = req->tstamp_ok;
 		if((newtp->sack_ok = req->sack_ok) != 0) {
diff -Nru a/net/ipv4/udp.c b/net/ipv4/udp.c
--- a/net/ipv4/udp.c	Thu Apr 10 23:35:45 2003
+++ b/net/ipv4/udp.c	Mon May 12 21:18:05 2003
@@ -920,17 +920,9 @@
 	inet->daddr = 0;
 	inet->dport = 0;
 	sk->bound_dev_if = 0;
-	if (!(sk->userlocks&SOCK_BINDADDR_LOCK)) {
-		inet->rcv_saddr = inet->saddr = 0;
-#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
-		if (sk->family == PF_INET6) {
-			struct ipv6_pinfo *np = inet6_sk(sk);
+	if (!(sk->userlocks & SOCK_BINDADDR_LOCK))
+		inet_reset_saddr(sk);
 
-			memset(&np->saddr, 0, 16);
-			memset(&np->rcv_saddr, 0, 16);
-		}
-#endif
-	}
 	if (!(sk->userlocks&SOCK_BINDPORT_LOCK)) {
 		sk->prot->unhash(sk);
 		inet->sport = 0;
@@ -1483,6 +1475,7 @@
 }
 
 static struct file_operations udp_seq_fops = {
+	.owner		= THIS_MODULE,
 	.open           = udp_seq_open,
 	.read           = seq_read,
 	.llseek         = seq_lseek,
diff -Nru a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c
--- a/net/ipv4/xfrm4_state.c	Thu Apr 17 18:56:05 2003
+++ b/net/ipv4/xfrm4_state.c	Mon May 12 21:19:48 2003
@@ -50,7 +50,7 @@
 		    spi == x->id.spi &&
 		    daddr->a4 == x->id.daddr.a4 &&
 		    proto == x->id.proto) {
-			atomic_inc(&x->refcnt);
+			xfrm_state_hold(x);
 			return x;
 		}
 	}
@@ -84,7 +84,7 @@
 		    }
 	}
 	if (x0) {
-		atomic_inc(&x0->refcnt);
+		xfrm_state_hold(x0);
 	} else if (create && (x0 = xfrm_state_alloc()) != NULL) {
 		x0->sel.daddr.a4 = daddr->a4;
 		x0->sel.saddr.a4 = saddr->a4;
@@ -99,9 +99,9 @@
 		x0->props.reqid = reqid;
 		x0->props.family = AF_INET;
 		x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
-		atomic_inc(&x0->refcnt);
+		xfrm_state_hold(x0);
 		mod_timer(&x0->timer, jiffies + XFRM_ACQ_EXPIRES*HZ);
-		atomic_inc(&x0->refcnt);
+		xfrm_state_hold(x0);
 		list_add_tail(&x0->bydst, xfrm4_state_afinfo.state_bydst+h);
 		wake_up(&km_waitq);
 	}
diff -Nru a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c
--- a/net/ipv4/xfrm4_tunnel.c	Thu May  1 03:21:46 2003
+++ b/net/ipv4/xfrm4_tunnel.c	Mon May 12 13:58:03 2003
@@ -163,36 +163,32 @@
 			      skb->nh.iph->saddr,
 			      IPPROTO_IPIP, AF_INET);
 
-	if (x) {
-		spin_lock(&x->lock);
+	if (!x)
+		goto drop;
 
-		if (unlikely(x->km.state != XFRM_STATE_VALID))
-			goto drop_unlock;
-	}
+	spin_lock(&x->lock);
+
+	if (unlikely(x->km.state != XFRM_STATE_VALID))
+		goto drop_unlock;
 
 	err = ipip_xfrm_rcv(x, NULL, skb);
 	if (err)
 		goto drop_unlock;
 
-	if (x) {
-		x->curlft.bytes += skb->len;
-		x->curlft.packets++;
-
-		spin_unlock(&x->lock);
-
-		xfrm_state_put(x);
-	}
-
-	return 0;
+	x->curlft.bytes += skb->len;
+	x->curlft.packets++;
+	spin_unlock(&x->lock);
+	xfrm_state_put(x);
+out:	
+	return err;
 
 drop_unlock:
-	if (x) {
-		spin_unlock(&x->lock);
-		xfrm_state_put(x);
-	}
+	spin_unlock(&x->lock);
+	xfrm_state_put(x);
+drop:
+	err = NET_RX_DROP;
 	kfree_skb(skb);
-out:
-	return 0;
+	goto out;
 }
 
 static void ipip_err(struct sk_buff *skb, u32 info)
diff -Nru a/net/ipv6/Kconfig b/net/ipv6/Kconfig
--- a/net/ipv6/Kconfig	Wed Mar  5 15:45:36 2003
+++ b/net/ipv6/Kconfig	Fri May 16 14:02:36 2003
@@ -33,4 +33,13 @@
 
 	  If unsure, say Y.
 
+config INET6_IPCOMP
+	tristate "IPv6: IPComp transformation"
+	depends on IPV6
+	---help---
+	  Support for IP Paylod Compression (RFC3173), typically needed
+	  for IPsec.
+
+	  If unsure, say Y.
+
 source "net/ipv6/netfilter/Kconfig"
diff -Nru a/net/ipv6/Makefile b/net/ipv6/Makefile
--- a/net/ipv6/Makefile	Sun Mar 23 02:21:29 2003
+++ b/net/ipv6/Makefile	Fri May 16 14:02:36 2003
@@ -13,4 +13,5 @@
 
 obj-$(CONFIG_INET6_AH) += ah6.o
 obj-$(CONFIG_INET6_ESP) += esp6.o
+obj-$(CONFIG_INET6_IPCOMP) += ipcomp6.o
 obj-$(CONFIG_NETFILTER)	+= netfilter/
diff -Nru a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
--- a/net/ipv6/addrconf.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv6/addrconf.c	Mon May 19 23:49:42 2003
@@ -32,6 +32,7 @@
  *						support.
  *	Yuji SEKIYA @USAGI		:	Don't assign a same IPv6
  *						address on a same interface.
+ *	YOSHIFUJI Hideaki @USAGI	:	ARCnet support
  */
 
 #include <linux/config.h>
@@ -44,6 +45,7 @@
 #include <linux/in6.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
+#include <linux/if_arcnet.h>
 #include <linux/route.h>
 #include <linux/inetdevice.h>
 #include <linux/init.h>
@@ -1061,6 +1063,13 @@
 		eui[4] = 0xFE;
 		eui[0] ^= 2;
 		return 0;
+	case ARPHRD_ARCNET:
+		/* XXX: inherit EUI-64 fro mother interface -- yoshfuji */
+		if (dev->addr_len != ARCNET_ALEN)
+			return -1;
+		memset(eui, 0, 7);
+		eui[7] = *(u8*)dev->dev_addr;
+		return 0;
 	}
 	return -1;
 }
@@ -1131,7 +1140,7 @@
 	 *
 	 *  - Reserved subnet anycast (RFC 2526)
 	 *	11111101 11....11 1xxxxxxx
-	 *  - ISATAP (draft-ietf-ngtrans-isatap-01.txt) 4.3
+	 *  - ISATAP (draft-ietf-ngtrans-isatap-13.txt) 5.1
 	 *	00-00-5E-FE-xx-xx-xx-xx
 	 *  - value 0
 	 *  - XXX: already assigned to an address on the device
@@ -1195,7 +1204,7 @@
 	struct in6_rtmsg rtmsg;
 
 	memset(&rtmsg, 0, sizeof(rtmsg));
-	memcpy(&rtmsg.rtmsg_dst, pfx, sizeof(struct in6_addr));
+	ipv6_addr_copy(&rtmsg.rtmsg_dst, pfx);
 	rtmsg.rtmsg_dst_len = plen;
 	rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
 	rtmsg.rtmsg_ifindex = dev->ifindex;
@@ -1210,7 +1219,7 @@
 	if (dev->type == ARPHRD_SIT && (dev->flags&IFF_POINTOPOINT))
 		rtmsg.rtmsg_flags |= RTF_NONEXTHOP;
 
-	ip6_route_add(&rtmsg, NULL);
+	ip6_route_add(&rtmsg, NULL, NULL);
 }
 
 /* Create "default" multicast route to the interface */
@@ -1227,7 +1236,7 @@
 	rtmsg.rtmsg_ifindex = dev->ifindex;
 	rtmsg.rtmsg_flags = RTF_UP|RTF_ADDRCONF;
 	rtmsg.rtmsg_type = RTMSG_NEWROUTE;
-	ip6_route_add(&rtmsg, NULL);
+	ip6_route_add(&rtmsg, NULL, NULL);
 }
 
 static void sit_route_add(struct net_device *dev)
@@ -1244,7 +1253,7 @@
 	rtmsg.rtmsg_flags	= RTF_UP|RTF_NONEXTHOP;
 	rtmsg.rtmsg_ifindex	= dev->ifindex;
 
-	ip6_route_add(&rtmsg, NULL);
+	ip6_route_add(&rtmsg, NULL, NULL);
 }
 
 static void addrconf_add_lroute(struct net_device *dev)
@@ -1336,7 +1345,7 @@
 	if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) {
 		if (rt->rt6i_flags&RTF_EXPIRES) {
 			if (pinfo->onlink == 0 || valid_lft == 0) {
-				ip6_del_rt(rt, NULL);
+				ip6_del_rt(rt, NULL, NULL);
 				rt = NULL;
 			} else {
 				rt->rt6i_expires = rt_expires;
@@ -1732,7 +1741,8 @@
 
 	if ((dev->type != ARPHRD_ETHER) && 
 	    (dev->type != ARPHRD_FDDI) &&
-	    (dev->type != ARPHRD_IEEE802_TR)) {
+	    (dev->type != ARPHRD_IEEE802_TR) &&
+	    (dev->type != ARPHRD_ARCNET)) {
 		/* Alas, we support only Ethernet autoconfiguration. */
 		return;
 	}
@@ -1960,7 +1970,7 @@
 
 		rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;
 
-		ip6_route_add(&rtmsg, NULL);
+		ip6_route_add(&rtmsg, NULL, NULL);
 	}
 
 out:
@@ -2379,22 +2389,14 @@
 	netlink_broadcast(rtnl, skb, 0, RTMGRP_IPV6_IFADDR, GFP_ATOMIC);
 }
 
-static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX-RTM_BASE+1] =
-{
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-	{ NULL,			NULL,			},
-
-	{ inet6_rtm_newaddr,	NULL,			},
-	{ inet6_rtm_deladdr,	NULL,			},
-	{ NULL,			inet6_dump_ifaddr,	},
-	{ NULL,			NULL,			},
-
-	{ inet6_rtm_newroute,	NULL,			},
-	{ inet6_rtm_delroute,	NULL,			},
-	{ inet6_rtm_getroute,	inet6_dump_fib,		},
-	{ NULL,			NULL,			},
+static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX - RTM_BASE + 1] = {
+	[RTM_NEWADDR - RTM_BASE] = { .doit	= inet6_rtm_newaddr, },
+	[RTM_DELADDR - RTM_BASE] = { .doit	= inet6_rtm_deladdr, },
+	[RTM_GETADDR - RTM_BASE] = { .dumpit	= inet6_dump_ifaddr, },
+	[RTM_NEWROUTE - RTM_BASE] = { .doit	= inet6_rtm_newroute, },
+	[RTM_DELROUTE - RTM_BASE] = { .doit	= inet6_rtm_delroute, },
+	[RTM_GETROUTE - RTM_BASE] = { .doit	= inet6_rtm_getroute,
+				      .dumpit	= inet6_dump_fib, },
 };
 
 static void ipv6_ifa_notify(int event, struct inet6_ifaddr *ifp)
@@ -2715,6 +2717,7 @@
 		case ARPHRD_ETHER:
 		case ARPHRD_FDDI:
 		case ARPHRD_IEEE802_TR:	
+		case ARPHRD_ARCNET:
 			addrconf_dev_config(dev);
 			break;
 		default:;
diff -Nru a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
--- a/net/ipv6/af_inet6.c	Fri May  2 23:42:26 2003
+++ b/net/ipv6/af_inet6.c	Fri May 16 01:07:43 2003
@@ -45,7 +45,6 @@
 #include <linux/inet.h>
 #include <linux/netdevice.h>
 #include <linux/icmpv6.h>
-#include <linux/brlock.h>
 #include <linux/smp_lock.h>
 
 #include <net/ip.h>
@@ -75,8 +74,10 @@
 /* IPv6 procfs goodies... */
 
 #ifdef CONFIG_PROC_FS
+extern int raw6_proc_init(void);
+extern int raw6_proc_exit(void);
+
 extern int anycast6_get_info(char *, char **, off_t, int);
-extern int raw6_get_info(char *, char **, off_t, int);
 extern int tcp6_get_info(char *, char **, off_t, int);
 extern int udp6_get_info(char *, char **, off_t, int);
 extern int afinet6_get_info(char *, char **, off_t, int);
@@ -102,7 +103,8 @@
 /* The inetsw table contains everything that inet_create needs to
  * build a new socket.
  */
-struct list_head inetsw6[SOCK_MAX];
+static struct list_head inetsw6[SOCK_MAX];
+static spinlock_t inetsw6_lock = SPIN_LOCK_UNLOCKED;
 
 static void inet6_sock_destruct(struct sock *sk)
 {
@@ -111,7 +113,6 @@
 #ifdef INET_REFCNT_DEBUG
 	atomic_dec(&inet6_sock_nr);
 #endif
-	module_put(THIS_MODULE);
 }
 
 static __inline__ kmem_cache_t *inet6_sk_slab(int protocol)
@@ -163,8 +164,8 @@
 
 	/* Look for the requested type/protocol pair. */
 	answer = NULL;
-	br_read_lock_bh(BR_NETPROTO_LOCK);
-	list_for_each(p, &inetsw6[sock->type]) {
+	rcu_read_lock();
+	list_for_each_rcu(p, &inetsw6[sock->type]) {
 		answer = list_entry(p, struct inet_protosw, list);
 
 		/* Check the non-wild match. */
@@ -182,7 +183,6 @@
 		}
 		answer = NULL;
 	}
-	br_read_unlock_bh(BR_NETPROTO_LOCK);
 
 	if (!answer)
 		goto free_and_badtype;
@@ -199,6 +199,7 @@
 	sk->no_check = answer->no_check;
 	if (INET_PROTOSW_REUSE & answer->flags)
 		sk->reuse = 1;
+	rcu_read_unlock();
 
 	inet = inet_sk(sk);
 
@@ -226,7 +227,7 @@
 	/* Init the ipv4 part of the socket since we can have sockets
 	 * using v6 API for ipv4.
 	 */
-	inet->ttl	= 64;
+	inet->uc_ttl	= -1;
 
 	inet->mc_loop	= 1;
 	inet->mc_ttl	= 1;
@@ -243,11 +244,6 @@
 	atomic_inc(&inet6_sock_nr);
 	atomic_inc(&inet_sock_nr);
 #endif
-	if (!try_module_get(THIS_MODULE)) {
-		inet_sock_release(sk);
-		return -EBUSY;
-	}
-
 	if (inet->num) {
 		/* It assumes that any protocol which allows
 		 * the user to assign a number at socket
@@ -259,7 +255,6 @@
 	if (sk->prot->init) {
 		int err = sk->prot->init(sk);
 		if (err != 0) {
-			module_put(THIS_MODULE);
 			inet_sock_release(sk);
 			return err;
 		}
@@ -267,12 +262,15 @@
 	return 0;
 
 free_and_badtype:
+	rcu_read_unlock();
 	sk_free(sk);
 	return -ESOCKTNOSUPPORT;
 free_and_badperm:
+	rcu_read_unlock();
 	sk_free(sk);
 	return -EPERM;
 free_and_noproto:
+	rcu_read_unlock();
 	sk_free(sk);
 	return -EPROTONOSUPPORT;
 do_oom:
@@ -357,10 +355,7 @@
 
 	/* Make sure we are allowed to bind here. */
 	if (sk->prot->get_port(sk, snum) != 0) {
-		inet->rcv_saddr = inet->saddr = 0;
-		memset(&np->rcv_saddr, 0, sizeof(struct in6_addr));
-		memset(&np->saddr, 0, sizeof(struct in6_addr));
-
+		inet_reset_saddr(sk);
 		release_sock(sk);
 		return -EADDRINUSE;
 	}
@@ -442,16 +437,14 @@
 		if (((1<<sk->state)&(TCPF_CLOSE|TCPF_SYN_SENT)) && peer == 1)
 			return -ENOTCONN;
 		sin->sin6_port = inet->dport;
-		memcpy(&sin->sin6_addr, &np->daddr, sizeof(struct in6_addr));
+		ipv6_addr_copy(&sin->sin6_addr, &np->daddr);
 		if (np->sndflow)
 			sin->sin6_flowinfo = np->flow_label;
 	} else {
 		if (ipv6_addr_type(&np->rcv_saddr) == IPV6_ADDR_ANY)
-			memcpy(&sin->sin6_addr, &np->saddr,
-			       sizeof(struct in6_addr));
+			ipv6_addr_copy(&sin->sin6_addr, &np->saddr);
 		else
-			memcpy(&sin->sin6_addr, &np->rcv_saddr,
-			       sizeof(struct in6_addr));
+			ipv6_addr_copy(&sin->sin6_addr, &np->rcv_saddr);
 
 		sin->sin6_port = inet->sport;
 	}
@@ -542,6 +535,7 @@
 struct net_proto_family inet6_family_ops = {
 	.family = PF_INET6,
 	.create = inet6_create,
+	.owner	= THIS_MODULE,
 };
 
 #ifdef MODULE
@@ -580,7 +574,7 @@
 	int protocol = p->protocol;
 	struct list_head *last_perm;
 
-	br_write_lock_bh(BR_NETPROTO_LOCK);
+	spin_lock_bh(&inetsw6_lock);
 
 	if (p->type > SOCK_MAX)
 		goto out_illegal;
@@ -609,9 +603,9 @@
 	 * non-permanent entry.  This means that when we remove this entry, the 
 	 * system automatically returns to the old behavior.
 	 */
-	list_add(&p->list, last_perm);
+	list_add_rcu(&p->list, last_perm);
 out:
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	spin_unlock_bh(&inetsw6_lock);
 	return;
 
 out_permanent:
@@ -629,7 +623,17 @@
 void
 inet6_unregister_protosw(struct inet_protosw *p)
 {
-	inet_unregister_protosw(p);
+	if (INET_PROTOSW_PERMANENT & p->flags) {
+		printk(KERN_ERR
+		       "Attempt to unregister permanent protocol %d.\n",
+		       p->protocol);
+	} else {
+		spin_lock_bh(&inetsw6_lock);
+		list_del_rcu(&p->list);
+		spin_unlock_bh(&inetsw6_lock);
+
+		synchronize_net();
+	}
 }
 
 int
@@ -779,7 +783,7 @@
 	/* Create /proc/foo6 entries. */
 #ifdef CONFIG_PROC_FS
 	err = -ENOMEM;
-	if (!proc_net_create("raw6", 0, raw6_get_info))
+	if (raw6_proc_init())
 		goto proc_raw6_fail;
 	if (!proc_net_create("tcp6", 0, tcp6_get_info))
 		goto proc_tcp6_fail;
@@ -820,7 +824,7 @@
 proc_udp6_fail:
 	proc_net_remove("tcp6");
 proc_tcp6_fail:
-        proc_net_remove("raw6");
+	raw6_proc_exit();
 proc_raw6_fail:
 	igmp6_cleanup();
 #endif
@@ -845,7 +849,7 @@
 	/* First of all disallow new sockets creation. */
 	sock_unregister(PF_INET6);
 #ifdef CONFIG_PROC_FS
-	proc_net_remove("raw6");
+	raw6_proc_exit();
 	proc_net_remove("tcp6");
 	proc_net_remove("udp6");
 	proc_net_remove("sockstat6");
@@ -867,6 +871,9 @@
 	ipv6_sysctl_unregister();	
 #endif
 	cleanup_ipv6_mibs();
+	kmem_cache_destroy(tcp6_sk_cachep);
+	kmem_cache_destroy(udp6_sk_cachep);
+	kmem_cache_destroy(raw6_sk_cachep);
 }
 module_exit(inet6_exit);
 #endif /* MODULE */
diff -Nru a/net/ipv6/ah6.c b/net/ipv6/ah6.c
--- a/net/ipv6/ah6.c	Sun May  4 06:26:55 2003
+++ b/net/ipv6/ah6.c	Mon May 19 23:48:31 2003
@@ -36,17 +36,6 @@
 #include <net/xfrm.h>
 #include <asm/scatterlist.h>
 
-/* XXX no ipv6 ah specific */
-#define NIP6(addr) \
-	ntohs((addr).s6_addr16[0]),\
-	ntohs((addr).s6_addr16[1]),\
-	ntohs((addr).s6_addr16[2]),\
-	ntohs((addr).s6_addr16[3]),\
-	ntohs((addr).s6_addr16[4]),\
-	ntohs((addr).s6_addr16[5]),\
-	ntohs((addr).s6_addr16[6]),\
-	ntohs((addr).s6_addr16[7])
-
 int ah6_output(struct sk_buff *skb)
 {
 	int err;
@@ -75,8 +64,10 @@
 		skb->nh.ipv6h->version = 6;
 		skb->nh.ipv6h->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
 		skb->nh.ipv6h->nexthdr = IPPROTO_AH;
-		memcpy(&skb->nh.ipv6h->saddr, &x->props.saddr, sizeof(struct in6_addr));
-		memcpy(&skb->nh.ipv6h->daddr, &x->id.daddr, sizeof(struct in6_addr));
+		ipv6_addr_copy(&skb->nh.ipv6h->saddr,
+			       (struct in6_addr *) &x->props.saddr);
+		ipv6_addr_copy(&skb->nh.ipv6h->daddr,
+			       (struct in6_addr *) &x->id.daddr);
 		ah = (struct ip_auth_hdr*)(skb->nh.ipv6h+1);
 		ah->nexthdr = IPPROTO_IPV6;
 	} else {
diff -Nru a/net/ipv6/datagram.c b/net/ipv6/datagram.c
--- a/net/ipv6/datagram.c	Thu Apr 17 18:56:05 2003
+++ b/net/ipv6/datagram.c	Tue May 13 05:52:50 2003
@@ -80,7 +80,7 @@
 
 	iph = (struct ipv6hdr*)skb_put(skb, sizeof(struct ipv6hdr));
 	skb->nh.ipv6h = iph;
-	memcpy(&iph->daddr, fl->fl6_dst, 16);
+	ipv6_addr_copy(&iph->daddr, fl->fl6_dst);
 
 	serr = SKB_EXT_ERR(skb);
 	serr->ee.ee_errno = err;
@@ -141,7 +141,8 @@
 		sin->sin6_port = serr->port; 
 		sin->sin6_scope_id = 0;
 		if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
-			memcpy(&sin->sin6_addr, skb->nh.raw + serr->addr_offset, 16);
+			ipv6_addr_copy(&sin->sin6_addr,
+			  (struct in6_addr *)(skb->nh.raw + serr->addr_offset));
 			if (np->sndflow)
 				sin->sin6_flowinfo = *(u32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK;
 			if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
@@ -163,7 +164,7 @@
 		sin->sin6_flowinfo = 0;
 		sin->sin6_scope_id = 0;
 		if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
-			memcpy(&sin->sin6_addr, &skb->nh.ipv6h->saddr, 16);
+			ipv6_addr_copy(&sin->sin6_addr, &skb->nh.ipv6h->saddr);
 			if (np->rxopt.all)
 				datagram_recv_ctl(sk, msg, skb);
 			if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
diff -Nru a/net/ipv6/esp6.c b/net/ipv6/esp6.c
--- a/net/ipv6/esp6.c	Sun May  4 06:26:55 2003
+++ b/net/ipv6/esp6.c	Mon May 19 23:48:31 2003
@@ -46,17 +46,6 @@
 /* Move to common area: it is shared with AH. */
 /* Common with AH after some work on arguments. */
 
-/* XXX no ipv6 esp specific */
-#define NIP6(addr) \
-	ntohs((addr).s6_addr16[0]),\
-	ntohs((addr).s6_addr16[1]),\
-	ntohs((addr).s6_addr16[2]),\
-	ntohs((addr).s6_addr16[3]),\
-	ntohs((addr).s6_addr16[4]),\
-	ntohs((addr).s6_addr16[5]),\
-	ntohs((addr).s6_addr16[6]),\
-	ntohs((addr).s6_addr16[7])
-
 static int get_offset(u8 *packet, u32 packet_len, u8 *nexthdr, struct ipv6_opt_hdr **prevhdr)
 {
 	u16 offset = sizeof(struct ipv6hdr);
@@ -184,8 +173,10 @@
 		top_iph->nexthdr = IPPROTO_ESP;
 		top_iph->payload_len = htons(skb->len + alen - sizeof(struct ipv6hdr));
 		top_iph->hop_limit = iph->hop_limit;
-		memcpy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr, sizeof(struct in6_addr));
-		memcpy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr, sizeof(struct in6_addr));
+		ipv6_addr_copy(&top_iph->saddr,
+			       (struct in6_addr *)&x->props.saddr);
+		ipv6_addr_copy(&top_iph->daddr,
+			       (struct in6_addr *)&x->id.daddr);
 	} else { 
 		/* XXX exthdr */
 		esph = (struct ipv6_esp_hdr*)skb_push(skb, x->props.header_len);
diff -Nru a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c
--- a/net/ipv6/exthdrs.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv6/exthdrs.c	Mon May 19 23:49:42 2003
@@ -54,10 +54,9 @@
  *	It MUST NOT touch skb->h.
  */
 
-struct tlvtype_proc
-{
+struct tlvtype_proc {
 	int	type;
-	int	(*func) (struct sk_buff *, int offset);
+	int	(*func)(struct sk_buff *skb, int offset);
 };
 
 /*********************
@@ -175,8 +174,7 @@
 	return -1;
 }
 
-static struct inet6_protocol destopt_protocol =
-{
+static struct inet6_protocol destopt_protocol = {
 	.handler	=	ipv6_destopt_rcv,
 	.flags		=	INET6_PROTO_NOPOLICY,
 };
@@ -199,8 +197,7 @@
 	return 0;
 }
 
-static struct inet6_protocol nodata_protocol =
-{
+static struct inet6_protocol nodata_protocol = {
 	.handler	=	ipv6_nodata_rcv,
 	.flags		=	INET6_PROTO_NOPOLICY,
 };
@@ -252,8 +249,13 @@
 		return 1;
 	}
 
-	if (hdr->type != IPV6_SRCRT_TYPE_0 || (hdr->hdrlen & 0x01)) {
-		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, hdr->type != IPV6_SRCRT_TYPE_0 ? 2 : 1);
+	if (hdr->type != IPV6_SRCRT_TYPE_0) {
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->type) - skb->nh.raw);
+		return -1;
+	}
+	
+	if (hdr->hdrlen & 0x01) {
+		icmpv6_param_prob(skb, ICMPV6_HDR_FIELD, (&hdr->hdrlen) - skb->nh.raw);
 		return -1;
 	}
 
@@ -323,8 +325,7 @@
 	return -1;
 }
 
-static struct inet6_protocol rthdr_protocol =
-{
+static struct inet6_protocol rthdr_protocol = {
 	.handler	=	ipv6_rthdr_rcv,
 	.flags		=	INET6_PROTO_NOPOLICY,
 };
@@ -404,7 +405,7 @@
   Hop-by-hop options.
  **********************************/
 
-/* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */
+/* Router Alert as of RFC 2711 */
 
 static int ipv6_hop_ra(struct sk_buff *skb, int optoff)
 {
@@ -457,9 +458,15 @@
 }
 
 static struct tlvtype_proc tlvprochopopt_lst[] = {
-	{IPV6_TLV_ROUTERALERT,	ipv6_hop_ra},
-	{IPV6_TLV_JUMBO,	ipv6_hop_jumbo},
-	{-1,			NULL}
+	{
+		.type	= IPV6_TLV_ROUTERALERT,
+		.func	= ipv6_hop_ra,
+	},
+	{
+		.type	= IPV6_TLV_JUMBO,
+		.func	= ipv6_hop_jumbo,
+	},
+	{ -1, }
 };
 
 int ipv6_parse_hopopts(struct sk_buff *skb, int nhoff)
@@ -677,7 +684,7 @@
 /*
  * Skip any extension headers. This is used by the ICMP module.
  *
- * Note that strictly speaking this conflicts with RFC1883 4.0:
+ * Note that strictly speaking this conflicts with RFC 2460 4.0:
  * ...The contents and semantics of each extension header determine whether 
  * or not to proceed to the next header.  Therefore, extension headers must
  * be processed strictly in the order they appear in the packet; a
diff -Nru a/net/ipv6/icmp.c b/net/ipv6/icmp.c
--- a/net/ipv6/icmp.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv6/icmp.c	Mon May 19 23:48:31 2003
@@ -28,6 +28,7 @@
  *	YOSHIFUJI Hideaki @USAGI:	added sysctl for icmp rate limit.
  *	Randy Dunlap and
  *	YOSHIFUJI Hideaki @USAGI:	Per-interface statistics support
+ *	Kazunori MIYAZAWA @USAGI:       change output process to use ip6_append_data
  */
 
 #include <linux/module.h>
@@ -104,42 +105,6 @@
 	spin_unlock_bh(&icmpv6_socket->sk->lock.slock);
 }
 
-
-
-/*
- *	getfrag callback
- */
-
-static int icmpv6_getfrag(const void *data, struct in6_addr *saddr, 
-			   char *buff, unsigned int offset, unsigned int len)
-{
-	struct icmpv6_msg *msg = (struct icmpv6_msg *) data;
-	struct icmp6hdr *icmph;
-	__u32 csum;
-
-	if (offset) {
-		csum = skb_copy_and_csum_bits(msg->skb, msg->offset +
-					      (offset - sizeof(struct icmp6hdr)),
-					      buff, len, msg->csum);
-		msg->csum = csum;
-		return 0;
-	}
-
-	csum = csum_partial_copy_nocheck((void *) &msg->icmph, buff,
-					 sizeof(struct icmp6hdr), msg->csum);
-
-	csum = skb_copy_and_csum_bits(msg->skb, msg->offset,
-				      buff + sizeof(struct icmp6hdr),
-				      len - sizeof(struct icmp6hdr), csum);
-
-	icmph = (struct icmp6hdr *) buff;
-
-	icmph->icmp6_cksum = csum_ipv6_magic(saddr, msg->daddr, msg->len,
-					     IPPROTO_ICMPV6, csum);
-	return 0; 
-}
-
-
 /* 
  * Slightly more convenient version of icmpv6_send.
  */
@@ -242,22 +207,74 @@
 	return (optval&0xC0) == 0x80;
 }
 
+int icmpv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct icmp6hdr *thdr, int len)
+{
+	struct sk_buff *skb;
+	struct icmp6hdr *icmp6h;
+	int err = 0;
+
+	if ((skb = skb_peek(&sk->write_queue)) == NULL)
+		goto out;
+
+	icmp6h = (struct icmp6hdr*) skb->h.raw;
+	memcpy(icmp6h, thdr, sizeof(struct icmp6hdr));
+	icmp6h->icmp6_cksum = 0;
+
+	if (skb_queue_len(&sk->write_queue) == 1) {
+		skb->csum = csum_partial((char *)icmp6h,
+					sizeof(struct icmp6hdr), skb->csum);
+		icmp6h->icmp6_cksum = csum_ipv6_magic(fl->fl6_src,
+					     fl->fl6_dst,
+					     len, fl->proto, skb->csum);
+	} else {
+		u32 tmp_csum = 0;
+
+		skb_queue_walk(&sk->write_queue, skb) {
+			tmp_csum = csum_add(tmp_csum, skb->csum);
+		}
+
+		tmp_csum = csum_partial((char *)icmp6h,
+					sizeof(struct icmp6hdr), tmp_csum);
+		tmp_csum = csum_ipv6_magic(fl->fl6_src,
+					   fl->fl6_dst,
+					   len, fl->proto, tmp_csum);
+		icmp6h->icmp6_cksum = tmp_csum;
+	}
+	if (icmp6h->icmp6_cksum == 0)
+		icmp6h->icmp6_cksum = -1;
+	ip6_push_pending_frames(sk);
+out:
+	return err;
+}
+
+static int icmpv6_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb)
+{
+	struct sk_buff *org_skb = (struct sk_buff *)from;
+	__u32 csum = 0;
+	csum = skb_copy_and_csum_bits(org_skb, offset, to, len, csum);
+	skb->csum = csum_block_add(skb->csum, csum, odd);
+	return 0;
+}
+
 /*
  *	Send an ICMP message in response to a packet in error
  */
-
 void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, 
 		 struct net_device *dev)
 {
 	struct inet6_dev *idev;
 	struct ipv6hdr *hdr = skb->nh.ipv6h;
 	struct sock *sk = icmpv6_socket->sk;
-	struct in6_addr *saddr = NULL;
-	int iif = 0;
-	struct icmpv6_msg msg;
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct in6_addr *saddr = NULL, *tmp_saddr = NULL;
+	struct dst_entry *dst;
+	struct icmp6hdr tmp_hdr;
 	struct flowi fl;
+	int iif = 0;
 	int addr_type = 0;
-	int len;
+	int len, plen;
+	int hlimit = -1;
+	int err = 0;
 
 	if ((u8*)hdr < skb->head || (u8*)(hdr+1) > skb->tail)
 		return;
@@ -328,36 +345,48 @@
 	if (!icmpv6_xrlim_allow(sk, type, &fl))
 		goto out;
 
-	/*
-	 *	ok. kick it. checksum will be provided by the 
-	 *	getfrag_t callback.
-	 */
-
-	msg.icmph.icmp6_type = type;
-	msg.icmph.icmp6_code = code;
-	msg.icmph.icmp6_cksum = 0;
-	msg.icmph.icmp6_pointer = htonl(info);
-
-	msg.skb = skb;
-	msg.offset = skb->nh.raw - skb->data;
-	msg.csum = 0;
-	msg.daddr = &hdr->saddr;
-
-	len = skb->len - msg.offset + sizeof(struct icmp6hdr);
-	len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr));
-
+	tmp_hdr.icmp6_type = type;
+	tmp_hdr.icmp6_code = code;
+	tmp_hdr.icmp6_cksum = 0;
+	tmp_hdr.icmp6_pointer = htonl(info);
+
+	if (!fl.oif && ipv6_addr_is_multicast(fl.fl6_dst))
+		fl.oif = np->mcast_oif;
+
+	err = ip6_dst_lookup(sk, &dst, &fl, &tmp_saddr);
+	if (err) goto out;
+
+	if (hlimit < 0) {
+		if (ipv6_addr_is_multicast(fl.fl6_dst))
+			hlimit = np->mcast_hops;
+		else
+			hlimit = np->hop_limit;
+		if (hlimit < 0)
+			hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+	}
+
+	plen = skb->nh.raw - skb->data;
+	__skb_pull(skb, plen);
+	len = skb->len;
+	len = min_t(unsigned int, len, IPV6_MIN_MTU - sizeof(struct ipv6hdr) -sizeof(struct icmp6hdr));
 	if (len < 0) {
 		if (net_ratelimit())
 			printk(KERN_DEBUG "icmp: len problem\n");
+		__skb_push(skb, plen);
 		goto out;
 	}
 
-	msg.len = len;
-
 	idev = in6_dev_get(skb->dev);
-	
-	ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, len, NULL, -1,
-		       MSG_DONTWAIT);
+
+	err = ip6_append_data(sk, icmpv6_getfrag, skb, len + sizeof(struct icmp6hdr), sizeof(struct icmp6hdr),
+				hlimit, NULL, &fl, (struct rt6_info*)dst, MSG_DONTWAIT);
+	if (err) {
+		ip6_flush_pending_frames(sk);
+		goto out;
+	}
+	err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, len + sizeof(struct icmp6hdr));
+	__skb_push(skb, plen);
+
 	if (type >= ICMPV6_DEST_UNREACH && type <= ICMPV6_PARAMPROB)
 		ICMP6_INC_STATS_OFFSET_BH(idev, Icmp6OutDestUnreachs, type - ICMPV6_DEST_UNREACH);
 	ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs);
@@ -365,6 +394,7 @@
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
 out:
+	if (tmp_saddr) kfree(tmp_saddr);
 	icmpv6_xmit_unlock();
 }
 
@@ -372,10 +402,14 @@
 {
 	struct sock *sk = icmpv6_socket->sk;
 	struct inet6_dev *idev;
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct in6_addr *saddr = NULL, *tmp_saddr = NULL;
 	struct icmp6hdr *icmph = (struct icmp6hdr *) skb->h.raw;
-	struct in6_addr *saddr;
-	struct icmpv6_msg msg;
+	struct icmp6hdr tmp_hdr;
 	struct flowi fl;
+	struct dst_entry *dst;
+	int err = 0;
+	int hlimit = -1;
 
 	saddr = &skb->nh.ipv6h->daddr;
 
@@ -383,39 +417,55 @@
 	    ipv6_chk_acast_addr(0, saddr)) 
 		saddr = NULL;
 
-	msg.icmph.icmp6_type = ICMPV6_ECHO_REPLY;
-	msg.icmph.icmp6_code = 0;
-	msg.icmph.icmp6_cksum = 0;
-	msg.icmph.icmp6_identifier = icmph->icmp6_identifier;
-	msg.icmph.icmp6_sequence = icmph->icmp6_sequence;
-
-	msg.skb = skb;
-	msg.offset = 0;
-	msg.csum = 0;
-	msg.len = skb->len + sizeof(struct icmp6hdr);
-	msg.daddr =  &skb->nh.ipv6h->saddr;
+	memcpy(&tmp_hdr, icmph, sizeof(tmp_hdr));
+	tmp_hdr.icmp6_type = ICMPV6_ECHO_REPLY;
 
 	fl.proto = IPPROTO_ICMPV6;
-	fl.fl6_dst = msg.daddr;
+	fl.fl6_dst = &skb->nh.ipv6h->saddr;
 	fl.fl6_src = saddr;
 	fl.oif = skb->dev->ifindex;
 	fl.fl6_flowlabel = 0;
 	fl.fl_icmp_type = ICMPV6_ECHO_REPLY;
 	fl.fl_icmp_code = 0;
 
+	icmpv6_xmit_lock();
+
+	if (!fl.oif && ipv6_addr_is_multicast(fl.nl_u.ip6_u.daddr))
+		fl.oif = np->mcast_oif;
+
+	err = ip6_dst_lookup(sk, &dst, &fl, &tmp_saddr);
+
+	if (err) goto out;
+
+	if (hlimit < 0) {
+		if (ipv6_addr_is_multicast(fl.fl6_dst))
+			hlimit = np->mcast_hops;
+		else
+			hlimit = np->hop_limit;
+		if (hlimit < 0)
+			hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+	}
+
 	idev = in6_dev_get(skb->dev);
 
-	icmpv6_xmit_lock();
+	err = ip6_append_data(sk, icmpv6_getfrag, skb, skb->len + sizeof(struct icmp6hdr),
+				sizeof(struct icmp6hdr), hlimit, NULL, &fl,
+				(struct rt6_info*)dst, MSG_DONTWAIT);
 
-	ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
-		       MSG_DONTWAIT);
-	ICMP6_INC_STATS_BH(idev, Icmp6OutEchoReplies);
-	ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs);
+	if (err) {
+		ip6_flush_pending_frames(sk);
+		goto out;
+	}
+	err = icmpv6_push_pending_frames(sk, &fl, &tmp_hdr, skb->len + sizeof(struct icmp6hdr));
 
-	icmpv6_xmit_unlock();
+        ICMP6_INC_STATS_BH(idev, Icmp6OutEchoReplies);
+        ICMP6_INC_STATS_BH(idev, Icmp6OutMsgs);
 
 	if (likely(idev != NULL))
 		in6_dev_put(idev);
+out: 
+	if (tmp_saddr) kfree(tmp_saddr);
+	icmpv6_xmit_unlock();
 }
 
 static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
@@ -456,9 +506,12 @@
 
 	hash = nexthdr & (MAX_INET_PROTOS - 1);
 
+	rcu_read_lock();
 	ipprot = inet6_protos[hash];
+	smp_read_barrier_depends();
 	if (ipprot && ipprot->err_handler)
 		ipprot->err_handler(skb, NULL, type, code, inner_offset, info);
+	rcu_read_unlock();
 
 	read_lock(&raw_v6_lock);
 	if ((sk = raw_v6_htable[hash]) != NULL) {
@@ -504,22 +557,7 @@
 				    skb_checksum(skb, 0, skb->len, 0))) {
 			if (net_ratelimit())
 				printk(KERN_DEBUG "ICMPv6 checksum failed [%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x > %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x]\n",
-				       ntohs(saddr->s6_addr16[0]),
-				       ntohs(saddr->s6_addr16[1]),
-				       ntohs(saddr->s6_addr16[2]),
-				       ntohs(saddr->s6_addr16[3]),
-				       ntohs(saddr->s6_addr16[4]),
-				       ntohs(saddr->s6_addr16[5]),
-				       ntohs(saddr->s6_addr16[6]),
-				       ntohs(saddr->s6_addr16[7]),
-				       ntohs(daddr->s6_addr16[0]),
-				       ntohs(daddr->s6_addr16[1]),
-				       ntohs(daddr->s6_addr16[2]),
-				       ntohs(daddr->s6_addr16[3]),
-				       ntohs(daddr->s6_addr16[4]),
-				       ntohs(daddr->s6_addr16[5]),
-				       ntohs(daddr->s6_addr16[6]),
-				       ntohs(daddr->s6_addr16[7]));
+				       NIP6(*saddr), NIP6(*daddr));
 			goto discard_it;
 		}
 	}
@@ -684,11 +722,26 @@
 	int err;
 	int fatal;
 } tab_unreach[] = {
-	{ ENETUNREACH,	0},	/* NOROUTE		*/
-	{ EACCES,	1},	/* ADM_PROHIBITED	*/
-	{ EHOSTUNREACH,	0},	/* Was NOT_NEIGHBOUR, now reserved */
-	{ EHOSTUNREACH,	0},	/* ADDR_UNREACH		*/
-	{ ECONNREFUSED,	1},	/* PORT_UNREACH		*/
+	{	/* NOROUTE */
+		.err	= ENETUNREACH,
+		.fatal	= 0,
+	},
+	{	/* ADM_PROHIBITED */
+		.err	= EACCES,
+		.fatal	= 1,
+	},
+	{	/* Was NOT_NEIGHBOUR, now reserved */
+		.err	= EHOSTUNREACH,
+		.fatal	= 0,
+	},
+	{	/* ADDR_UNREACH	*/
+		.err	= EHOSTUNREACH,
+		.fatal	= 0,
+	},
+	{	/* PORT_UNREACH	*/
+		.err	= ECONNREFUSED,
+		.fatal	= 1,
+	},
 };
 
 int icmpv6_err_convert(int type, int code, int *err)
diff -Nru a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
--- a/net/ipv6/ip6_fib.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv6/ip6_fib.c	Sat May 17 16:10:46 2003
@@ -91,12 +91,13 @@
  *	result of redirects, path MTU changes, etc.
  */
 
-static __u32	rt_sernum	= 0;
+static __u32 rt_sernum;
 
 static struct timer_list ip6_fib_timer = TIMER_INITIALIZER(fib6_run_gc, 0, 0);
 
 static struct fib6_walker_t fib6_walker_list = {
-	&fib6_walker_list, &fib6_walker_list, 
+	.prev	= &fib6_walker_list,
+	.next	= &fib6_walker_list, 
 };
 
 #define FOR_WALKERS(w) for ((w)=fib6_walker_list.next; (w) != &fib6_walker_list; (w)=(w)->next)
@@ -434,9 +435,6 @@
 	if (fn->fn_flags&RTN_TL_ROOT &&
 	    fn->leaf == &ip6_null_entry &&
 	    !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF | RTF_ALLONLINK)) ){
-		/*
-		 * The top fib of ip6 routing table includes ip6_null_entry.
-		 */
 		fn->leaf = rt;
 		rt->u.next = NULL;
 		goto out;
@@ -505,7 +503,7 @@
  *	with source addr info in sub-trees
  */
 
-int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh)
+int fib6_add(struct fib6_node *root, struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr)
 {
 	struct fib6_node *fn;
 	int err = -ENOMEM;
@@ -593,7 +591,7 @@
 
 #ifdef CONFIG_IPV6_SUBTREES
 	/* Subtree creation failed, probably main tree node
-	   is orphan. If it is, shot it.
+	   is orphan. If it is, shoot it.
 	 */
 st_failure:
 	if (fn && !(fn->fn_flags&RTN_RTINFO|RTN_ROOT))
@@ -887,7 +885,7 @@
 }
 
 static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
-    struct nlmsghdr *nlh)
+    struct nlmsghdr *nlh, void *_rtattr)
 {
 	struct fib6_walker_t *w;
 	struct rt6_info *rt = *rtp;
@@ -946,14 +944,14 @@
 	rt6_release(rt);
 }
 
-int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh)
+int fib6_del(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr)
 {
 	struct fib6_node *fn = rt->rt6i_node;
 	struct rt6_info **rtp;
 
 #if RT6_DEBUG >= 2
 	if (rt->u.dst.obsolete>0) {
-		BUG_TRAP(fn==NULL || rt->u.dst.obsolete<=0);
+		BUG_TRAP(fn==NULL);
 		return -ENOENT;
 	}
 #endif
@@ -971,7 +969,7 @@
 
 	for (rtp = &fn->leaf; *rtp; rtp = &(*rtp)->u.next) {
 		if (*rtp == rt) {
-			fib6_del_route(fn, rtp, nlh);
+			fib6_del_route(fn, rtp, nlh, _rtattr);
 			return 0;
 		}
 	}
@@ -979,7 +977,7 @@
 }
 
 /*
- *	Tree transversal function.
+ *	Tree traversal function.
  *
  *	Certainly, it is not interrupt safe.
  *	However, it is internally reenterable wrt itself and fib6_add/fib6_del.
@@ -1100,7 +1098,7 @@
 		res = c->func(rt, c->arg);
 		if (res < 0) {
 			w->leaf = rt;
-			res = fib6_del(rt, NULL);
+			res = fib6_del(rt, NULL, NULL);
 			if (res) {
 #if RT6_DEBUG >= 2
 				printk(KERN_DEBUG "fib6_clean_node: del failed: rt=%p@%p err=%d\n", rt, rt->rt6i_node, res);
@@ -1179,14 +1177,14 @@
 	 */
 
 	if (rt->rt6i_flags&RTF_EXPIRES && rt->rt6i_expires) {
-		if ((long)(now - rt->rt6i_expires) > 0) {
+		if (time_after(now, rt->rt6i_expires)) {
 			RT6_TRACE("expiring %p\n", rt);
 			return -1;
 		}
 		gc_args.more++;
 	} else if (rt->rt6i_flags & RTF_CACHE) {
 		if (atomic_read(&rt->u.dst.__refcnt) == 0 &&
-		    (long)(now - rt->u.dst.lastuse) >= gc_args.timeout) {
+		    time_after_eq(now, rt->u.dst.lastuse + gc_args.timeout)) {
 			RT6_TRACE("aging clone %p\n", rt);
 			return -1;
 		}
@@ -1230,17 +1228,17 @@
 
 void __init fib6_init(void)
 {
-	if (!fib6_node_kmem)
-		fib6_node_kmem = kmem_cache_create("fib6_nodes",
-						   sizeof(struct fib6_node),
-						   0, SLAB_HWCACHE_ALIGN,
-						   NULL, NULL);
+	fib6_node_kmem = kmem_cache_create("fib6_nodes",
+					   sizeof(struct fib6_node),
+					   0, SLAB_HWCACHE_ALIGN,
+					   NULL, NULL);
 }
 
 #ifdef MODULE
 void fib6_gc_cleanup(void)
 {
 	del_timer(&ip6_fib_timer);
+	kmem_cache_destroy(fib6_node_kmem);
 }
 #endif
 
diff -Nru a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
--- a/net/ipv6/ip6_input.c	Wed Apr 16 01:45:42 2003
+++ b/net/ipv6/ip6_input.c	Sat May 10 05:25:34 2003
@@ -152,6 +152,7 @@
 		skb->h.raw += (skb->h.raw[1]+1)<<3;
 	}
 
+	rcu_read_lock();
 resubmit:
 	if (!pskb_pull(skb, skb->h.raw - skb->data))
 		goto discard;
@@ -165,6 +166,7 @@
 	if ((ipprot = inet6_protos[hash]) != NULL) {
 		int ret;
 		
+		smp_read_barrier_depends();
 		if (ipprot->flags & INET6_PROTO_FINAL) {
 			if (!cksum_sub && skb->ip_summed == CHECKSUM_HW) {
 				skb->csum = csum_sub(skb->csum,
@@ -173,10 +175,8 @@
 			}
 		}
 		if (!(ipprot->flags & INET6_PROTO_NOPOLICY) &&
-		    !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) {
-			kfree_skb(skb);
-			return 0;
-		}
+		    !xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) 
+			goto discard;
 		
 		ret = ipprot->handler(&skb, &nhoff);
 		if (ret > 0)
@@ -194,10 +194,11 @@
 			kfree_skb(skb);
 		}
 	}
-
+	rcu_read_unlock();
 	return 0;
 
 discard:
+	rcu_read_unlock();
 	kfree_skb(skb);
 	return 0;
 }
diff -Nru a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
--- a/net/ipv6/ip6_output.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv6/ip6_output.c	Fri May 16 14:02:36 2003
@@ -23,6 +23,9 @@
  *
  *      H. von Brand    :       Added missing #include <linux/string.h>
  *	Imran Patel	: 	frag id should be in NBO
+ *      Kazunori MIYAZAWA @USAGI
+ *			:       add ip6_append_data and related functions
+ *				for datagram xmit
  */
 
 #include <linux/config.h>
@@ -52,6 +55,8 @@
 #include <net/icmp.h>
 #include <net/xfrm.h>
 
+static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*));
+
 static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *fhdr)
 {
 	static u32 ipv6_fragmentation_id = 1;
@@ -98,7 +103,7 @@
 }
 
 
-int ip6_output(struct sk_buff *skb)
+int ip6_output2(struct sk_buff *skb)
 {
 	struct dst_entry *dst = skb->dst;
 	struct net_device *dev = dst->dev;
@@ -134,6 +139,13 @@
 	return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish);
 }
 
+int ip6_output(struct sk_buff *skb)
+{
+	if ((skb->len > dst_pmtu(skb->dst) || skb_shinfo(skb)->frag_list))
+		return ip6_fragment(skb, ip6_output2);
+	else
+		return ip6_output2(skb);
+}
 
 #ifdef CONFIG_NETFILTER
 int ip6_route_me_harder(struct sk_buff *skb)
@@ -237,7 +249,7 @@
 	if (np)
 		hlimit = np->hop_limit;
 	if (hlimit < 0)
-		hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit;
+		hlimit = dst_metric(dst, RTAX_HOPLIMIT);
 
 	hdr->payload_len = htons(seg_len);
 	hdr->nexthdr = proto;
@@ -597,7 +609,7 @@
 		else
 			hlimit = np->hop_limit;
 		if (hlimit < 0)
-			hlimit = ((struct rt6_info*)dst)->rt6i_hoplimit;
+			hlimit = dst_metric(dst, RTAX_HOPLIMIT);
 	}
 
 	jumbolen = 0;
@@ -846,4 +858,659 @@
 drop:
 	kfree_skb(skb);
 	return -EINVAL;
+}
+
+static void ip6_copy_metadata(struct sk_buff *to, struct sk_buff *from)
+{
+	to->pkt_type = from->pkt_type;
+	to->priority = from->priority;
+	to->protocol = from->protocol;
+	to->security = from->security;
+	to->dst = dst_clone(from->dst);
+	to->dev = from->dev;
+
+#ifdef CONFIG_NET_SCHED
+	to->tc_index = from->tc_index;
+#endif
+#ifdef CONFIG_NETFILTER
+	to->nfmark = from->nfmark;
+	/* Connection association is same as pre-frag packet */
+	to->nfct = from->nfct;
+	nf_conntrack_get(to->nfct);
+#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
+	to->nf_bridge = from->nf_bridge;
+	nf_bridge_get(to->nf_bridge);
+#endif
+#ifdef CONFIG_NETFILTER_DEBUG
+	to->nf_debug = from->nf_debug;
+#endif
+#endif
+}
+
+int ip6_found_nexthdr(struct sk_buff *skb, u8 **nexthdr)
+{
+	u16 offset = sizeof(struct ipv6hdr);
+	struct ipv6_opt_hdr *exthdr = (struct ipv6_opt_hdr*)(skb->nh.ipv6h + 1);
+	unsigned int packet_len = skb->tail - skb->nh.raw;
+	int found_rhdr = 0;
+	*nexthdr = &skb->nh.ipv6h->nexthdr;
+
+	while (offset + 1 <= packet_len) {
+
+		switch (**nexthdr) {
+
+		case NEXTHDR_HOP:
+		case NEXTHDR_ROUTING:
+		case NEXTHDR_DEST:
+			if (**nexthdr == NEXTHDR_ROUTING) found_rhdr = 1;
+			if (**nexthdr == NEXTHDR_DEST && found_rhdr) return offset;
+			offset += ipv6_optlen(exthdr);
+			*nexthdr = &exthdr->nexthdr;
+			exthdr = (struct ipv6_opt_hdr*)(skb->nh.raw + offset);
+			break;
+		default :
+			return offset;
+		}
+	}
+
+	return offset;
+}
+
+static int ip6_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*))
+{
+	struct net_device *dev;
+	struct rt6_info *rt = (struct rt6_info*)skb->dst;
+	struct sk_buff *frag;
+	struct ipv6hdr *tmp_hdr;
+	struct frag_hdr *fh;
+	unsigned int mtu, hlen, left, len;
+	u32 frag_id = 0;
+	int ptr, offset = 0, err=0;
+	u8 *prevhdr, nexthdr = 0;
+
+	dev = rt->u.dst.dev;
+	hlen = ip6_found_nexthdr(skb, &prevhdr);
+	nexthdr = *prevhdr;
+
+	mtu = dst_pmtu(&rt->u.dst) - hlen - sizeof(struct frag_hdr);
+
+	if (skb_shinfo(skb)->frag_list) {
+		int first_len = 0;
+
+		if (first_len - hlen > mtu ||
+		    ((first_len - hlen) & 7) ||
+		    skb_cloned(skb))
+			goto slow_path;
+
+		for (frag = skb_shinfo(skb)->frag_list; frag; frag = frag->next) {
+			/* Correct geometry. */
+			if (frag->len > mtu ||
+			    ((frag->len & 7) && frag->next) ||
+			    skb_headroom(frag) < hlen)
+			    goto slow_path;
+
+			/* Correct socket ownership. */
+			if (frag->sk == NULL)
+				goto slow_path;
+
+			/* Partially cloned skb? */
+			if (skb_shared(frag))
+				goto slow_path;
+		}
+
+		err = 0;
+		offset = 0;
+		frag = skb_shinfo(skb)->frag_list;
+		skb_shinfo(skb)->frag_list = 0;
+		/* BUILD HEADER */
+
+		tmp_hdr = kmalloc(hlen, GFP_ATOMIC);
+		if (!tmp_hdr) {
+			IP6_INC_STATS(Ip6FragFails);
+			return -ENOMEM;
+		}
+
+		*prevhdr = NEXTHDR_FRAGMENT;
+		memcpy(tmp_hdr, skb->nh.raw, hlen);
+		__skb_pull(skb, hlen);
+		fh = (struct frag_hdr*)__skb_push(skb, sizeof(struct frag_hdr));
+		skb->nh.raw = __skb_push(skb, hlen);
+		memcpy(skb->nh.raw, tmp_hdr, hlen);
+
+		ipv6_select_ident(skb, fh);
+		fh->nexthdr = nexthdr;
+		fh->reserved = 0;
+		fh->frag_off = htons(0x0001);
+		frag_id = fh->identification;
+
+		first_len = skb_pagelen(skb);
+		skb->data_len = first_len - skb_headlen(skb);
+		skb->len = first_len;
+		skb->nh.ipv6h->payload_len = htons(first_len - sizeof(struct ipv6hdr));
+ 
+
+		for (;;) {
+			/* Prepare header of the next frame,
+			 * before previous one went down. */
+			if (frag) {
+				frag->h.raw = frag->data;
+				fh = (struct frag_hdr*)__skb_push(frag, sizeof(struct frag_hdr));
+				frag->nh.raw = __skb_push(frag, hlen);
+				memcpy(frag->nh.raw, tmp_hdr, hlen);
+				offset += skb->len - hlen - sizeof(struct frag_hdr);
+				fh->nexthdr = nexthdr;
+				fh->reserved = 0;
+				if (frag->next != NULL)
+					offset |= 0x0001;
+				fh->frag_off = htons(offset);
+				fh->identification = frag_id;
+				frag->nh.ipv6h->payload_len = htons(frag->len - sizeof(struct ipv6hdr));
+				ip6_copy_metadata(frag, skb);
+			}
+			err = output(skb);
+
+			if (err || !frag)
+				break;
+
+			skb = frag;
+			frag = skb->next;
+			skb->next = NULL;
+		}
+
+		if (tmp_hdr)
+			kfree(tmp_hdr);
+
+		if (err == 0) {
+			IP6_INC_STATS(Ip6FragOKs);
+			return 0;
+		}
+
+		while (frag) {
+			skb = frag->next;
+			kfree_skb(frag);
+			frag = skb;
+		}
+
+		IP6_INC_STATS(Ip6FragFails);
+		return err;
+	}
+
+slow_path:
+	left = skb->len - hlen;		/* Space per frame */
+	ptr = hlen;			/* Where to start from */
+
+	/*
+	 *	Fragment the datagram.
+	 */
+
+	*prevhdr = NEXTHDR_FRAGMENT;
+
+	/*
+	 *	Keep copying data until we run out.
+	 */
+	while(left > 0)	{
+		len = left;
+		/* IF: it doesn't fit, use 'mtu' - the data space left */
+		if (len > mtu)
+			len = mtu;
+		/* IF: we are not sending upto and including the packet end
+		   then align the next start on an eight byte boundary */
+		if (len < left)	{
+			len &= ~7;
+		}
+		/*
+		 *	Allocate buffer.
+		 */
+
+		if ((frag = alloc_skb(len+hlen+sizeof(struct frag_hdr)+LL_RESERVED_SPACE(rt->u.dst.dev), GFP_ATOMIC)) == NULL) {
+			NETDEBUG(printk(KERN_INFO "IPv6: frag: no memory for new fragment!\n"));
+			err = -ENOMEM;
+			goto fail;
+		}
+
+		/*
+		 *	Set up data on packet
+		 */
+
+		ip6_copy_metadata(frag, skb);
+		skb_reserve(frag, LL_RESERVED_SPACE(rt->u.dst.dev));
+		skb_put(frag, len + hlen + sizeof(struct frag_hdr));
+		frag->nh.raw = frag->data;
+		fh = (struct frag_hdr*)(frag->data + hlen);
+		frag->h.raw = frag->data + hlen + sizeof(struct frag_hdr);
+
+		/*
+		 *	Charge the memory for the fragment to any owner
+		 *	it might possess
+		 */
+		if (skb->sk)
+			skb_set_owner_w(frag, skb->sk);
+
+		/*
+		 *	Copy the packet header into the new buffer.
+		 */
+		memcpy(frag->nh.raw, skb->data, hlen);
+
+		/*
+		 *	Build fragment header.
+		 */
+		fh->nexthdr = nexthdr;
+		fh->reserved = 0;
+		if (frag_id) {
+			ipv6_select_ident(skb, fh);
+			frag_id = fh->identification;
+		} else
+			fh->identification = frag_id;
+
+		/*
+		 *	Copy a block of the IP datagram.
+		 */
+		if (skb_copy_bits(skb, ptr, frag->h.raw, len))
+			BUG();
+		left -= len;
+
+		fh->frag_off = htons( left > 0 ?  (offset | 0x0001) : offset);
+		frag->nh.ipv6h->payload_len = htons(frag->len - sizeof(struct ipv6hdr));
+
+		ptr += len;
+		offset += len;
+
+		/*
+		 *	Put this fragment into the sending queue.
+		 */
+
+		IP6_INC_STATS(Ip6FragCreates);
+
+		err = output(frag);
+		if (err)
+			goto fail;
+	}
+	kfree_skb(skb);
+	IP6_INC_STATS(Ip6FragOKs);
+	return err;
+
+fail:
+	kfree_skb(skb); 
+	IP6_INC_STATS(Ip6FragFails);
+	return err;
+}
+
+int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl, struct in6_addr **saddr)
+{
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	int err = 0;
+
+	*dst = __sk_dst_check(sk, np->dst_cookie);
+	if (*dst) {
+		struct rt6_info *rt = (struct rt6_info*)*dst;
+
+			/* Yes, checking route validity in not connected
+			   case is not very simple. Take into account,
+			   that we do not support routing by source, TOS,
+			   and MSG_DONTROUTE 		--ANK (980726)
+
+			   1. If route was host route, check that
+			      cached destination is current.
+			      If it is network route, we still may
+			      check its validity using saved pointer
+			      to the last used address: daddr_cache.
+			      We do not want to save whole address now,
+			      (because main consumer of this service
+			       is tcp, which has not this problem),
+			      so that the last trick works only on connected
+			      sockets.
+			   2. oif also should be the same.
+			 */
+
+		if (((rt->rt6i_dst.plen != 128 ||
+		      ipv6_addr_cmp(fl->fl6_dst, &rt->rt6i_dst.addr))
+		     && (np->daddr_cache == NULL ||
+			 ipv6_addr_cmp(fl->fl6_dst, np->daddr_cache)))
+		    || (fl->oif && fl->oif != (*dst)->dev->ifindex)) {
+			*dst = NULL;
+		} else
+			dst_hold(*dst);
+	}
+
+	if (*dst == NULL)
+		*dst = ip6_route_output(sk, fl);
+
+	if ((*dst)->error) {
+		IP6_INC_STATS(Ip6OutNoRoutes);
+		dst_release(*dst);
+		return -ENETUNREACH;
+	}
+
+	if (fl->fl6_src == NULL) {
+		*saddr = kmalloc(sizeof(struct in6_addr), GFP_ATOMIC);
+		err = ipv6_get_saddr(*dst, fl->fl6_dst, *saddr);
+
+		if (err) {
+#if IP6_DEBUG >= 2
+			printk(KERN_DEBUG "ip6_build_xmit: "
+			       "no availiable source address\n");
+#endif
+			return err;
+		}
+		fl->fl6_src = *saddr;
+	}
+
+        if (*dst) {
+		if ((err = xfrm_lookup(dst, fl, sk, 0)) < 0) {
+			dst_release(*dst);	
+			return -ENETUNREACH;
+		}
+        }
+
+	return 0;
+}
+
+int ip6_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb),
+		    void *from, int length, int transhdrlen,
+		    int hlimit, struct ipv6_txoptions *opt, struct flowi *fl, struct rt6_info *rt,
+		    unsigned int flags)
+{
+	struct inet_opt *inet = inet_sk(sk);
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct sk_buff *skb;
+	unsigned int maxfraglen, fragheaderlen;
+	int exthdrlen;
+	int hh_len;
+	int mtu;
+	int copy = 0;
+	int err;
+	int offset = 0;
+	int csummode = CHECKSUM_NONE;
+
+	if (flags&MSG_PROBE)
+		return 0;
+	if (skb_queue_empty(&sk->write_queue)) {
+		/*
+		 * setup for corking
+		 */
+		if (opt) {
+			if (np->cork.opt == NULL)
+				np->cork.opt = kmalloc(opt->tot_len, sk->allocation);
+			memcpy(np->cork.opt, opt, opt->tot_len);
+			inet->cork.flags |= IPCORK_OPT;
+			/* need source address above miyazawa*/
+			exthdrlen += opt->opt_flen ? opt->opt_flen : 0;
+		}
+		dst_hold(&rt->u.dst);
+		np->cork.rt = rt;
+		np->cork.fl = fl;
+		inet->cork.fragsize = mtu = dst_pmtu(&rt->u.dst);
+		inet->cork.length = 0;
+		inet->sndmsg_page = NULL;
+		inet->sndmsg_off = 0;
+		if ((exthdrlen = rt->u.dst.header_len) != 0) {
+			length += exthdrlen;
+			transhdrlen += exthdrlen;
+		}
+	} else {
+		rt = np->cork.rt;
+		if (inet->cork.flags & IPCORK_OPT)
+			opt = np->cork.opt;
+		transhdrlen = 0;
+		exthdrlen = 0;
+		mtu = inet->cork.fragsize;
+	}
+
+	hh_len = (rt->u.dst.dev->hard_header_len&~15) + 16;
+
+	fragheaderlen = sizeof(struct ipv6hdr) + (opt ? opt->opt_nflen : 0);
+	maxfraglen = ((mtu - fragheaderlen) & ~7) + fragheaderlen - sizeof(struct frag_hdr);
+
+	if (mtu < 65576) {
+		if (inet->cork.length + length > 0xFFFF - fragheaderlen) {
+			ipv6_local_error(sk, EMSGSIZE, fl, mtu-exthdrlen);
+			return -EMSGSIZE;
+		}
+	}
+
+	inet->cork.length += length;
+
+	if ((skb = skb_peek_tail(&sk->write_queue)) == NULL)
+		goto alloc_new_skb;
+
+	while (length > 0) {
+		if ((copy = maxfraglen - skb->len) <= 0) {
+			char *data;
+			unsigned int datalen;
+			unsigned int fraglen;
+			unsigned int alloclen;
+			BUG_TRAP(copy == 0);
+alloc_new_skb:
+			datalen = maxfraglen - fragheaderlen;
+			if (datalen > length)
+				datalen = length;
+			fraglen = datalen + fragheaderlen;
+			if ((flags & MSG_MORE) &&
+			    !(rt->u.dst.dev->features&NETIF_F_SG))
+				alloclen = maxfraglen;
+			else
+				alloclen = fraglen;
+			alloclen += sizeof(struct frag_hdr);
+			if (transhdrlen) {
+				skb = sock_alloc_send_skb(sk,
+						alloclen + hh_len + 15,
+						(flags & MSG_DONTWAIT), &err);
+			} else {
+				skb = NULL;
+				if (atomic_read(&sk->wmem_alloc) <= 2*sk->sndbuf)
+					skb = sock_wmalloc(sk,
+							   alloclen + hh_len + 15, 1,
+							   sk->allocation);
+				if (unlikely(skb == NULL))
+					err = -ENOBUFS;
+			}
+			if (skb == NULL)
+				goto error;
+			/*
+			 *	Fill in the control structures
+			 */
+			skb->ip_summed = csummode;
+			skb->csum = 0;
+			/* reserve 8 byte for fragmentation */
+			skb_reserve(skb, hh_len+sizeof(struct frag_hdr));
+
+			/*
+			 *	Find where to start putting bytes
+			 */
+			data = skb_put(skb, fraglen);
+			skb->nh.raw = data + exthdrlen;
+			data += fragheaderlen;
+			skb->h.raw = data + exthdrlen;
+			copy = datalen - transhdrlen;
+			if (copy > 0 && getfrag(from, data + transhdrlen, offset, copy, 0, skb) < 0) {
+				err = -EFAULT;
+				kfree_skb(skb);
+				goto error;
+			}
+
+			offset += copy;
+			length -= datalen;
+			transhdrlen = 0;
+			exthdrlen = 0;
+			csummode = CHECKSUM_NONE;
+
+			/*
+			 * Put the packet on the pending queue
+			 */
+			__skb_queue_tail(&sk->write_queue, skb);
+			continue;
+		}
+
+		if (copy > length)
+			copy = length;
+
+		if (!(rt->u.dst.dev->features&NETIF_F_SG)) {
+			unsigned int off;
+
+			off = skb->len;
+			if (getfrag(from, skb_put(skb, copy),
+						offset, copy, off, skb) < 0) {
+				__skb_trim(skb, off);
+				err = -EFAULT;
+				goto error;
+			}
+		} else {
+			int i = skb_shinfo(skb)->nr_frags;
+			skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1];
+			struct page *page = inet->sndmsg_page;
+			int off = inet->sndmsg_off;
+			unsigned int left;
+
+			if (page && (left = PAGE_SIZE - off) > 0) {
+				if (copy >= left)
+					copy = left;
+				if (page != frag->page) {
+					if (i == MAX_SKB_FRAGS) {
+						err = -EMSGSIZE;
+						goto error;
+					}
+					get_page(page);
+					skb_fill_page_desc(skb, i, page, inet->sndmsg_off, 0);
+					frag = &skb_shinfo(skb)->frags[i];
+				}
+			} else if(i < MAX_SKB_FRAGS) {
+				if (copy > PAGE_SIZE)
+					copy = PAGE_SIZE;
+				page = alloc_pages(sk->allocation, 0);
+				if (page == NULL) {
+					err = -ENOMEM;
+					goto error;
+				}
+				inet->sndmsg_page = page;
+				inet->sndmsg_off = 0;
+
+				skb_fill_page_desc(skb, i, page, 0, 0);
+				frag = &skb_shinfo(skb)->frags[i];
+				skb->truesize += PAGE_SIZE;
+				atomic_add(PAGE_SIZE, &sk->wmem_alloc);
+			} else {
+				err = -EMSGSIZE;
+				goto error;
+			}
+			if (getfrag(from, page_address(frag->page)+frag->page_offset+frag->size, offset, copy, skb->len, skb) < 0) {
+				err = -EFAULT;
+				goto error;
+			}
+			inet->sndmsg_off += copy;
+			frag->size += copy;
+			skb->len += copy;
+			skb->data_len += copy;
+		}
+		offset += copy;
+		length -= copy;
+	}
+	return 0;
+error:
+	inet->cork.length -= length;
+	IP6_INC_STATS(Ip6OutDiscards);
+	return err;
+}
+
+int ip6_push_pending_frames(struct sock *sk)
+{
+	struct sk_buff *skb, *tmp_skb;
+	struct sk_buff **tail_skb;
+	struct in6_addr *final_dst = NULL;
+	struct inet_opt *inet = inet_sk(sk);
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct ipv6hdr *hdr;
+	struct ipv6_txoptions *opt = np->cork.opt;
+	struct rt6_info *rt = np->cork.rt;
+	struct flowi *fl = np->cork.fl;
+	unsigned char proto = fl->proto;
+	int err = 0;
+
+	if ((skb = __skb_dequeue(&sk->write_queue)) == NULL)
+		goto out;
+	tail_skb = &(skb_shinfo(skb)->frag_list);
+
+	/* move skb->data to ip header from ext header */
+	if (skb->data < skb->nh.raw)
+		__skb_pull(skb, skb->nh.raw - skb->data);
+	while ((tmp_skb = __skb_dequeue(&sk->write_queue)) != NULL) {
+		__skb_pull(tmp_skb, skb->h.raw - skb->nh.raw);
+		*tail_skb = tmp_skb;
+		tail_skb = &(tmp_skb->next);
+		skb->len += tmp_skb->len;
+		skb->data_len += tmp_skb->len;
+#if 0 /* Logically correct, but useless work, ip_fragment() will have to undo */
+		skb->truesize += tmp_skb->truesize;
+		__sock_put(tmp_skb->sk);
+		tmp_skb->destructor = NULL;
+		tmp_skb->sk = NULL;
+#endif
+	}
+
+	final_dst = fl->fl6_dst;
+	__skb_pull(skb, skb->h.raw - skb->nh.raw);
+	if (opt && opt->opt_flen)
+		ipv6_push_frag_opts(skb, opt, &proto);
+	if (opt && opt->opt_nflen)
+		ipv6_push_nfrag_opts(skb, opt, &proto, &final_dst);
+
+	skb->nh.ipv6h = hdr = (struct ipv6hdr*) skb_push(skb, sizeof(struct ipv6hdr));
+	
+	*(u32*)hdr = fl->fl6_flowlabel | htonl(0x60000000);
+
+	if (skb->len < 65536)
+		hdr->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+	else
+		hdr->payload_len = 0;
+	hdr->hop_limit = np->hop_limit;
+	hdr->nexthdr = proto;
+	ipv6_addr_copy(&hdr->saddr, fl->fl6_src);
+	ipv6_addr_copy(&hdr->daddr, final_dst);
+
+	skb->dst = dst_clone(&rt->u.dst);
+	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, skb->dst->dev, dst_output);
+	if (err) {
+		if (err > 0)
+			err = inet->recverr ? net_xmit_errno(err) : 0;
+		if (err)
+			goto error;
+	}
+
+out:
+	inet->cork.flags &= ~IPCORK_OPT;
+	if (np->cork.opt) {
+		kfree(np->cork.opt);
+		np->cork.opt = NULL;
+	}
+	if (np->cork.rt) {
+		np->cork.rt = NULL;
+	}
+	if (np->cork.fl) {
+		np->cork.fl = NULL;
+	}
+	return err;
+error:
+	goto out;
+}
+
+void ip6_flush_pending_frames(struct sock *sk)
+{
+	struct inet_opt *inet = inet_sk(sk);
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct sk_buff *skb;
+
+	while ((skb = __skb_dequeue_tail(&sk->write_queue)) != NULL)
+		kfree_skb(skb);
+
+	inet->cork.flags &= ~IPCORK_OPT;
+
+	if (np->cork.opt) {
+		kfree(np->cork.opt);
+		np->cork.opt = NULL;
+	}
+	if (np->cork.rt) {
+		np->cork.rt = NULL;
+	}
+	if (np->cork.fl) {
+		np->cork.fl = NULL;
+	}
 }
diff -Nru a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipv6/ipcomp6.c	Mon May 19 23:48:31 2003
@@ -0,0 +1,357 @@
+/*
+ * IP Payload Compression Protocol (IPComp) for IPv6 - RFC3173
+ *
+ * Copyright (C)2003 USAGI/WIDE Project
+ *
+ * Author	Mitsuru KANDA  <mk@linux-ipv6.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ * 
+ * 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
+ */
+/* 
+ * [Memo]
+ *
+ * Outbound:
+ *  The compression of IP datagram MUST be done before AH/ESP processing, 
+ *  fragmentation, and the addition of Hop-by-Hop/Routing header. 
+ *
+ * Inbound:
+ *  The decompression of IP datagram MUST be done after the reassembly, 
+ *  AH/ESP processing.
+ */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <net/ip.h>
+#include <net/xfrm.h>
+#include <net/ipcomp.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
+#include <linux/pfkeyv2.h>
+#include <linux/random.h>
+#include <net/icmp.h>
+#include <net/ipv6.h>
+#include <linux/ipv6.h>
+#include <linux/icmpv6.h>
+
+static int ipcomp6_input(struct xfrm_state *x, struct xfrm_decap_state *decap, struct sk_buff *skb)
+{
+	int err = 0;
+	u8 nexthdr = 0;
+	u8 *prevhdr;
+	int hdr_len = skb->h.raw - skb->nh.raw;
+	unsigned char *tmp_hdr = NULL;
+	struct ipv6hdr *iph;
+	int plen, dlen;
+	struct ipcomp_data *ipcd = x->data;
+	u8 *start, *scratch = ipcd->scratch;
+
+	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
+		skb_linearize(skb, GFP_ATOMIC) != 0) {
+		err = -ENOMEM;
+		goto out;
+	}
+
+	skb->ip_summed = CHECKSUM_NONE;
+
+	/* Remove ipcomp header and decompress original payload */
+	iph = skb->nh.ipv6h;
+	tmp_hdr = kmalloc(hdr_len, GFP_ATOMIC);
+	if (!tmp_hdr)
+		goto out;
+	memcpy(tmp_hdr, iph, hdr_len);
+	nexthdr = *(u8 *)skb->data;
+	skb_pull(skb, sizeof(struct ipv6_comp_hdr)); 
+	skb->nh.raw += sizeof(struct ipv6_comp_hdr);
+	memcpy(skb->nh.raw, tmp_hdr, hdr_len);
+	iph = skb->nh.ipv6h;
+	iph->payload_len = htons(ntohs(iph->payload_len) - sizeof(struct ipv6_comp_hdr));
+	skb->h.raw = skb->data;
+
+	/* decompression */
+	plen = skb->len;
+	dlen = IPCOMP_SCRATCH_SIZE;
+	start = skb->data;
+
+	err = crypto_comp_decompress(ipcd->tfm, start, plen, scratch, &dlen);
+	if (err) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (dlen < (plen + sizeof(struct ipv6_comp_hdr))) {
+		err = -EINVAL;
+		goto out;
+	}
+
+	err = pskb_expand_head(skb, 0, dlen - plen, GFP_ATOMIC);
+	if (err) {
+		goto out;
+	}
+
+	skb_put(skb, dlen - plen);
+	memcpy(skb->data, scratch, dlen);
+
+	iph = skb->nh.ipv6h;
+	iph->payload_len = htons(skb->len);
+	
+	ip6_found_nexthdr(skb, &prevhdr);
+	*prevhdr = nexthdr;
+out:
+	if (tmp_hdr)
+		kfree(tmp_hdr);
+	if (err)
+		goto error_out;
+	return nexthdr;
+error_out:
+	return err;
+}
+
+static int ipcomp6_output(struct sk_buff *skb)
+{
+	int err;
+	struct dst_entry *dst = skb->dst;
+	struct xfrm_state *x = dst->xfrm;
+	struct ipv6hdr *tmp_iph = NULL, *iph, *top_iph;
+	int hdr_len = 0;
+	struct ipv6_comp_hdr *ipch;
+	struct ipcomp_data *ipcd = x->data;
+	u8 *prevhdr;
+	u8 nexthdr = 0;
+	int plen, dlen;
+	u8 *start, *scratch = ipcd->scratch;
+
+	if (skb->ip_summed == CHECKSUM_HW && skb_checksum_help(skb) == NULL) {
+		err = -EINVAL;
+		goto error_nolock;
+	}
+
+	spin_lock_bh(&x->lock);
+
+	err = xfrm_check_output(x, skb, AF_INET6);
+	if (err)
+		goto error;
+
+	if (x->props.mode) {
+		hdr_len = sizeof(struct ipv6hdr);
+		nexthdr = IPPROTO_IPV6;
+		iph = skb->nh.ipv6h;
+		top_iph = (struct ipv6hdr *)skb_push(skb, sizeof(struct ipv6hdr));
+		top_iph->version = 6;
+		top_iph->priority = iph->priority;
+		top_iph->flow_lbl[0] = iph->flow_lbl[0];
+		top_iph->flow_lbl[1] = iph->flow_lbl[1];
+		top_iph->flow_lbl[2] = iph->flow_lbl[2];
+		top_iph->nexthdr = IPPROTO_IPV6; /* initial */
+		top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+		top_iph->hop_limit = iph->hop_limit;
+		memcpy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr, sizeof(struct in6_addr));
+		memcpy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr, sizeof(struct in6_addr));
+		skb->nh.raw = skb->data; /* == top_iph */
+		skb->h.raw = skb->nh.raw + hdr_len;
+	} else {
+		hdr_len = ip6_found_nexthdr(skb, &prevhdr);
+		nexthdr = *prevhdr;
+	}
+
+	/* check whether datagram len is larger than threshold */
+	if ((skb->len - hdr_len) < ipcd->threshold) {
+		goto out_ok;
+	}
+
+	if ((skb_is_nonlinear(skb) || skb_cloned(skb)) &&
+		skb_linearize(skb, GFP_ATOMIC) != 0) {
+		err = -ENOMEM;
+		goto error;
+	}
+
+	/* compression */
+	plen = skb->len - hdr_len;
+	dlen = IPCOMP_SCRATCH_SIZE;
+	start = skb->data + hdr_len;
+
+	err = crypto_comp_compress(ipcd->tfm, start, plen, scratch, &dlen);
+	if (err) {
+		goto error;
+	}
+	if ((dlen + sizeof(struct ipv6_comp_hdr)) >= plen) {
+		goto out_ok;
+	}
+	memcpy(start, scratch, dlen);
+	pskb_trim(skb, hdr_len+dlen);
+
+	/* insert ipcomp header and replace datagram */
+	tmp_iph = kmalloc(hdr_len, GFP_ATOMIC);
+	if (!tmp_iph) {
+		err = -ENOMEM;
+		goto error;
+	}
+	memcpy(tmp_iph, skb->nh.raw, hdr_len);
+	top_iph = (struct ipv6hdr*)skb_push(skb, sizeof(struct ipv6_comp_hdr));
+	memcpy(top_iph, tmp_iph, hdr_len);
+	kfree(tmp_iph);
+
+	top_iph->payload_len = htons(skb->len - sizeof(struct ipv6hdr));
+	skb->nh.raw = skb->data; /* top_iph */
+	ip6_found_nexthdr(skb, &prevhdr); 
+	*prevhdr = IPPROTO_COMP;
+
+	ipch = (struct ipv6_comp_hdr *)((unsigned char *)top_iph + hdr_len);
+	ipch->nexthdr = nexthdr;
+	ipch->flags = 0;
+	ipch->cpi = htons((u16 )ntohl(x->id.spi));
+
+	skb->h.raw = (unsigned char*)ipch;
+out_ok:
+	x->curlft.bytes += skb->len;
+	x->curlft.packets++;
+	spin_unlock_bh(&x->lock);
+
+	if ((skb->dst = dst_pop(dst)) == NULL) {
+		err = -EHOSTUNREACH;
+		goto error_nolock;
+	}
+	err = NET_XMIT_BYPASS;
+
+out_exit:
+	return err;
+error:
+	spin_unlock_bh(&x->lock);
+error_nolock:
+	kfree_skb(skb);
+	goto out_exit;
+}
+
+static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+		                int type, int code, int offset, __u32 info)
+{
+	u32 spi;
+	struct ipv6hdr *iph = (struct ipv6hdr*)skb->data;
+	struct ipv6_comp_hdr *ipcomph = (struct ipv6_comp_hdr*)(skb->data+offset);
+	struct xfrm_state *x;
+
+	if (type != ICMPV6_DEST_UNREACH || type != ICMPV6_PKT_TOOBIG)
+		return;
+
+	spi = ntohl(ntohs(ipcomph->cpi));
+	x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6);
+	if (!x)
+		return;
+
+	printk(KERN_DEBUG "pmtu discvovery on SA IPCOMP/%08x/"
+			"%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+			spi, NIP6(iph->daddr));
+	xfrm_state_put(x);
+}
+
+static void ipcomp6_free_data(struct ipcomp_data *ipcd)
+{
+	if (ipcd->tfm)
+		crypto_free_tfm(ipcd->tfm);
+	if (ipcd->scratch)
+		kfree(ipcd->scratch);
+}
+
+static void ipcomp6_destroy(struct xfrm_state *x)
+{
+	struct ipcomp_data *ipcd = x->data;
+	ipcomp6_free_data(ipcd);
+	kfree(ipcd);
+}
+
+static int ipcomp6_init_state(struct xfrm_state *x, void *args)
+{
+	int err = -ENOMEM;
+	struct ipcomp_data *ipcd;
+	struct xfrm_algo_desc *calg_desc;
+
+	ipcd = kmalloc(sizeof(*ipcd), GFP_KERNEL);
+	if (!ipcd)
+		goto error;
+
+	memset(ipcd, 0, sizeof(*ipcd));
+	x->props.header_len = sizeof(struct ipv6_comp_hdr);
+	if (x->props.mode)
+		x->props.header_len += sizeof(struct ipv6hdr);
+	x->data = ipcd;
+	
+	ipcd->scratch = kmalloc(IPCOMP_SCRATCH_SIZE, GFP_KERNEL);
+	if (!ipcd->scratch)
+		goto error;
+
+	ipcd->tfm = crypto_alloc_tfm(x->calg->alg_name, 0);
+	if (!ipcd->tfm)
+		goto error;
+
+	calg_desc = xfrm_calg_get_byname(x->calg->alg_name);
+	BUG_ON(!calg_desc);
+	ipcd->threshold = calg_desc->uinfo.comp.threshold;
+	err = 0;
+out:
+	return err;
+error:
+	if (ipcd) {
+		ipcomp6_free_data(ipcd);
+		kfree(ipcd);
+	}
+
+	goto out;
+}
+
+static struct xfrm_type ipcomp6_type = 
+{
+	.description	= "IPCOMP6",
+	.owner		= THIS_MODULE,
+	.proto		= IPPROTO_COMP,
+	.init_state	= ipcomp6_init_state,
+	.destructor	= ipcomp6_destroy,
+	.input		= ipcomp6_input,
+	.output		= ipcomp6_output,
+};
+
+static struct inet6_protocol ipcomp6_protocol = 
+{
+	.handler	= xfrm6_rcv,
+	.err_handler	= ipcomp6_err,
+	.flags		= INET6_PROTO_NOPOLICY,
+};
+
+static int __init ipcomp6_init(void)
+{
+	if (xfrm_register_type(&ipcomp6_type, AF_INET6) < 0) {
+		printk(KERN_INFO "ipcomp6 init: can't add xfrm type\n");
+		return -EAGAIN;
+	}
+	if (inet6_add_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0) {
+		printk(KERN_INFO "ipcomp6 init: can't add protocol\n");
+		xfrm_unregister_type(&ipcomp6_type, AF_INET6);
+		return -EAGAIN;
+	}
+	return 0;
+}
+
+static void __exit ipcomp6_fini(void)
+{
+	if (inet6_del_protocol(&ipcomp6_protocol, IPPROTO_COMP) < 0) 
+		printk(KERN_INFO "ipv6 ipcomp close: can't remove protocol\n");
+	if (xfrm_unregister_type(&ipcomp6_type, AF_INET6) < 0)
+		printk(KERN_INFO "ipv6 ipcomp close: can't remove xfrm type\n");
+}
+
+module_init(ipcomp6_init);
+module_exit(ipcomp6_fini);
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("IP Payload Compression Protocol (IPComp) for IPv6 - RFC3173");
+MODULE_AUTHOR("Mitsuru KANDA <mk@linux-ipv6.org>");
+
+
diff -Nru a/net/ipv6/ipv6_syms.c b/net/ipv6/ipv6_syms.c
--- a/net/ipv6/ipv6_syms.c	Fri Apr 25 22:13:35 2003
+++ b/net/ipv6/ipv6_syms.c	Fri May 16 14:02:36 2003
@@ -35,5 +35,6 @@
 EXPORT_SYMBOL(in6addr_any);
 EXPORT_SYMBOL(in6addr_loopback);
 EXPORT_SYMBOL(in6_dev_finish_destroy);
+EXPORT_SYMBOL(ip6_found_nexthdr);
 EXPORT_SYMBOL(xfrm6_rcv);
 EXPORT_SYMBOL(xfrm6_clear_mutable_options);
diff -Nru a/net/ipv6/mcast.c b/net/ipv6/mcast.c
--- a/net/ipv6/mcast.c	Tue Apr 29 03:18:55 2003
+++ b/net/ipv6/mcast.c	Mon May 19 23:49:42 2003
@@ -20,7 +20,7 @@
  *	yoshfuji	: fix format of router-alert option
  *	YOSHIFUJI Hideaki @USAGI:
  *		Fixed source address for MLD message based on
- *		<draft-ietf-magma-mld-source-02.txt>.
+ *		<draft-ietf-magma-mld-source-05.txt>.
  *	YOSHIFUJI Hideaki @USAGI:
  *		- Ignore Queries for invalid addresses.
  *		- MLD for link-local addresses.
@@ -179,7 +179,7 @@
 		return -ENOMEM;
 
 	mc_lst->next = NULL;
-	memcpy(&mc_lst->addr, addr, sizeof(struct in6_addr));
+	ipv6_addr_copy(&mc_lst->addr, addr);
 
 	if (ifindex == 0) {
 		struct rt6_info *rt;
@@ -825,7 +825,7 @@
 	mc->mca_timer.function = igmp6_timer_handler;
 	mc->mca_timer.data = (unsigned long) mc;
 
-	memcpy(&mc->mca_addr, addr, sizeof(struct in6_addr));
+	ipv6_addr_copy(&mc->mca_addr, addr);
 	mc->idev = idev;
 	mc->mca_users = 1;
 	atomic_set(&mc->mca_refcnt, 2);
@@ -1227,7 +1227,7 @@
 	}
 
 	if (ipv6_get_lladdr(dev, &addr_buf)) {
-		/* <draft-ietf-magma-mld-source-02.txt>:
+		/* <draft-ietf-magma-mld-source-05.txt>:
 		 * use unspecified address as the source address 
 		 * when a valid link-local address is not available.
 		 */
@@ -1559,7 +1559,7 @@
 	}
 
 	if (ipv6_get_lladdr(dev, &addr_buf)) {
-		/* <draft-ietf-magma-mld-source-02.txt>:
+		/* <draft-ietf-magma-mld-source-05.txt>:
 		 * use unspecified address as the source address 
 		 * when a valid link-local address is not available.
 		 */
diff -Nru a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
--- a/net/ipv6/ndisc.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv6/ndisc.c	Thu May 15 23:27:55 2003
@@ -232,6 +232,9 @@
 	case ARPHRD_IEEE802_TR:
 		ipv6_tr_mc_map(addr,buf);
 		return 0;
+	case ARPHRD_ARCNET:
+		ipv6_arcnet_mc_map(addr, buf);
+		return 0;
 	default:
 		if (dir) {
 			memcpy(buf, dev->broadcast, dev->addr_len);
@@ -394,7 +397,7 @@
 	rt->rt6i_expires  = 0;
 	rt->rt6i_flags    = RTF_LOCAL;
 	rt->rt6i_metric   = 0;
-	rt->rt6i_hoplimit = 255;
+	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
 	rt->u.dst.output  = ndisc_output;
 }
 
@@ -976,7 +979,7 @@
 				struct rt6_info *rt;
 				rt = rt6_get_dflt_router(saddr, dev);
 				if (rt)
-					ip6_del_rt(rt, NULL);
+					ip6_del_rt(rt, NULL, NULL);
 			}
 		} else {
 			if (msg->icmph.icmp6_router)
@@ -1050,7 +1053,7 @@
 	rt = rt6_get_dflt_router(&skb->nh.ipv6h->saddr, skb->dev);
 
 	if (rt && lifetime == 0) {
-		ip6_del_rt(rt, NULL);
+		ip6_del_rt(rt, NULL, NULL);
 		rt = NULL;
 	}
 
diff -Nru a/net/ipv6/netfilter/ip6_tables.c b/net/ipv6/netfilter/ip6_tables.c
--- a/net/ipv6/netfilter/ip6_tables.c	Wed Apr  9 22:08:17 2003
+++ b/net/ipv6/netfilter/ip6_tables.c	Sat May 17 12:39:13 2003
@@ -527,11 +527,8 @@
 
 	ret = find_inlist_lock_noload(head, name, error, mutex);
 	if (!ret) {
-		char modulename[IP6T_FUNCTION_MAXNAMELEN + strlen(prefix) + 1];
-		strcpy(modulename, prefix);
-		strcat(modulename, name);
-		duprintf("find_inlist: loading `%s'.\n", modulename);
-		request_module(modulename);
+		duprintf("find_inlist: loading `%s%s'.\n", prefix, name);
+		request_module("%s%s", prefix, name);
 		ret = find_inlist_lock_noload(head, name, error, mutex);
 	}
 
diff -Nru a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c
--- a/net/ipv6/netfilter/ip6t_LOG.c	Mon Apr 28 02:35:56 2003
+++ b/net/ipv6/netfilter/ip6t_LOG.c	Mon May 19 23:48:31 2003
@@ -25,16 +25,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-#define NIP6(addr) \
-	ntohs((addr).s6_addr16[0]), \
-	ntohs((addr).s6_addr16[1]), \
-	ntohs((addr).s6_addr16[2]), \
-	ntohs((addr).s6_addr16[3]), \
-	ntohs((addr).s6_addr16[4]), \
-	ntohs((addr).s6_addr16[5]), \
-	ntohs((addr).s6_addr16[6]), \
-	ntohs((addr).s6_addr16[7])
-
 struct esphdr {
 	__u32   spi;
 }; /* FIXME evil kludge */
diff -Nru a/net/ipv6/netfilter/ip6t_ah.c b/net/ipv6/netfilter/ip6t_ah.c
--- a/net/ipv6/netfilter/ip6t_ah.c	Thu Mar 20 00:49:19 2003
+++ b/net/ipv6/netfilter/ip6t_ah.c	Sun May  4 18:18:36 2003
@@ -19,13 +19,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-struct ahhdr {
-       __u8    nexthdr;
-       __u8    hdrlen;
-       __u16   reserved;
-       __u32   spi;
-};
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
@@ -48,7 +41,7 @@
       u_int16_t datalen,
       int *hotdrop)
 {
-       struct ahhdr *ah = NULL;
+       struct ip_auth_hdr *ah = NULL;
        const struct ip6t_ah *ahinfo = matchinfo;
        unsigned int temp;
        int len;
@@ -128,12 +121,12 @@
        /* AH header not found */
        if ( temp != MASK_AH ) return 0;
 
-       if (len < (int)sizeof(struct ahhdr)){
+       if (len < (int)sizeof(struct ip_auth_hdr)){
 	       *hotdrop = 1;
        		return 0;
        }
 
-       ah=skb->data+ptr;
+       ah = (struct ip_auth_hdr *) (skb->data + ptr);
 
        DEBUGP("IPv6 AH LEN %u %u ", hdrlen, ah->hdrlen);
        DEBUGP("RES %04X ", ah->reserved);
diff -Nru a/net/ipv6/netfilter/ip6t_esp.c b/net/ipv6/netfilter/ip6t_esp.c
--- a/net/ipv6/netfilter/ip6t_esp.c	Thu Mar 20 00:49:19 2003
+++ b/net/ipv6/netfilter/ip6t_esp.c	Sun May  4 18:16:34 2003
@@ -19,10 +19,6 @@
 #define DEBUGP(format, args...)
 #endif
 
-struct esphdr {
-	__u32   spi;
-};
-
 /* Returns 1 if the spi is matched by the range, 0 otherwise */
 static inline int
 spi_match(u_int32_t min, u_int32_t max, u_int32_t spi, int invert)
@@ -45,7 +41,7 @@
       u_int16_t datalen,
       int *hotdrop)
 {
-	struct esphdr *esp = NULL;
+	struct ip_esp_hdr *esp = NULL;
 	const struct ip6t_esp *espinfo = matchinfo;
 	unsigned int temp;
 	int len;
@@ -118,12 +114,12 @@
 	/* ESP header not found */
 	if ( temp != MASK_ESP ) return 0;
 
-       if (len < (int)sizeof(struct esphdr)){
+       if (len < (int)sizeof(struct ip_esp_hdr)){
 	       *hotdrop = 1;
        		return 0;
        }
 
-	esp=skb->data+ptr;
+	esp = (struct ip_esp_hdr *) (skb->data + ptr);
 
 	DEBUGP("IPv6 ESP SPI %u %08X\n", ntohl(esp->spi), ntohl(esp->spi));
 
diff -Nru a/net/ipv6/netfilter/ip6t_frag.c b/net/ipv6/netfilter/ip6t_frag.c
--- a/net/ipv6/netfilter/ip6t_frag.c	Thu Mar 20 00:49:19 2003
+++ b/net/ipv6/netfilter/ip6t_frag.c	Sun May  4 18:13:39 2003
@@ -147,7 +147,7 @@
        		return 0;
        }
 
-       frag=skb->data+ptr;
+       frag = (struct fraghdr *) (skb->data + ptr);
 
        DEBUGP("IPv6 FRAG LEN %u %u ", hdrlen, frag->hdrlen);
        DEBUGP("INFO %04X ", frag->info);
diff -Nru a/net/ipv6/netfilter/ip6t_ipv6header.c b/net/ipv6/netfilter/ip6t_ipv6header.c
--- a/net/ipv6/netfilter/ip6t_ipv6header.c	Thu Mar 20 00:49:19 2003
+++ b/net/ipv6/netfilter/ip6t_ipv6header.c	Sun May  4 18:12:36 2003
@@ -18,12 +18,6 @@
 MODULE_DESCRIPTION("IPv6 headers match");
 MODULE_AUTHOR("Andras Kis-Szabo <kisza@sch.bme.hu>");
 
-#if 0
-#define DEBUGP printk
-#else
-#define DEBUGP(format, args...)
-#endif
-
 static int
 ipv6header_match(const struct sk_buff *skb,
 		 const struct net_device *in,
@@ -39,10 +33,8 @@
 	int len;
 	u8 nexthdr;
 	unsigned int ptr;
-        struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb;
 
 	/* Make sure this isn't an evil packet */
-	DEBUGP("ipv6_header entered \n");
 
 	/* type of the 1st exthdr */
 	nexthdr = skb->nh.ipv6h->nexthdr;
@@ -52,44 +44,10 @@
 	len = skb->len - ptr;
 	temp = 0;
 
-	DEBUGP("ipv6_header nexthdr %02X \n",nexthdr);
-	DEBUGP("ipv6_header ptr %08X \n",ptr);
-	DEBUGP("ipv6_header skblen %04X \n",skb->len);
-	DEBUGP("ipv6_header skbdatalen %04X \n",skb->data_len);
-	DEBUGP("ipv6_header len %04X \n",len);
-#if 0
-	for (temp=0;temp<skb->len;temp++){
-		if (!(temp % 16 )) DEBUGP("\nipv6_header data ");
-		DEBUGP("%02X ",skb->data[temp]);
-	}
-#endif
-	DEBUGP("\nipv6_header h.raw %02X %02X %02X %02X \n",
-			skb->h.raw[0],
-			skb->h.raw[1],
-			skb->h.raw[2],
-			skb->h.raw[3]);
-	DEBUGP("ipv6_header nh.raw %02X %02X %02X %02X \n",
-			skb->nh.raw[0],
-			skb->nh.raw[1],
-			skb->nh.raw[2],
-			skb->nh.raw[3]);
-	DEBUGP("ipv6_header CB %02X %02X %02X %02X %02X %02X %02X \n",
-			opt->iif,
-			opt->ra,
-			opt->hop,
-			opt->auth,
-			opt->dst0,
-			opt->srcrt,
-			opt->dst1);
-
-	temp = 0;
-
         while (ip6t_ext_hdr(nexthdr)) {
         	struct ipv6_opt_hdr *hdr;
         	int hdrlen;
 
-		DEBUGP("ipv6_header header iteration \n");
-
 		/* Is there enough space for the next ext header? */
                 if (len < (int)sizeof(struct ipv6_opt_hdr))
                         return 0;
@@ -114,8 +72,6 @@
                 else
                         hdrlen = ipv6_optlen(hdr);
 
-		DEBUGP("ipv6_header hdrlen %04X \n",hdrlen);
-
 		/* set the flag */
 		switch (nexthdr){
 			case NEXTHDR_HOP:
@@ -134,7 +90,6 @@
 				temp |= MASK_DSTOPTS;
 				break;
 			default:
-				DEBUGP("IPV6HEADER match: unknown nextheader %u\n",nexthdr);
 				return 0;
 				break;
 		}
@@ -142,17 +97,13 @@
                 nexthdr = hdr->nexthdr;
                 len -= hdrlen;
                 ptr += hdrlen;
-		if ( ptr > skb->len ) {
-			DEBUGP("ipv6_header new ptr %04X \n",ptr);
+		if (ptr > skb->len)
 			break;
-		}
         }
 
 	if ( (nexthdr != NEXTHDR_NONE ) && (nexthdr != NEXTHDR_ESP) )
 		temp |= MASK_PROTO;
 
-	DEBUGP ("ipv6header: %02X %02X \n", temp, info->matchflags);
-
 	if (info->modeflag)
 		return (!( (temp & info->matchflags)
 			^ info->matchflags) ^ info->invflags);
@@ -169,11 +120,8 @@
 {
 	/* Check for obvious errors */
 	/* This match is valid in all hooks! */
-	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info))) {
-		DEBUGP("ip6t_ipv6header: matchsize != %u\n",
-			 IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)));
+	if (matchsize != IP6T_ALIGN(sizeof(struct ip6t_ipv6header_info)))
 		return 0;
-	}
 
 	return 1;
 }
diff -Nru a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
--- a/net/ipv6/netfilter/ip6t_rt.c	Thu Mar 20 00:49:19 2003
+++ b/net/ipv6/netfilter/ip6t_rt.c	Sun May  4 18:07:00 2003
@@ -130,7 +130,7 @@
        		return 0;
        }
 
-       route=skb->data+ptr;
+       route = (struct ipv6_rt_hdr *) (skb->data + ptr);
 
        DEBUGP("IPv6 RT LEN %u %u ", hdrlen, route->hdrlen);
        DEBUGP("TYPE %04X ", route->type);
diff -Nru a/net/ipv6/proc.c b/net/ipv6/proc.c
--- a/net/ipv6/proc.c	Fri Apr 25 21:06:34 2003
+++ b/net/ipv6/proc.c	Mon May 19 23:49:42 2003
@@ -67,7 +67,7 @@
 #define SNMP6_SENTINEL	{ .name = NULL, .offset = 0 }
 
 static struct snmp6_item snmp6_ipv6_list[] = {
-/* ipv6 mib according to draft-ietf-ipngwg-ipv6-mib-04 */
+/* ipv6 mib according to RFC 2465 */
 #define SNMP6_GEN(x) { .name = #x , .offset = offsetof(struct ipv6_mib, x) }
 	SNMP6_GEN(Ip6InReceives),
 	SNMP6_GEN(Ip6InHdrErrors),
@@ -96,7 +96,7 @@
 };
 
 static struct snmp6_item snmp6_icmp6_list[] = {
-/* icmpv6 mib according to draft-ietf-ipngwg-ipv6-icmp-mib-02
+/* icmpv6 mib according to RFC 2466
 
    Exceptions:  {In|Out}AdminProhibs are removed, because I see
                 no good reasons to account them separately
@@ -198,6 +198,7 @@
 }
 
 static struct file_operations sockstat6_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open	 = sockstat6_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
@@ -210,6 +211,7 @@
 }
 
 static struct file_operations snmp6_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open	 = snmp6_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
diff -Nru a/net/ipv6/protocol.c b/net/ipv6/protocol.c
--- a/net/ipv6/protocol.c	Tue Oct  8 16:44:53 2002
+++ b/net/ipv6/protocol.c	Sun May 11 13:53:56 2003
@@ -32,7 +32,6 @@
 #include <linux/in6.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
-#include <linux/brlock.h>
 
 #include <net/sock.h>
 #include <net/snmp.h>
@@ -41,12 +40,14 @@
 #include <net/protocol.h>
 
 struct inet6_protocol *inet6_protos[MAX_INET_PROTOS];
+static spinlock_t inet6_proto_lock = SPIN_LOCK_UNLOCKED;
+
 
 int inet6_add_protocol(struct inet6_protocol *prot, unsigned char protocol)
 {
 	int ret, hash = protocol & (MAX_INET_PROTOS - 1);
 
-	br_write_lock_bh(BR_NETPROTO_LOCK);
+	spin_lock_bh(&inet6_proto_lock);
 
 	if (inet6_protos[hash]) {
 		ret = -1;
@@ -55,7 +56,7 @@
 		ret = 0;
 	}
 
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	spin_unlock_bh(&inet6_proto_lock);
 
 	return ret;
 }
@@ -68,7 +69,7 @@
 {
 	int ret, hash = protocol & (MAX_INET_PROTOS - 1);
 
-	br_write_lock_bh(BR_NETPROTO_LOCK);
+	spin_lock_bh(&inet6_proto_lock);
 
 	if (inet6_protos[hash] != prot) {
 		ret = -1;
@@ -77,7 +78,9 @@
 		ret = 0;
 	}
 
-	br_write_unlock_bh(BR_NETPROTO_LOCK);
+	spin_unlock_bh(&inet6_proto_lock);
+
+	synchronize_net();
 
 	return ret;
 }
diff -Nru a/net/ipv6/raw.c b/net/ipv6/raw.c
--- a/net/ipv6/raw.c	Thu Apr 17 18:56:05 2003
+++ b/net/ipv6/raw.c	Thu May 15 23:27:55 2003
@@ -12,6 +12,7 @@
  *	Fixes:
  *	Hideaki YOSHIFUJI	:	sin6_scope_id support
  *	YOSHIFUJI,H.@USAGI	:	raw checksum (RFC2292(bis) compliance) 
+ *	Kazunori MIYAZAWA @USAGI:	change process style to use ip6_append_data
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -29,6 +30,8 @@
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/icmpv6.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 
@@ -47,6 +50,9 @@
 #include <net/rawv6.h>
 #include <net/xfrm.h>
 
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
 struct sock *raw_v6_htable[RAWV6_HTABLE_SIZE];
 rwlock_t raw_v6_lock = RW_LOCK_UNLOCKED;
 
@@ -392,8 +398,7 @@
 	/* Copy the address. */
 	if (sin6) {
 		sin6->sin6_family = AF_INET6;
-		memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr, 
-		       sizeof(struct in6_addr));
+		ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
 		sin6->sin6_flowinfo = 0;
 		sin6->sin6_scope_id = 0;
 		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
@@ -435,87 +440,115 @@
 	goto out_free;
 }
 
-/*
- *	Sending...
- */
+static int rawv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct raw6_opt *opt, int len)
+{
+	struct sk_buff *skb;
+	int err = 0;
+	u16 *csum;
 
-struct rawv6_fakehdr {
-	struct iovec	*iov;
-	struct sock	*sk;
-	__u32		len;
-	__u32		cksum;
-	__u32		proto;
-	struct in6_addr *daddr;
-};
+	if ((skb = skb_peek(&sk->write_queue)) == NULL)
+		goto out;
 
-static int rawv6_getfrag(const void *data, struct in6_addr *saddr, 
-			  char *buff, unsigned int offset, unsigned int len)
-{
-	struct iovec *iov = (struct iovec *) data;
+	if (opt->offset + 1 < len)
+		csum = (u16 *)(skb->h.raw + opt->offset);
+	else {
+		err = -EINVAL;
+		goto out;
+	}
+
+	if (skb_queue_len(&sk->write_queue) == 1) {
+		/*
+		 * Only one fragment on the socket.
+		 */
+		/* should be check HW csum miyazawa */
+		*csum = csum_ipv6_magic(fl->fl6_src,
+					     fl->fl6_dst,
+					     len, fl->proto, skb->csum);
+	} else {
+		u32 tmp_csum = 0;
 
-	return memcpy_fromiovecend(buff, iov, offset, len);
+		skb_queue_walk(&sk->write_queue, skb) {
+			tmp_csum = csum_add(tmp_csum, skb->csum);
+		}
+
+		tmp_csum = csum_ipv6_magic(fl->fl6_src,
+					fl->fl6_dst,
+					len, fl->proto, tmp_csum);
+		*csum = tmp_csum;
+	}
+	if (*csum == 0)
+		*csum = -1;
+	ip6_push_pending_frames(sk);
+out:
+	return err;
 }
 
-static int rawv6_frag_cksum(const void *data, struct in6_addr *addr,
-			     char *buff, unsigned int offset, 
-			     unsigned int len)
+static int rawv6_send_hdrinc(struct sock *sk, void *from, int length,
+			struct flowi *fl, struct rt6_info *rt, 
+			unsigned int flags)
 {
-	struct rawv6_fakehdr *hdr = (struct rawv6_fakehdr *) data;
-	
-	if (csum_partial_copy_fromiovecend(buff, hdr->iov, offset, 
-						    len, &hdr->cksum))
-		return -EFAULT;
-	
-	if (offset == 0) {
-		struct sock *sk;
-		struct raw6_opt *opt;
-		struct in6_addr *daddr;
-		
-		sk = hdr->sk;
-		opt = raw6_sk(sk);
+	struct inet_opt *inet = inet_sk(sk);
+	struct ipv6hdr *iph;
+	struct sk_buff *skb;
+	unsigned int hh_len;
+	int err;
 
-		if (hdr->daddr)
-			daddr = hdr->daddr;
-		else
-			daddr = addr + 1;
-		
-		hdr->cksum = csum_ipv6_magic(addr, daddr, hdr->len,
-					     hdr->proto, hdr->cksum);
-		
-		if (opt->offset + 1 < len) {
-			__u16 *csum;
+	if (length > rt->u.dst.dev->mtu) {
+		ipv6_local_error(sk, EMSGSIZE, fl, rt->u.dst.dev->mtu);
+		return -EMSGSIZE;
+	}
+	if (flags&MSG_PROBE)
+		goto out;
 
-			csum = (__u16 *) (buff + opt->offset);
-			if (*csum) {
-				/* in case cksum was not initialized */
-				__u32 sum = hdr->cksum;
-				sum += *csum;
-				*csum = hdr->cksum = (sum + (sum>>16));
-			} else {
-				*csum = hdr->cksum;
-			}
-		} else {
-			if (net_ratelimit())
-				printk(KERN_DEBUG "icmp: cksum offset too big\n");
-			return -EINVAL;
-		}
-	}	
-	return 0; 
-}
+	hh_len = LL_RESERVED_SPACE(rt->u.dst.dev);
+
+	skb = sock_alloc_send_skb(sk, length+hh_len+15,
+				  flags&MSG_DONTWAIT, &err);
+	if (skb == NULL)
+		goto error; 
+	skb_reserve(skb, hh_len);
+
+	skb->priority = sk->priority;
+	skb->dst = dst_clone(&rt->u.dst);
 
+	skb->nh.ipv6h = iph = (struct ipv6hdr *)skb_put(skb, length);
 
+	skb->ip_summed = CHECKSUM_NONE;
+
+	skb->h.raw = skb->nh.raw;
+	err = memcpy_fromiovecend((void *)iph, from, 0, length);
+	if (err)
+		goto error_fault;
+
+	err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, rt->u.dst.dev,
+		      dst_output);
+	if (err > 0)
+		err = inet->recverr ? net_xmit_errno(err) : 0;
+	if (err)
+		goto error;
+out:
+	return 0;
+
+error_fault:
+	err = -EFAULT;
+	kfree_skb(skb);
+error:
+	IP6_INC_STATS(Ip6OutDiscards);
+	return err; 
+}
 static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int len)
 {
 	struct ipv6_txoptions opt_space;
 	struct sockaddr_in6 * sin6 = (struct sockaddr_in6 *) msg->msg_name;
+	struct in6_addr *daddr, *saddr = NULL;
 	struct inet_opt *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct raw6_opt *raw_opt = raw6_sk(sk);
 	struct ipv6_txoptions *opt = NULL;
 	struct ip6_flowlabel *flowlabel = NULL;
+	struct dst_entry *dst = NULL;
 	struct flowi fl;
 	int addr_len = msg->msg_namelen;
-	struct in6_addr *daddr;
-	struct raw6_opt *raw_opt;
 	int hlimit = -1;
 	u16 proto;
 	int err;
@@ -549,6 +582,8 @@
 
 		if (!proto)
 			proto = inet->num;
+		else if (proto != inet->num)
+			return(-EINVAL);
 
 		if (proto > 255)
 			return(-EINVAL);
@@ -587,6 +622,7 @@
 		 * unspecfied destination address 
 		 * treated as error... is this correct ?
 		 */
+		fl6_sock_release(flowlabel);
 		return(-EINVAL);
 	}
 
@@ -616,39 +652,71 @@
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
 
-	raw_opt = raw6_sk(sk);
-
 	fl.proto = proto;
 	fl.fl6_dst = daddr;
 	if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr))
 		fl.fl6_src = &np->saddr;
 	fl.fl_icmp_type = 0;
 	fl.fl_icmp_code = 0;
-	
-	if (raw_opt->checksum) {
-		struct rawv6_fakehdr hdr;
-		
-		hdr.iov = msg->msg_iov;
-		hdr.sk  = sk;
-		hdr.len = len;
-		hdr.cksum = 0;
-		hdr.proto = proto;
 
-		if (opt && opt->srcrt)
-			hdr.daddr = daddr;
+	/* merge ip6_build_xmit from ip6_output */
+	if (opt && opt->srcrt) {
+		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+		fl.fl6_dst = rt0->addr;
+	}
+
+	if (!fl.oif && ipv6_addr_is_multicast(fl.nl_u.ip6_u.daddr))
+		fl.oif = np->mcast_oif;
+
+	err = ip6_dst_lookup(sk, &dst, &fl, &saddr);
+	if (err) goto out;
+
+	if (hlimit < 0) {
+		if (ipv6_addr_is_multicast(fl.fl6_dst))
+			hlimit = np->mcast_hops;
 		else
-			hdr.daddr = NULL;
+			hlimit = np->hop_limit;
+		if (hlimit < 0)
+			hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+	}
 
-		err = ip6_build_xmit(sk, rawv6_frag_cksum, &hdr, &fl, len,
-				     opt, hlimit, msg->msg_flags);
+	if (msg->msg_flags&MSG_CONFIRM)
+		goto do_confirm;
+
+back_from_confirm:
+	if (inet->hdrincl) {
+		err = rawv6_send_hdrinc(sk, msg->msg_iov, len, &fl, (struct rt6_info*)dst, msg->msg_flags);
 	} else {
-		err = ip6_build_xmit(sk, rawv6_getfrag, msg->msg_iov, &fl, len,
-				     opt, hlimit, msg->msg_flags);
+		lock_sock(sk);
+		err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0,
+					hlimit, opt, &fl, (struct rt6_info*)dst, msg->msg_flags);
+
+		if (err)
+			ip6_flush_pending_frames(sk);
+		else if (!(msg->msg_flags & MSG_MORE)) {
+			if (raw_opt->checksum) {
+				err = rawv6_push_pending_frames(sk, &fl, raw_opt, len);
+			} else {
+				err = ip6_push_pending_frames(sk);
+			}
+		}
 	}
+done:
+	ip6_dst_store(sk, dst, fl.nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
+	if (err > 0)
+		err = np->recverr ? net_xmit_errno(err) : 0;
 
+	release_sock(sk);
+out:	
 	fl6_sock_release(flowlabel);
-
+	if (saddr) kfree(saddr);
 	return err<0?err:len;
+do_confirm:
+	dst_confirm(dst);
+	if (!(msg->msg_flags & MSG_PROBE) || len)
+		goto back_from_confirm;
+	err = 0;
+	goto done;
 }
 
 static int rawv6_seticmpfilter(struct sock *sk, int level, int optname, 
@@ -831,80 +899,6 @@
 	return(0);
 }
 
-#define LINE_LEN 190
-#define LINE_FMT "%-190s\n"
-
-static void get_raw6_sock(struct sock *sp, char *tmpbuf, int i)
-{
-	struct ipv6_pinfo *np = inet6_sk(sp);
-	struct in6_addr *dest, *src;
-	__u16 destp, srcp;
-
-	dest  = &np->daddr;
-	src   = &np->rcv_saddr;
-	destp = 0;
-	srcp  = inet_sk(sp)->num;
-	sprintf(tmpbuf,
-		"%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
-		"%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
-		i,
-		src->s6_addr32[0], src->s6_addr32[1],
-		src->s6_addr32[2], src->s6_addr32[3], srcp,
-		dest->s6_addr32[0], dest->s6_addr32[1],
-		dest->s6_addr32[2], dest->s6_addr32[3], destp,
-		sp->state, 
-		atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
-		0, 0L, 0,
-		sock_i_uid(sp), 0,
-		sock_i_ino(sp),
-		atomic_read(&sp->refcnt), sp);
-}
-
-int raw6_get_info(char *buffer, char **start, off_t offset, int length)
-{
-	int len = 0, num = 0, i;
-	off_t pos = 0;
-	off_t begin;
-	char tmpbuf[LINE_LEN+2];
-
-	if (offset < LINE_LEN+1)
-		len += sprintf(buffer, LINE_FMT,
-			       "  sl  "						/* 6 */
-			       "local_address                         "		/* 38 */
-			       "remote_address                        "		/* 38 */
-			       "st tx_queue rx_queue tr tm->when retrnsmt"	/* 41 */
-			       "   uid  timeout inode");			/* 21 */
-										/*----*/
-										/*144 */
-	pos = LINE_LEN+1;
-	read_lock(&raw_v6_lock);
-	for (i = 0; i < RAWV6_HTABLE_SIZE; i++) {
-		struct sock *sk;
-
-		for (sk = raw_v6_htable[i]; sk; sk = sk->next, num++) {
-			if (sk->family != PF_INET6)
-				continue;
-			pos += LINE_LEN+1;
-			if (pos <= offset)
-				continue;
-			get_raw6_sock(sk, tmpbuf, i);
-			len += sprintf(buffer+len, LINE_FMT, tmpbuf);
-			if(len >= length)
-				goto out;
-		}
-	}
-out:
-	read_unlock(&raw_v6_lock);
-	begin = len - (pos - offset);
-	*start = buffer + begin;
-	len -= begin;
-	if(len > length)
-		len = length;
-	if (len < 0)
-		len = 0; 
-	return len;
-}
-
 struct proto rawv6_prot = {
 	.name =		"RAW",
 	.close =	rawv6_close,
@@ -922,3 +916,151 @@
 	.hash =		raw_v6_hash,
 	.unhash =	raw_v6_unhash,
 };
+
+#ifdef CONFIG_PROC_FS
+struct raw6_iter_state {
+	int bucket;
+};
+
+#define raw6_seq_private(seq) ((struct raw6_iter_state *)&seq->private)
+
+static struct sock *raw6_get_first(struct seq_file *seq)
+{
+	struct sock *sk = NULL;
+	struct raw6_iter_state* state = raw6_seq_private(seq);
+
+	for (state->bucket = 0; state->bucket < RAWV6_HTABLE_SIZE; ++state->bucket) {
+		sk = raw_v6_htable[state->bucket];
+		while (sk && sk->family != PF_INET6)
+			sk = sk->next;
+		if (sk)
+			break;
+	}
+	return sk;
+}
+
+static struct sock *raw6_get_next(struct seq_file *seq, struct sock *sk)
+{
+	struct raw6_iter_state* state = raw6_seq_private(seq);
+
+	do {
+		sk = sk->next;
+try_again:
+		;
+	} while (sk && sk->family != PF_INET6);
+
+	if (!sk && ++state->bucket < RAWV6_HTABLE_SIZE) {
+		sk = raw_v6_htable[state->bucket];
+		goto try_again;
+	}
+	return sk;
+}
+
+static struct sock *raw6_get_idx(struct seq_file *seq, loff_t pos)
+{
+	struct sock *sk = raw6_get_first(seq);
+	if (sk)
+		while (pos && (sk = raw6_get_next(seq, sk)) != NULL)
+			--pos;
+	return pos ? NULL : sk;
+}
+
+static void *raw6_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	read_lock(&raw_v6_lock);
+	return *pos ? raw6_get_idx(seq, *pos) : (void *)1;
+}
+
+static void *raw6_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	struct sock *sk;
+
+	if (v == (void *)1)
+		sk = raw6_get_first(seq);
+	else
+		sk = raw6_get_next(seq, v);
+	++*pos;
+	return sk;
+}
+
+static void raw6_seq_stop(struct seq_file *seq, void *v)
+{
+	read_unlock(&raw_v6_lock);
+}
+
+static void raw6_sock_seq_show(struct seq_file *seq, struct sock *sp, int i)
+{
+	struct ipv6_pinfo *np = inet6_sk(sp);
+	struct in6_addr *dest, *src;
+	__u16 destp, srcp;
+
+	dest  = &np->daddr;
+	src   = &np->rcv_saddr;
+	destp = 0;
+	srcp  = inet_sk(sp)->num;
+	seq_printf(seq,
+		   "%4d: %08X%08X%08X%08X:%04X %08X%08X%08X%08X:%04X "
+		   "%02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p\n",
+		   i,
+		   src->s6_addr32[0], src->s6_addr32[1],
+		   src->s6_addr32[2], src->s6_addr32[3], srcp,
+		   dest->s6_addr32[0], dest->s6_addr32[1],
+		   dest->s6_addr32[2], dest->s6_addr32[3], destp,
+		   sp->state, 
+		   atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
+		   0, 0L, 0,
+		   sock_i_uid(sp), 0,
+		   sock_i_ino(sp),
+		   atomic_read(&sp->refcnt), sp);
+}
+
+static int raw6_seq_show(struct seq_file *seq, void *v)
+{
+	if (v == (void *)1)
+		seq_printf(seq,
+			   "  sl  "
+			   "local_address                         "
+			   "remote_address                        "
+			   "st tx_queue rx_queue tr tm->when retrnsmt"
+			   "   uid  timeout inode\n");
+	else
+		raw6_sock_seq_show(seq, v, raw6_seq_private(seq)->bucket);
+	return 0;
+}
+
+static struct seq_operations raw6_seq_ops = {
+	.start =	raw6_seq_start,
+	.next =		raw6_seq_next,
+	.stop =		raw6_seq_stop,
+	.show =		raw6_seq_show,
+};
+
+static int raw6_seq_open(struct inode *inode, struct file *file)
+{
+	return seq_open(file, &raw6_seq_ops);
+}
+
+static struct file_operations raw6_seq_fops = {
+	.owner =	THIS_MODULE,
+	.open =		raw6_seq_open,
+	.read =		seq_read,
+	.llseek =	seq_lseek,
+	.release =	seq_release,
+};
+
+int __init raw6_proc_init(void)
+{
+	struct proc_dir_entry *p = create_proc_entry("raw6", S_IRUGO, proc_net);
+
+	if (!p)
+		return -ENOMEM;
+	p->proc_fops = &raw6_seq_fops;
+
+	return 0;
+}
+
+void raw6_proc_exit(void)
+{
+	remove_proc_entry("raw6", proc_net);
+}
+#endif	/* CONFIG_PROC_FS */
diff -Nru a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
--- a/net/ipv6/reassembly.c	Mon Apr 14 11:25:51 2003
+++ b/net/ipv6/reassembly.c	Wed May 14 20:21:58 2003
@@ -132,19 +132,19 @@
 atomic_t ip6_frag_mem = ATOMIC_INIT(0);
 
 /* Memory Tracking Functions. */
-extern __inline__ void frag_kfree_skb(struct sk_buff *skb)
+static inline void frag_kfree_skb(struct sk_buff *skb)
 {
 	atomic_sub(skb->truesize, &ip6_frag_mem);
 	kfree_skb(skb);
 }
 
-extern __inline__ void frag_free_queue(struct frag_queue *fq)
+static inline void frag_free_queue(struct frag_queue *fq)
 {
 	atomic_sub(sizeof(struct frag_queue), &ip6_frag_mem);
 	kfree(fq);
 }
 
-extern __inline__ struct frag_queue *frag_alloc_queue(void)
+static inline struct frag_queue *frag_alloc_queue(void)
 {
 	struct frag_queue *fq = kmalloc(sizeof(struct frag_queue), GFP_ATOMIC);
 
diff -Nru a/net/ipv6/route.c b/net/ipv6/route.c
--- a/net/ipv6/route.c	Tue Apr 22 23:57:43 2003
+++ b/net/ipv6/route.c	Mon May 19 23:49:42 2003
@@ -39,6 +39,7 @@
 
 #ifdef 	CONFIG_PROC_FS
 #include <linux/proc_fs.h>
+#include <linux/seq_file.h>
 #endif
 
 #include <net/snmp.h>
@@ -107,6 +108,7 @@
 			.dev		= &loopback_dev,
 			.obsolete	= -1,
 			.error		= -ENETUNREACH,
+			.metrics	= { [RTAX_HOPLIMIT - 1] = 255, },
 			.input		= ip6_pkt_discard,
 			.output		= ip6_pkt_discard,
 			.ops		= &ip6_dst_ops,
@@ -115,14 +117,12 @@
 	},
 	.rt6i_flags	= (RTF_REJECT | RTF_NONEXTHOP),
 	.rt6i_metric	= ~(u32) 0,
-	.rt6i_hoplimit	= 255,
 	.rt6i_ref	= ATOMIC_INIT(1),
 };
 
 struct fib6_node ip6_routing_table = {
-	NULL, NULL, NULL, NULL,
-	&ip6_null_entry,
-	0, RTN_ROOT|RTN_TL_ROOT|RTN_RTINFO, 0
+	.leaf		= &ip6_null_entry,
+	.fn_flags	= RTN_ROOT | RTN_TL_ROOT | RTN_RTINFO,
 };
 
 /* Protects all the ip6 fib */
@@ -173,7 +173,7 @@
 /*
  *	pointer to the last default router chosen. BH is disabled locally.
  */
-static struct rt6_info *rt6_dflt_pointer = NULL;
+static struct rt6_info *rt6_dflt_pointer;
 static spinlock_t rt6_dflt_lock = SPIN_LOCK_UNLOCKED;
 
 /* Default Router Selection (RFC 2461 6.3.6) */
@@ -323,12 +323,12 @@
    be destroyed.
  */
 
-static int rt6_ins(struct rt6_info *rt, struct nlmsghdr *nlh)
+static int rt6_ins(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr)
 {
 	int err;
 
 	write_lock_bh(&rt6_lock);
-	err = fib6_add(&ip6_routing_table, rt, nlh);
+	err = fib6_add(&ip6_routing_table, rt, nlh, _rtattr);
 	write_unlock_bh(&rt6_lock);
 
 	return err;
@@ -371,7 +371,7 @@
 
 		dst_hold(&rt->u.dst);
 
-		err = rt6_ins(rt, NULL);
+		err = rt6_ins(rt, NULL, NULL);
 		if (err == 0)
 			return rt;
 
@@ -525,7 +525,7 @@
 
 	if (rt) {
 		if (rt->rt6i_flags & RTF_CACHE)
-			ip6_del_rt(rt, NULL);
+			ip6_del_rt(rt, NULL, NULL);
 		else
 			dst_release(dst);
 	}
@@ -558,13 +558,13 @@
 	}
 }
 
-static int ip6_dst_gc()
+static int ip6_dst_gc(void)
 {
 	static unsigned expire = 30*HZ;
 	static unsigned long last_gc;
 	unsigned long now = jiffies;
 
-	if ((long)(now - last_gc) < ip6_rt_gc_min_interval &&
+	if (time_after(last_gc + ip6_rt_gc_min_interval, now) &&
 	    atomic_read(&ip6_dst_ops.entries) <= ip6_rt_max_size)
 		goto out;
 
@@ -628,14 +628,17 @@
  *
  */
 
-int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh)
+int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr)
 {
 	int err;
 	struct rtmsg *r;
+	struct rtattr **rta;
 	struct rt6_info *rt;
 	struct net_device *dev = NULL;
 	int addr_type;
 
+	rta = (struct rtattr **) _rtattr;
+
 	if (rtmsg->rtmsg_dst_len > 128 || rtmsg->rtmsg_src_len > 128)
 		return -EINVAL;
 #ifndef CONFIG_IPV6_SUBTREES
@@ -765,15 +768,43 @@
 		}
 	}
 
-	if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))
-		rt->rt6i_hoplimit = IPV6_DEFAULT_MCASTHOPS;
-	else
-		rt->rt6i_hoplimit = ipv6_get_hoplimit(dev);
 	rt->rt6i_flags = rtmsg->rtmsg_flags;
 
 install_route:
-	rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
-	rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60, ip6_rt_min_advmss);
+	if (rta && rta[RTA_METRICS-1]) {
+		int attrlen = RTA_PAYLOAD(rta[RTA_METRICS-1]);
+		struct rtattr *attr = RTA_DATA(rta[RTA_METRICS-1]);
+
+		while (RTA_OK(attr, attrlen)) {
+			unsigned flavor = attr->rta_type;
+			if (flavor) {
+				if (flavor > RTAX_MAX) {
+					err = -EINVAL;
+					goto out;
+				}
+				rt->u.dst.metrics[flavor-1] =
+					*(u32 *)RTA_DATA(attr);
+			}
+			attr = RTA_NEXT(attr, attrlen);
+		}
+	}
+
+	if (rt->u.dst.metrics[RTAX_HOPLIMIT-1] == 0) {
+		if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr))
+			rt->u.dst.metrics[RTAX_HOPLIMIT-1] =
+				IPV6_DEFAULT_MCASTHOPS;
+		else
+			rt->u.dst.metrics[RTAX_HOPLIMIT-1] =
+				ipv6_get_hoplimit(dev);
+	}
+
+	if (!rt->u.dst.metrics[RTAX_MTU-1])
+		rt->u.dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
+	if (!rt->u.dst.metrics[RTAX_ADVMSS-1])
+		rt->u.dst.metrics[RTAX_ADVMSS-1] =
+			max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60,
+			      ip6_rt_min_advmss);
+
 	/* Maximal non-jumbo IPv6 payload is 65535 and corresponding
 	   MSS is 65535 - tcp_header_size. 65535 is also valid and
 	   means: "any MSS, rely only on pmtu discovery"
@@ -781,7 +812,7 @@
 	if (dst_metric(&rt->u.dst, RTAX_ADVMSS) > 65535-20)
 		rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
 	rt->u.dst.dev = dev;
-	return rt6_ins(rt, nlh);
+	return rt6_ins(rt, nlh, _rtattr);
 
 out:
 	if (dev)
@@ -790,7 +821,7 @@
 	return err;
 }
 
-int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh)
+int ip6_del_rt(struct rt6_info *rt, struct nlmsghdr *nlh, void *_rtattr)
 {
 	int err;
 
@@ -802,13 +833,13 @@
 
 	dst_release(&rt->u.dst);
 
-	err = fib6_del(rt, nlh);
+	err = fib6_del(rt, nlh, _rtattr);
 	write_unlock_bh(&rt6_lock);
 
 	return err;
 }
 
-static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh)
+static int ip6_route_del(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr)
 {
 	struct fib6_node *fn;
 	struct rt6_info *rt;
@@ -835,7 +866,7 @@
 			dst_hold(&rt->u.dst);
 			read_unlock_bh(&rt6_lock);
 
-			return ip6_del_rt(rt, nlh);
+			return ip6_del_rt(rt, nlh, _rtattr);
 		}
 	}
 	read_unlock_bh(&rt6_lock);
@@ -881,7 +912,7 @@
 		goto out;
 
 	/*
-	 *	RFC 1970 specifies that redirects should only be
+	 *	RFC 2461 specifies that redirects should only be
 	 *	accepted if they come from the nexthop to the target.
 	 *	Due to the way default routers are chosen, this notion
 	 *	is a bit fuzzy and one might need to check all default
@@ -935,13 +966,12 @@
 	nrt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&nrt->u.dst) - 60, ip6_rt_min_advmss);
 	if (nrt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20)
 		nrt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
-	nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev);
 
-	if (rt6_ins(nrt, NULL))
+	if (rt6_ins(nrt, NULL, NULL))
 		goto out;
 
 	if (rt->rt6i_flags&RTF_CACHE) {
-		ip6_del_rt(rt, NULL);
+		ip6_del_rt(rt, NULL, NULL);
 		return;
 	}
 
@@ -1027,7 +1057,7 @@
 		dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires);
 		nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES;
 		nrt->u.dst.metrics[RTAX_MTU-1] = pmtu;
-		rt6_ins(nrt, NULL);
+		rt6_ins(nrt, NULL, NULL);
 	}
 
 out:
@@ -1051,7 +1081,6 @@
 		if (rt->u.dst.dev)
 			dev_hold(rt->u.dst.dev);
 		rt->u.dst.lastuse = jiffies;
-		rt->rt6i_hoplimit = ort->rt6i_hoplimit;
 		rt->rt6i_expires = 0;
 
 		ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway);
@@ -1098,7 +1127,7 @@
 
 	rtmsg.rtmsg_ifindex = dev->ifindex;
 
-	ip6_route_add(&rtmsg, NULL);
+	ip6_route_add(&rtmsg, NULL, NULL);
 	return rt6_get_dflt_router(gwaddr, dev);
 }
 
@@ -1124,7 +1153,7 @@
 
 			read_unlock_bh(&rt6_lock);
 
-			ip6_del_rt(rt, NULL);
+			ip6_del_rt(rt, NULL, NULL);
 
 			goto restart;
 		}
@@ -1150,10 +1179,10 @@
 		rtnl_lock();
 		switch (cmd) {
 		case SIOCADDRT:
-			err = ip6_route_add(&rtmsg, NULL);
+			err = ip6_route_add(&rtmsg, NULL, NULL);
 			break;
 		case SIOCDELRT:
-			err = ip6_route_del(&rtmsg, NULL);
+			err = ip6_route_del(&rtmsg, NULL, NULL);
 			break;
 		default:
 			err = -EINVAL;
@@ -1173,7 +1202,7 @@
 int ip6_pkt_discard(struct sk_buff *skb)
 {
 	IP6_INC_STATS(Ip6OutNoRoutes);
-	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADDR_UNREACH, 0, skb->dev);
+	icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev);
 	kfree_skb(skb);
 	return 0;
 }
@@ -1197,7 +1226,7 @@
 	rt->u.dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, dst_pmtu(&rt->u.dst) - 60, ip6_rt_min_advmss);
 	if (rt->u.dst.metrics[RTAX_ADVMSS-1] > 65535-20)
 		rt->u.dst.metrics[RTAX_ADVMSS-1] = 65535;
-	rt->rt6i_hoplimit = ipv6_get_hoplimit(rt->rt6i_dev);
+	rt->u.dst.metrics[RTAX_HOPLIMIT-1] = ipv6_get_hoplimit(rt->rt6i_dev);
 	rt->u.dst.obsolete = -1;
 
 	rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
@@ -1209,7 +1238,7 @@
 
 	ipv6_addr_copy(&rt->rt6i_dst.addr, addr);
 	rt->rt6i_dst.plen = 128;
-	rt6_ins(rt, NULL);
+	rt6_ins(rt, NULL, NULL);
 
 	return 0;
 }
@@ -1226,7 +1255,7 @@
 	rt = rt6_lookup(addr, NULL, loopback_dev.ifindex, 1);
 	if (rt) {
 		if (rt->rt6i_dst.plen == 128)
-			err = ip6_del_rt(rt, NULL);
+			err = ip6_del_rt(rt, NULL, NULL);
 		else
 			dst_release(&rt->u.dst);
 	}
@@ -1356,7 +1385,7 @@
 
 	if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
 		return -EINVAL;
-	return ip6_route_del(&rtmsg, nlh);
+	return ip6_route_del(&rtmsg, nlh, arg);
 }
 
 int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
@@ -1366,7 +1395,7 @@
 
 	if (inet6_rtm_to_rtmsg(r, arg, &rtmsg))
 		return -EINVAL;
-	return ip6_route_add(&rtmsg, nlh);
+	return ip6_route_add(&rtmsg, nlh, arg);
 }
 
 struct rt6_rtnl_dump_arg
@@ -1751,27 +1780,29 @@
 
 extern struct rt6_statistics rt6_stats;
 
-static int rt6_proc_stats(char *buffer, char **start, off_t offset, int length)
+static int rt6_stats_seq_show(struct seq_file *seq, void *v)
 {
-	int len;
-
-	len = sprintf(buffer, "%04x %04x %04x %04x %04x %04x\n",
+	seq_printf(seq, "%04x %04x %04x %04x %04x %04x\n",
 		      rt6_stats.fib_nodes, rt6_stats.fib_route_nodes,
 		      rt6_stats.fib_rt_alloc, rt6_stats.fib_rt_entries,
 		      rt6_stats.fib_rt_cache,
 		      atomic_read(&ip6_dst_ops.entries));
 
-	len -= offset;
-
-	if (len > length)
-		len = length;
-	if(len < 0)
-		len = 0;
-
-	*start = buffer + offset;
+	return 0;
+}
 
-	return len;
+static int rt6_stats_seq_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, rt6_stats_seq_show, NULL);
 }
+
+static struct file_operations rt6_stats_seq_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = rt6_stats_seq_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = single_release,
+};
 #endif	/* CONFIG_PROC_FS */
 
 #ifdef CONFIG_SYSCTL
@@ -1877,6 +1908,8 @@
 
 void __init ip6_route_init(void)
 {
+	struct proc_dir_entry *p;
+
 	ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache",
 						     sizeof(struct rt6_info),
 						     0, SLAB_HWCACHE_ALIGN,
@@ -1884,7 +1917,9 @@
 	fib6_init();
 #ifdef 	CONFIG_PROC_FS
 	proc_net_create("ipv6_route", 0, rt6_proc_info);
-	proc_net_create("rt6_stats", 0, rt6_proc_stats);
+	p = create_proc_entry("rt6_stats", S_IRUGO, proc_net);
+	if (p)
+		p->proc_fops = &rt6_stats_seq_fops;
 #endif
 	xfrm6_init();
 }
@@ -1894,10 +1929,11 @@
 {
 #ifdef CONFIG_PROC_FS
 	proc_net_remove("ipv6_route");
-	proc_net_remove("rt6_stats");
+	remove_proc_entry("rt6_stats", proc_net);
 #endif
 	xfrm6_fini();
 	rt6_ifdown(NULL);
 	fib6_gc_cleanup();
+	kmem_cache_destroy(ip6_dst_ops.kmem_cachep);
 }
 #endif	/* MODULE */
diff -Nru a/net/ipv6/sit.c b/net/ipv6/sit.c
--- a/net/ipv6/sit.c	Wed Apr  9 23:54:59 2003
+++ b/net/ipv6/sit.c	Mon May 19 23:49:42 2003
@@ -420,7 +420,7 @@
 }
 
 /* Returns the embedded IPv4 address if the IPv6 address
-   comes from 6to4 (draft-ietf-ngtrans-6to4-04) addr space */
+   comes from 6to4 (RFC 3056) addr space */
 
 static inline u32 try_6to4(struct in6_addr *v6dst)
 {
diff -Nru a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
--- a/net/ipv6/tcp_ipv6.c	Sat May  3 10:01:19 2003
+++ b/net/ipv6/tcp_ipv6.c	Wed May 14 20:16:59 2003
@@ -370,9 +370,9 @@
 	return tcp_v6_lookup_listener(daddr, hnum, dif);
 }
 
-__inline__ struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
-				      struct in6_addr *daddr, u16 dport,
-				      int dif)
+inline struct sock *tcp_v6_lookup(struct in6_addr *saddr, u16 sport,
+				  struct in6_addr *daddr, u16 dport,
+				  int dif)
 {
 	struct sock *sk;
 
@@ -505,7 +505,6 @@
 		/* Silly. Should hash-dance instead... */
 		local_bh_disable();
 		tcp_tw_deschedule(tw);
-		tcp_timewait_kill(tw);
 		NET_INC_STATS_BH(TimeWaitRecycled);
 		local_bh_enable();
 
@@ -1698,7 +1697,6 @@
 		sk2 = tcp_v6_lookup_listener(&skb->nh.ipv6h->daddr, ntohs(th->dest), tcp_v6_iif(skb));
 		if (sk2 != NULL) {
 			tcp_tw_deschedule((struct tcp_tw_bucket *)sk);
-			tcp_timewait_kill((struct tcp_tw_bucket *)sk);
 			tcp_tw_put((struct tcp_tw_bucket *)sk);
 			sk = sk2;
 			goto process;
diff -Nru a/net/ipv6/udp.c b/net/ipv6/udp.c
--- a/net/ipv6/udp.c	Tue Apr 29 02:29:48 2003
+++ b/net/ipv6/udp.c	Mon May 19 23:49:42 2003
@@ -14,6 +14,7 @@
  *	YOSHIFUJI Hideaki @USAGI and:	Support IPV6_V6ONLY socket option, which
  *	Alexey Kuznetsov		allow both IPv4 and IPv6 sockets to bind
  *					a single port at the same time.
+ *      Kazunori MIYAZAWA @USAGI:       change process style to use ip6_append_data
  *
  *	This program is free software; you can redistribute it and/or
  *      modify it under the terms of the GNU General Public License
@@ -466,8 +467,7 @@
 			if (inet->cmsg_flags)
 				ip_cmsg_recv(msg, skb);
 		} else {
-			memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
-			       sizeof(struct in6_addr));
+			ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
 
 			if (np->rxopt.all)
 				datagram_recv_ctl(sk, msg, skb);
@@ -575,7 +575,7 @@
 	for(; s; s = s->next) {
 		struct inet_opt *inet = inet_sk(s);
 
-		if (inet->num == num) {
+		if (inet->num == num && sk->family == PF_INET6) {
 			struct ipv6_pinfo *np = inet6_sk(s);
 			if (inet->dport) {
 				if (inet->dport != rmt_port)
@@ -666,7 +666,7 @@
 		goto short_packet;
 
 	if (uh->check == 0) {
-		/* IPv6 draft-v2 section 8.1 says that we SHOULD log
+		/* RFC 2460 section 8.1 says that we SHOULD log
 		   this error. Well, it is reasonable.
 		 */
 		if (net_ratelimit())
@@ -738,96 +738,117 @@
 	kfree_skb(skb);
 	return(0);	
 }
-
 /*
- *	Sending
+ * Throw away all pending data and cancel the corking. Socket is locked.
  */
-
-struct udpv6fakehdr 
+static void udp_v6_flush_pending_frames(struct sock *sk)
 {
-	struct udphdr	uh;
-	struct iovec	*iov;
-	__u32		wcheck;
-	__u32		pl_len;
-	struct in6_addr *daddr;
-};
+	struct udp_opt *up = udp_sk(sk);
+
+	if (up->pending) {
+		up->pending = 0;
+		ip6_flush_pending_frames(sk);
+        }
+}
 
 /*
- *	with checksum
+ *	Sending
  */
 
-static int udpv6_getfrag(const void *data, struct in6_addr *addr,
-			 char *buff, unsigned int offset, unsigned int len)
+static int udp_v6_push_pending_frames(struct sock *sk, struct udp_opt *up)
 {
-	struct udpv6fakehdr *udh = (struct udpv6fakehdr *) data;
-	char *dst;
-	int final = 0;
-	int clen = len;
+	struct sk_buff *skb;
+	struct udphdr *uh;
+	struct ipv6_pinfo *np = inet6_sk(sk);
+	struct flowi *fl = np->cork.fl;
+	int err = 0;
 
-	dst = buff;
+	/* Grab the skbuff where UDP header space exists. */
+	if ((skb = skb_peek(&sk->write_queue)) == NULL)
+		goto out;
 
-	if (offset) {
-		offset -= sizeof(struct udphdr);
+	/*
+	 * Create a UDP header
+	 */
+	uh = skb->h.uh;
+	uh->source = fl->fl_ip_sport;
+	uh->dest = fl->fl_ip_dport;
+	uh->len = htons(up->len);
+	uh->check = 0;
+
+	if (sk->no_check == UDP_CSUM_NOXMIT) {
+		skb->ip_summed = CHECKSUM_NONE;
+		goto send;
+	}
+
+	if (skb_queue_len(&sk->write_queue) == 1) {
+		skb->csum = csum_partial((char *)uh,
+				sizeof(struct udphdr), skb->csum);
+		uh->check = csum_ipv6_magic(fl->fl6_src,
+					    fl->fl6_dst,
+					    up->len, fl->proto, skb->csum);
 	} else {
-		dst += sizeof(struct udphdr);
-		final = 1;
-		clen -= sizeof(struct udphdr);
-	}
-
-	if (csum_partial_copy_fromiovecend(dst, udh->iov, offset,
-					   clen, &udh->wcheck))
-		return -EFAULT;
+		u32 tmp_csum = 0;
 
-	if (final) {
-		struct in6_addr *daddr;
-		
-		udh->wcheck = csum_partial((char *)udh, sizeof(struct udphdr),
-					   udh->wcheck);
-
-		if (udh->daddr) {
-			daddr = udh->daddr;
-		} else {
-			/*
-			 *	use packet destination address
-			 *	this should improve cache locality
-			 */
-			daddr = addr + 1;
-		}
-		udh->uh.check = csum_ipv6_magic(addr, daddr,
-						udh->pl_len, IPPROTO_UDP,
-						udh->wcheck);
-		if (udh->uh.check == 0)
-			udh->uh.check = -1;
+		skb_queue_walk(&sk->write_queue, skb) {
+			tmp_csum = csum_add(tmp_csum, skb->csum);
+		}
+		tmp_csum = csum_partial((char *)uh,
+				sizeof(struct udphdr), tmp_csum);
+                tmp_csum = csum_ipv6_magic(fl->fl6_src,
+					   fl->fl6_dst,
+					   up->len, fl->proto, tmp_csum);
+                uh->check = tmp_csum;
 
-		memcpy(buff, udh, sizeof(struct udphdr));
 	}
-	return 0;
+	if (uh->check == 0)
+		uh->check = -1;
+
+send:
+	err = ip6_push_pending_frames(sk);
+out:
+	up->len = 0;
+	up->pending = 0;
+	return err;
 }
 
-static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int ulen)
+static int udpv6_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, int len)
 {
 	struct ipv6_txoptions opt_space;
-	struct udpv6fakehdr udh;
+	struct udp_opt *up = udp_sk(sk);
 	struct inet_opt *inet = inet_sk(sk);
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *) msg->msg_name;
+	struct in6_addr *daddr, *saddr = NULL;
 	struct ipv6_txoptions *opt = NULL;
 	struct ip6_flowlabel *flowlabel = NULL;
 	struct flowi fl;
+	struct dst_entry *dst;
 	int addr_len = msg->msg_namelen;
-	struct in6_addr *daddr;
-	int len = ulen + sizeof(struct udphdr);
+	int ulen = len;
 	int addr_type;
 	int hlimit = -1;
-	
+	int corkreq = up->corkflag || msg->msg_flags&MSG_MORE;
 	int err;
 	
 	/* Rough check on arithmetic overflow,
 	   better check is made in ip6_build_xmit
 	   */
-	if (ulen < 0 || ulen > INT_MAX - sizeof(struct udphdr))
+	if (len < 0 || len > INT_MAX - sizeof(struct udphdr))
 		return -EMSGSIZE;
 	
+	if (up->pending) {
+		/*
+		 * There are pending frames.
+		 * The socket lock must be held while it's corked.
+		 */
+		lock_sock(sk);
+		if (likely(up->pending))
+			goto do_append_data;
+		release_sock(sk);
+	}
+	ulen += sizeof(struct udphdr);
+
 	fl.fl6_flowlabel = 0;
 	fl.oif = 0;
 
@@ -835,7 +856,7 @@
 		if (sin6->sin6_family == AF_INET) {
 			if (__ipv6_only_sock(sk))
 				return -ENETUNREACH;
-			return udp_sendmsg(iocb, sk, msg, ulen);
+			return udp_sendmsg(iocb, sk, msg, len);
 		}
 
 		if (addr_len < SIN6_LEN_RFC2133)
@@ -847,7 +868,7 @@
 		if (sin6->sin6_port == 0)
 			return -EINVAL;
 
-		udh.uh.dest = sin6->sin6_port;
+		up->dport = sin6->sin6_port;
 		daddr = &sin6->sin6_addr;
 
 		if (np->sndflow) {
@@ -873,7 +894,7 @@
 		if (sk->state != TCP_ESTABLISHED)
 			return -ENOTCONN;
 
-		udh.uh.dest = inet->dport;
+		up->dport = inet->dport;
 		daddr = &np->daddr;
 		fl.fl6_flowlabel = np->flow_label;
 	}
@@ -888,15 +909,14 @@
 
 		sin.sin_family = AF_INET;
 		sin.sin_addr.s_addr = daddr->s6_addr32[3];
-		sin.sin_port = udh.uh.dest;
+		sin.sin_port = up->dport;
 		msg->msg_name = (struct sockaddr *)(&sin);
 		msg->msg_namelen = sizeof(sin);
 		fl6_sock_release(flowlabel);
 
-		return udp_sendmsg(iocb, sk, msg, ulen);
+		return udp_sendmsg(iocb, sk, msg, len);
 	}
 
-	udh.daddr = NULL;
 	if (!fl.oif)
 		fl.oif = sk->bound_dev_if;
 	fl.fl6_src = NULL;
@@ -922,33 +942,172 @@
 		opt = np->opt;
 	if (flowlabel)
 		opt = fl6_merge_options(&opt_space, flowlabel, opt);
-	if (opt && opt->srcrt)
-		udh.daddr = daddr;
-
-	udh.uh.source = inet->sport;
-	udh.uh.len = len < 0x10000 ? htons(len) : 0;
-	udh.uh.check = 0;
-	udh.iov = msg->msg_iov;
-	udh.wcheck = 0;
-	udh.pl_len = len;
 
 	fl.proto = IPPROTO_UDP;
 	fl.fl6_dst = daddr;
 	if (fl.fl6_src == NULL && !ipv6_addr_any(&np->saddr))
 		fl.fl6_src = &np->saddr;
-	fl.fl_ip_dport = udh.uh.dest;
-	fl.fl_ip_sport = udh.uh.source;
+	fl.fl_ip_dport = up->dport;
+	fl.fl_ip_sport = inet->sport;
+	
+	/* merge ip6_build_xmit from ip6_output */
+	if (opt && opt->srcrt) {
+		struct rt0_hdr *rt0 = (struct rt0_hdr *) opt->srcrt;
+		fl.fl6_dst = rt0->addr;
+	}
 
-	err = ip6_build_xmit(sk, udpv6_getfrag, &udh, &fl, len, opt, hlimit,
-			     msg->msg_flags);
+	if (!fl.oif && ipv6_addr_is_multicast(fl.nl_u.ip6_u.daddr))
+		fl.oif = np->mcast_oif;
 
+	err = ip6_dst_lookup(sk, &dst, &fl, &saddr);
+	if (err) goto out;
+
+	if (hlimit < 0) {
+		if (ipv6_addr_is_multicast(fl.fl6_dst))
+			hlimit = np->mcast_hops;
+		else
+			hlimit = np->hop_limit;
+		if (hlimit < 0)
+			hlimit = dst_metric(dst, RTAX_HOPLIMIT);
+	}
+
+	if (msg->msg_flags&MSG_CONFIRM)
+		goto do_confirm;
+back_from_confirm:
+
+	lock_sock(sk);
+	if (unlikely(up->pending)) {
+		/* The socket is already corked while preparing it. */
+		/* ... which is an evident application bug. --ANK */
+		release_sock(sk);
+
+		NETDEBUG(if (net_ratelimit()) printk(KERN_DEBUG "udp cork app bug 2\n"));
+		err = -EINVAL;
+		goto out;
+	}
+
+	up->pending = 1;
+
+do_append_data:
+	up->len += ulen;
+	err = ip6_append_data(sk, ip_generic_getfrag, msg->msg_iov, ulen, sizeof(struct udphdr),
+			      hlimit, opt, &fl, (struct rt6_info*)dst,
+			      corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags);
+	if (err)
+		udp_v6_flush_pending_frames(sk);
+	else if (!corkreq)
+		err = udp_v6_push_pending_frames(sk, up);
+
+	ip6_dst_store(sk, dst, fl.nl_u.ip6_u.daddr == &np->daddr ? &np->daddr : NULL);
+	if (err > 0)
+		err = np->recverr ? net_xmit_errno(err) : 0;
+	release_sock(sk);
+out:
 	fl6_sock_release(flowlabel);
+	if (saddr) kfree(saddr);
+	if (!err) {
+		UDP6_INC_STATS_USER(UdpOutDatagrams);
+		return len;
+	}
+	return err;
 
-	if (err < 0)
-		return err;
+do_confirm:
+	dst_confirm(dst);
+	if (!(msg->msg_flags&MSG_PROBE) || len)
+		goto back_from_confirm;
+	err = 0;
+	goto out;
+}
+
+static int udpv6_destroy_sock(struct sock *sk)
+{
+	lock_sock(sk);
+	udp_v6_flush_pending_frames(sk);
+	release_sock(sk);
+
+	inet6_destroy_sock(sk);
+
+	return 0;
+}
+
+/*
+ *	Socket option code for UDP
+ */
+static int udpv6_setsockopt(struct sock *sk, int level, int optname, 
+			  char *optval, int optlen)
+{
+	struct udp_opt *up = udp_sk(sk);
+	int val;
+	int err = 0;
+
+	if (level != SOL_UDP)
+		return ipv6_setsockopt(sk, level, optname, optval, optlen);
 
-	UDP6_INC_STATS_USER(UdpOutDatagrams);
-	return ulen;
+	if(optlen<sizeof(int))
+		return -EINVAL;
+
+	if (get_user(val, (int *)optval))
+		return -EFAULT;
+
+	switch(optname) {
+	case UDP_CORK:
+		if (val != 0) {
+			up->corkflag = 1;
+		} else {
+			up->corkflag = 0;
+			lock_sock(sk);
+			udp_v6_push_pending_frames(sk, up);
+			release_sock(sk);
+		}
+		break;
+		
+	case UDP_ENCAP:
+		up->encap_type = val;
+		break;
+
+	default:
+		err = -ENOPROTOOPT;
+		break;
+	};
+
+	return err;
+}
+
+static int udpv6_getsockopt(struct sock *sk, int level, int optname, 
+			  char *optval, int *optlen)
+{
+	struct udp_opt *up = udp_sk(sk);
+	int val, len;
+
+	if (level != SOL_UDP)
+		return ipv6_getsockopt(sk, level, optname, optval, optlen);
+
+	if(get_user(len,optlen))
+		return -EFAULT;
+
+	len = min_t(unsigned int, len, sizeof(int));
+	
+	if(len < 0)
+		return -EINVAL;
+
+	switch(optname) {
+	case UDP_CORK:
+		val = up->corkflag;
+		break;
+
+	case UDP_ENCAP:
+		val = up->encap_type;
+		break;
+
+	default:
+		return -ENOPROTOOPT;
+	};
+
+  	if(put_user(len, optlen))
+  		return -EFAULT;
+	if(copy_to_user(optval, &val,len))
+		return -EFAULT;
+  	return 0;
 }
 
 static struct inet6_protocol udpv6_protocol = {
@@ -1038,9 +1197,9 @@
 	.connect =	udpv6_connect,
 	.disconnect =	udp_disconnect,
 	.ioctl =	udp_ioctl,
-	.destroy =	inet6_destroy_sock,
-	.setsockopt =	ipv6_setsockopt,
-	.getsockopt =	ipv6_getsockopt,
+	.destroy =	udpv6_destroy_sock,
+	.setsockopt =	udpv6_setsockopt,
+	.getsockopt =	udpv6_getsockopt,
 	.sendmsg =	udpv6_sendmsg,
 	.recvmsg =	udpv6_recvmsg,
 	.backlog_rcv =	udpv6_queue_rcv_skb,
diff -Nru a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c
--- a/net/ipv6/xfrm6_policy.c	Thu Apr 17 18:56:05 2003
+++ b/net/ipv6/xfrm6_policy.c	Thu May 15 23:27:55 2003
@@ -153,7 +153,6 @@
 		x->u.rt6.rt6i_flags    = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
 		x->u.rt6.rt6i_metric   = rt0->rt6i_metric;
 		x->u.rt6.rt6i_node     = rt0->rt6i_node;
-		x->u.rt6.rt6i_hoplimit = rt0->rt6i_hoplimit;
 		x->u.rt6.rt6i_gateway  = rt0->rt6i_gateway;
 		memcpy(&x->u.rt6.rt6i_gateway, &rt0->rt6i_gateway, sizeof(x->u.rt6.rt6i_gateway)); 
 		header_len -= x->u.dst.xfrm->props.header_len;
diff -Nru a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c
--- a/net/ipv6/xfrm6_state.c	Thu Apr 17 18:56:05 2003
+++ b/net/ipv6/xfrm6_state.c	Tue May 13 05:52:50 2003
@@ -25,8 +25,8 @@
 {
 	/* Initialize temporary selector matching only
 	 * to current session. */
-	memcpy(&x->sel.daddr, fl->fl6_dst, sizeof(struct in6_addr));
-	memcpy(&x->sel.saddr, fl->fl6_src, sizeof(struct in6_addr));
+	ipv6_addr_copy((struct in6_addr *)&x->sel.daddr, fl->fl6_dst);
+	ipv6_addr_copy((struct in6_addr *)&x->sel.saddr, fl->fl6_src);
 	x->sel.dport = fl->fl_ip_dport;
 	x->sel.dport_mask = ~0;
 	x->sel.sport = fl->fl_ip_sport;
@@ -57,7 +57,7 @@
 		    spi == x->id.spi &&
 		    !ipv6_addr_cmp((struct in6_addr *)daddr, (struct in6_addr *)x->id.daddr.a6) &&
 		    proto == x->id.proto) {
-			atomic_inc(&x->refcnt);
+			xfrm_state_hold(x);
 			return x;
 		}
 	}
@@ -91,23 +91,27 @@
 		    }
 	}
 	if (x0) {
-		atomic_inc(&x0->refcnt);
+		xfrm_state_hold(x0);
 	} else if (create && (x0 = xfrm_state_alloc()) != NULL) {
-		memcpy(x0->sel.daddr.a6, daddr, sizeof(struct in6_addr));
-		memcpy(x0->sel.saddr.a6, saddr, sizeof(struct in6_addr));
+		ipv6_addr_copy((struct in6_addr *)x0->sel.daddr.a6,
+			       (struct in6_addr *)daddr);
+		ipv6_addr_copy((struct in6_addr *)x0->sel.saddr.a6,
+			       (struct in6_addr *)saddr);
 		x0->sel.prefixlen_d = 128;
 		x0->sel.prefixlen_s = 128;
-		memcpy(x0->props.saddr.a6, saddr, sizeof(struct in6_addr));
+		ipv6_addr_copy((struct in6_addr *)x0->props.saddr.a6,
+			       (struct in6_addr *)saddr);
 		x0->km.state = XFRM_STATE_ACQ;
-		memcpy(x0->id.daddr.a6, daddr, sizeof(struct in6_addr));
+		ipv6_addr_copy((struct in6_addr *)x0->id.daddr.a6,
+			       (struct in6_addr *)daddr);
 		x0->id.proto = proto;
 		x0->props.family = AF_INET6;
 		x0->props.mode = mode;
 		x0->props.reqid = reqid;
 		x0->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
-		atomic_inc(&x0->refcnt);
+		xfrm_state_hold(x0);
 		mod_timer(&x0->timer, jiffies + XFRM_ACQ_EXPIRES*HZ);
-		atomic_inc(&x0->refcnt);
+		xfrm_state_hold(x0);
 		list_add_tail(&x0->bydst, xfrm6_state_afinfo.state_bydst+h);
 		wake_up(&km_waitq);
 	}
diff -Nru a/net/ipx/Makefile b/net/ipx/Makefile
--- a/net/ipx/Makefile	Sat Dec 14 04:38:56 2002
+++ b/net/ipx/Makefile	Fri May 16 11:47:00 2003
@@ -4,5 +4,5 @@
 
 obj-$(CONFIG_IPX) += ipx.o
 
-ipx-y			:= af_ipx.o ipx_proc.o
+ipx-y			:= af_ipx.o ipx_route.o ipx_proc.o
 ipx-$(CONFIG_SYSCTL)	+= sysctl_net_ipx.o
diff -Nru a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
--- a/net/ipx/af_ipx.c	Fri May  2 23:17:58 2003
+++ b/net/ipx/af_ipx.c	Fri May 16 11:47:00 2003
@@ -15,7 +15,7 @@
  *	liability nor provide warranty for any of this software. This material
  *	is provided as is and at no charge.
  *
- *	Portions Copyright (c) 2000-2002 Conectiva, Inc. <acme@conectiva.com.br>
+ *	Portions Copyright (c) 2000-2003 Conectiva, Inc. <acme@conectiva.com.br>
  *	Neither Arnaldo Carvalho de Melo nor Conectiva, Inc. admit liability nor
  *	provide warranty for any of this software. This material is provided
  *	"AS-IS" and at no charge.
@@ -29,35 +29,31 @@
  */
 
 #include <linux/config.h>
-#include <linux/module.h>
 #include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/init.h>
+#include <linux/ipx.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
+#include <linux/list.h>
+#include <linux/module.h>
 #include <linux/net.h>
 #include <linux/netdevice.h>
-#include <net/ipx.h>
-#include <linux/inet.h>
+#include <linux/uio.h>
+#include <linux/skbuff.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/string.h>
 #include <linux/tcp.h>
-#include <linux/route.h>
-#include <net/sock.h>
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/termios.h>	/* For TIOCOUTQ/INQ */
-#include <linux/interrupt.h>
+#include <linux/types.h>
+#include <linux/termios.h>
+
+#include <net/ipx.h>
 #include <net/p8022.h>
 #include <net/psnap.h>
-#include <linux/proc_fs.h>
-#include <linux/stat.h>
-#include <linux/init.h>
-#include <linux/if_arp.h>
+#include <net/sock.h>
+
+#include <asm/uaccess.h>
 
 #ifdef CONFIG_SYSCTL
 extern void ipx_register_sysctl(void);
@@ -81,25 +77,41 @@
 
 static struct proto_ops ipx_dgram_ops;
 
-struct ipx_route *ipx_routes;
-rwlock_t ipx_routes_lock = RW_LOCK_UNLOCKED;
-
-struct ipx_interface *ipx_interfaces;
+LIST_HEAD(ipx_interfaces);
 spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED;
 
 struct ipx_interface *ipx_primary_net;
-static struct ipx_interface *ipx_internal_net;
+struct ipx_interface *ipx_internal_net;
+
+extern int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc,
+			    unsigned char *node);
+extern void ipxrtr_del_routes(struct ipx_interface *intrfc);
+extern int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
+			       struct iovec *iov, int len, int noblock);
+extern int ipxrtr_route_skb(struct sk_buff *skb);
+extern struct ipx_route *ipxrtr_lookup(__u32 net);
+extern int ipxrtr_ioctl(unsigned int cmd, void *arg);
 
 #undef IPX_REFCNT_DEBUG
 #ifdef IPX_REFCNT_DEBUG
 atomic_t ipx_sock_nr;
 #endif
 
+struct ipx_interface *ipx_interfaces_head(void)
+{
+	struct ipx_interface *rc = NULL;
+
+	if (!list_empty(&ipx_interfaces))
+		rc = list_entry(ipx_interfaces.next,
+				struct ipx_interface, node);
+	return rc;
+}
+
 static void ipxcfg_set_auto_select(char val)
 {
 	ipxcfg_auto_select_primary = val;
 	if (val && !ipx_primary_net)
-		ipx_primary_net = ipx_interfaces;
+		ipx_primary_net = ipx_interfaces_head();
 }
 
 static int ipxcfg_get_config_data(struct ipx_config_data *arg)
@@ -112,28 +124,6 @@
 	return copy_to_user(arg, &vals, sizeof(vals)) ? -EFAULT : 0;
 }
 
-/* Handlers for the socket list. */
-
-static __inline__ void ipxitf_hold(struct ipx_interface *intrfc)
-{
-	atomic_inc(&intrfc->refcnt);
-}
-
-static void ipxitf_down(struct ipx_interface *intrfc);
-
-static __inline__ void ipxitf_put(struct ipx_interface *intrfc)
-{
-	if (atomic_dec_and_test(&intrfc->refcnt))
-		ipxitf_down(intrfc);
-}
-
-static void __ipxitf_down(struct ipx_interface *intrfc);
-
-static __inline__ void __ipxitf_put(struct ipx_interface *intrfc)
-{
-	if (atomic_dec_and_test(&intrfc->refcnt))
-		__ipxitf_down(intrfc);
-}
 /*
  * Note: Sockets may not be removed _during_ an interrupt or inet_bh
  * handler using this technique. They can be added although we do not
@@ -191,23 +181,26 @@
  * The following code is used to support IPX Interfaces (IPXITF).  An
  * IPX interface is defined by a physical device and a frame type.
  */
-static struct ipx_route *ipxrtr_lookup(__u32 net);
 
 /* ipxitf_clear_primary_net has to be called with ipx_interfaces_lock held */
 
 static void ipxitf_clear_primary_net(void)
 {
-	ipx_primary_net = ipxcfg_auto_select_primary ? ipx_interfaces : NULL;
+	ipx_primary_net = NULL;
+	if (ipxcfg_auto_select_primary)
+		ipx_primary_net = ipx_interfaces_head();
 }
 
 static struct ipx_interface *__ipxitf_find_using_phys(struct net_device *dev,
 						      unsigned short datalink)
 {
-	struct ipx_interface *i = ipx_interfaces;
-
-	while (i && (i->if_dev != dev || i->if_dlink_type != datalink))
-		i = i->if_next;
+	struct ipx_interface *i;
 
+	list_for_each_entry(i, &ipx_interfaces, node)
+		if (i->if_dev == dev && i->if_dlink_type == datalink)
+			goto out;
+	i = NULL;
+out:
 	return i;
 }
 
@@ -224,21 +217,25 @@
 	return i;
 }
 
-static struct ipx_interface *ipxitf_find_using_net(__u32 net)
+struct ipx_interface *ipxitf_find_using_net(__u32 net)
 {
 	struct ipx_interface *i;
 
 	spin_lock_bh(&ipx_interfaces_lock);
-	if (net)
-		for (i = ipx_interfaces; i && i->if_netnum != net;
-		     i = i->if_next)
-		;
-	else
-		i = ipx_primary_net;
+	if (net) {
+		list_for_each_entry(i, &ipx_interfaces, node)
+			if (i->if_netnum == net)
+				goto hold;
+		i = NULL;
+		goto unlock;
+	}
+
+	i = ipx_primary_net;
 	if (i)
+hold:
 		ipxitf_hold(i);
+unlock:
 	spin_unlock_bh(&ipx_interfaces_lock);
-
 	return i;
 }
 
@@ -315,9 +312,7 @@
 }
 #endif
 
-static void ipxrtr_del_routes(struct ipx_interface *intrfc);
-
-static void __ipxitf_down(struct ipx_interface *intrfc)
+void __ipxitf_down(struct ipx_interface *intrfc)
 {
 	struct sock *s, *t;
 
@@ -342,15 +337,7 @@
 	spin_unlock_bh(&intrfc->if_sklist_lock);
 
 	/* remove this interface from list */
-	if (intrfc == ipx_interfaces)
-		ipx_interfaces = intrfc->if_next;
-	else {
-		struct ipx_interface *i = ipx_interfaces;
-		while (i && i->if_next != intrfc)
-		     i = i->if_next;
-		if (i && i->if_next == intrfc)
-			i->if_next = intrfc->if_next;
-	}
+	list_del(&intrfc->node);
 
 	/* remove this interface from *special* networks */
 	if (intrfc == ipx_primary_net)
@@ -361,9 +348,10 @@
 	if (intrfc->if_dev)
 		dev_put(intrfc->if_dev);
 	kfree(intrfc);
+	module_put(THIS_MODULE);
 }
 
-static void ipxitf_down(struct ipx_interface *intrfc)
+void ipxitf_down(struct ipx_interface *intrfc)
 {
 	spin_lock_bh(&ipx_interfaces_lock);
 	__ipxitf_down(intrfc);
@@ -380,16 +368,13 @@
 		goto out;
 
 	spin_lock_bh(&ipx_interfaces_lock);
-	for (i = ipx_interfaces; i;) {
-		tmp = i->if_next;
+	list_for_each_entry_safe(i, tmp, &ipx_interfaces, node)
 		if (i->if_dev == dev) {
 			if (event == NETDEV_UP)
 				ipxitf_hold(i);
 			else
 				__ipxitf_put(i);
 		}
-		i = tmp;
-	}
 	spin_unlock_bh(&ipx_interfaces_lock);
 out:
 	return NOTIFY_DONE;
@@ -604,9 +589,7 @@
 }
 
 /* caller must hold a reference to intrfc and the skb has to be unshared */
-
-static int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb,
-		       char *node)
+int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb, char *node)
 {
 	struct ipxhdr *ipx = ipx_hdr(skb);
 	struct net_device *dev = intrfc->if_dev;
@@ -712,9 +695,6 @@
 	return 0;
 }
 
-static int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc,
-			    unsigned char *);
-
 static int ipxitf_add_local_route(struct ipx_interface *intrfc)
 {
 	return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL);
@@ -723,7 +703,6 @@
 static void ipxitf_discover_netnum(struct ipx_interface *intrfc,
 				   struct sk_buff *skb);
 static int ipxitf_pprop(struct ipx_interface *intrfc, struct sk_buff *skb);
-static int ipxrtr_route_skb(struct sk_buff *skb);
 
 static int ipxitf_rcv(struct ipx_interface *intrfc, struct sk_buff *skb)
 {
@@ -872,7 +851,7 @@
 	IPX_SKB_CB(skb)->last_hop.netnum = intrfc->if_netnum;
 	/* xmit on all other interfaces... */
 	spin_lock_bh(&ipx_interfaces_lock);
-	for (ifcs = ipx_interfaces; ifcs; ifcs = ifcs->if_next) {
+	list_for_each_entry(ifcs, &ipx_interfaces, node) {
 		/* Except unconfigured interfaces */
 		if (!ifcs->if_netnum)
 			continue;
@@ -902,16 +881,8 @@
 
 static void ipxitf_insert(struct ipx_interface *intrfc)
 {
-	intrfc->if_next = NULL;
 	spin_lock_bh(&ipx_interfaces_lock);
-	if (!ipx_interfaces)
-		ipx_interfaces = intrfc;
-	else {
-		struct ipx_interface *i = ipx_interfaces;
-		while (i->if_next)
-			i = i->if_next;
-		i->if_next = intrfc;
-	}
+	list_add_tail(&intrfc->node, &ipx_interfaces);
 	spin_unlock_bh(&ipx_interfaces_lock);
 
 	if (ipxcfg_auto_select_primary && !ipx_primary_net)
@@ -937,6 +908,7 @@
 		intrfc->if_sklist 	= NULL;
 		atomic_set(&intrfc->refcnt, 1);
 		spin_lock_init(&intrfc->if_sklist_lock);
+		__module_get(THIS_MODULE);
 	}
 
 	return intrfc;
@@ -1260,136 +1232,6 @@
 	return rc;
 }
 
-/* Routing tables for the IPX socket layer. */
-
-static __inline__ void ipxrtr_hold(struct ipx_route *rt)
-{
-	atomic_inc(&rt->refcnt);
-}
-
-static __inline__ void ipxrtr_put(struct ipx_route *rt)
-{
-	if (atomic_dec_and_test(&rt->refcnt))
-		kfree(rt);
-}
-
-static struct ipx_route *ipxrtr_lookup(__u32 net)
-{
-	struct ipx_route *r;
-
-	read_lock_bh(&ipx_routes_lock);
-	for (r = ipx_routes; r && r->ir_net != net; r = r->ir_next)
-		;
-	if (r)
-		ipxrtr_hold(r);
-	read_unlock_bh(&ipx_routes_lock);
-
-	return r;
-}
-
-/* caller must hold a reference to intrfc */
-
-static int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc,
-			    unsigned char *node)
-{
-	struct ipx_route *rt;
-	int rc;
-
-	/* Get a route structure; either existing or create */
-	rt = ipxrtr_lookup(network);
-	if (!rt) {
-		rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
-		rc = -EAGAIN;
-		if (!rt)
-			goto out;
-
-		atomic_set(&rt->refcnt, 1);
-		ipxrtr_hold(rt);
-		write_lock_bh(&ipx_routes_lock);
-		rt->ir_next	= ipx_routes;
-		ipx_routes	= rt;
-		write_unlock_bh(&ipx_routes_lock);
-	} else {
-		rc = -EEXIST;
-		if (intrfc == ipx_internal_net)
-			goto out_put;
-	}
-
-	rt->ir_net 	= network;
-	rt->ir_intrfc 	= intrfc;
-	if (!node) {
-		memset(rt->ir_router_node, '\0', IPX_NODE_LEN);
-		rt->ir_routed = 0;
-	} else {
-		memcpy(rt->ir_router_node, node, IPX_NODE_LEN);
-		rt->ir_routed = 1;
-	}
-
-	rc = 0;
-out_put:
-	ipxrtr_put(rt);
-out:
-	return rc;
-}
-
-static void ipxrtr_del_routes(struct ipx_interface *intrfc)
-{
-	struct ipx_route **r, *tmp;
-
-	write_lock_bh(&ipx_routes_lock);
-	for (r = &ipx_routes; (tmp = *r) != NULL;) {
-		if (tmp->ir_intrfc == intrfc) {
-			*r = tmp->ir_next;
-			ipxrtr_put(tmp);
-		} else
-			r = &(tmp->ir_next);
-	}
-	write_unlock_bh(&ipx_routes_lock);
-}
-
-static int ipxrtr_create(struct ipx_route_definition *rd)
-{
-	struct ipx_interface *intrfc;
-	int rc = -ENETUNREACH;
-
-	/* Find the appropriate interface */
-	intrfc = ipxitf_find_using_net(rd->ipx_router_network);
-	if (!intrfc)
-		goto out;
-	rc = ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node);
-	ipxitf_put(intrfc);
-out:
-	return rc;
-}
-
-static int ipxrtr_delete(long net)
-{
-	struct ipx_route **r;
-	struct ipx_route *tmp;
-	int rc;
-
-	write_lock_bh(&ipx_routes_lock);
-	for (r = &ipx_routes; (tmp = *r) != NULL;) {
-		if (tmp->ir_net == net) {
-			/* Directly connected; can't lose route */
-			rc = -EPERM;
-			if (!tmp->ir_routed)
-				goto out;
-
-			*r = tmp->ir_next;
-			ipxrtr_put(tmp);
-			rc = 0;
-			goto out;
-		}
-
-		r = &(tmp->ir_next);
-	}
-	rc = -ENOENT;
-out:
-	write_unlock_bh(&ipx_routes_lock);
-	return rc;
-}
-
 /*
  *	Checksum routine for IPX
  */
@@ -1397,7 +1239,7 @@
 /* Note: We assume ipx_tctrl==0 and htons(length)==ipx_pktsize */
 /* This functions should *not* mess with packet contents */
 
-static __u16 ipx_cksum(struct ipxhdr *packet, int length) 
+__u16 ipx_cksum(struct ipxhdr *packet, int length) 
 {
 	/* 
 	 *	NOTE: sum is a net byte order quantity, which optimizes the 
@@ -1429,154 +1271,6 @@
 	return ~sum;
 }
 
-/*
- * Route an outgoing frame from a socket.
- */
-static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
-				struct iovec *iov, int len, int noblock)
-{
-	struct sk_buff *skb;
-	struct ipx_opt *ipxs = ipx_sk(sk);
-	struct ipx_interface *intrfc;
-	struct ipxhdr *ipx;
-	int size;
-	int ipx_offset;
-	struct ipx_route *rt = NULL;
-	int rc;
-
-	/* Find the appropriate interface on which to send packet */
-	if (!usipx->sipx_network && ipx_primary_net) {
-		usipx->sipx_network = ipx_primary_net->if_netnum;
-		intrfc = ipx_primary_net;
-	} else {
-		rt = ipxrtr_lookup(usipx->sipx_network);
-		rc = -ENETUNREACH;
-		if (!rt)
-			goto out;
-		intrfc = rt->ir_intrfc;
-	}
-
-	ipxitf_hold(intrfc);
-	ipx_offset = intrfc->if_ipx_offset;
-	size = sizeof(struct ipxhdr) + len + ipx_offset;
-
-	skb = sock_alloc_send_skb(sk, size, noblock, &rc);
-	if (!skb)
-		goto out_put;
-
-	skb_reserve(skb, ipx_offset);
-	skb->sk = sk;
-
-	/* Fill in IPX header */
-	skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxhdr));
-	ipx = ipx_hdr(skb);
-	ipx->ipx_pktsize = htons(len + sizeof(struct ipxhdr));
-	IPX_SKB_CB(skb)->ipx_tctrl = 0;
-	ipx->ipx_type 	 = usipx->sipx_type;
-
-	IPX_SKB_CB(skb)->last_hop.index = -1;
-#ifdef CONFIG_IPX_INTERN
-	IPX_SKB_CB(skb)->ipx_source_net = ipxs->intrfc->if_netnum;
-	memcpy(ipx->ipx_source.node, ipxs->node, IPX_NODE_LEN);
-#else
-	rc = ntohs(ipxs->port);
-	if (rc == 0x453 || rc == 0x452) {
-		/* RIP/SAP special handling for mars_nwe */
-		IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum;
-		memcpy(ipx->ipx_source.node, intrfc->if_node, IPX_NODE_LEN);
-	} else {
-		IPX_SKB_CB(skb)->ipx_source_net = ipxs->intrfc->if_netnum;
-		memcpy(ipx->ipx_source.node, ipxs->intrfc->if_node,
-			IPX_NODE_LEN);
-	}
-#endif	/* CONFIG_IPX_INTERN */
-	ipx->ipx_source.sock		= ipxs->port;
-	IPX_SKB_CB(skb)->ipx_dest_net	= usipx->sipx_network;
-	memcpy(ipx->ipx_dest.node, usipx->sipx_node, IPX_NODE_LEN);
-	ipx->ipx_dest.sock		= usipx->sipx_port;
-
-	rc = memcpy_fromiovec(skb_put(skb, len), iov, len);
-	if (rc) {
-		kfree_skb(skb);
-		goto out_put;
-	}	
-
-	/* Apply checksum. Not allowed on 802.3 links. */
-	if (sk->no_check || intrfc->if_dlink_type == IPX_FRAME_8023)
-		ipx->ipx_checksum = 0xFFFF;
-	else
-		ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr));
-
-	rc = ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? 
-			 rt->ir_router_node : ipx->ipx_dest.node);
-out_put:
-	ipxitf_put(intrfc);
-	if (rt)
-		ipxrtr_put(rt);
-out:
-	return rc;
-}
-
-/* the skb has to be unshared, we'll end up calling ipxitf_send, that'll
- * modify the packet */
-int ipxrtr_route_skb(struct sk_buff *skb)
-{
-	struct ipxhdr *ipx = ipx_hdr(skb);
-	struct ipx_route *r = ipxrtr_lookup(IPX_SKB_CB(skb)->ipx_dest_net);
-
-	if (!r) {	/* no known route */
-		kfree_skb(skb);
-		return 0;
-	}
-
-	ipxitf_hold(r->ir_intrfc);
-	ipxitf_send(r->ir_intrfc, skb, r->ir_routed ?
-			r->ir_router_node : ipx->ipx_dest.node);
-	ipxitf_put(r->ir_intrfc);
-	ipxrtr_put(r);
-
-	return 0;
-}
-
-/*
- * We use a normal struct rtentry for route handling
- */
-static int ipxrtr_ioctl(unsigned int cmd, void *arg)
-{
-	struct rtentry rt;	/* Use these to behave like 'other' stacks */
-	struct sockaddr_ipx *sg, *st;
-	int rc = -EFAULT;
-
-	if (copy_from_user(&rt, arg, sizeof(rt)))
-		goto out;
-
-	sg = (struct sockaddr_ipx *)&rt.rt_gateway;
-	st = (struct sockaddr_ipx *)&rt.rt_dst;
-
-	rc = -EINVAL;
-	if (!(rt.rt_flags & RTF_GATEWAY) || /* Direct routes are fixed */
-	    sg->sipx_family != AF_IPX ||
-	    st->sipx_family != AF_IPX)
-		goto out;
-
-	switch (cmd) {
-	case SIOCDELRT:
-		rc = ipxrtr_delete(st->sipx_network);
-		break;
-	case SIOCADDRT: {
-		struct ipx_route_definition f;
-		f.ipx_network		= st->sipx_network;
-		f.ipx_router_network	= sg->sipx_network;
-		memcpy(f.ipx_router_node, sg->sipx_node, IPX_NODE_LEN);
-		rc = ipxrtr_create(&f);
-		break;
-	}
-	}
-
-out:
-	return rc;
-}
-
 const char *ipx_frame_name(unsigned short frame)
 {
 	char* rc = "None";
@@ -1827,7 +1521,6 @@
 
 	ipxitf_insert_socket(intrfc, sk);
 	sk->zapped = 0;
-	SOCK_DEBUG(sk, "IPX: bound socket 0x%04X.\n", ntohs(addr->sipx_port) );
 
 	rc = 0;
 out_put:
@@ -2267,9 +1960,9 @@
 static unsigned char ipx_8022_type = 0xE0;
 static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
 static char ipx_banner[] __initdata =
-	KERN_INFO "NET4: Linux IPX 0.50 for NET4.0\n"
+	KERN_INFO "NET4: Linux IPX 0.51 for NET4.0\n"
 	KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n" \
-	KERN_INFO "IPX Portions Copyright (c) 2000-2002 Conectiva, Inc.\n";
+	KERN_INFO "IPX Portions Copyright (c) 2000-2003 Conectiva, Inc.\n";
 static char ipx_EII_err_msg[] __initdata =
 	KERN_CRIT "IPX: Unable to register with Ethernet II\n";
 static char ipx_8023_err_msg[] __initdata =
@@ -2317,6 +2010,10 @@
 	 * when a interface is created we increment the module usage count, so
 	 * the module will only be unloaded when there are no more interfaces
 	 */
+	if (unlikely(!list_empty(&ipx_interfaces)))
+		BUG();
+	if (unlikely(!list_empty(&ipx_routes)))
+		BUG();
 
 	ipx_proc_exit();
 	ipx_unregister_sysctl();
diff -Nru a/net/ipx/ipx_proc.c b/net/ipx/ipx_proc.c
--- a/net/ipx/ipx_proc.c	Mon Oct  7 20:18:35 2002
+++ b/net/ipx/ipx_proc.c	Fri May 16 11:47:00 2003
@@ -5,6 +5,7 @@
  */
 
 #include <linux/config.h>
+#ifdef CONFIG_PROC_FS
 #include <linux/init.h>
 #include <linux/proc_fs.h>
 #include <linux/spinlock.h>
@@ -12,17 +13,27 @@
 #include <linux/tcp.h>
 #include <net/ipx.h>
 
-#ifdef CONFIG_PROC_FS
 static __inline__ struct ipx_interface *ipx_get_interface_idx(loff_t pos)
 {
 	struct ipx_interface *i;
 
-	for (i = ipx_interfaces; pos && i; i = i->if_next)
-		--pos;
-
+	list_for_each_entry(i, &ipx_interfaces, node)
+		if (!pos--)
+			goto out;
+	i = NULL;
+out:
 	return i;
 }
 
+static struct ipx_interface *ipx_interfaces_next(struct ipx_interface *i)
+{
+	struct ipx_interface *rc = NULL;
+
+	if (i->node.next != &ipx_interfaces)
+		rc = list_entry(i->node.next, struct ipx_interface, node);
+	return rc;
+}
+
 static void *ipx_seq_interface_start(struct seq_file *seq, loff_t *pos)
 {
 	loff_t l = *pos;
@@ -36,15 +47,10 @@
 	struct ipx_interface *i;
 
 	++*pos;
-	if (v == (void *)1) {
-		i = NULL;
-		if (ipx_interfaces)
-			i = ipx_interfaces;
-		goto out;
-	}
-	i = v;
-	i = i->if_next;
-out:
+	if (v == (void *)1)
+		i = ipx_interfaces_head();
+	else
+		i = ipx_interfaces_next(v);
 	return i;
 }
 
@@ -83,13 +89,33 @@
 	return 0;
 }
 
+static struct ipx_route *ipx_routes_head(void)
+{
+	struct ipx_route *rc = NULL;
+
+	if (!list_empty(&ipx_routes))
+		rc = list_entry(ipx_routes.next, struct ipx_route, node);
+	return rc;
+}
+
+static struct ipx_route *ipx_routes_next(struct ipx_route *r)
+{
+	struct ipx_route *rc = NULL;
+
+	if (r->node.next != &ipx_routes)
+		rc = list_entry(r->node.next, struct ipx_route, node);
+	return rc;
+}
+
 static __inline__ struct ipx_route *ipx_get_route_idx(loff_t pos)
 {
 	struct ipx_route *r;
 
-	for (r = ipx_routes; pos && r; r = r->ir_next)
-		--pos;
-
+	list_for_each_entry(r, &ipx_routes, node)
+		if (!pos--)
+			goto out;
+	r = NULL;
+out:
 	return r;
 }
 
@@ -105,15 +131,10 @@
 	struct ipx_route *r;
 
 	++*pos;
-	if (v == (void *)1) {
-		r = NULL;
-		if (ipx_routes)
-			r = ipx_routes;
-		goto out;
-	}
-	r = v;
-	r = r->ir_next;
-out:
+	if (v == (void *)1)
+		r = ipx_routes_head();
+	else
+		r = ipx_routes_next(v);
 	return r;
 }
 
@@ -149,7 +170,9 @@
 	struct sock *s = NULL;
 	struct ipx_interface *i;
 
-	for (i = ipx_interfaces; pos && i; i = i->if_next) {
+	list_for_each_entry(i, &ipx_interfaces, node) {
+		if (!pos)
+			break;
 		spin_lock_bh(&i->if_sklist_lock);
 		for (s = i->if_sklist; pos && s; s = s->next)
 			--pos;
@@ -181,11 +204,12 @@
 	++*pos;
 	if (v == (void *)1) {
 		sk = NULL;
-		if (!ipx_interfaces)
+		i = ipx_interfaces_head();
+		if (!i)
 			goto out;
-		sk = ipx_interfaces->if_sklist;
+		sk = i->if_sklist;
 		if (sk)
-			spin_lock_bh(&ipx_interfaces->if_sklist_lock);
+			spin_lock_bh(&i->if_sklist_lock);
 		goto out;
 	}
 	sk = v;
@@ -198,9 +222,9 @@
 	spin_unlock_bh(&i->if_sklist_lock);
 	sk = NULL;
 	for (;;) {
-		if (!i->if_next)
+		i = ipx_interfaces_next(i);
+		if (!i)
 			break;
-		i = i->if_next;
 		spin_lock_bh(&i->if_sklist_lock);
 		if (i->if_sklist) {
 			sk = i->if_sklist;
@@ -295,6 +319,7 @@
 }
 
 static struct file_operations ipx_seq_interface_fops = {
+	.owner		= THIS_MODULE,
 	.open           = ipx_seq_interface_open,
 	.read           = seq_read,
 	.llseek         = seq_lseek,
@@ -302,6 +327,7 @@
 };
 
 static struct file_operations ipx_seq_route_fops = {
+	.owner		= THIS_MODULE,
 	.open           = ipx_seq_route_open,
 	.read           = seq_read,
 	.llseek         = seq_lseek,
@@ -309,6 +335,7 @@
 };
 
 static struct file_operations ipx_seq_socket_fops = {
+	.owner		= THIS_MODULE,
 	.open           = ipx_seq_socket_open,
 	.read           = seq_read,
 	.llseek         = seq_lseek,
diff -Nru a/net/ipx/ipx_route.c b/net/ipx/ipx_route.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/ipx/ipx_route.c	Fri May 16 11:47:00 2003
@@ -0,0 +1,293 @@
+/*
+ *	Implements the IPX routing routines.
+ *	Code moved from af_ipx.c.
+ *
+ *	Arnaldo Carvalho de Melo <acme@conectiva.com.br>, 2003
+ *
+ *	See net/ipx/ChangeLog.
+ */
+
+#include <linux/config.h>
+#include <linux/list.h>
+#include <linux/route.h>
+#include <linux/spinlock.h>
+
+#include <net/ipx.h>
+#include <net/sock.h>
+
+LIST_HEAD(ipx_routes);
+rwlock_t ipx_routes_lock = RW_LOCK_UNLOCKED;
+
+extern struct ipx_interface *ipx_internal_net;
+
+extern __u16 ipx_cksum(struct ipxhdr *packet, int length);
+extern struct ipx_interface *ipxitf_find_using_net(__u32 net);
+extern int ipxitf_demux_socket(struct ipx_interface *intrfc,
+			       struct sk_buff *skb, int copy);
+extern int ipxitf_demux_socket(struct ipx_interface *intrfc,
+			       struct sk_buff *skb, int copy);
+extern int ipxitf_send(struct ipx_interface *intrfc, struct sk_buff *skb,
+		       char *node);
+extern struct ipx_interface *ipxitf_find_using_net(__u32 net);
+
+struct ipx_route *ipxrtr_lookup(__u32 net)
+{
+	struct ipx_route *r;
+
+	read_lock_bh(&ipx_routes_lock);
+	list_for_each_entry(r, &ipx_routes, node)
+		if (r->ir_net == net) {
+			ipxrtr_hold(r);
+			goto unlock;
+		}
+	r = NULL;
+unlock:
+	read_unlock_bh(&ipx_routes_lock);
+	return r;
+}
+
+/*
+ * Caller must hold a reference to intrfc
+ */
+int ipxrtr_add_route(__u32 network, struct ipx_interface *intrfc,
+		     unsigned char *node)
+{
+	struct ipx_route *rt;
+	int rc;
+
+	/* Get a route structure; either existing or create */
+	rt = ipxrtr_lookup(network);
+	if (!rt) {
+		rt = kmalloc(sizeof(*rt), GFP_ATOMIC);
+		rc = -EAGAIN;
+		if (!rt)
+			goto out;
+
+		atomic_set(&rt->refcnt, 1);
+		ipxrtr_hold(rt);
+		write_lock_bh(&ipx_routes_lock);
+		list_add(&rt->node, &ipx_routes);
+		write_unlock_bh(&ipx_routes_lock);
+	} else {
+		rc = -EEXIST;
+		if (intrfc == ipx_internal_net)
+			goto out_put;
+	}
+
+	rt->ir_net 	= network;
+	rt->ir_intrfc 	= intrfc;
+	if (!node) {
+		memset(rt->ir_router_node, '\0', IPX_NODE_LEN);
+		rt->ir_routed = 0;
+	} else {
+		memcpy(rt->ir_router_node, node, IPX_NODE_LEN);
+		rt->ir_routed = 1;
+	}
+
+	rc = 0;
+out_put:
+	ipxrtr_put(rt);
+out:
+	return rc;
+}
+
+void ipxrtr_del_routes(struct ipx_interface *intrfc)
+{
+	struct ipx_route *r, *tmp;
+
+	write_lock_bh(&ipx_routes_lock);
+	list_for_each_entry_safe(r, tmp, &ipx_routes, node)
+		if (r->ir_intrfc == intrfc) {
+			list_del(&r->node);
+			ipxrtr_put(r);
+		}
+	write_unlock_bh(&ipx_routes_lock);
+}
+
+static int ipxrtr_create(struct ipx_route_definition *rd)
+{
+	struct ipx_interface *intrfc;
+	int rc = -ENETUNREACH;
+
+	/* Find the appropriate interface */
+	intrfc = ipxitf_find_using_net(rd->ipx_router_network);
+	if (!intrfc)
+		goto out;
+	rc = ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node);
+	ipxitf_put(intrfc);
+out:
+	return rc;
+}
+
+static int ipxrtr_delete(long net)
+{
+	struct ipx_route *r, *tmp;
+	int rc;
+
+	write_lock_bh(&ipx_routes_lock);
+	list_for_each_entry_safe(r, tmp, &ipx_routes, node)
+		if (r->ir_net == net) {
+			/* Directly connected; can't lose route */
+			rc = -EPERM;
+			if (!r->ir_routed)
+				goto out;
+			list_del(&r->node);
+			ipxrtr_put(r);
+			rc = 0;
+			goto out;
+		}
+	rc = -ENOENT;
+out:
+	write_unlock_bh(&ipx_routes_lock);
+	return rc;
+}
+
+/*
+ * The skb has to be unshared, we'll end up calling ipxitf_send, that'll
+ * modify the packet
+ */
+int ipxrtr_route_skb(struct sk_buff *skb)
+{
+	struct ipxhdr *ipx = ipx_hdr(skb);
+	struct ipx_route *r = ipxrtr_lookup(IPX_SKB_CB(skb)->ipx_dest_net);
+
+	if (!r) {	/* no known route */
+		kfree_skb(skb);
+		return 0;
+	}
+
+	ipxitf_hold(r->ir_intrfc);
+	ipxitf_send(r->ir_intrfc, skb, r->ir_routed ?
+			r->ir_router_node : ipx->ipx_dest.node);
+	ipxitf_put(r->ir_intrfc);
+	ipxrtr_put(r);
+
+	return 0;
+}
+
+/*
+ * Route an outgoing frame from a socket.
+ */
+int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx,
+			struct iovec *iov, int len, int noblock)
+{
+	struct sk_buff *skb;
+	struct ipx_opt *ipxs = ipx_sk(sk);
+	struct ipx_interface *intrfc;
+	struct ipxhdr *ipx;
+	int size;
+	int ipx_offset;
+	struct ipx_route *rt = NULL;
+	int rc;
+
+	/* Find the appropriate interface on which to send packet */
+	if (!usipx->sipx_network && ipx_primary_net) {
+		usipx->sipx_network = ipx_primary_net->if_netnum;
+		intrfc = ipx_primary_net;
+	} else {
+		rt = ipxrtr_lookup(usipx->sipx_network);
+		rc = -ENETUNREACH;
+		if (!rt)
+			goto out;
+		intrfc = rt->ir_intrfc;
+	}
+
+	ipxitf_hold(intrfc);
+	ipx_offset = intrfc->if_ipx_offset;
+	size = sizeof(struct ipxhdr) + len + ipx_offset;
+
+	skb = sock_alloc_send_skb(sk, size, noblock, &rc);
+	if (!skb)
+		goto out_put;
+
+	skb_reserve(skb, ipx_offset);
+	skb->sk = sk;
+
+	/* Fill in IPX header */
+	skb->h.raw = skb->nh.raw = skb_put(skb, sizeof(struct ipxhdr));
+	ipx = ipx_hdr(skb);
+	ipx->ipx_pktsize = htons(len + sizeof(struct ipxhdr));
+	IPX_SKB_CB(skb)->ipx_tctrl = 0;
+	ipx->ipx_type 	 = usipx->sipx_type;
+
+	IPX_SKB_CB(skb)->last_hop.index = -1;
+#ifdef CONFIG_IPX_INTERN
+	IPX_SKB_CB(skb)->ipx_source_net = ipxs->intrfc->if_netnum;
+	memcpy(ipx->ipx_source.node, ipxs->node, IPX_NODE_LEN);
+#else
+	rc = ntohs(ipxs->port);
+	if (rc == 0x453 || rc == 0x452) {
+		/* RIP/SAP special handling for mars_nwe */
+		IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum;
+		memcpy(ipx->ipx_source.node, intrfc->if_node, IPX_NODE_LEN);
+	} else {
+		IPX_SKB_CB(skb)->ipx_source_net = ipxs->intrfc->if_netnum;
+		memcpy(ipx->ipx_source.node, ipxs->intrfc->if_node,
+			IPX_NODE_LEN);
+	}
+#endif	/* CONFIG_IPX_INTERN */
+	ipx->ipx_source.sock		= ipxs->port;
+	IPX_SKB_CB(skb)->ipx_dest_net	= usipx->sipx_network;
+	memcpy(ipx->ipx_dest.node, usipx->sipx_node, IPX_NODE_LEN);
+	ipx->ipx_dest.sock		= usipx->sipx_port;
+
+	rc = memcpy_fromiovec(skb_put(skb, len), iov, len);
+	if (rc) {
+		kfree_skb(skb);
+		goto out_put;
+	}	
+
+	/* Apply checksum. Not allowed on 802.3 links. */
+	if (sk->no_check || intrfc->if_dlink_type == IPX_FRAME_8023)
+		ipx->ipx_checksum = 0xFFFF;
+	else
+		ipx->ipx_checksum = ipx_cksum(ipx, len + sizeof(struct ipxhdr));
+
+	rc = ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ? 
+			 rt->ir_router_node : ipx->ipx_dest.node);
+out_put:
+	ipxitf_put(intrfc);
+	if (rt)
+		ipxrtr_put(rt);
+out:
+	return rc;
+}
+
+/*
+ * We use a normal struct rtentry for route handling
+ */
+int ipxrtr_ioctl(unsigned int cmd, void *arg)
+{
+	struct rtentry rt;	/* Use these to behave like 'other' stacks */
+	struct sockaddr_ipx *sg, *st;
+	int rc = -EFAULT;
+
+	if (copy_from_user(&rt, arg, sizeof(rt)))
+		goto out;
+
+	sg = (struct sockaddr_ipx *)&rt.rt_gateway;
+	st = (struct sockaddr_ipx *)&rt.rt_dst;
+
+	rc = -EINVAL;
+	if (!(rt.rt_flags & RTF_GATEWAY) || /* Direct routes are fixed */
+	    sg->sipx_family != AF_IPX ||
+	    st->sipx_family != AF_IPX)
+		goto out;
+
+	switch (cmd) {
+	case SIOCDELRT:
+		rc = ipxrtr_delete(st->sipx_network);
+		break;
+	case SIOCADDRT: {
+		struct ipx_route_definition f;
+		f.ipx_network		= st->sipx_network;
+		f.ipx_router_network	= sg->sipx_network;
+		memcpy(f.ipx_router_node, sg->sipx_node, IPX_NODE_LEN);
+		rc = ipxrtr_create(&f);
+		break;
+	}
+	}
+
+out:
+	return rc;
+}
diff -Nru a/net/irda/irda_device.c b/net/irda/irda_device.c
--- a/net/irda/irda_device.c	Tue Apr 29 02:29:48 2003
+++ b/net/irda/irda_device.c	Sat May 17 12:39:14 2003
@@ -433,13 +433,9 @@
 	ASSERT(dev != NULL, return NULL;);
 
 #ifdef CONFIG_KMOD
-	{
-	char modname[32];
 	ASSERT(!in_interrupt(), return NULL;);
 	/* Try to load the module needed */
-	sprintf(modname, "irda-dongle-%d", type);
-	request_module(modname);
-	}
+	request_module("irda-dongle-%d", type);
 #endif
 
 	if (!(reg = hashbin_lock_find(dongles, type, NULL))) {
diff -Nru a/net/irda/irlap.c b/net/irda/irlap.c
--- a/net/irda/irlap.c	Tue Apr 29 02:29:48 2003
+++ b/net/irda/irlap.c	Mon May 12 18:59:25 2003
@@ -1117,7 +1117,7 @@
 		len += sprintf(buf+len, "  win size: %d, ",
 			       self->window_size);
 		len += sprintf(buf+len, "win: %d, ", self->window);
-#if CONFIG_IRDA_DYNAMIC_WINDOW
+#ifdef CONFIG_IRDA_DYNAMIC_WINDOW
 		len += sprintf(buf+len, "line capacity: %d, ",
 			       self->line_capacity);
 		len += sprintf(buf+len, "bytes left: %d\n", self->bytes_left);
diff -Nru a/net/irda/irlap_event.c b/net/irda/irlap_event.c
--- a/net/irda/irlap_event.c	Tue Apr 29 02:29:48 2003
+++ b/net/irda/irlap_event.c	Mon May 12 18:59:24 2003
@@ -43,7 +43,7 @@
 
 #include <net/irda/irda_device.h>
 
-#if CONFIG_IRDA_FAST_RR
+#ifdef CONFIG_IRDA_FAST_RR
 int sysctl_fast_poll_increase = 50;
 #endif
 
diff -Nru a/net/irda/irproc.c b/net/irda/irproc.c
--- a/net/irda/irproc.c	Sat Feb 22 16:15:34 2003
+++ b/net/irda/irproc.c	Tue May 20 19:39:24 2003
@@ -53,8 +53,6 @@
 	{"irias",	irias_proc_read},
 };
 
-#define IRDA_ENTRIES_NUM (sizeof(dir)/sizeof(dir[0]))
- 
 /*
  * Function irda_proc_register (void)
  *
@@ -70,7 +68,7 @@
 		return;
 	proc_irda->owner = THIS_MODULE;
 
-	for (i=0;i<IRDA_ENTRIES_NUM;i++)
+	for (i=0; i<ARRAY_SIZE(dir); i++)
 		create_proc_info_entry(dir[i].name,0,proc_irda,dir[i].fn);
 }
 
@@ -85,7 +83,7 @@
 	int i;
 
         if (proc_irda) {
-                for (i=0;i<IRDA_ENTRIES_NUM;i++)
+                for (i=0; i<ARRAY_SIZE(dir); i++)
                         remove_proc_entry(dir[i].name, proc_irda);
 
                 remove_proc_entry("net/irda", NULL);
diff -Nru a/net/key/af_key.c b/net/key/af_key.c
--- a/net/key/af_key.c	Fri May  2 23:20:13 2003
+++ b/net/key/af_key.c	Wed May 14 13:12:43 2003
@@ -1090,15 +1090,8 @@
 	return x;
 
 out:
-	if (x->aalg)
-		kfree(x->aalg);
-	if (x->ealg)
-		kfree(x->ealg);
-	if (x->calg)
-		kfree(x->calg);
-	if (x->encap)
-		kfree(x->encap);
-	kfree(x);
+	x->km.state = XFRM_STATE_DEAD;
+	xfrm_state_put(x);
 	return ERR_PTR(-ENOBUFS);
 }
 
@@ -1249,7 +1242,8 @@
 		}
 	}
 
-	if (x1 && x1->id.spi && hdr->sadb_msg_type == SADB_ADD) {
+	if (x1 && ((x1->id.spi && hdr->sadb_msg_type == SADB_ADD) ||
+	     (hdr->sadb_msg_type == SADB_UPDATE && xfrm_state_kern(x1)))) {
 		x->km.state = XFRM_STATE_DEAD;
 		xfrm_state_put(x);
 		xfrm_state_put(x1);
@@ -1294,6 +1288,11 @@
 	if (x == NULL)
 		return -ESRCH;
 
+	if (xfrm_state_kern(x)) {
+		xfrm_state_put(x);
+		return -EPERM;
+	}
+	
 	xfrm_state_delete(x);
 	xfrm_state_put(x);
 
diff -Nru a/net/llc/llc_proc.c b/net/llc/llc_proc.c
--- a/net/llc/llc_proc.c	Tue Apr 29 22:38:37 2003
+++ b/net/llc/llc_proc.c	Sat May 10 11:46:35 2003
@@ -211,6 +211,7 @@
 }
 
 static struct file_operations llc_seq_socket_fops = {
+	.owner		= THIS_MODULE,
 	.open		= llc_seq_socket_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -218,6 +219,7 @@
 };
 
 static struct file_operations llc_seq_core_fops = {
+	.owner		= THIS_MODULE,
 	.open		= llc_seq_core_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
diff -Nru a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
--- a/net/netlink/af_netlink.c	Fri May  2 23:31:31 2003
+++ b/net/netlink/af_netlink.c	Wed May 14 19:19:15 2003
@@ -1082,7 +1082,7 @@
        remove_proc_entry("net/netlink", NULL);
 }
 
-subsys_initcall(netlink_proto_init);
+core_initcall(netlink_proto_init);
 module_exit(netlink_proto_exit);
 
 MODULE_LICENSE("GPL");
diff -Nru a/net/netlink/netlink_dev.c b/net/netlink/netlink_dev.c
--- a/net/netlink/netlink_dev.c	Tue Apr 22 00:00:05 2003
+++ b/net/netlink/netlink_dev.c	Tue May 20 19:39:24 2003
@@ -220,14 +220,6 @@
 	},
 };
 
-static void __init make_devfs_entries (const char *name, int minor)
-{
-	devfs_register (NULL, name, DEVFS_FL_DEFAULT,
-			NETLINK_MAJOR, minor,
-			S_IFCHR | S_IRUSR | S_IWUSR,
-			&netlink_fops, NULL);
-}
-
 int __init init_netlink(void)
 {
 	int i;
@@ -236,18 +228,20 @@
 		printk(KERN_ERR "netlink: unable to get major %d\n", NETLINK_MAJOR);
 		return -EIO;
 	}
+
 	devfs_mk_dir("netlink");
+
 	/*  Someone tell me the official names for the uppercase ones  */
-	for (i = 0; i < sizeof(entries)/sizeof(entries[0]); i++) {
-		char name[20];
-		sprintf(name, "netlink/%s", entries[i].name);
-		make_devfs_entries(name, entries[i].minor);
+	for (i = 0; i < ARRAY_SIZE(entries); i++) {
+		devfs_mk_cdev(MKDEV(NETLINK_MAJOR, entries[i].minor),
+			S_IFCHR|S_IRUSR|S_IWUSR, "netlink/%s", entries[i].name);
 	}
+
 	for (i = 0; i < 16; i++) {
-		char name[20];
-		sprintf(name, "netlink/tap%d", i);
-		make_devfs_entries(name, i + 16);
+		devfs_mk_cdev(MKDEV(NETLINK_MAJOR, i + 16),
+			S_IFCHR|S_IRUSR|S_IWUSR, "netlink/tap%d", i);
 	}
+
 	return 0;
 }
 
@@ -265,7 +259,7 @@
 {
 	int i;
 
-	for (i = 0; i < sizeof(entries)/sizeof(entries[0]); i++)
+	for (i = 0; i < ARRAY_SIZE(entries); i++)
 		devfs_remove("netlink/%s", entries[i].name);
 	for (i = 0; i < 16; i++)
 		devfs_remove("netlink/tap%d", i);
diff -Nru a/net/netrom/nr_loopback.c b/net/netrom/nr_loopback.c
--- a/net/netrom/nr_loopback.c	Mon Aug  5 06:20:38 2002
+++ b/net/netrom/nr_loopback.c	Wed May 14 20:40:01 2003
@@ -76,6 +76,9 @@
 		if (dev == NULL || nr_rx_frame(skb, dev) == 0)
 			kfree_skb(skb);
 
+		if (dev != NULL)
+			dev_put(dev);
+
 		if (!skb_queue_empty(&loopback_queue) && !nr_loopback_running())
 			nr_set_loopback_timer();
 	}
diff -Nru a/net/netrom/nr_route.c b/net/netrom/nr_route.c
--- a/net/netrom/nr_route.c	Mon Aug  5 09:23:19 2002
+++ b/net/netrom/nr_route.c	Sat May 17 14:09:51 2003
@@ -110,7 +110,8 @@
 				kfree(nr_neigh);
 				return -ENOMEM;
 			}
-			memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
+			memcpy(nr_neigh->digipeat, ax25_digi,
+					sizeof(*ax25_digi));
 		}
 
 		spin_lock_bh(&nr_neigh_lock);
@@ -387,7 +388,7 @@
 			kfree(nr_neigh);
 			return -ENOMEM;
 		}
-		memcpy(nr_neigh->digipeat, ax25_digi, sizeof(ax25_digi));
+		memcpy(nr_neigh->digipeat, ax25_digi, sizeof(*ax25_digi));
 	}
 
 	spin_lock_bh(&nr_neigh_lock);
diff -Nru a/net/netsyms.c b/net/netsyms.c
--- a/net/netsyms.c	Sun May  4 06:26:55 2003
+++ b/net/netsyms.c	Mon May 19 18:25:08 2003
@@ -45,6 +45,9 @@
 #include <linux/ip.h>
 #include <net/protocol.h>
 #include <net/arp.h>
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+#include <net/atmclip.h>
+#endif
 #include <net/ip.h>
 #include <net/udp.h>
 #include <net/tcp.h>
@@ -79,8 +82,6 @@
 
 #endif
 
-extern int netdev_finish_unregister(struct net_device *dev);
-
 #include <linux/rtnetlink.h>
 
 #ifdef CONFIG_IPX_MODULE
@@ -228,13 +229,11 @@
 #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
 EXPORT_SYMBOL(dev_change_flags);
 #endif
-EXPORT_SYMBOL(vlan_ioctl_set);
 
 EXPORT_SYMBOL(scm_detach_fds);
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 EXPORT_SYMBOL(br_handle_frame_hook);
-EXPORT_SYMBOL(brioctl_set);
 #endif
 
 #ifdef CONFIG_NET_DIVERT
@@ -285,18 +284,12 @@
 /* needed for ip_gre -cw */
 EXPORT_SYMBOL(ip_statistics);
 
-#ifdef CONFIG_DLCI_MODULE
-extern int (*dlci_ioctl_hook)(unsigned int, void *);
-EXPORT_SYMBOL(dlci_ioctl_hook);
-#endif
-
 EXPORT_SYMBOL(xfrm_user_policy);
 EXPORT_SYMBOL(km_waitq);
 EXPORT_SYMBOL(km_new_mapping);
 EXPORT_SYMBOL(xfrm_cfg_sem);
 EXPORT_SYMBOL(xfrm_policy_alloc);
 EXPORT_SYMBOL(__xfrm_policy_destroy);
-EXPORT_SYMBOL(xfrm_policy_lookup);
 EXPORT_SYMBOL(xfrm_lookup);
 EXPORT_SYMBOL(__xfrm_policy_check);
 EXPORT_SYMBOL(__xfrm_route_forward);
@@ -311,6 +304,7 @@
 EXPORT_SYMBOL(xfrm_state_unregister_afinfo);
 EXPORT_SYMBOL(xfrm_state_get_afinfo);
 EXPORT_SYMBOL(xfrm_state_put_afinfo);
+EXPORT_SYMBOL(xfrm_state_delete_tunnel);
 EXPORT_SYMBOL(xfrm_replay_check);
 EXPORT_SYMBOL(xfrm_replay_advance);
 EXPORT_SYMBOL(xfrm_check_selectors);
@@ -366,6 +360,9 @@
 EXPORT_SYMBOL_GPL(skb_to_sgvec);
 #endif
 
+EXPORT_SYMBOL(flow_cache_lookup);
+EXPORT_SYMBOL(flow_cache_genid);
+
 #if defined (CONFIG_IPV6_MODULE) || defined (CONFIG_IP_SCTP_MODULE)
 /* inet functions common to v4 and v6 */
 EXPORT_SYMBOL(inet_release);
@@ -423,7 +420,6 @@
 EXPORT_SYMBOL(tcp_rcv_state_process);
 EXPORT_SYMBOL(tcp_timewait_state_process);
 EXPORT_SYMBOL(tcp_timewait_cachep);
-EXPORT_SYMBOL(tcp_timewait_kill);
 EXPORT_SYMBOL(tcp_sendmsg);
 EXPORT_SYMBOL(tcp_v4_rebuild_header);
 EXPORT_SYMBOL(tcp_v4_send_check);
@@ -473,6 +469,8 @@
 EXPORT_SYMBOL(sysctl_max_syn_backlog);
 #endif
 
+EXPORT_SYMBOL(ip_generic_getfrag);
+
 #endif
 
 EXPORT_SYMBOL(tcp_read_sock);
@@ -530,6 +528,9 @@
 EXPORT_SYMBOL(ip_rcv);
 EXPORT_SYMBOL(arp_rcv);
 EXPORT_SYMBOL(arp_tbl);
+#if defined(CONFIG_ATM_CLIP) || defined(CONFIG_ATM_CLIP_MODULE)
+EXPORT_SYMBOL(clip_tbl_hook);
+#endif
 EXPORT_SYMBOL(arp_find);
 
 #endif  /* CONFIG_INET */
@@ -559,7 +560,6 @@
 EXPORT_SYMBOL(dev_get_by_name);
 EXPORT_SYMBOL(__dev_get_by_name);
 EXPORT_SYMBOL(dev_getbyhwaddr);
-EXPORT_SYMBOL(netdev_finish_unregister);
 EXPORT_SYMBOL(netdev_set_master);
 EXPORT_SYMBOL(eth_type_trans);
 #ifdef CONFIG_FDDI
@@ -577,6 +577,7 @@
 EXPORT_SYMBOL(netif_receive_skb);
 EXPORT_SYMBOL(dev_add_pack);
 EXPORT_SYMBOL(dev_remove_pack);
+EXPORT_SYMBOL(__dev_remove_pack);
 EXPORT_SYMBOL(dev_get);
 EXPORT_SYMBOL(dev_alloc);
 EXPORT_SYMBOL(dev_alloc_name);
@@ -673,10 +674,13 @@
 EXPORT_SYMBOL(softnet_data);
 
 #ifdef CONFIG_NET_RADIO
-/* Don't include the whole header mess for a single function */
-union iwreq_data;
-extern void wireless_send_event(struct net_device *dev, unsigned int cmd, union iwreq_data *wrqu, char *extra);
+#include <net/iw_handler.h>		/* Wireless Extensions driver API */
 EXPORT_SYMBOL(wireless_send_event);
+EXPORT_SYMBOL(iw_handler_set_spy);
+EXPORT_SYMBOL(iw_handler_get_spy);
+EXPORT_SYMBOL(iw_handler_set_thrspy);
+EXPORT_SYMBOL(iw_handler_get_thrspy);
+EXPORT_SYMBOL(wireless_spy_update);
 #endif	/* CONFIG_NET_RADIO */
 
 EXPORT_SYMBOL(linkwatch_fire_event);
diff -Nru a/net/nonet.c b/net/nonet.c
--- a/net/nonet.c	Thu Mar 20 00:55:20 2003
+++ b/net/nonet.c	Mon May 12 21:15:50 2003
@@ -8,6 +8,7 @@
  * Copyright (c) Matthew Wilcox 2003
  */
 
+#include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/init.h>
@@ -24,5 +25,6 @@
 }
 
 struct file_operations bad_sock_fops = {
+	.owner = THIS_MODULE,
 	.open = sock_no_open,
 };
diff -Nru a/net/packet/af_packet.c b/net/packet/af_packet.c
--- a/net/packet/af_packet.c	Fri May  2 23:37:54 2003
+++ b/net/packet/af_packet.c	Mon May 19 23:22:52 2003
@@ -774,6 +774,7 @@
 		 */
 		dev_remove_pack(&po->prot_hook);
 		po->running = 0;
+		po->num = 0;
 		__sock_put(sk);
 	}
 
@@ -819,9 +820,12 @@
 
 	spin_lock(&po->bind_lock);
 	if (po->running) {
-		dev_remove_pack(&po->prot_hook);
 		__sock_put(sk);
 		po->running = 0;
+		po->num = 0;
+		spin_unlock(&po->bind_lock);
+		dev_remove_pack(&po->prot_hook);
+		spin_lock(&po->bind_lock);
 	}
 
 	po->num = protocol;
@@ -1374,7 +1378,7 @@
 			if (dev->ifindex == po->ifindex) {
 				spin_lock(&po->bind_lock);
 				if (po->running) {
-					dev_remove_pack(&po->prot_hook);
+					__dev_remove_pack(&po->prot_hook);
 					__sock_put(sk);
 					po->running = 0;
 					sk->err = ENETDOWN;
@@ -1618,9 +1622,14 @@
 
 	/* Detach socket from network */
 	spin_lock(&po->bind_lock);
-	if (po->running)
-		dev_remove_pack(&po->prot_hook);
+	if (po->running) {
+		__dev_remove_pack(&po->prot_hook);
+		po->num = 0;
+		po->running = 0;
+	}
 	spin_unlock(&po->bind_lock);
+		
+	synchronize_net();
 
 	err = -EBUSY;
 	if (closing || atomic_read(&po->mapped) == 0) {
diff -Nru a/net/rxrpc/proc.c b/net/rxrpc/proc.c
--- a/net/rxrpc/proc.c	Wed Oct 16 05:37:40 2002
+++ b/net/rxrpc/proc.c	Mon May 12 21:11:28 2003
@@ -38,6 +38,7 @@
 };
 
 static struct file_operations rxrpc_proc_transports_fops = {
+	.owner		= THIS_MODULE,
 	.open		= rxrpc_proc_transports_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -58,6 +59,7 @@
 };
 
 static struct file_operations rxrpc_proc_peers_fops = {
+	.owner		= THIS_MODULE,
 	.open		= rxrpc_proc_peers_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -78,6 +80,7 @@
 };
 
 static struct file_operations rxrpc_proc_conns_fops = {
+	.owner		= THIS_MODULE,
 	.open		= rxrpc_proc_conns_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -98,6 +101,7 @@
 };
 
 static struct file_operations rxrpc_proc_calls_fops = {
+	.owner		= THIS_MODULE,
 	.open		= rxrpc_proc_calls_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
diff -Nru a/net/sched/Kconfig b/net/sched/Kconfig
--- a/net/sched/Kconfig	Fri Apr  4 10:01:38 2003
+++ b/net/sched/Kconfig	Thu May 15 21:12:28 2003
@@ -63,7 +63,7 @@
 #tristate '  H-PFQ packet scheduler' CONFIG_NET_SCH_HPFQ
 #tristate '  H-FSC packet scheduler' CONFIG_NET_SCH_HFCS
 config NET_SCH_ATM
-	bool "ATM pseudo-scheduler"
+	tristate "ATM pseudo-scheduler"
 	depends on NET_SCHED && ATM
 	---help---
 	  Say Y here if you want to use the ATM pseudo-scheduler.  This
diff -Nru a/net/sched/cls_api.c b/net/sched/cls_api.c
--- a/net/sched/cls_api.c	Tue Apr 29 22:49:12 2003
+++ b/net/sched/cls_api.c	Sat May 17 12:39:14 2003
@@ -204,11 +204,9 @@
 #ifdef CONFIG_KMOD
 		if (tp_ops==NULL && tca[TCA_KIND-1] != NULL) {
 			struct rtattr *kind = tca[TCA_KIND-1];
-			char module_name[4 + IFNAMSIZ + 1];
 
 			if (RTA_PAYLOAD(kind) <= IFNAMSIZ) {
-				sprintf(module_name, "cls_%s", (char*)RTA_DATA(kind));
-				request_module (module_name);
+				request_module("cls_%s", (char*)RTA_DATA(kind));
 				tp_ops = tcf_proto_lookup_ops(kind);
 			}
 		}
diff -Nru a/net/sched/sch_api.c b/net/sched/sch_api.c
--- a/net/sched/sch_api.c	Tue Apr 29 22:49:12 2003
+++ b/net/sched/sch_api.c	Sat May 17 12:39:14 2003
@@ -396,11 +396,8 @@
 	ops = qdisc_lookup_ops(kind);
 #ifdef CONFIG_KMOD
 	if (ops==NULL && tca[TCA_KIND-1] != NULL) {
-		char module_name[4 + IFNAMSIZ + 1];
-
 		if (RTA_PAYLOAD(kind) <= IFNAMSIZ) {
-			sprintf(module_name, "sch_%s", (char*)RTA_DATA(kind));
-			request_module (module_name);
+			request_module("sch_%s", (char*)RTA_DATA(kind));
 			ops = qdisc_lookup_ops(kind);
 		}
 	}
diff -Nru a/net/sched/sch_atm.c b/net/sched/sch_atm.c
--- a/net/sched/sch_atm.c	Sun Apr 20 00:57:16 2003
+++ b/net/sched/sch_atm.c	Wed May  7 15:25:42 2003
@@ -509,7 +509,6 @@
 			memcpy(skb_push(skb,flow->hdr_len),flow->hdr,
 			    flow->hdr_len);
 			atomic_add(skb->truesize,&flow->vcc->sk->wmem_alloc);
-			ATM_SKB(skb)->iovcnt = 0;
 			/* atm.atm_options are already set by atm_tc_enqueue */
 			(void) flow->vcc->send(flow->vcc,skb);
 		}
diff -Nru a/net/sched/sch_csz.c b/net/sched/sch_csz.c
--- a/net/sched/sch_csz.c	Sun May  4 06:08:13 2003
+++ b/net/sched/sch_csz.c	Wed May 14 20:36:13 2003
@@ -301,8 +301,8 @@
 
 #if 0
 /* Scan forward */
-extern __inline__ void csz_insert_finish(struct csz_head *b,
-					 struct csz_flow *this)
+static inline void csz_insert_finish(struct csz_head *b,
+				     struct csz_flow *this)
 {
 	struct csz_head *f = b->fnext;
 	unsigned long finish = this->finish;
@@ -318,8 +318,8 @@
 }
 #else
 /* Scan backward */
-extern __inline__ void csz_insert_finish(struct csz_head *b,
-					 struct csz_flow *this)
+static inline void csz_insert_finish(struct csz_head *b,
+				     struct csz_flow *this)
 {
 	struct csz_head *f = b->fprev;
 	unsigned long finish = this->finish;
@@ -339,8 +339,8 @@
    flow with greater start number.
  */
 
-extern __inline__ void csz_insert_start(struct csz_head *b,
-					struct csz_flow *this)
+static inline void csz_insert_start(struct csz_head *b,
+				    struct csz_flow *this)
 {
 	struct csz_head *f = b->snext;
 	unsigned long start = this->start;
diff -Nru a/net/sched/sch_ingress.c b/net/sched/sch_ingress.c
--- a/net/sched/sch_ingress.c	Wed Apr 30 02:03:57 2003
+++ b/net/sched/sch_ingress.c	Mon May 12 15:38:32 2003
@@ -222,11 +222,6 @@
 */
 
 	if (dev->qdisc_ingress) {
-		/* FIXME: Push down to ->enqueue functions --RR */
-		if (skb_is_nonlinear(*pskb)
-		    && skb_linearize(*pskb, GFP_ATOMIC) != 0)
-			return NF_DROP;
-
 		spin_lock(&dev->queue_lock);
 		if ((q = dev->qdisc_ingress) != NULL)
 			fwres = q->enqueue(skb, q);
diff -Nru a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c
--- a/net/sched/sch_sfq.c	Sun Apr 20 00:57:16 2003
+++ b/net/sched/sch_sfq.c	Wed May 14 20:36:13 2003
@@ -166,7 +166,7 @@
 	return sfq_fold_hash(q, h, h2);
 }
 
-extern __inline__ void sfq_link(struct sfq_sched_data *q, sfq_index x)
+static inline void sfq_link(struct sfq_sched_data *q, sfq_index x)
 {
 	sfq_index p, n;
 	int d = q->qs[x].qlen + SFQ_DEPTH;
@@ -178,7 +178,7 @@
 	q->dep[p].next = q->dep[n].prev = x;
 }
 
-extern __inline__ void sfq_dec(struct sfq_sched_data *q, sfq_index x)
+static inline void sfq_dec(struct sfq_sched_data *q, sfq_index x)
 {
 	sfq_index p, n;
 
@@ -193,7 +193,7 @@
 	sfq_link(q, x);
 }
 
-extern __inline__ void sfq_inc(struct sfq_sched_data *q, sfq_index x)
+static inline void sfq_inc(struct sfq_sched_data *q, sfq_index x)
 {
 	sfq_index p, n;
 	int d;
diff -Nru a/net/sctp/Kconfig b/net/sctp/Kconfig
--- a/net/sctp/Kconfig	Mon Feb 10 14:44:44 2003
+++ b/net/sctp/Kconfig	Sat May 10 05:18:59 2003
@@ -43,12 +43,12 @@
 	bool "SCTP: Use old checksum (Adler-32)"
 	depends on IP_SCTP
 	help
-	  RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP.  
+	  RCF2960 currently specifies the Adler-32 checksum algorithm for SCTP.
 	  This has been deprecated and replaced by an algorithm now referred
 	  to as crc32c.
 
-	  If you say Y, this will use the Adler-32 algorithm, this might be useful
-	  for interoperation with downlevel peers. 
+	  If you say Y, this will use the Adler-32 algorithm, this might be 
+	  useful for interoperation with downlevel peers. 
 
 	  If unsure, say N.  
 
@@ -58,19 +58,47 @@
 	help
 	  If you say Y, this will enable verbose debugging messages. 
 
-	  If unsure, say N.  However, if you are running into problems, use this
-	  option to gather detailed trace information
+	  If unsure, say N.  However, if you are running into problems, use 
+	  this option to gather detailed trace information
 
 config SCTP_DBG_OBJCNT
 	bool "SCTP: Debug object counts"
 	depends on IP_SCTP
 	help
-	  If you say Y, this will enable debugging support for counting the types
-	  of objects that are currently allocated.  This is useful for identifying
-	  memory leaks.   If the /proc filesystem is enabled this debug information
-	  can be viewed by 'cat /proc/net/sctp/sctp_dbg_objcnt'
+	  If you say Y, this will enable debugging support for counting the 
+	  type of objects that are currently allocated.  This is useful for 
+	  identifying memory leaks.   If the /proc filesystem is enabled this 
+	  debug information can be viewed by 
+	  'cat /proc/net/sctp/sctp_dbg_objcnt'
 
 	  If unsure, say N
 
-endmenu
+choice
+	prompt "SCTP: Cookie HMAC Algorithm"
+	depends on IP_SCTP
+	help
+	  HMAC algorithm to be used during association initialization.  It
+	  is strongly recommended to use HMAC-SHA1 or HMAC-MD5.  See 
+	  configuration for Cryptographic API and enable those algorithms
+          to make usable by SCTP. 
+
+config SCTP_HMAC_NONE
+	bool "None"
+	help 
+	  Choosing this disables the use of an HMAC during association 
+	  establishment.  It is advised to use either HMAC-MD5 or HMAC-SHA1.
+
+config SCTP_HMAC_SHA1
+	bool "HMAC-SHA1" if CRYPTO_HMAC=y && CRYPTO_SHA1=y || CRYPTO_SHA1=m
+	help 
+	  Enable the use of HMAC-SHA1 during association establishment.  It 
+	  is advised to use either HMAC-MD5 or HMAC-SHA1.
 
+config SCTP_HMAC_MD5
+	bool "HMAC-MD5" if CRYPTO_HMAC=y && CRYPTO_MD5=y || CRYPTO_MD5=m
+	help
+	  Enable the use of HMAC-MD5 during association establishment.  It is 
+	  advised to use either HMAC-MD5 or HMAC-SHA1.
+
+endchoice
+endmenu
diff -Nru a/net/sctp/Makefile b/net/sctp/Makefile
--- a/net/sctp/Makefile	Wed Feb 12 10:46:17 2003
+++ b/net/sctp/Makefile	Mon Apr 21 10:26:19 2003
@@ -6,11 +6,10 @@
 
 sctp-y := sm_statetable.o sm_statefuns.o sm_sideeffect.o \
 	  protocol.o endpointola.o associola.o \
-	  transport.o sm_make_chunk.o ulpevent.o \
+	  transport.o chunk.o sm_make_chunk.o ulpevent.o \
 	  inqueue.o outqueue.o ulpqueue.o command.o \
 	  tsnmap.o bind_addr.o socket.o primitive.o \
-	  output.o input.o hashdriver.o sla1.o \
-	  debug.o ssnmap.o proc.o
+	  output.o input.o debug.o ssnmap.o proc.o
 
 ifeq ($(CONFIG_SCTP_ADLER32), y)
 sctp-y += adler32.o
diff -Nru a/net/sctp/adler32.c b/net/sctp/adler32.c
--- a/net/sctp/adler32.c	Tue Apr 29 02:29:48 2003
+++ b/net/sctp/adler32.c	Tue May  6 16:40:02 2003
@@ -2,43 +2,43 @@
  * Copyright (c) 1999-2000 Cisco, Inc.
  * Copyright (c) 1999-2001 Motorola, Inc.
  * Copyright (c) 2003 International Business Machines, Corp.
- * 
+ *
  * This file is part of the SCTP kernel reference Implementation
- * 
- * This file has direct heritage from the SCTP user-level reference 
+ *
+ * This file has direct heritage from the SCTP user-level reference
  * implementation by R. Stewart, et al.  These functions implement the
- * Adler-32 algorithm as specified by RFC 2960. 
- * 
- * The SCTP reference implementation is free software; 
- * you can redistribute it and/or modify it under the terms of 
+ * Adler-32 algorithm as specified by RFC 2960.
+ *
+ * The SCTP reference implementation 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.
- * 
- * The SCTP reference implementation is distributed in the hope that it 
+ *
+ * The SCTP reference implementation 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 GNU CC; see the file COPYING.  If not, write to
  * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.  
- * 
+ * Boston, MA 02111-1307, USA.
+ *
  * Please send any bug reports or fixes you make to the
  * email address(es):
  *    lksctp developers <lksctp-developers@lists.sourceforge.net>
- * 
+ *
  * Or submit a bug report through the following website:
  *    http://www.sf.net/projects/lksctp
  *
- * Written or modified by: 
+ * Written or modified by:
  *    Randall Stewart <rstewar1@email.mot.com>
  *    Ken Morneau     <kmorneau@cisco.com>
  *    Qiaobing Xie    <qxie1@email.mot.com>
  *    Sridhar Samudrala <sri@us.ibm.com>
- * 
+ *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
  */
@@ -65,7 +65,7 @@
  * tad, but I have commented the original lines below
  */
 
-#include <linux/types.h> 
+#include <linux/types.h>
 #include <net/sctp/sctp.h>
 
 #define BASE 65521 /* largest prime smaller than 65536 */
@@ -111,7 +111,7 @@
 		 * This would then be (2 * BASE) - 2, which
 		 * will still only do one subtract. On Intel
 		 * this is much better to do this way and
-		 * avoid the divide. Have not -pg'd on 
+		 * avoid the divide. Have not -pg'd on
 		 * sparc.
 		 */
 		if (s2 >= BASE) {
@@ -135,7 +135,7 @@
 	__u32 zero = 0L;
 
 	/* Calculate the CRC up to the checksum field. */
-	adler = update_adler32(adler, ptr, 
+	adler = update_adler32(adler, ptr,
 			       sizeof(struct sctphdr) - sizeof(__u32));
 	/* Skip over the checksum field. */
 	adler = update_adler32(adler, (unsigned char *) &zero,
@@ -152,6 +152,15 @@
 __u32 sctp_update_cksum(__u8 *ptr, __u16 count, __u32 adler)
 {
 	adler = update_adler32(adler, ptr, count);
+
+	return adler;
+}
+
+__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 count, __u32 adler)
+{
+	/* Its not worth it to try harder.  Adler32 is obsolescent. */
+	adler = update_adler32(adler, from, count);
+	memcpy(to, from, count);
 
 	return adler;
 }
diff -Nru a/net/sctp/associola.c b/net/sctp/associola.c
--- a/net/sctp/associola.c	Tue Apr 29 02:29:48 2003
+++ b/net/sctp/associola.c	Tue May  6 16:40:02 2003
@@ -58,23 +58,23 @@
 #include <net/sctp/sctp.h>
 
 /* Forward declarations for internal functions. */
-static void sctp_assoc_bh_rcv(sctp_association_t *asoc);
+static void sctp_assoc_bh_rcv(struct sctp_association *asoc);
 
 
 /* 1st Level Abstractions. */
 
 /* Allocate and initialize a new association */
-sctp_association_t *sctp_association_new(const sctp_endpoint_t *ep,
+struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
 					 const struct sock *sk,
-					 sctp_scope_t scope, int priority)
+					 sctp_scope_t scope, int gfp)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
-	asoc = t_new(sctp_association_t, priority);
+	asoc = t_new(struct sctp_association, gfp);
 	if (!asoc)
 		goto fail;
 
-	if (!sctp_association_init(asoc, ep, sk, scope, priority))
+	if (!sctp_association_init(asoc, ep, sk, scope, gfp))
 		goto fail_init;
 
 	asoc->base.malloced = 1;
@@ -89,23 +89,24 @@
 }
 
 /* Initialize a new association from provided memory. */
-sctp_association_t *sctp_association_init(sctp_association_t *asoc,
-					  const sctp_endpoint_t *ep,
+struct sctp_association *sctp_association_init(struct sctp_association *asoc,
+					  const struct sctp_endpoint *ep,
 					  const struct sock *sk,
 					  sctp_scope_t scope,
-					  int priority)
+					  int gfp)
 {
 	struct sctp_opt *sp;
+	struct sctp_protocol *proto = sctp_get_protocol();
 	int i;
 
 	/* Retrieve the SCTP per socket area.  */
 	sp = sctp_sk((struct sock *)sk);
 
 	/* Init all variables to a known value.  */
-	memset(asoc, 0, sizeof(sctp_association_t));
+	memset(asoc, 0, sizeof(struct sctp_association));
 
 	/* Discarding const is appropriate here.  */
-	asoc->ep = (sctp_endpoint_t *)ep;
+	asoc->ep = (struct sctp_endpoint *)ep;
 	sctp_endpoint_hold(asoc->ep);
 
 	/* Hold the sock.  */
@@ -136,10 +137,10 @@
 	asoc->frag_point = 0;
 
 	/* Initialize the default association max_retrans and RTO values.  */
-	asoc->max_retrans = ep->proto->max_retrans_association;
-	asoc->rto_initial = ep->proto->rto_initial;
-	asoc->rto_max = ep->proto->rto_max;
-	asoc->rto_min = ep->proto->rto_min;
+	asoc->max_retrans = proto->max_retrans_association;
+	asoc->rto_initial = proto->rto_initial;
+	asoc->rto_max = proto->rto_max;
+	asoc->rto_min = proto->rto_min;
 
 	asoc->overall_error_threshold = 0;
 	asoc->overall_error_count = 0;
@@ -147,7 +148,7 @@
 	/* Initialize the maximum mumber of new data packets that can be sent
 	 * in a burst.
 	 */
-	asoc->max_burst = ep->proto->max_burst;
+	asoc->max_burst = proto->max_burst;
 
 	/* Copy things from the endpoint.  */
 	for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i) {
@@ -255,7 +256,7 @@
 				      sctp_packet_transmit_chunk,
 				      sctp_packet_transmit);
 
-	if (NULL == sctp_ulpq_init(&asoc->ulpq, asoc))
+	if (!sctp_ulpq_init(&asoc->ulpq, asoc))
 		goto fail_init;
 
 	/* Set up the tsn tracking. */
@@ -265,7 +266,6 @@
 
 	asoc->need_ecne = 0;
 
-	asoc->debug_name = "unnamedasoc";
 	asoc->eyecatcher = SCTP_ASSOC_EYECATCHER;
 
 	/* Assume that peer would support both address types unless we are
@@ -288,7 +288,7 @@
 /* Free this association if possible.  There may still be users, so
  * the actual deallocation may be delayed.
  */
-void sctp_association_free(sctp_association_t *asoc)
+void sctp_association_free(struct sctp_association *asoc)
 {
 	struct sock *sk = asoc->base.sk;
 	struct sctp_transport *transport;
@@ -298,8 +298,7 @@
 	list_del(&asoc->asocs);
 
 	/* Decrement the backlog value for a TCP-style listening socket. */
-	if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
-	    (SCTP_SS_LISTENING == sk->state))
+	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
 		sk->ack_backlog--;
 
 	/* Mark as dead, so other users can know this structure is
@@ -351,7 +350,7 @@
 }
 
 /* Cleanup and free up an association. */
-static void sctp_association_destroy(sctp_association_t *asoc)
+static void sctp_association_destroy(struct sctp_association *asoc)
 {
 	SCTP_ASSERT(asoc->base.dead, "Assoc is not dead", return);
 
@@ -379,31 +378,56 @@
 	 */
 	if (transport->active)
 		asoc->peer.active_path = transport;
+
+	/* 
+	 * SFR-CACC algorithm:
+	 * Upon the receipt of a request to change the primary
+	 * destination address, on the data structure for the new
+	 * primary destination, the sender MUST do the following:
+	 *
+	 * 1) If CHANGEOVER_ACTIVE is set, then there was a switch
+	 * to this destination address earlier. The sender MUST set
+	 * CYCLING_CHANGEOVER to indicate that this switch is a
+	 * double switch to the same destination address.
+	 */
+	if (transport->cacc.changeover_active)
+		transport->cacc.cycling_changeover = 1;
+
+	/* 2) The sender MUST set CHANGEOVER_ACTIVE to indicate that
+	 * a changeover has occurred.
+	 */
+	transport->cacc.changeover_active = 1;
+
+	/* 3) The sender MUST store the next TSN to be sent in
+	 * next_tsn_at_change.
+	 */
+	transport->cacc.next_tsn_at_change = asoc->next_tsn;
 }
 
 /* Add a transport address to an association.  */
 struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
 					   const union sctp_addr *addr,
-					   int priority)
+					   int gfp)
 {
 	struct sctp_transport *peer;
 	struct sctp_opt *sp;
 	unsigned short port;
 
+	sp = sctp_sk(asoc->base.sk);
+
 	/* AF_INET and AF_INET6 share common port field. */
 	port = addr->v4.sin_port;
 
 	/* Set the port if it has not been set yet.  */
-	if (0 == asoc->peer.port) {
+	if (0 == asoc->peer.port)
 		asoc->peer.port = port;
-	}
 
 	/* Check to see if this is a duplicate. */
 	peer = sctp_assoc_lookup_paddr(asoc, addr);
 	if (peer)
 		return peer;
 
-	peer = sctp_transport_new(addr, priority);
+	peer = sctp_transport_new(addr, gfp);
 	if (!peer)
 		return NULL;
 
@@ -425,7 +449,7 @@
 	SCTP_DEBUG_PRINTK("sctp_assoc_add_peer:association %p PMTU set to "
 			  "%d\n", asoc, asoc->pmtu);
 
-	asoc->frag_point = sctp_frag_point(asoc->pmtu);
+	asoc->frag_point = sctp_frag_point(sp, asoc->pmtu);
 
 	/* The asoc->peer.port might not be meaningful yet, but
 	 * initialize the packet structure anyway.
@@ -470,14 +494,14 @@
 	/* Initialize the peer's heartbeat interval based on the
 	 * sock configured value.
 	 */
-	sp = sctp_sk(asoc->base.sk);
+
 	peer->hb_interval = sp->paddrparam.spp_hbinterval * HZ;
 
 	/* Attach the remote transport to our asoc.  */
 	list_add_tail(&peer->transports, &asoc->peer.transport_addr_list);
 
 	/* If we do not yet have a primary path, set one.  */
-	if (NULL == asoc->peer.primary_path) {
+	if (!asoc->peer.primary_path) {
 		sctp_assoc_set_primary(asoc, peer);
 		asoc->peer.retran_path = peer;
 	}
@@ -489,8 +513,9 @@
 }
 
 /* Lookup a transport by address. */
-struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *asoc,
-					  const union sctp_addr *address)
+struct sctp_transport *sctp_assoc_lookup_paddr(
+					const struct sctp_association *asoc,
+					const union sctp_addr *address)
 {
 	struct sctp_transport *t;
 	struct list_head *pos;
@@ -510,7 +535,7 @@
  * Mark the transport up or down and send a notification to the user.
  * Select and update the new active and retran paths.
  */
-void sctp_assoc_control_transport(sctp_association_t *asoc,
+void sctp_assoc_control_transport(struct sctp_association *asoc,
 				  struct sctp_transport *transport,
 				  sctp_transport_cmd_t command,
 				  sctp_sn_error_t error)
@@ -589,7 +614,7 @@
 	/* If we failed to find a usable transport, just camp on the
 	 * primary, even if it is inactive.
 	 */
-	if (NULL == first) {
+	if (!first) {
 		first = asoc->peer.primary_path;
 		second = asoc->peer.primary_path;
 	}
@@ -600,7 +625,7 @@
 }
 
 /* Hold a reference to an association. */
-void sctp_association_hold(sctp_association_t *asoc)
+void sctp_association_hold(struct sctp_association *asoc)
 {
 	atomic_inc(&asoc->base.refcnt);
 }
@@ -608,7 +633,7 @@
 /* Release a reference to an association and cleanup
  * if there are no more references.
  */
-void sctp_association_put(sctp_association_t *asoc)
+void sctp_association_put(struct sctp_association *asoc)
 {
 	if (atomic_dec_and_test(&asoc->base.refcnt))
 		sctp_association_destroy(asoc);
@@ -617,7 +642,7 @@
 /* Allocate the next TSN, Transmission Sequence Number, for the given
  * association.
  */
-__u32 sctp_association_get_next_tsn(sctp_association_t *asoc)
+__u32 sctp_association_get_next_tsn(struct sctp_association *asoc)
 {
 	/* From Section 1.6 Serial Number Arithmetic:
 	 * Transmission Sequence Numbers wrap around when they reach
@@ -632,7 +657,7 @@
 }
 
 /* Allocate 'num' TSNs by incrementing the association's TSN by num. */
-__u32 sctp_association_get_tsn_block(sctp_association_t *asoc, int num)
+__u32 sctp_association_get_tsn_block(struct sctp_association *asoc, int num)
 {
 	__u32 retval = asoc->next_tsn;
 
@@ -662,7 +687,7 @@
  * Note:  We are sly and return a shared, prealloced chunk.  FIXME:
  * No we don't, but we could/should.
  */
-sctp_chunk_t *sctp_get_ecne_prepend(struct sctp_association *asoc)
+struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc)
 {
 	struct sctp_chunk *chunk;
 
@@ -680,7 +705,7 @@
 /* Use this function for the packet prepend callback when no ECNE
  * packet is desired (e.g. some packets don't like to be bundled).
  */
-sctp_chunk_t *sctp_get_no_prepend(sctp_association_t *asoc)
+struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc)
 {
 	return NULL;
 }
@@ -688,13 +713,14 @@
 /*
  * Find which transport this TSN was sent on.
  */
-struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *asoc, __u32 tsn)
+struct sctp_transport *sctp_assoc_lookup_tsn(struct sctp_association *asoc,
+					     __u32 tsn)
 {
 	struct sctp_transport *active;
 	struct sctp_transport *match;
 	struct list_head *entry, *pos;
 	struct sctp_transport *transport;
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 	__u32 key = htonl(tsn);
 
 	match = NULL;
@@ -717,7 +743,7 @@
 	active = asoc->peer.active_path;
 
 	list_for_each(entry, &active->transmitted) {
-		chunk = list_entry(entry, sctp_chunk_t, transmitted_list);
+		chunk = list_entry(entry, struct sctp_chunk, transmitted_list);
 
 		if (key == chunk->subh.data_hdr->tsn) {
 			match = active;
@@ -732,7 +758,7 @@
 		if (transport == active)
 			break;
 		list_for_each(entry, &transport->transmitted) {
-			chunk = list_entry(entry, sctp_chunk_t,
+			chunk = list_entry(entry, struct sctp_chunk,
 					   transmitted_list);
 			if (key == chunk->subh.data_hdr->tsn) {
 				match = transport;
@@ -745,7 +771,7 @@
 }
 
 /* Is this the association we are looking for? */
-struct sctp_transport *sctp_assoc_is_match(sctp_association_t *asoc,
+struct sctp_transport *sctp_assoc_is_match(struct sctp_association *asoc,
 					   const union sctp_addr *laddr,
 					   const union sctp_addr *paddr)
 {
@@ -771,10 +797,10 @@
 }
 
 /* Do delayed input processing.  This is scheduled by sctp_rcv(). */
-static void sctp_assoc_bh_rcv(sctp_association_t *asoc)
+static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
 {
-	sctp_endpoint_t *ep;
-	sctp_chunk_t *chunk;
+	struct sctp_endpoint *ep;
+	struct sctp_chunk *chunk;
 	struct sock *sk;
 	struct sctp_inq *inqueue;
 	int state, subtype;
@@ -819,7 +845,7 @@
 }
 
 /* This routine moves an association from its old sk to a new sk.  */
-void sctp_assoc_migrate(sctp_association_t *assoc, struct sock *newsk)
+void sctp_assoc_migrate(struct sctp_association *assoc, struct sock *newsk)
 {
 	struct sctp_opt *newsp = sctp_sk(newsk);
 	struct sock *oldsk = assoc->base.sk;
@@ -830,7 +856,7 @@
 	list_del(&assoc->asocs);
 
 	/* Decrement the backlog value for a TCP-style socket. */
-	if (SCTP_SOCKET_TCP == sctp_sk(oldsk)->type)
+	if (sctp_style(oldsk, TCP))
 		oldsk->ack_backlog--;
 
 	/* Release references to the old endpoint and the sock.  */
@@ -850,7 +876,8 @@
 }
 
 /* Update an association (possibly from unexpected COOKIE-ECHO processing).  */
-void sctp_assoc_update(sctp_association_t *asoc, sctp_association_t *new)
+void sctp_assoc_update(struct sctp_association *asoc,
+		       struct sctp_association *new)
 {
 	/* Copy in new parameters of peer. */
 	asoc->c = new->c;
@@ -872,7 +899,7 @@
 	 * current next_tsn in case data sent to peer
 	 * has been discarded and needs retransmission.
 	 */
-	if (SCTP_STATE_ESTABLISHED == asoc->state) {
+	if (sctp_state(asoc, ESTABLISHED)) {
 
 		asoc->next_tsn = new->next_tsn;
 		asoc->ctsn_ack_point = new->ctsn_ack_point;
@@ -898,7 +925,7 @@
  * through the inactive transports as this is the next best thing
  * we can try.
  */
-void sctp_assoc_update_retran_path(sctp_association_t *asoc)
+void sctp_assoc_update_retran_path(struct sctp_association *asoc)
 {
 	struct sctp_transport *t, *next;
 	struct list_head *head = &asoc->peer.transport_addr_list;
@@ -944,7 +971,8 @@
 }
 
 /* Choose the transport for sending a SHUTDOWN packet.  */
-struct sctp_transport *sctp_assoc_choose_shutdown_transport(sctp_association_t *asoc)
+struct sctp_transport *sctp_assoc_choose_shutdown_transport(
+	struct sctp_association *asoc)
 {
 	/* If this is the first time SHUTDOWN is sent, use the active path,
 	 * else use the retran path. If the last SHUTDOWN was sent over the
@@ -963,7 +991,7 @@
 /* Update the association's pmtu and frag_point by going through all the
  * transports. This routine is called when a transport's PMTU has changed.
  */
-void sctp_assoc_sync_pmtu(sctp_association_t *asoc)
+void sctp_assoc_sync_pmtu(struct sctp_association *asoc)
 {
 	struct sctp_transport *t;
 	struct list_head *pos;
@@ -980,8 +1008,9 @@
 	}
 
 	if (pmtu) {
+		struct sctp_opt *sp = sctp_sk(asoc->base.sk);
 		asoc->pmtu = pmtu;
-		asoc->frag_point = sctp_frag_point(pmtu);
+		asoc->frag_point = sctp_frag_point(sp, pmtu);
 	}
 
 	SCTP_DEBUG_PRINTK("%s: asoc:%p, pmtu:%d, frag_point:%d\n",
@@ -1007,9 +1036,9 @@
 }
 
 /* Increase asoc's rwnd by len and send any window update SACK if needed. */
-void sctp_assoc_rwnd_increase(sctp_association_t *asoc, int len)
+void sctp_assoc_rwnd_increase(struct sctp_association *asoc, int len)
 {
-	sctp_chunk_t *sack;
+	struct sctp_chunk *sack;
 	struct timer_list *timer;
 
 	if (asoc->rwnd_over) {
@@ -1053,7 +1082,7 @@
 }
 
 /* Decrease asoc's rwnd by len. */
-void sctp_assoc_rwnd_decrease(sctp_association_t *asoc, int len)
+void sctp_assoc_rwnd_decrease(struct sctp_association *asoc, int len)
 {
 	SCTP_ASSERT(asoc->rwnd, "rwnd zero", return);
 	SCTP_ASSERT(!asoc->rwnd_over, "rwnd_over not zero", return);
@@ -1092,7 +1121,7 @@
 }
 
 /* Build the association's bind address list from the cookie.  */
-int sctp_assoc_set_bind_addr_from_cookie(sctp_association_t *asoc,
+int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *asoc,
 					 sctp_cookie_t *cookie, int gfp)
 {
 	int var_size2 = ntohs(cookie->peer_init->chunk_hdr.length);
diff -Nru a/net/sctp/bind_addr.c b/net/sctp/bind_addr.c
--- a/net/sctp/bind_addr.c	Fri Mar 28 12:49:33 2003
+++ b/net/sctp/bind_addr.c	Thu Apr 17 06:44:11 2003
@@ -52,16 +52,17 @@
 #include <net/sctp/sm.h>
 
 /* Forward declarations for internal helpers. */
-static int sctp_copy_one_addr(sctp_bind_addr_t *, union sctp_addr *,
+static int sctp_copy_one_addr(struct sctp_bind_addr *, union sctp_addr *,
 			      sctp_scope_t scope, int gfp, int flags);
-static void sctp_bind_addr_clean(sctp_bind_addr_t *);
+static void sctp_bind_addr_clean(struct sctp_bind_addr *);
 
 /* First Level Abstractions. */
 
 /* Copy 'src' to 'dest' taking 'scope' into account.  Omit addresses
  * in 'src' which have a broader scope than 'scope'.
  */
-int sctp_bind_addr_copy(sctp_bind_addr_t *dest, const sctp_bind_addr_t *src,
+int sctp_bind_addr_copy(struct sctp_bind_addr *dest, 
+			const struct sctp_bind_addr *src,
 			sctp_scope_t scope, int gfp, int flags)
 {
 	struct sockaddr_storage_list *addr;
@@ -80,6 +81,22 @@
 			goto out;
 	}
 
+	/* If there are no addresses matching the scope and
+	 * this is global scope, try to get a link scope address, with
+	 * the assumption that we must be sitting behind a NAT.
+	 */
+	if (list_empty(&dest->address_list) && (SCTP_SCOPE_GLOBAL == scope)) {
+		list_for_each(pos, &src->address_list) {
+			addr = list_entry(pos, struct sockaddr_storage_list,
+					  list);
+			error = sctp_copy_one_addr(dest, &addr->a,
+						   SCTP_SCOPE_LINK, gfp,
+						   flags);
+			if (error < 0)
+				goto out;
+		}
+	}
+
 out:
 	if (error)
 		sctp_bind_addr_clean(dest);
@@ -88,11 +105,11 @@
 }
 
 /* Create a new SCTP_bind_addr from nothing.  */
-sctp_bind_addr_t *sctp_bind_addr_new(int gfp)
+struct sctp_bind_addr *sctp_bind_addr_new(int gfp)
 {
-	sctp_bind_addr_t *retval;
+	struct sctp_bind_addr *retval;
 
-	retval = t_new(sctp_bind_addr_t, gfp);
+	retval = t_new(struct sctp_bind_addr, gfp);
 	if (!retval)
 		goto nomem;
 
@@ -107,7 +124,7 @@
 /* Initialize the SCTP_bind_addr structure for either an endpoint or
  * an association.
  */
-void sctp_bind_addr_init(sctp_bind_addr_t *bp, __u16 port)
+void sctp_bind_addr_init(struct sctp_bind_addr *bp, __u16 port)
 {
 	bp->malloced = 0;
 
@@ -116,7 +133,7 @@
 }
 
 /* Dispose of the address list. */
-static void sctp_bind_addr_clean(sctp_bind_addr_t *bp)
+static void sctp_bind_addr_clean(struct sctp_bind_addr *bp)
 {
 	struct sockaddr_storage_list *addr;
 	struct list_head *pos, *temp;
@@ -131,7 +148,7 @@
 }
 
 /* Dispose of an SCTP_bind_addr structure  */
-void sctp_bind_addr_free(sctp_bind_addr_t *bp)
+void sctp_bind_addr_free(struct sctp_bind_addr *bp)
 {
 	/* Empty the bind address list. */
 	sctp_bind_addr_clean(bp);
@@ -143,7 +160,7 @@
 }
 
 /* Add an address to the bind address list in the SCTP_bind_addr structure. */
-int sctp_add_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *new,
+int sctp_add_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *new,
 		       int gfp)
 {
 	struct sockaddr_storage_list *addr;
@@ -171,7 +188,7 @@
 /* Delete an address from the bind address list in the SCTP_bind_addr
  * structure.
  */
-int sctp_del_bind_addr(sctp_bind_addr_t *bp, union sctp_addr *del_addr)
+int sctp_del_bind_addr(struct sctp_bind_addr *bp, union sctp_addr *del_addr)
 {
 	struct list_head *pos, *temp;
 	struct sockaddr_storage_list *addr;
@@ -196,7 +213,7 @@
  *
  * The second argument is the return value for the length.
  */
-union sctp_params sctp_bind_addrs_to_raw(const sctp_bind_addr_t *bp,
+union sctp_params sctp_bind_addrs_to_raw(const struct sctp_bind_addr *bp,
 					 int *addrs_len, int gfp)
 {
 	union sctp_params addrparms;
@@ -214,6 +231,14 @@
 		len += sizeof(sctp_addr_param_t);
 	}
 
+	/* Don't even bother embedding an address if there
+	 * is only one.
+	 */
+	if (len == sizeof(sctp_addr_param_t)) {
+		retval.v = NULL;
+		goto end_raw;
+	}
+
 	retval.v = kmalloc(len, gfp);
 	if (!retval.v)
 		goto end_raw;
@@ -237,7 +262,7 @@
  * Create an address list out of the raw address list format (IPv4 and IPv6
  * address parameters).
  */
-int sctp_raw_to_bind_addrs(sctp_bind_addr_t *bp, __u8 *raw_addr_list,
+int sctp_raw_to_bind_addrs(struct sctp_bind_addr *bp, __u8 *raw_addr_list,
 			   int addrs_len, __u16 port, int gfp)
 {
 	sctp_addr_param_t *rawaddr;
@@ -283,7 +308,8 @@
  ********************************************************************/
 
 /* Does this contain a specified address?  Allow wildcarding. */
-int sctp_bind_addr_match(sctp_bind_addr_t *bp, const union sctp_addr *addr,
+int sctp_bind_addr_match(struct sctp_bind_addr *bp, 
+			 const union sctp_addr *addr,
 			 struct sctp_opt *opt)
 {
 	struct sockaddr_storage_list *laddr;
@@ -299,7 +325,8 @@
 }
 
 /* Copy out addresses from the global local address list. */
-static int sctp_copy_one_addr(sctp_bind_addr_t *dest, union sctp_addr *addr,
+static int sctp_copy_one_addr(struct sctp_bind_addr *dest, 
+			      union sctp_addr *addr,
 			      sctp_scope_t scope, int gfp, int flags)
 {
 	struct sctp_protocol *proto = sctp_get_protocol();
diff -Nru a/net/sctp/chunk.c b/net/sctp/chunk.c
--- /dev/null	Wed Dec 31 16:00:00 1969
+++ b/net/sctp/chunk.c	Thu May  1 07:23:56 2003
@@ -0,0 +1,327 @@
+/* SCTP kernel reference Implementation
+ * Copyright (c) 2003 International Business Machines Corp.
+ *
+ * This file is part of the SCTP kernel reference Implementation
+ *
+ * This file contains the code relating the the chunk abstraction.
+ *
+ * The SCTP reference implementation 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.
+ *
+ * The SCTP reference implementation 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 GNU CC; see the file COPYING.  If not, write to
+ * the Free Software Foundation, 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Please send any bug reports or fixes you make to the
+ * email address(es):
+ *    lksctp developers <lksctp-developers@lists.sourceforge.net>
+ *
+ * Or submit a bug report through the following website:
+ *    http://www.sf.net/projects/lksctp
+ *
+ * Written or modified by:
+ *    Jon Grimm             <jgrimm@us.ibm.com>
+ *
+ * Any bugs reported given to us we will try to fix... any fixes shared will
+ * be incorporated into the next SCTP release.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/net.h>
+#include <linux/inet.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/sctp/sctp.h>
+#include <net/sctp/sm.h>
+
+/* This file is mostly in anticipation of future work, but initially
+ * populate with fragment tracking for an outbound message.
+ */
+
+/* Initialize datamsg from memory. */
+void sctp_datamsg_init(struct sctp_datamsg *msg)
+{
+	atomic_set(&msg->refcnt, 1);
+	msg->send_failed = 0;
+	msg->send_error = 0;
+	msg->can_expire = 0;
+	INIT_LIST_HEAD(&msg->chunks);
+}
+
+/* Allocate and initialize datamsg. */
+struct sctp_datamsg *sctp_datamsg_new(int gfp)
+{
+	struct sctp_datamsg *msg;
+	msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
+	if (msg)
+		sctp_datamsg_init(msg);
+	SCTP_DBG_OBJCNT_INC(datamsg);
+	return msg;
+}
+
+/* Final destructruction of datamsg memory. */
+static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
+{
+	struct list_head *pos, *temp;
+	struct sctp_chunk *chunk;
+	struct sctp_opt *sp;
+	struct sctp_ulpevent *ev;
+	struct sctp_association *asoc = NULL;
+	int error = 0, notify;
+
+	/* If we failed, we may need to notify. */
+	notify = msg->send_failed ? -1 : 0;
+
+	/* Release all references. */
+	list_for_each_safe(pos, temp, &msg->chunks) {
+		list_del(pos);
+		chunk = list_entry(pos, struct sctp_chunk, frag_list);
+		/* Check whether we _really_ need to notify. */
+		if (notify < 0) {
+			asoc = chunk->asoc;
+			if (msg->send_error)
+				error = msg->send_error;
+			else
+				error = asoc->outqueue.error;
+
+			sp = sctp_sk(asoc->base.sk);
+			notify = sctp_ulpevent_type_enabled(SCTP_SEND_FAILED,
+							    &sp->subscribe);
+		}
+
+		/* Generate a SEND FAILED event only if enabled. */
+		if (notify > 0) {
+			int sent;
+			if (chunk->has_tsn)
+				sent = SCTP_DATA_SENT;
+			else
+				sent = SCTP_DATA_UNSENT;
+
+			ev = sctp_ulpevent_make_send_failed(asoc, chunk, sent,
+							    error, GFP_ATOMIC);
+			if (ev)
+				sctp_ulpq_tail_event(&asoc->ulpq, ev);
+		}
+
+		sctp_chunk_put(chunk);
+	}
+
+	SCTP_DBG_OBJCNT_DEC(datamsg);
+	kfree(msg);
+}
+
+/* Hold a reference. */
+void sctp_datamsg_hold(struct sctp_datamsg *msg)
+{
+	atomic_inc(&msg->refcnt);
+}
+
+/* Release a reference. */
+void sctp_datamsg_put(struct sctp_datamsg *msg)
+{
+	if (atomic_dec_and_test(&msg->refcnt))
+		sctp_datamsg_destroy(msg);
+}
+
+/* Free a message.  Really just give up a reference, the
+ * really free happens in sctp_datamsg_destroy().
+ */
+void sctp_datamsg_free(struct sctp_datamsg *msg)
+{
+	sctp_datamsg_put(msg);
+}
+
+/* Hold on to all the fragments until all chunks have been sent. */
+void sctp_datamsg_track(struct sctp_chunk *chunk)
+{
+	sctp_chunk_hold(chunk);
+}
+
+/* Assign a chunk to this datamsg. */
+void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
+{
+	sctp_datamsg_hold(msg);
+	chunk->msg = msg;
+}
+
+
+/* A data chunk can have a maximum payload of (2^16 - 20).  Break
+ * down any such message into smaller chunks.  Opportunistically, fragment
+ * the chunks down to the current MTU constraints.  We may get refragmented
+ * later if the PMTU changes, but it is _much better_ to fragment immediately
+ * with a reasonable guess than always doing our fragmentation on the
+ * soft-interrupt.
+ */
+struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *asoc,
+					    struct sctp_sndrcvinfo *sinfo,
+					    struct msghdr *msgh, int msg_len)
+{
+	int max, whole, i, offset, over, err;
+	int len, first_len;
+	struct sctp_chunk *chunk;
+	struct sctp_datamsg *msg;
+	struct list_head *pos, *temp;
+	__u8 frag;
+
+	msg = sctp_datamsg_new(GFP_KERNEL);
+	if (!msg)
+		return NULL;
+
+	/* Note: Calculate this outside of the loop, so that all fragments
+	 * have the same expiration.
+	 */
+	if (sinfo->sinfo_timetolive) {
+		struct timeval tv;
+		__u32 ttl = sinfo->sinfo_timetolive;
+
+		/* sinfo_timetolive is in milliseconds */
+		tv.tv_sec = ttl / 1000;
+		tv.tv_usec = ttl % 1000 * 1000;
+		msg->expires_at = jiffies + timeval_to_jiffies(&tv);
+		msg->can_expire = 1;
+	}
+
+	/* What is a reasonable fragmentation point right now? */
+	max = asoc->pmtu;
+	if (max < SCTP_MIN_PMTU)
+		max = SCTP_MIN_PMTU;
+	max -= SCTP_IP_OVERHEAD;
+
+	/* Make sure not beyond maximum chunk size. */
+	if (max > SCTP_MAX_CHUNK_LEN)
+		max = SCTP_MAX_CHUNK_LEN;
+
+	/* Subtract out the overhead of a data chunk header. */
+	max -= sizeof(struct sctp_data_chunk);
+	whole = 0;
+
+	/* If user has specified smaller fragmentation, make it so. */
+	if (sctp_sk(asoc->base.sk)->user_frag)
+		max = min_t(int, max, sctp_sk(asoc->base.sk)->user_frag);
+
+	first_len = max;
+
+	/* Encourage Cookie-ECHO bundling. */
+	if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
+		whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN);
+
+		/* Account for the DATA to be bundled with the COOKIE-ECHO. */
+		if (whole) {
+			first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN;
+			msg_len -= first_len;
+			whole = 1;
+		}
+	}
+
+	/* How many full sized?  How many bytes leftover? */
+	whole += msg_len / max;
+	over = msg_len % max;
+	offset = 0;
+
+	if ((whole > 1) || (whole && over))
+		SCTP_INC_STATS_USER(SctpFragUsrMsgs);
+
+	/* Create chunks for all the full sized DATA chunks. */
+	for (i=0, len=first_len; i < whole; i++) {
+		frag = SCTP_DATA_MIDDLE_FRAG;
+
+		if (0 == i)
+			frag |= SCTP_DATA_FIRST_FRAG;
+
+		if ((i == (whole - 1)) && !over)
+			frag |= SCTP_DATA_LAST_FRAG;
+
+		chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0);
+
+		if (!chunk)
+			goto errout;
+		err = sctp_user_addto_chunk(chunk, offset, len, msgh->msg_iov);
+		if (err < 0)
+			goto errout;
+
+		offset += len;
+
+		/* Put the chunk->skb back into the form expected by send.  */
+		__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
+			   - (__u8 *)chunk->skb->data);
+
+		sctp_datamsg_assign(msg, chunk);
+		list_add_tail(&chunk->frag_list, &msg->chunks);
+
+		/* The first chunk, the first chunk was likely short
+		 * to allow bundling, so reset to full size.
+		 */
+		if (0 == i)
+			len = max;
+	}
+
+	/* .. now the leftover bytes. */
+	if (over) {
+		if (!whole)
+			frag = SCTP_DATA_NOT_FRAG;
+		else
+			frag = SCTP_DATA_LAST_FRAG;
+
+		chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0);
+
+		if (!chunk)
+			goto errout;
+
+		err = sctp_user_addto_chunk(chunk, offset, over,msgh->msg_iov);
+
+		/* Put the chunk->skb back into the form expected by send.  */
+		__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
+			   - (__u8 *)chunk->skb->data);
+		if (err < 0)
+			goto errout;
+
+		sctp_datamsg_assign(msg, chunk);
+		list_add_tail(&chunk->frag_list, &msg->chunks);
+	}
+
+	return msg;
+
+errout:
+	list_for_each_safe(pos, temp, &msg->chunks) {
+		list_del(pos);
+		chunk = list_entry(pos, struct sctp_chunk, frag_list);
+		sctp_chunk_free(chunk);
+	}
+	sctp_datamsg_free(msg);
+	return NULL;
+}
+
+/* Check whether this message has expired. */
+int sctp_datamsg_expires(struct sctp_chunk *chunk)
+{
+	struct sctp_datamsg *msg = chunk->msg;
+
+	/* FIXME: When PR-SCTP is supported we can make this
+	 * check more lenient.
+	 */
+	if (!msg->can_expire)
+		return 0;
+
+	if (time_after(jiffies, msg->expires_at))
+		return 1;
+
+	return 0;
+}
+
+/* This chunk (and consequently entire message) has failed in its sending. */
+void sctp_datamsg_fail(struct sctp_chunk *chunk, int error)
+{
+	chunk->msg->send_failed = 1;
+	chunk->msg->send_error = error;
+}
diff -Nru a/net/sctp/command.c b/net/sctp/command.c
--- a/net/sctp/command.c	Fri Jan 17 13:35:51 2003
+++ b/net/sctp/command.c	Wed Apr  9 12:24:28 2003
@@ -43,9 +43,9 @@
 #include <net/sctp/sm.h>
 
 /* Create a new sctp_command_sequence.  */
-sctp_cmd_seq_t *sctp_new_cmd_seq(int priority)
+sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp)
 {
-	sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, priority);
+	sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, gfp);
 
 	if (retval)
 		sctp_init_cmd_seq(retval);
diff -Nru a/net/sctp/crc32c.c b/net/sctp/crc32c.c
--- a/net/sctp/crc32c.c	Thu Jan  9 17:39:08 2003
+++ b/net/sctp/crc32c.c	Wed Apr  9 21:17:20 2003
@@ -170,6 +170,23 @@
 	return crc32;
 }
 
+__u32 sctp_update_copy_cksum(__u8 *to, __u8 *from, __u16 length, __u32 crc32)
+{
+	__u32 i;
+	__u32 *_to = (__u32 *)to;
+	__u32 *_from = (__u32 *)from;
+	
+	for (i = 0; i < (length/4); i++) {
+		_to[i] = _from[i];
+		CRC32C(crc32, from[i*4]);
+		CRC32C(crc32, from[i*4+1]);
+		CRC32C(crc32, from[i*4+2]);
+		CRC32C(crc32, from[i*4+3]);	
+	}
+
+	return crc32;
+}
+
 __u32 sctp_end_cksum(__u32 crc32)
 {
 	__u32 result;
diff -Nru a/net/sctp/endpointola.c b/net/sctp/endpointola.c
--- a/net/sctp/endpointola.c	Wed Apr  2 12:21:15 2003
+++ b/net/sctp/endpointola.c	Fri Apr 25 17:19:51 2003
@@ -54,27 +54,27 @@
 #include <linux/slab.h>
 #include <linux/in.h>
 #include <linux/random.h>	/* get_random_bytes() */
+#include <linux/crypto.h>
 #include <net/sock.h>
 #include <net/ipv6.h>
 #include <net/sctp/sctp.h>
 #include <net/sctp/sm.h>
 
 /* Forward declarations for internal helpers. */
-static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep);
+static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep);
 
-/* Create a sctp_endpoint_t with all that boring stuff initialized.
+/* Create a sctp_endpoint with all that boring stuff initialized.
  * Returns NULL if there isn't enough memory.
  */
-sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *proto,
-				   struct sock *sk, int priority)
+struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp)
 {
-	sctp_endpoint_t *ep;
+	struct sctp_endpoint *ep;
 
 	/* Build a local endpoint. */
-	ep = t_new(sctp_endpoint_t, priority);
+	ep = t_new(struct sctp_endpoint, gfp);
 	if (!ep)
 		goto fail;
-	if (!sctp_endpoint_init(ep, proto, sk, priority))
+	if (!sctp_endpoint_init(ep, sk, gfp))
 		goto fail_init;
 	ep->base.malloced = 1;
 	SCTP_DBG_OBJCNT_INC(ep);
@@ -89,12 +89,11 @@
 /*
  * Initialize the base fields of the endpoint structure.
  */
-sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, 
-				    struct sctp_protocol *proto,
-				    struct sock *sk, int priority)
+struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
+					 struct sock *sk, int gfp)
 {
 	struct sctp_opt *sp = sctp_sk(sk);
-	memset(ep, 0, sizeof(sctp_endpoint_t));
+	memset(ep, 0, sizeof(struct sctp_endpoint));
 
 	/* Initialize the base structure. */
 	/* What type of endpoint are we?  */
@@ -110,8 +109,7 @@
 
 	/* Set its top-half handler */
 	sctp_inq_set_th_handler(&ep->base.inqueue,
-				    (void (*)(void *))sctp_endpoint_bh_rcv,
-				    ep);
+				(void (*)(void *))sctp_endpoint_bh_rcv, ep);
 
 	/* Initialize the bind addr area */
 	sctp_bind_addr_init(&ep->base.bind_addr, 0);
@@ -121,21 +119,16 @@
 	ep->base.sk = sk;
 	sock_hold(ep->base.sk);
 
-	/* This pointer is useful to access the default protocol parameter
-	 * values.
-	 */
-	ep->proto = proto;
-
 	/* Create the lists of associations.  */
 	INIT_LIST_HEAD(&ep->asocs);
 
 	/* Set up the base timeout information.  */
 	ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0;
-	ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] = 
+	ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] =
 		SCTP_DEFAULT_TIMEOUT_T1_COOKIE;
-	ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] = 
+	ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
 		SCTP_DEFAULT_TIMEOUT_T1_INIT;
-	ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] = 
+	ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
 		sp->rtoinfo.srto_initial;
 	ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
 
@@ -146,11 +139,11 @@
         ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
 		= 5 * sp->rtoinfo.srto_max;
 
-	ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 
+	ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] =
 		SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
-	ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] = 
+	ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
 		SCTP_DEFAULT_TIMEOUT_SACK;
-	ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] = 
+	ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
 		sp->autoclose * HZ;
 
 	/* Set up the default send/receive buffer space.  */
@@ -175,7 +168,8 @@
 }
 
 /* Add an association to an endpoint.  */
-void sctp_endpoint_add_asoc(sctp_endpoint_t *ep, sctp_association_t *asoc)
+void sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
+			    struct sctp_association *asoc)
 {
 	struct sock *sk = ep->base.sk;
 
@@ -183,22 +177,21 @@
 	list_add_tail(&asoc->asocs, &ep->asocs);
 
 	/* Increment the backlog value for a TCP-style listening socket. */
-	if ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
-	    (SCTP_SS_LISTENING == sk->state))
+	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
 		sk->ack_backlog++;
 }
 
 /* Free the endpoint structure.  Delay cleanup until
  * all users have released their reference count on this structure.
  */
-void sctp_endpoint_free(sctp_endpoint_t *ep)
+void sctp_endpoint_free(struct sctp_endpoint *ep)
 {
 	ep->base.dead = 1;
 	sctp_endpoint_put(ep);
 }
 
 /* Final destructor for endpoint.  */
-void sctp_endpoint_destroy(sctp_endpoint_t *ep)
+void sctp_endpoint_destroy(struct sctp_endpoint *ep)
 {
 	SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return);
 
@@ -207,9 +200,12 @@
 	/* Unlink this endpoint, so we can't find it again! */
 	sctp_unhash_endpoint(ep);
 
-	/* Cleanup the inqueue. */
-	sctp_inq_free(&ep->base.inqueue);
+	/* Free up the HMAC transform. */
+	if (sctp_sk(ep->base.sk)->hmac)
+		sctp_crypto_free_tfm(sctp_sk(ep->base.sk)->hmac);
 
+	/* Cleanup. */
+	sctp_inq_free(&ep->base.inqueue);
 	sctp_bind_addr_free(&ep->base.bind_addr);
 
 	/* Remove and free the port */
@@ -228,7 +224,7 @@
 }
 
 /* Hold a reference to an endpoint. */
-void sctp_endpoint_hold(sctp_endpoint_t *ep)
+void sctp_endpoint_hold(struct sctp_endpoint *ep)
 {
 	atomic_inc(&ep->base.refcnt);
 }
@@ -236,17 +232,17 @@
 /* Release a reference to an endpoint and clean up if there are
  * no more references.
  */
-void sctp_endpoint_put(sctp_endpoint_t *ep)
+void sctp_endpoint_put(struct sctp_endpoint *ep)
 {
 	if (atomic_dec_and_test(&ep->base.refcnt))
 		sctp_endpoint_destroy(ep);
 }
 
 /* Is this the endpoint we are looking for?  */
-sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
-					const union sctp_addr *laddr)
+struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
+					       const union sctp_addr *laddr)
 {
-	sctp_endpoint_t *retval;
+	struct sctp_endpoint *retval;
 
 	sctp_read_lock(&ep->base.addr_lock);
 	if (ep->base.bind_addr.port == laddr->v4.sin_port) {
@@ -268,19 +264,19 @@
  * We do a linear search of the associations for this endpoint.
  * We return the matching transport address too.
  */
-sctp_association_t *__sctp_endpoint_lookup_assoc(
-	const sctp_endpoint_t *endpoint,
+struct sctp_association *__sctp_endpoint_lookup_assoc(
+	const struct sctp_endpoint *ep,
 	const union sctp_addr *paddr,
 	struct sctp_transport **transport)
 {
 	int rport;
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	struct list_head *pos;
 
 	rport = paddr->v4.sin_port;
 
-	list_for_each(pos, &endpoint->asocs) {
-		asoc = list_entry(pos, sctp_association_t, asocs);
+	list_for_each(pos, &ep->asocs) {
+		asoc = list_entry(pos, struct sctp_association, asocs);
 		if (rport == asoc->peer.port) {
 			sctp_read_lock(&asoc->base.addr_lock);
 			*transport = sctp_assoc_lookup_paddr(asoc, paddr);
@@ -296,12 +292,12 @@
 }
 
 /* Lookup association on an endpoint based on a peer address.  BH-safe.  */
-sctp_association_t *sctp_endpoint_lookup_assoc(
-	const sctp_endpoint_t *ep,
+struct sctp_association *sctp_endpoint_lookup_assoc(
+	const struct sctp_endpoint *ep,
 	const union sctp_addr *paddr,
 	struct sctp_transport **transport)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
 	sctp_local_bh_disable();
 	asoc = __sctp_endpoint_lookup_assoc(ep, paddr, transport);
@@ -313,12 +309,12 @@
 /* Look for any peeled off association from the endpoint that matches the
  * given peer address.
  */
-int sctp_endpoint_is_peeled_off(sctp_endpoint_t *ep,
+int sctp_endpoint_is_peeled_off(struct sctp_endpoint *ep,
 				const union sctp_addr *paddr)
 {
 	struct list_head *pos;
 	struct sockaddr_storage_list *addr;
-	sctp_bind_addr_t *bp;
+	struct sctp_bind_addr *bp;
 
 	sctp_read_lock(&ep->base.addr_lock);
 	bp = &ep->base.bind_addr;
@@ -337,12 +333,12 @@
 /* Do delayed input processing.  This is scheduled by sctp_rcv().
  * This may be called on BH or task time.
  */
-static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
+static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	struct sock *sk;
 	struct sctp_transport *transport;
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 	struct sctp_inq *inqueue;
 	sctp_subtype_t subtype;
 	sctp_state_t state;
@@ -355,7 +351,7 @@
 	inqueue = &ep->base.inqueue;
 	sk = ep->base.sk;
 
-	while (NULL != (chunk = sctp_inq_pop(inqueue))) {		
+	while (NULL != (chunk = sctp_inq_pop(inqueue))) {
 		subtype.chunk = chunk->chunk_hdr->type;
 
 		/* We might have grown an association since last we
diff -Nru a/net/sctp/input.c b/net/sctp/input.c
--- a/net/sctp/input.c	Fri Mar 28 12:49:33 2003
+++ b/net/sctp/input.c	Thu Apr 17 06:44:11 2003
@@ -63,11 +63,11 @@
 
 /* Forward declarations for internal helpers. */
 static int sctp_rcv_ootb(struct sk_buff *);
-sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
+struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
 				      const union sctp_addr *laddr,
 				      const union sctp_addr *paddr,
 				      struct sctp_transport **transportp);
-sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
+struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
 
 
 /* Calculate the SCTP checksum of an SCTP packet.  */
@@ -102,11 +102,11 @@
 int sctp_rcv(struct sk_buff *skb)
 {
 	struct sock *sk;
-	sctp_association_t *asoc;
-	sctp_endpoint_t *ep = NULL;
-	sctp_endpoint_common_t *rcvr;
+	struct sctp_association *asoc;
+	struct sctp_endpoint *ep = NULL;
+	struct sctp_ep_common *rcvr;
 	struct sctp_transport *transport = NULL;
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 	struct sctphdr *sh;
 	union sctp_addr src;
 	union sctp_addr dest;
@@ -128,11 +128,11 @@
 	if (sctp_rcv_checksum(skb) < 0)
 		goto bad_packet;
 
-	skb_pull(skb, sizeof(struct sctphdr));	
+	skb_pull(skb, sizeof(struct sctphdr));
 
 	family = ipver2af(skb->nh.iph->version);
 	af = sctp_get_af_specific(family);
-	if (unlikely(!af)) 
+	if (unlikely(!af))
 		goto bad_packet;
 
 	/* Initialize local addresses for lookups. */
@@ -224,9 +224,7 @@
 	return ret;
 
 bad_packet:
-#if 0 /* FIXME */
-	SCTP_INC_STATS(SctpInErrs);
-#endif /* FIXME*/
+	SCTP_INC_STATS(SctpChecksumErrors);
 
 discard_it:
 	kfree_skb(skb);
@@ -252,13 +250,13 @@
  */
 int sctp_backlog_rcv(struct sock *sk, struct sk_buff *skb)
 {
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 	struct sctp_inq *inqueue;
 
 	/* One day chunk will live inside the skb, but for
 	 * now this works.
 	 */
-	chunk = (sctp_chunk_t *) skb;
+	chunk = (struct sctp_chunk *) skb;
 	inqueue = &chunk->rcvr->inqueue;
 
 	sctp_inq_push(inqueue, chunk);
@@ -286,8 +284,8 @@
 /* Common lookup code for icmp/icmpv6 error handler. */
 struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
 			     struct sctphdr *sctphdr,
-			     struct sctp_endpoint **epp, 
-			     struct sctp_association **app, 
+			     struct sctp_endpoint **epp,
+			     struct sctp_association **app,
 			     struct sctp_transport **tpp)
 {
 	union sctp_addr saddr;
@@ -309,15 +307,15 @@
 	af->from_skb(&saddr, skb, 1);
 	af->from_skb(&daddr, skb, 0);
 
-	/* Look for an association that matches the incoming ICMP error 
+	/* Look for an association that matches the incoming ICMP error
 	 * packet.
 	 */
 	asoc = __sctp_lookup_association(&saddr, &daddr, &transport);
 	if (!asoc) {
 		/* If there is no matching association, see if it matches any
-		 * endpoint. This may happen for an ICMP error generated in 
-		 * response to an INIT_ACK. 
-		 */ 
+		 * endpoint. This may happen for an ICMP error generated in
+		 * response to an INIT_ACK.
+		 */
 		ep = __sctp_rcv_lookup_endpoint(&daddr);
 		if (!ep) {
 			return NULL;
@@ -345,25 +343,25 @@
 	*app = asoc;
 	*tpp = transport;
 	return sk;
-	
+
 out:
 	sock_put(sk);
 	if (asoc)
 		sctp_association_put(asoc);
-	if (ep)	
+	if (ep)
 		sctp_endpoint_put(ep);
 	return NULL;
 }
 
 /* Common cleanup code for icmp/icmpv6 error handler. */
-void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep, 
+void sctp_err_finish(struct sock *sk, struct sctp_endpoint *ep,
 		     struct sctp_association *asoc)
 {
 	sctp_bh_unlock_sock(sk);
 	sock_put(sk);
 	if (asoc)
 		sctp_association_put(asoc);
-	if (ep)	
+	if (ep)
 		sctp_endpoint_put(ep);
 }
 
@@ -389,8 +387,8 @@
 	int type = skb->h.icmph->type;
 	int code = skb->h.icmph->code;
 	struct sock *sk;
-	sctp_endpoint_t *ep;
-	sctp_association_t *asoc;
+	struct sctp_endpoint *ep;
+	struct sctp_association *asoc;
 	struct sctp_transport *transport;
 	struct inet_opt *inet;
 	char *saveip, *savesctp;
@@ -414,7 +412,7 @@
 		ICMP_INC_STATS_BH(IcmpInErrors);
 		return;
 	}
-	/* Warning:  The sock lock is held.  Remember to call 
+	/* Warning:  The sock lock is held.  Remember to call
 	 * sctp_err_finish!
 	 */
 
@@ -520,10 +518,10 @@
 }
 
 /* Insert endpoint into the hash table.  */
-void __sctp_hash_endpoint(sctp_endpoint_t *ep)
+void __sctp_hash_endpoint(struct sctp_endpoint *ep)
 {
-	sctp_endpoint_common_t **epp;
-	sctp_endpoint_common_t *epb;
+	struct sctp_ep_common **epp;
+	struct sctp_ep_common *epb;
 	sctp_hashbucket_t *head;
 
 	epb = &ep->base;
@@ -542,7 +540,7 @@
 }
 
 /* Add an endpoint to the hash. Local BH-safe. */
-void sctp_hash_endpoint(sctp_endpoint_t *ep)
+void sctp_hash_endpoint(struct sctp_endpoint *ep)
 {
 	sctp_local_bh_disable();
 	__sctp_hash_endpoint(ep);
@@ -550,10 +548,10 @@
 }
 
 /* Remove endpoint from the hash table.  */
-void __sctp_unhash_endpoint(sctp_endpoint_t *ep)
+void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
 {
 	sctp_hashbucket_t *head;
-	sctp_endpoint_common_t *epb;
+	struct sctp_ep_common *epb;
 
 	epb = &ep->base;
 
@@ -574,7 +572,7 @@
 }
 
 /* Remove endpoint from the hash.  Local BH-safe. */
-void sctp_unhash_endpoint(sctp_endpoint_t *ep)
+void sctp_unhash_endpoint(struct sctp_endpoint *ep)
 {
 	sctp_local_bh_disable();
 	__sctp_unhash_endpoint(ep);
@@ -582,11 +580,11 @@
 }
 
 /* Look up an endpoint. */
-sctp_endpoint_t *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
+struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
 {
 	sctp_hashbucket_t *head;
-	sctp_endpoint_common_t *epb;
-	sctp_endpoint_t *ep;
+	struct sctp_ep_common *epb;
+	struct sctp_endpoint *ep;
 	int hash;
 
 	hash = sctp_ep_hashfn(laddr->v4.sin_port);
@@ -609,7 +607,7 @@
 }
 
 /* Add an association to the hash. Local BH-safe. */
-void sctp_hash_established(sctp_association_t *asoc)
+void sctp_hash_established(struct sctp_association *asoc)
 {
 	sctp_local_bh_disable();
 	__sctp_hash_established(asoc);
@@ -617,10 +615,10 @@
 }
 
 /* Insert association into the hash table.  */
-void __sctp_hash_established(sctp_association_t *asoc)
+void __sctp_hash_established(struct sctp_association *asoc)
 {
-	sctp_endpoint_common_t **epp;
-	sctp_endpoint_common_t *epb;
+	struct sctp_ep_common **epp;
+	struct sctp_ep_common *epb;
 	sctp_hashbucket_t *head;
 
 	epb = &asoc->base;
@@ -641,7 +639,7 @@
 }
 
 /* Remove association from the hash table.  Local BH-safe. */
-void sctp_unhash_established(sctp_association_t *asoc)
+void sctp_unhash_established(struct sctp_association *asoc)
 {
 	sctp_local_bh_disable();
 	__sctp_unhash_established(asoc);
@@ -649,10 +647,10 @@
 }
 
 /* Remove association from the hash table.  */
-void __sctp_unhash_established(sctp_association_t *asoc)
+void __sctp_unhash_established(struct sctp_association *asoc)
 {
 	sctp_hashbucket_t *head;
-	sctp_endpoint_common_t *epb;
+	struct sctp_ep_common *epb;
 
 	epb = &asoc->base;
 
@@ -674,13 +672,14 @@
 }
 
 /* Look up an association. */
-sctp_association_t *__sctp_lookup_association(const union sctp_addr *local,
-					      const union sctp_addr *peer,
-					      struct sctp_transport **pt)
+struct sctp_association *__sctp_lookup_association(
+					const union sctp_addr *local,
+					const union sctp_addr *peer,
+					struct sctp_transport **pt)
 {
 	sctp_hashbucket_t *head;
-	sctp_endpoint_common_t *epb;
-	sctp_association_t *asoc;
+	struct sctp_ep_common *epb;
+	struct sctp_association *asoc;
 	struct sctp_transport *transport;
 	int hash;
 
@@ -710,11 +709,11 @@
 }
 
 /* Look up an association. BH-safe. */
-sctp_association_t *sctp_lookup_association(const union sctp_addr *laddr,
+struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr,
 					    const union sctp_addr *paddr,
 					    struct sctp_transport **transportp)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
 	sctp_local_bh_disable();
 	asoc = __sctp_lookup_association(laddr, paddr, transportp);
@@ -727,7 +726,7 @@
 int sctp_has_association(const union sctp_addr *laddr,
 			 const union sctp_addr *paddr)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	struct sctp_transport *transport;
 
 	if ((asoc = sctp_lookup_association(laddr, paddr, &transport))) {
@@ -757,10 +756,10 @@
  * in certain circumstances.
  *
  */
-static sctp_association_t *__sctp_rcv_init_lookup(struct sk_buff *skb,
+static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
 	const union sctp_addr *laddr, struct sctp_transport **transportp)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	union sctp_addr addr;
 	union sctp_addr *paddr = &addr;
 	struct sctphdr *sh = (struct sctphdr *) skb->h.raw;
@@ -815,12 +814,12 @@
 }
 
 /* Lookup an association for an inbound skb. */
-sctp_association_t *__sctp_rcv_lookup(struct sk_buff *skb,
+struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
 				      const union sctp_addr *paddr,
 				      const union sctp_addr *laddr,
 				      struct sctp_transport **transportp)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
 	asoc = __sctp_lookup_association(laddr, paddr, transportp);
 
diff -Nru a/net/sctp/inqueue.c b/net/sctp/inqueue.c
--- a/net/sctp/inqueue.c	Thu Feb  6 11:42:55 2003
+++ b/net/sctp/inqueue.c	Mon Apr 21 10:26:19 2003
@@ -75,17 +75,17 @@
 /* Release the memory associated with an SCTP inqueue.  */
 void sctp_inq_free(struct sctp_inq *queue)
 {
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 
 	/* Empty the queue.  */
-	while ((chunk = (sctp_chunk_t *) skb_dequeue(&queue->in)) != NULL)
-		sctp_free_chunk(chunk);
+	while ((chunk = (struct sctp_chunk *) skb_dequeue(&queue->in)))
+		sctp_chunk_free(chunk);
 
 	/* If there is a packet which is currently being worked on,
 	 * free it as well.
 	 */
 	if (queue->in_progress)
-		sctp_free_chunk(queue->in_progress);
+		sctp_chunk_free(queue->in_progress);
 
 	if (queue->malloced) {
 		/* Dump the master memory segment.  */
@@ -96,7 +96,7 @@
 /* Put a new packet in an SCTP inqueue.
  * We assume that packet->sctp_hdr is set and in host byte order.
  */
-void sctp_inq_push(struct sctp_inq *q, sctp_chunk_t *packet)
+void sctp_inq_push(struct sctp_inq *q, struct sctp_chunk *packet)
 {
 	/* Directly call the packet handling routine. */
 
@@ -114,23 +114,23 @@
  * WARNING:  If you need to put the chunk on another queue, you need to
  * make a shallow copy (clone) of it.
  */
-sctp_chunk_t *sctp_inq_pop(struct sctp_inq *queue)
+struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
 {
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 	sctp_chunkhdr_t *ch = NULL;
 
 	/* The assumption is that we are safe to process the chunks
 	 * at this time.
 	 */
 
-	if ((chunk = queue->in_progress) != NULL) {
+	if ((chunk = queue->in_progress)) {
 		/* There is a packet that we have been working on.
 		 * Any post processing work to do before we move on?
 		 */
 		if (chunk->singleton ||
 		    chunk->end_of_packet ||
 		    chunk->pdiscard) {
-			sctp_free_chunk(chunk);
+			sctp_chunk_free(chunk);
 			chunk = queue->in_progress = NULL;
 		} else {
 			/* Nothing to do. Next chunk in the packet, please. */
@@ -149,7 +149,7 @@
 			return NULL;
 
 		chunk = queue->in_progress =
-			(sctp_chunk_t *) skb_dequeue(&queue->in);
+			(struct sctp_chunk *) skb_dequeue(&queue->in);
 
 		/* This is the first chunk in the packet.  */
 		chunk->singleton = 1;
diff -Nru a/net/sctp/ipv6.c b/net/sctp/ipv6.c
--- a/net/sctp/ipv6.c	Fri May  2 23:41:46 2003
+++ b/net/sctp/ipv6.c	Mon May 19 23:48:31 2003
@@ -77,17 +77,6 @@
 
 extern struct notifier_block sctp_inetaddr_notifier;
 
-/* FIXME: This macro needs to be moved to a common header file. */
-#define NIP6(addr) \
-        ntohs((addr)->s6_addr16[0]), \
-        ntohs((addr)->s6_addr16[1]), \
-        ntohs((addr)->s6_addr16[2]), \
-        ntohs((addr)->s6_addr16[3]), \
-        ntohs((addr)->s6_addr16[4]), \
-        ntohs((addr)->s6_addr16[5]), \
-        ntohs((addr)->s6_addr16[6]), \
-        ntohs((addr)->s6_addr16[7])
-
 /* ICMP error handler. */
 void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
 		 int type, int code, int offset, __u32 info)
@@ -96,8 +85,8 @@
 	struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
 	struct sctphdr *sh = (struct sctphdr *)(skb->data + offset);
 	struct sock *sk;
-	sctp_endpoint_t *ep;
-	sctp_association_t *asoc;
+	struct sctp_endpoint *ep;
+	struct sctp_association *asoc;
 	struct sctp_transport *transport;
 	struct ipv6_pinfo *np;
 	char *saveip, *savesctp;
@@ -119,7 +108,7 @@
 		goto out;
 	}
 
-	/* Warning:  The sock lock is held.  Remember to call 
+	/* Warning:  The sock lock is held.  Remember to call
 	 * sctp_err_finish!
 	 */
 
@@ -148,21 +137,19 @@
 }
 
 /* Based on tcp_v6_xmit() in tcp_ipv6.c. */
-static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport, 
+static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
 			int ipfragok)
 {
 	struct sock *sk = skb->sk;
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct flowi fl;
-	struct dst_entry *dst = skb->dst;
-	struct rt6_info *rt6 = (struct rt6_info *)dst;
 
 	fl.proto = sk->protocol;
 
 	/* Fill in the dest address from the route entry passed with the skb
 	 * and the source address from the transport.
 	 */
-	fl.fl6_dst = &rt6->rt6i_dst.addr;
+	fl.fl6_dst = &transport->ipaddr.v6.sin6_addr;
 	fl.fl6_src = &transport->saddr.v6.sin6_addr;
 
 	fl.fl6_flowlabel = np->flow_label;
@@ -182,8 +169,8 @@
 	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
 			  "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
 			  "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-			  __FUNCTION__, skb, skb->len, NIP6(fl.fl6_src),
-			  NIP6(fl.fl6_dst));
+			  __FUNCTION__, skb, skb->len, 
+			  NIP6(*fl.fl6_src), NIP6(*fl.fl6_dst));
 
 	SCTP_INC_STATS(SctpOutSCTPPacks);
 
@@ -193,7 +180,7 @@
 /* Returns the dst cache entry for the given source and destination ip
  * addresses.
  */
-struct dst_entry *sctp_v6_get_dst(sctp_association_t *asoc,
+struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
 				  union sctp_addr *daddr,
 				  union sctp_addr *saddr)
 {
@@ -202,13 +189,13 @@
 		.nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } };
 
 	SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
-			  __FUNCTION__, NIP6(fl.fl6_dst));
+			  __FUNCTION__, NIP6(*fl.fl6_dst));
 
 	if (saddr) {
 		fl.fl6_src = &saddr->v6.sin6_addr;
 		SCTP_DEBUG_PRINTK(
 			"SRC=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x - ",
-			NIP6(fl.fl6_src));
+			NIP6(*fl.fl6_src));
 	}
 
 	dst = ip6_route_output(NULL, &fl);
@@ -218,7 +205,7 @@
 		SCTP_DEBUG_PRINTK(
 			"rt6_dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
 			"rt6_src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-			NIP6(&rt->rt6i_dst.addr), NIP6(&rt->rt6i_src.addr));
+			NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
 	} else {
 		SCTP_DEBUG_PRINTK("NO ROUTE\n");
 	}
@@ -251,10 +238,10 @@
 /* Fills in the source address(saddr) based on the destination address(daddr)
  * and asoc's bind address list.
  */
-void sctp_v6_get_saddr(sctp_association_t *asoc, struct dst_entry *dst,
+void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst,
 		       union sctp_addr *daddr, union sctp_addr *saddr)
 {
-	sctp_bind_addr_t *bp;
+	struct sctp_bind_addr *bp;
 	rwlock_t *addr_lock;
 	struct sockaddr_storage_list *laddr;
 	struct list_head *pos;
@@ -265,13 +252,13 @@
 
 	SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
 			  "daddr:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
-			  __FUNCTION__, asoc, dst, NIP6(&daddr->v6.sin6_addr));
+			  __FUNCTION__, asoc, dst, NIP6(daddr->v6.sin6_addr));
 
 	if (!asoc) {
 		ipv6_get_saddr(dst, &daddr->v6.sin6_addr,&saddr->v6.sin6_addr);
 		SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: "
 				  "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-				  NIP6(&saddr->v6.sin6_addr));
+				  NIP6(saddr->v6.sin6_addr));
 		return;
 	}
 
@@ -300,12 +287,12 @@
 		memcpy(saddr, baddr, sizeof(union sctp_addr));
 		SCTP_DEBUG_PRINTK("saddr: "
 				  "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-				  NIP6(&saddr->v6.sin6_addr));
+				  NIP6(saddr->v6.sin6_addr));
 	} else {
 		printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
 		       "address for the "
 		       "dest:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-		       __FUNCTION__, asoc, NIP6(&daddr->v6.sin6_addr));
+		       __FUNCTION__, asoc, NIP6(daddr->v6.sin6_addr));
 	}
 
 	sctp_read_unlock(addr_lock);
@@ -376,11 +363,17 @@
 }
 
 /* Initialize sk->rcv_saddr from sctp_addr. */
-static void sctp_v6_to_sk(union sctp_addr *addr, struct sock *sk)
+static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
 {
 	inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr;
 }
 
+/* Initialize sk->daddr from sctp_addr. */
+static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
+{
+	inet6_sk(sk)->daddr = addr->v6.sin6_addr;
+}
+
 /* Initialize a sctp_addr from a dst_entry. */
 static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
 			      unsigned short port)
@@ -391,7 +384,7 @@
 	ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr);
 }
 
-/* Compare addresses exactly.  
+/* Compare addresses exactly.
  * FIXME: v4-mapped-v6.
  */
 static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
@@ -521,6 +514,7 @@
 	newsk->family = PF_INET6;
 	newsk->protocol = IPPROTO_SCTP;
 	newsk->backlog_rcv = sk->prot->backlog_rcv;
+	newsk->shutdown = sk->shutdown;
 
 	newsctp6sk = (struct sctp6_sock *)newsk;
 	newsctp6sk->pinet6 = &newsctp6sk->inet6;
@@ -530,10 +524,28 @@
 
 	memcpy(newnp, np, sizeof(struct ipv6_pinfo));
 
-	ipv6_addr_copy(&newnp->daddr, &asoc->peer.primary_addr.v6.sin6_addr);
-
+	/* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
+	 * and getpeername().
+	 */
 	newinet->sport = inet->sport;
-	newinet->dport = asoc->peer.port;
+	newnp->saddr = np->saddr;
+	newnp->rcv_saddr = np->rcv_saddr;
+	newinet->dport = htons(asoc->peer.port);
+	newnp->daddr =  asoc->peer.primary_addr.v6.sin6_addr;
+
+	/* Init the ipv4 part of the socket since we can have sockets
+	 * using v6 API for ipv4.
+	 */
+	newinet->uc_ttl = -1;
+	newinet->mc_loop = 1;
+	newinet->mc_ttl = 1;
+	newinet->mc_index = 0;
+	newinet->mc_list = NULL;
+
+	if (ipv4_config.no_pmtu_disc)
+		newinet->pmtudisc = IP_PMTUDISC_DONT;
+	else
+		newinet->pmtudisc = IP_PMTUDISC_WANT;
 
 #ifdef INET_REFCNT_DEBUG
 	atomic_inc(&inet6_sock_nr);
@@ -556,6 +568,12 @@
 	return opt->iif;
 }
 
+/* Was this packet marked by Explicit Congestion Notification? */
+static int sctp_v6_is_ce(const struct sk_buff *skb)
+{
+	return *((__u32 *)(skb->nh.ipv6h)) & htonl(1<<20);
+}
+
 /* Initialize a PF_INET6 socket msg_name. */
 static void sctp_inet6_msgname(char *msgname, int *addr_len)
 {
@@ -569,7 +587,7 @@
 }
 
 /* Initialize a PF_INET msgname from a ulpevent. */
-static void sctp_inet6_event_msgname(struct sctp_ulpevent *event, 
+static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
 				     char *msgname, int *addrlen)
 {
 	struct sockaddr_in6 *sin6, *sin6from;
@@ -596,7 +614,7 @@
 
 		sin6from = &event->asoc->peer.primary_addr.v6;
 		ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr);
-		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) 
+		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
 			sin6->sin6_scope_id = sin6from->sin6_scope_id;
 	}
 }
@@ -696,7 +714,7 @@
 			if (addr->v6.sin6_scope_id)
 				sk->bound_dev_if = addr->v6.sin6_scope_id;
 			if (!sk->bound_dev_if)
-				return 0;			
+				return 0;
 		}
 		af = opt->pf->af;
 	}
@@ -726,11 +744,11 @@
 			if (addr->v6.sin6_scope_id)
 				sk->bound_dev_if = addr->v6.sin6_scope_id;
 			if (!sk->bound_dev_if)
-				return 0;			
+				return 0;
 		}
 		af = opt->pf->af;
 	}
-	
+
 	return af != NULL;
 }
 
@@ -807,7 +825,8 @@
 	.copy_addrlist   = sctp_v6_copy_addrlist,
 	.from_skb        = sctp_v6_from_skb,
 	.from_sk         = sctp_v6_from_sk,
-	.to_sk           = sctp_v6_to_sk,
+	.to_sk_saddr     = sctp_v6_to_sk_saddr,
+	.to_sk_daddr     = sctp_v6_to_sk_daddr,
 	.dst_saddr       = sctp_v6_dst_saddr,
 	.cmp_addr        = sctp_v6_cmp_addr,
 	.scope           = sctp_v6_scope,
@@ -816,6 +835,7 @@
 	.is_any          = sctp_v6_is_any,
 	.available       = sctp_v6_available,
 	.skb_iif         = sctp_v6_skb_iif,
+	.is_ce           = sctp_v6_is_ce,
 	.net_header_len  = sizeof(struct ipv6hdr),
 	.sockaddr_len    = sizeof(struct sockaddr_in6),
 	.sa_family       = AF_INET6,
diff -Nru a/net/sctp/objcnt.c b/net/sctp/objcnt.c
--- a/net/sctp/objcnt.c	Fri Jan 17 13:35:51 2003
+++ b/net/sctp/objcnt.c	Tue May 20 19:39:24 2003
@@ -38,6 +38,7 @@
  * be incorporated into the next SCTP release.
  */
 
+#include <linux/kernel.h>
 #include <net/sctp/sctp.h>
 
 /*
@@ -55,6 +56,7 @@
 SCTP_DBG_OBJCNT(chunk);
 SCTP_DBG_OBJCNT(addr);
 SCTP_DBG_OBJCNT(ssnmap);
+SCTP_DBG_OBJCNT(datamsg);
 
 /* An array to make it easy to pretty print the debug information
  * to the proc fs.
@@ -68,6 +70,7 @@
 	SCTP_DBG_OBJCNT_ENTRY(bind_addr),
 	SCTP_DBG_OBJCNT_ENTRY(addr),
 	SCTP_DBG_OBJCNT_ENTRY(ssnmap),
+	SCTP_DBG_OBJCNT_ENTRY(datamsg),
 };
 
 /* Callback from procfs to read out objcount information.
@@ -86,7 +89,7 @@
 	char temp[128];
 
 	/* How many entries? */
-	entries = sizeof(sctp_dbg_objcnt)/sizeof(sctp_dbg_objcnt[0]);
+	entries = ARRAY_SIZE(sctp_dbg_objcnt);
 
 	/* Walk the entries and print out the debug information
 	 * for proc fs.
diff -Nru a/net/sctp/output.c b/net/sctp/output.c
--- a/net/sctp/output.c	Mon Mar 31 08:57:37 2003
+++ b/net/sctp/output.c	Mon May  5 15:42:16 2003
@@ -114,7 +114,7 @@
 	struct sctp_chunk *chunk;
 
         while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks)))
-		sctp_free_chunk(chunk);
+		sctp_chunk_free(chunk);
 
 	if (packet->malloced)
 		kfree(packet);
@@ -166,11 +166,11 @@
 	/* If sending DATA and haven't aleady bundled a SACK, try to
 	 * bundle one in to the packet.
 	 */
-	if (sctp_chunk_is_data(chunk) && !pkt->has_sack && 
+	if (sctp_chunk_is_data(chunk) && !pkt->has_sack &&
 	    !pkt->has_cookie_echo) {
 		struct sctp_association *asoc;
 		asoc = pkt->transport->asoc;
-			
+
 		if (asoc->a_rwnd > asoc->rwnd) {
 			struct sctp_chunk *sack;
 			asoc->a_rwnd = asoc->rwnd;
@@ -205,7 +205,7 @@
 
 	if (retval != SCTP_XMIT_OK)
 		goto finish;
-		
+
 	pmtu  = ((packet->transport->asoc) ?
 		 (packet->transport->asoc->pmtu) :
 		 (packet->transport->pmtu));
@@ -219,21 +219,16 @@
 		/* Both control chunks and data chunks with TSNs are
 		 * non-fragmentable.
 		 */
-		int fragmentable = sctp_chunk_is_data(chunk) &&
-			(!chunk->has_tsn);
 		if (packet_empty) {
-			if (fragmentable) {
-				retval = SCTP_XMIT_MUST_FRAG;
-				goto finish;
-			} else {
-				/* The packet is too big but we can
-				 * not fragment it--we have to just
-				 * transmit and rely on IP
-				 * fragmentation.
-				 */
-				packet->ipfragok = 1;
-				goto append;
-			}
+
+			/* We no longer do refragmentation at all.
+			 * Just fragment at the IP layer, if we
+			 * actually hit this condition
+			 */
+
+			packet->ipfragok = 1;
+			goto append;
+
 		} else { /* !packet_empty */
 			retval = SCTP_XMIT_PMTU_FULL;
 			goto finish;
@@ -259,7 +254,7 @@
 			goto finish;
 	} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
 		packet->has_cookie_echo = 1;
-	else if (SCTP_CID_SACK == chunk->chunk_hdr->type) 
+	else if (SCTP_CID_SACK == chunk->chunk_hdr->type)
 		packet->has_sack = 1;
 
 	/* It is OK to send this chunk.  */
@@ -276,8 +271,8 @@
  */
 int sctp_packet_transmit(struct sctp_packet *packet)
 {
-	struct sctp_transport *transport = packet->transport;
-	struct sctp_association *asoc = transport->asoc;
+	struct sctp_transport *tp = packet->transport;
+	struct sctp_association *asoc = tp->asoc;
 	struct sctphdr *sh;
 	__u32 crc32;
 	struct sk_buff *nskb;
@@ -311,6 +306,31 @@
 	 */
 	skb_set_owner_w(nskb, sk);
 
+	/* Build the SCTP header.  */
+	sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
+	sh->source = htons(packet->source_port);
+	sh->dest   = htons(packet->destination_port);
+
+	/* From 6.8 Adler-32 Checksum Calculation:
+	 * After the packet is constructed (containing the SCTP common
+	 * header and one or more control or DATA chunks), the
+	 * transmitter shall:
+	 *
+	 * 1) Fill in the proper Verification Tag in the SCTP common
+	 *    header and initialize the checksum field to 0's.
+	 */
+	sh->vtag     = htonl(packet->vtag);
+	sh->checksum = 0;
+
+	/* 2) Calculate the Adler-32 checksum of the whole packet,
+	 *    including the SCTP common header and all the
+	 *    chunks.
+	 *
+	 * Note: Adler-32 is no longer applicable, as has been replaced
+	 * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
+	 */
+	crc32 = sctp_start_cksum((__u8 *)sh, sizeof(struct sctphdr));
+
 	/**
 	 * 6.10 Bundling
 	 *
@@ -332,10 +352,12 @@
 	 */
 	SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n");
 	while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) {
-		chunk->num_times_sent++;
-		chunk->sent_at = jiffies;
+
 		if (sctp_chunk_is_data(chunk)) {
-			sctp_chunk_assign_tsn(chunk);
+
+			if (!chunk->has_tsn) {
+				sctp_chunk_assign_ssn(chunk);
+				sctp_chunk_assign_tsn(chunk);
 
 			/* 6.3.1 C4) When data is in flight and when allowed
 			 * by rule C5, a new RTT measurement MUST be made each
@@ -343,19 +365,27 @@
 			 * SHOULD be made no more than once per round-trip
 			 * for a given destination transport address.
 			 */
-			if ((1 == chunk->num_times_sent) &&
-			    (!transport->rto_pending)) {
-				chunk->rtt_in_progress = 1;
-				transport->rto_pending = 1;
-			}
+
+				if (!tp->rto_pending) {
+					chunk->rtt_in_progress = 1;
+					tp->rto_pending = 1;
+				}
+			} else
+				chunk->resent = 1;
+
+			chunk->sent_at = jiffies;
 			has_data = 1;
 		}
-		memcpy(skb_put(nskb, chunk->skb->len),
-		       chunk->skb->data, chunk->skb->len);
+
 		padding = WORD_ROUND(chunk->skb->len) - chunk->skb->len;
-		memset(skb_put(nskb, padding), 0, padding);
-		SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d, "
-				  "%s %d\n",
+		if (padding)
+			memset(skb_put(chunk->skb, padding), 0, padding);
+
+		crc32 = sctp_update_copy_cksum(skb_put(nskb, chunk->skb->len),
+					       chunk->skb->data,
+					       chunk->skb->len, crc32);
+
+		SCTP_DEBUG_PRINTK("%s %p[%s] %s 0x%x, %s %d, %s %d, %s %d\n",
 				  "*** Chunk", chunk,
 				  sctp_cname(SCTP_ST_CHUNK(
 					  chunk->chunk_hdr->type)),
@@ -364,7 +394,6 @@
 				  ntohl(chunk->subh.data_hdr->tsn) : 0,
 				  "length", ntohs(chunk->chunk_hdr->length),
 				  "chunk->skb->len", chunk->skb->len,
-				  "num_times_sent", chunk->num_times_sent,
 				  "rtt_in_progress", chunk->rtt_in_progress);
 
 		/*
@@ -373,33 +402,10 @@
 		 * acknowledged or have failed.
 		 */
 		if (!sctp_chunk_is_data(chunk))
-			sctp_free_chunk(chunk);
+    			sctp_chunk_free(chunk);
 	}
 
-	/* Build the SCTP header.  */
-	sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
-	sh->source = htons(packet->source_port);
-	sh->dest   = htons(packet->destination_port);
-
-	/* From 6.8 Adler-32 Checksum Calculation:
-	 * After the packet is constructed (containing the SCTP common
-	 * header and one or more control or DATA chunks), the
-	 * transmitter shall:
-	 *
-	 * 1) Fill in the proper Verification Tag in the SCTP common
-	 *    header and initialize the checksum field to 0's.
-	 */
-	sh->vtag     = htonl(packet->vtag);
-	sh->checksum = 0;
-
-	/* 2) Calculate the Adler-32 checksum of the whole packet,
-	 *    including the SCTP common header and all the
-	 *    chunks.
-	 *
-	 * Note: Adler-32 is no longer applicable, as has been replaced
-	 * by CRC32-C as described in <draft-ietf-tsvwg-sctpcsum-02.txt>.
-	 */
-	crc32 = sctp_start_cksum((__u8 *)sh, nskb->len);
+	/* Perform final transformation on checksum. */
 	crc32 = sctp_end_cksum(crc32);
 
 	/* 3) Put the resultant value into the checksum field in the
@@ -413,17 +419,13 @@
 	 *   data sender to indicate that the end-points of the
 	 *   transport protocol are ECN-capable."
 	 *
-	 * If ECN capable && negotiated && it makes sense for
-	 * this packet to support it (e.g. post ECN negotiation)
-	 * then lets set the ECT bit
+	 * Now setting the ECT bit all the time, as it should not cause
+	 * any problems protocol-wise even if our peer ignores it.
 	 *
-	 * FIXME:  Need to do something else for IPv6
+	 * Note: The works for IPv6 layer checks this bit too later
+	 * in transmission.  See IP6_ECN_flow_xmit().
 	 */
-	if (packet->ecn_capable) {
-		INET_ECN_xmit(nskb->sk);
-	} else {
-		INET_ECN_dontxmit(nskb->sk);
-	}
+	INET_ECN_xmit(nskb->sk);
 
 	/* Set up the IP options.  */
 	/* BUG: not implemented
@@ -431,22 +433,21 @@
 	 */
 
 	/* Dump that on IP!  */
-	if (asoc && asoc->peer.last_sent_to != transport) {
+	if (asoc && asoc->peer.last_sent_to != tp) {
 		/* Considering the multiple CPU scenario, this is a
 		 * "correcter" place for last_sent_to.  --xguo
 		 */
-		asoc->peer.last_sent_to = transport;
+		asoc->peer.last_sent_to = tp;
 	}
 
 	if (has_data) {
 		struct timer_list *timer;
 		unsigned long timeout;
 
-		transport->last_time_used = jiffies;
+		tp->last_time_used = jiffies;
 
 		/* Restart the AUTOCLOSE timer when sending data. */
-		if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
-		    (asoc->autoclose)) {
+		if (sctp_state(asoc, ESTABLISHED) && asoc->autoclose) {
 			timer = &asoc->timers[SCTP_EVENT_TIMEOUT_AUTOCLOSE];
 			timeout = asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE];
 
@@ -455,21 +456,21 @@
 		}
 	}
 
-	dst = transport->dst;
+	dst = tp->dst;
 	/* The 'obsolete' field of dst is set to 2 when a dst is freed. */
 	if (!dst || (dst->obsolete > 1)) {
 		dst_release(dst);
-		sctp_transport_route(transport, NULL, sctp_sk(sk));
+		sctp_transport_route(tp, NULL, sctp_sk(sk));
 		sctp_assoc_sync_pmtu(asoc);
 	}
 
-	nskb->dst = dst_clone(transport->dst);
+	nskb->dst = dst_clone(tp->dst);
 	if (!nskb->dst)
 		goto no_route;
 
 	SCTP_DEBUG_PRINTK("***sctp_transmit_packet*** skb length %d\n",
 			  nskb->len);
-	(*transport->af_specific->sctp_xmit)(nskb, transport, packet->ipfragok);
+	(*tp->af_specific->sctp_xmit)(nskb, tp, packet->ipfragok);
 out:
 	packet->size = SCTP_IP_OVERHEAD;
 	return err;
@@ -596,8 +597,8 @@
 	 * if any previously transmitted data on the connection remains
 	 * unacknowledged.
 	 */
-	if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size && 
-	    q->outstanding_bytes && SCTP_STATE_ESTABLISHED == asoc->state) {
+	if (!sp->nodelay && SCTP_IP_OVERHEAD == packet->size &&
+	    q->outstanding_bytes && sctp_state(asoc, ESTABLISHED)) {
 		unsigned len = datasize + q->out_qlen;
 
 		/* Check whether this chunk and all the rest of pending
@@ -623,6 +624,8 @@
 		rwnd = 0;
 
 	asoc->peer.rwnd = rwnd;
+	/* Has been accepted for transmission. */
+	chunk->msg->can_expire = 0;
 
 finish:
 	return retval;
diff -Nru a/net/sctp/outqueue.c b/net/sctp/outqueue.c
--- a/net/sctp/outqueue.c	Tue Mar 25 14:11:33 2003
+++ b/net/sctp/outqueue.c	Thu May  1 07:23:56 2003
@@ -55,13 +55,19 @@
 #include <net/sctp/sctp.h>
 
 /* Declare internal functions here.  */
-static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn);
+static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn);
 static void sctp_check_transmitted(struct sctp_outq *q,
 				   struct list_head *transmitted_queue,
 				   struct sctp_transport *transport,
-				   sctp_sackhdr_t *sack,
+				   struct sctp_sackhdr *sack,
 				   __u32 highest_new_tsn);
 
+static void sctp_mark_missing(struct sctp_outq *q,
+			      struct list_head *transmitted_queue,
+			      struct sctp_transport *transport,
+			      __u32 highest_new_tsn,
+			      int count_of_newacks);
+
 /* Add data to the front of the queue. */
 static inline void sctp_outq_head_data(struct sctp_outq *q,
 					struct sctp_chunk *ch)
@@ -94,13 +100,105 @@
 					 struct sctp_chunk *ch,
 					 struct sctp_chunk *pos)
 {
-	__skb_insert((struct sk_buff *)ch, (struct sk_buff *)pos->prev, 
+	__skb_insert((struct sk_buff *)ch, (struct sk_buff *)pos->prev,
 		     (struct sk_buff *)pos, pos->list);
 	q->out_qlen += ch->skb->len;
 }
 
+/*
+ * SFR-CACC algorithm:
+ * D) If count_of_newacks is greater than or equal to 2
+ * and t was not sent to the current primary then the
+ * sender MUST NOT increment missing report count for t.
+ */
+static inline int sctp_cacc_skip_3_1_d(struct sctp_transport *primary,
+				       struct sctp_transport *transport,
+				       int count_of_newacks)
+{
+	if (count_of_newacks >=2 && transport != primary)
+		return 1;
+	return 0;
+}
+
+/*
+ * SFR-CACC algorithm:
+ * F) If count_of_newacks is less than 2, let d be the
+ * destination to which t was sent. If cacc_saw_newack
+ * is 0 for destination d, then the sender MUST NOT
+ * increment missing report count for t.
+ */
+static inline int sctp_cacc_skip_3_1_f(struct sctp_transport *transport,
+				       int count_of_newacks)
+{
+	if (count_of_newacks < 2 && !transport->cacc.cacc_saw_newack)
+		return 1;
+	return 0;
+}
+
+/*
+ * SFR-CACC algorithm:
+ * 3.1) If CYCLING_CHANGEOVER is 0, the sender SHOULD
+ * execute steps C, D, F.
+ *
+ * C has been implemented in sctp_outq_sack
+ */
+static inline int sctp_cacc_skip_3_1(struct sctp_transport *primary,
+				     struct sctp_transport *transport,
+				     int count_of_newacks)
+{
+	if (!primary->cacc.cycling_changeover) {
+		if (sctp_cacc_skip_3_1_d(primary, transport, count_of_newacks))
+			return 1;
+		if (sctp_cacc_skip_3_1_f(transport, count_of_newacks));
+			return 1;
+		return 0;
+	}
+	return 0;
+}
+
+/*
+ * SFR-CACC algorithm:
+ * 3.2) Else if CYCLING_CHANGEOVER is 1, and t is less
+ * than next_tsn_at_change of the current primary, then
+ * the sender MUST NOT increment missing report count
+ * for t.
+ */
+static inline int sctp_cacc_skip_3_2(struct sctp_transport *primary, __u32 tsn)
+{
+	if (primary->cacc.cycling_changeover &&
+	    TSN_lt(tsn, primary->cacc.next_tsn_at_change))
+		return 1;
+	return 0;
+}
+
+/*
+ * SFR-CACC algorithm:
+ * 3) If the missing report count for TSN t is to be
+ * incremented according to [RFC2960] and
+ * [SCTP_STEWART-2002], and CHANGEOVER_ACTIVE is set,
+ * then the sender MUST futher execute steps 3.1 and
+ * 3.2 to determine if the missing report count for
+ * TSN t SHOULD NOT be incremented.
+ *
+ * 3.3) If 3.1 and 3.2 do not dictate that the missing
+ * report count for t should not be incremented, then
+ * the sender SOULD increment missing report count for
+ * t (according to [RFC2960] and [SCTP_STEWART_2002]).
+ */
+static inline int sctp_cacc_skip(struct sctp_transport *primary,
+				 struct sctp_transport *transport,
+				 int count_of_newacks,
+				 __u32 tsn)
+{
+	if (primary->cacc.changeover_active &&
+	    (sctp_cacc_skip_3_1(primary, transport, count_of_newacks)
+	     || sctp_cacc_skip_3_2(primary, tsn)))
+		return 1;
+	return 0;
+}
+
 /* Generate a new outqueue.  */
-struct sctp_outq *sctp_outq_new(sctp_association_t *asoc)
+struct sctp_outq *sctp_outq_new(struct sctp_association *asoc)
 {
 	struct sctp_outq *q;
 
@@ -116,7 +214,7 @@
  * You still need to define handlers if you really want to DO
  * something with this structure...
  */
-void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q)
+void sctp_outq_init(struct sctp_association *asoc, struct sctp_outq *q)
 {
 	q->asoc = asoc;
 	skb_queue_head_init(&q->out);
@@ -132,6 +230,7 @@
 
 	q->outstanding_bytes = 0;
 	q->empty = 1;
+	q->cork  = 0;
 
 	q->malloced = 0;
 	q->out_qlen = 0;
@@ -143,59 +242,51 @@
 {
 	struct sctp_transport *transport;
 	struct list_head *lchunk, *pos, *temp;
-	sctp_chunk_t *chunk;
-	struct sctp_ulpevent *ev;
+	struct sctp_chunk *chunk;
 
 	/* Throw away unacknowledged chunks. */
 	list_for_each(pos, &q->asoc->peer.transport_addr_list) {
 		transport = list_entry(pos, struct sctp_transport, transports);
 		while ((lchunk = sctp_list_dequeue(&transport->transmitted))) {
-			chunk = list_entry(lchunk, sctp_chunk_t,
+			chunk = list_entry(lchunk, struct sctp_chunk,
 					   transmitted_list);
-
-			/* Generate a SEND FAILED event. */
-			ev = sctp_ulpevent_make_send_failed(q->asoc,
-					chunk, SCTP_DATA_SENT,
-					q->error, GFP_ATOMIC);
-			if (ev)
-				sctp_ulpq_tail_event(&q->asoc->ulpq, ev);
-
-			sctp_free_chunk(chunk);
+			/* Mark as part of a failed message. */
+			sctp_datamsg_fail(chunk, q->error);
+			sctp_chunk_free(chunk);
 		}
 	}
 
 	/* Throw away chunks that have been gap ACKed.  */
 	list_for_each_safe(lchunk, temp, &q->sacked) {
 		list_del(lchunk);
-		chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
-		sctp_free_chunk(chunk);
+		chunk = list_entry(lchunk, struct sctp_chunk,
+				   transmitted_list);
+		sctp_datamsg_fail(chunk, q->error);
+		sctp_chunk_free(chunk);
 	}
 
 	/* Throw away any chunks in the retransmit queue. */
 	list_for_each_safe(lchunk, temp, &q->retransmit) {
 		list_del(lchunk);
-		chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
-		sctp_free_chunk(chunk);
+		chunk = list_entry(lchunk, struct sctp_chunk,
+				   transmitted_list);
+		sctp_datamsg_fail(chunk, q->error);
+		sctp_chunk_free(chunk);
 	}
 
 	/* Throw away any leftover data chunks. */
 	while ((chunk = sctp_outq_dequeue_data(q))) {
 
-		/* Generate a SEND FAILED event. */
-		ev = sctp_ulpevent_make_send_failed(q->asoc,
-				chunk, SCTP_DATA_UNSENT,
-				q->error, GFP_ATOMIC);
-		if (ev)
-			sctp_ulpq_tail_event(&q->asoc->ulpq, ev);
-
-		sctp_free_chunk(chunk);
+		/* Mark as send failure. */
+		sctp_datamsg_fail(chunk, q->error);
+		sctp_chunk_free(chunk);
 	}
 
 	q->error = 0;
 
 	/* Throw away any leftover control chunks. */
-	while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->control)))
-		sctp_free_chunk(chunk);
+	while ((chunk = (struct sctp_chunk *) skb_dequeue(&q->control)))
+		sctp_chunk_free(chunk);
 }
 
 /* Free the outqueue structure and any related pending chunks.  */
@@ -210,7 +301,7 @@
 }
 
 /* Put a new chunk in an sctp_outq.  */
-int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk)
+int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
 {
 	int error = 0;
 
@@ -265,7 +356,8 @@
 	if (error < 0)
 		return error;
 
-	error = sctp_outq_flush(q, 0);
+	if (!q->cork)
+		error = sctp_outq_flush(q, 0);
 
 	return error;
 }
@@ -276,15 +368,16 @@
 void sctp_retransmit_insert(struct list_head *tlchunk, struct sctp_outq *q)
 {
 	struct list_head *rlchunk;
-	sctp_chunk_t *tchunk, *rchunk;
+	struct sctp_chunk *tchunk, *rchunk;
 	__u32 ttsn, rtsn;
 	int done = 0;
 
-	tchunk = list_entry(tlchunk, sctp_chunk_t, transmitted_list);
+	tchunk = list_entry(tlchunk, struct sctp_chunk, transmitted_list);
 	ttsn = ntohl(tchunk->subh.data_hdr->tsn);
 
 	list_for_each(rlchunk, &q->retransmit) {
-		rchunk = list_entry(rlchunk, sctp_chunk_t, transmitted_list);
+		rchunk = list_entry(rlchunk, struct sctp_chunk,
+				    transmitted_list);
 		rtsn = ntohl(rchunk->subh.data_hdr->tsn);
 		if (TSN_lt(ttsn, rtsn)) {
 			list_add(tlchunk, rlchunk->prev);
@@ -303,11 +396,12 @@
 			  __u8 fast_retransmit)
 {
 	struct list_head *lchunk, *ltemp;
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 
 	/* Walk through the specified transmitted queue.  */
 	list_for_each_safe(lchunk, ltemp, &transport->transmitted) {
-		chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
+		chunk = list_entry(lchunk, struct sctp_chunk,
+				   transmitted_list);
 
 		/* If we are doing retransmission due to a fast retransmit,
 		 * only the chunk's that are marked for fast retransmit
@@ -416,8 +510,8 @@
 	struct list_head *lchunk;
 	struct sctp_transport *transport = pkt->transport;
 	sctp_xmit_t status;
-	sctp_chunk_t *chunk;
-	sctp_association_t *asoc;
+	struct sctp_chunk *chunk;
+	struct sctp_association *asoc;
 	int error = 0;
 
 	asoc = q->asoc;
@@ -442,7 +536,8 @@
 	lchunk = sctp_list_dequeue(lqueue);
 
 	while (lchunk) {
-		chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
+		chunk = list_entry(lchunk, struct sctp_chunk,
+				   transmitted_list);
 
 		/* Make sure that Gap Acked TSNs are not retransmitted.  A
 		 * simple approach is just to move such TSNs out of the
@@ -504,215 +599,19 @@
 	return error;
 }
 
-/* This routine either transmits the fragment or puts it on the output
- * queue.  'pos' points to the next chunk in the output queue after the
- * chunk that is currently in the process of fragmentation.
- */
-void sctp_xmit_frag(struct sctp_outq *q, struct sctp_chunk *pos,
-		struct sctp_packet *packet, struct sctp_chunk *frag, __u32 tsn)
+/* Cork the outqueue so queued chunks are really queued. */
+int sctp_outq_uncork(struct sctp_outq *q)
 {
-	struct sctp_transport *transport = packet->transport;
-	struct sk_buff_head *queue = &q->out;
-	sctp_xmit_t status;
-	int error;
-
-	frag->subh.data_hdr->tsn = htonl(tsn);
-	frag->has_tsn = 1;
-
-	/* An inner fragment may be smaller than the earlier one and may get
-	 * in if we call q->build_output.  This ensures that all the fragments
-	 * are sent in order.
-	 */
-	if (!skb_queue_empty(queue)) {
-		SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. "
-				  "adding 0x%x to outqueue\n",
-				  ntohl(frag->subh.data_hdr->tsn));
-		if (pos)		
-			sctp_outq_insert_data(q, frag, pos);
-		else
-			sctp_outq_tail_data(q, frag);
-		return;
-	}
-
-	/* Add the chunk fragment to the packet.  */
-	status = (*q->build_output)(packet, frag);
-	switch (status) {
-	case SCTP_XMIT_RWND_FULL:
-		/* RWND is full, so put the chunk in the output queue. */
-		SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. "
-				  "adding 0x%x to outqueue\n",
-				  ntohl(frag->subh.data_hdr->tsn));
-		if (pos)
-			sctp_outq_insert_data(q, frag, pos);
-		else
-			sctp_outq_tail_data(q, frag);
-		break;
-
-	case SCTP_XMIT_OK:
-		error = (*q->force_output)(packet);
-		if (error < 0) {
-			/* Packet could not be transmitted, put the chunk in
-			 * the output queue
-			 */
-			SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output "
-					  "failed. adding 0x%x to outqueue\n",
-					  ntohl(frag->subh.data_hdr->tsn));
-			if (pos)
-				sctp_outq_insert_data(q, frag, pos);
-			else
-				sctp_outq_tail_data(q, frag);
-		} else {
-			SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output "
-					  "success. 0x%x sent\n",
-					  ntohl(frag->subh.data_hdr->tsn));
-			list_add_tail(&frag->transmitted_list,
-				      &transport->transmitted);
-
-			sctp_transport_reset_timers(transport);
-		}
-		break;
-
-	default:
-		BUG();
-	};
-}
-
-/* This routine calls sctp_xmit_frag() for all the fragments of a message.
- * The argument 'frag' point to the first fragment and it holds the list
- * of all the other fragments in the 'frag_list' field.
- */
-void sctp_xmit_fragmented_chunks(struct sctp_outq *q, struct sctp_packet *pkt,
-				 sctp_chunk_t *frag)
-{
-	sctp_association_t *asoc = frag->asoc;
-	struct list_head *lfrag, *frag_list;
-	__u32 tsn;
-	int nfrags = 1;
-	struct sctp_chunk *pos;
-
-	/* Count the number of fragments. */
-	frag_list = &frag->frag_list;
-	list_for_each(lfrag, frag_list) {
-		nfrags++;
-	}
-
-	/* Get a TSN block of nfrags TSNs. */
-	tsn = sctp_association_get_tsn_block(asoc, nfrags);
-
-	pos = (struct sctp_chunk *)skb_peek(&q->out);
-	/* Transmit the first fragment. */
-	sctp_xmit_frag(q, pos, pkt, frag, tsn++);
-
-	/* Transmit the rest of fragments. */
-	frag_list = &frag->frag_list;
-	list_for_each(lfrag, frag_list) {
-		frag = list_entry(lfrag, sctp_chunk_t, frag_list);
-		sctp_xmit_frag(q, pos, pkt, frag, tsn++);
-	}
-}
-
-/* This routine breaks the given chunk into 'max_frag_data_len' size
- * fragments.  It returns the first fragment with the frag_list field holding
- * the remaining fragments.
- */
-sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
-				  size_t max_frag_data_len)
-{
-	sctp_association_t *asoc = chunk->asoc;
-	void *data_ptr = chunk->subh.data_hdr;
-	struct sctp_sndrcvinfo *sinfo = &chunk->sinfo;
-	__u16 chunk_data_len = sctp_data_size(chunk);
-	__u16 ssn = ntohs(chunk->subh.data_hdr->ssn);
-	sctp_chunk_t *first_frag, *frag;
-	struct list_head *frag_list;
-	int nfrags;
-	__u8 old_flags, flags;
-
-	/* nfrags = no. of max size fragments + any smaller last fragment. */
-	nfrags = ((chunk_data_len / max_frag_data_len) +
-		  ((chunk_data_len % max_frag_data_len) ? 1 : 0));
-
-	/* Start of the data in the chunk. */
-	data_ptr += sizeof(sctp_datahdr_t);
-
-	/* Are we fragmenting an already fragmented large message? */
- 	old_flags = chunk->chunk_hdr->flags;
-	if (old_flags & SCTP_DATA_FIRST_FRAG)
-		flags = SCTP_DATA_FIRST_FRAG;
-	else
-		flags = SCTP_DATA_MIDDLE_FRAG;
-
-	/* Make the first fragment. */
-	first_frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len,
-					data_ptr, flags, ssn);
-
-	if (!first_frag)
-		goto err;
-	first_frag->has_ssn = 1;
-	/* All the fragments are added to the frag_list of the first chunk. */
-	frag_list = &first_frag->frag_list;
-
-	chunk_data_len -= max_frag_data_len;
-	data_ptr += max_frag_data_len;
-
-	/* Make the middle fragments. */
-	while (chunk_data_len > max_frag_data_len) {
-		frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len,
-					  data_ptr, SCTP_DATA_MIDDLE_FRAG,
-					  ssn);
-		if (!frag)
-			goto err;
-		frag->has_ssn = 1;
-		/* Add the middle fragment to the first fragment's
-		 * frag_list.
-		 */
-		list_add_tail(&frag->frag_list, frag_list);
-
-		chunk_data_len -= max_frag_data_len;
-		data_ptr += max_frag_data_len;
-	}
-
-	if (old_flags & SCTP_DATA_LAST_FRAG)
-		flags = SCTP_DATA_LAST_FRAG;
-	else
-		flags = SCTP_DATA_MIDDLE_FRAG;
-
-	/* Make the last fragment. */
-	frag = sctp_make_datafrag(asoc, sinfo, chunk_data_len, data_ptr,
-				  flags, ssn);
-	if (!frag)
-		goto err;
-	frag->has_ssn = 1;
-
-	/* Add the last fragment to the first fragment's frag_list. */
-	list_add_tail(&frag->frag_list, frag_list);
-
-	/* Free the original chunk. */
-	sctp_free_chunk(chunk);
-
-	return first_frag;
-
-err:
-	/* Free any fragments that are created before the failure.  */
-	if (first_frag) {
-		struct list_head *flist, *lfrag;
-
-		/* Free all the fragments off the first one. */
-		flist = &first_frag->frag_list;
-		while (NULL != (lfrag = sctp_list_dequeue(flist))) {
-			frag = list_entry(lfrag, sctp_chunk_t, frag_list);
-			sctp_free_chunk(frag);
-		}
-
-		/* Free the first fragment. */
-		sctp_free_chunk(first_frag);
+	int error = 0;
+	if (q->cork) {
+		q->cork = 0;
+		error = sctp_outq_flush(q, 0);
 	}
-
-	return NULL;
+	return error;
 }
 
 /*
- * sctp_outq_flush - Try to flush an outqueue.
+ * Try to flush an outqueue.
  *
  * Description: Send everything in q which we legally can, subject to
  * congestion limitations.
@@ -724,7 +623,7 @@
 {
 	struct sctp_packet *packet;
 	struct sctp_packet singleton;
-	sctp_association_t *asoc = q->asoc;
+	struct sctp_association *asoc = q->asoc;
 	int ecn_capable = asoc->peer.ecn_capable;
 	__u16 sport = asoc->base.bind_addr.port;
 	__u16 dport = asoc->peer.port;
@@ -735,7 +634,7 @@
 	struct sk_buff_head *queue;
 	struct sctp_transport *transport = NULL;
 	struct sctp_transport *new_transport;
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 	sctp_xmit_t status;
 	int error = 0;
 	int start_timer = 0;
@@ -762,7 +661,7 @@
 	}
 
 	queue = &q->control;
-	while ((chunk = (sctp_chunk_t *)skb_dequeue(queue))) {
+	while ((chunk = (struct sctp_chunk *)skb_dequeue(queue))) {
 		/* Pick the right transport to use. */
 		new_transport = chunk->transport;
 
@@ -902,32 +801,25 @@
 			 */
 			if (chunk->sinfo.sinfo_stream >=
 			    asoc->c.sinit_num_ostreams) {
-				struct sctp_ulpevent *ev;
-
-				/* Generate a SEND FAILED event. */
-				ev = sctp_ulpevent_make_send_failed(asoc,
-					    chunk, SCTP_DATA_UNSENT,
-					    SCTP_ERROR_INV_STRM, GFP_ATOMIC);
-				if (ev)
-					sctp_ulpq_tail_event(&asoc->ulpq, ev);
 
-				/* Free the chunk. */
-				sctp_free_chunk(chunk);
+				/* Mark as s failed send. */
+				sctp_datamsg_fail(chunk, SCTP_ERROR_INV_STRM);
+				sctp_chunk_free(chunk);
 				continue;
 			}
 
-			/* Now do delayed assignment of SSN.  This will
-			 * probably change again when we start supporting
-			 * large (> approximately 2^16) size messages.
-			 */
-			sctp_chunk_assign_ssn(chunk);
+			/* Has this chunk expired? */
+			if (sctp_datamsg_expires(chunk)) {
+				sctp_datamsg_fail(chunk, 0);
+				sctp_chunk_free(chunk);
+				continue;
+			}
 
 			/* If there is a specified transport, use it.
 			 * Otherwise, we want to use the active path.
 			 */
 			new_transport = chunk->transport;
-			if (new_transport == NULL ||
-			    !new_transport->active)
+			if (!new_transport || !new_transport->active)
 				new_transport = asoc->peer.active_path;
 
 			/* Change packets if necessary.  */
@@ -979,26 +871,6 @@
 				goto sctp_flush_out;
 				break;
 
-			case SCTP_XMIT_MUST_FRAG: {
-				sctp_chunk_t *frag;
-
-				frag = sctp_fragment_chunk(chunk,
-					packet->transport->asoc->frag_point);
-				if (!frag) {
-					/* We could not fragment due to out of
-					 * memory condition. Free the original
-					 * chunk and return ENOMEM.
-					 */
-					sctp_free_chunk(chunk);
-					error = -ENOMEM;
-					return error;
-				}
-
-				sctp_xmit_fragmented_chunks(q, packet, frag);
-				goto sctp_flush_out;
-				break;
-			}
-
 			case SCTP_XMIT_OK:
 				break;
 
@@ -1077,8 +949,8 @@
 }
 
 /* Update unack_data based on the incoming SACK chunk */
-static void sctp_sack_update_unack_data(sctp_association_t *assoc,
-					sctp_sackhdr_t *sack)
+static void sctp_sack_update_unack_data(struct sctp_association *assoc,
+					struct sctp_sackhdr *sack)
 {
 	sctp_sack_variable_t *frags;
 	__u16 unack_data;
@@ -1096,12 +968,12 @@
 }
 
 /* Return the highest new tsn that is acknowledged by the given SACK chunk. */
-static __u32 sctp_highest_new_tsn(sctp_sackhdr_t *sack,
-				  sctp_association_t *asoc)
+static __u32 sctp_highest_new_tsn(struct sctp_sackhdr *sack,
+				  struct sctp_association *asoc)
 {
 	struct list_head *ltransport, *lchunk;
 	struct sctp_transport *transport;
-	sctp_chunk_t *chunk;
+	struct sctp_chunk *chunk;
 	__u32 highest_new_tsn, tsn;
 	struct list_head *transport_list = &asoc->peer.transport_addr_list;
 
@@ -1111,7 +983,7 @@
 		transport = list_entry(ltransport, struct sctp_transport,
 				       transports);
 		list_for_each(lchunk, &transport->transmitted) {
-			chunk = list_entry(lchunk, sctp_chunk_t,
+			chunk = list_entry(lchunk, struct sctp_chunk,
 					   transmitted_list);
 			tsn = ntohl(chunk->subh.data_hdr->tsn);
 
@@ -1130,26 +1002,64 @@
  * Process the SACK against the outqueue.  Mostly, this just frees
  * things off the transmitted queue.
  */
-int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack)
+int sctp_outq_sack(struct sctp_outq *q, struct sctp_sackhdr *sack)
 {
-	sctp_association_t *asoc = q->asoc;
+	struct sctp_association *asoc = q->asoc;
 	struct sctp_transport *transport;
-	sctp_chunk_t *tchunk;
+	struct sctp_chunk *tchunk;
 	struct list_head *lchunk, *transport_list, *pos;
 	sctp_sack_variable_t *frags = sack->variable;
 	__u32 sack_ctsn, ctsn, tsn;
 	__u32 highest_tsn, highest_new_tsn;
 	__u32 sack_a_rwnd;
 	int outstanding;
+	struct sctp_transport *primary = asoc->peer.primary_path;
+	int count_of_newacks = 0;
 
 	/* Grab the association's destination address list. */
 	transport_list = &asoc->peer.transport_addr_list;
 
 	sack_ctsn = ntohl(sack->cum_tsn_ack);
 
+	/*
+	 * SFR-CACC algorithm:
+	 * On receipt of a SACK the sender SHOULD execute the
+	 * following statements.
+	 *
+	 * 1) If the cumulative ack in the SACK passes next tsn_at_change
+	 * on the current primary, the CHANGEOVER_ACTIVE flag SHOULD be
+	 * cleared. The CYCLING_CHANGEOVER flag SHOULD also be cleared for
+	 * all destinations.
+	 */
+	if (TSN_lte(primary->cacc.next_tsn_at_change, sack_ctsn)) {
+		primary->cacc.changeover_active = 0;
+		list_for_each(pos, transport_list) {
+			transport = list_entry(pos, struct sctp_transport,
+					transports);
+			transport->cacc.cycling_changeover = 0;
+		}
+	}
+
+	/*
+	 * SFR-CACC algorithm:
+	 * 2) If the SACK contains gap acks and the flag CHANGEOVER_ACTIVE
+	 * is set the receiver of the SACK MUST take the following actions:
+	 *
+	 * A) Initialize the cacc_saw_newack to 0 for all destination
+	 * addresses.
+	 */
+	if (sack->num_gap_ack_blocks > 0 &&
+	    primary->cacc.changeover_active) {
+		list_for_each(pos, transport_list) {
+			transport = list_entry(pos, struct sctp_transport,
+					transports);
+			transport->cacc.cacc_saw_newack = 0;
+		}
+	}
+
 	/* Get the highest TSN in the sack. */
 	highest_tsn = sack_ctsn +
-		      ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end);
+		ntohs(frags[ntohs(sack->num_gap_ack_blocks) - 1].gab.end);
 
 	if (TSN_lt(asoc->highest_sacked, highest_tsn)) {
 		highest_new_tsn = highest_tsn;
@@ -1162,6 +1072,7 @@
 	 * and free those chunks that we can.
 	 */
 	sctp_check_transmitted(q, &q->retransmit, NULL, sack, highest_new_tsn);
+	sctp_mark_missing(q, &q->retransmit, NULL, highest_new_tsn, 0);
 
 	/* Run through the transmitted queue.
 	 * Credit bytes received and free those chunks which we can.
@@ -1173,6 +1084,20 @@
 					transports);
 		sctp_check_transmitted(q, &transport->transmitted,
 				       transport, sack, highest_new_tsn);
+		/*
+		 * SFR-CACC algorithm:
+		 * C) Let count_of_newacks be the number of
+		 * destinations for which cacc_saw_newack is set.
+		 */
+		if (transport->cacc.cacc_saw_newack)
+			count_of_newacks ++;
+	}
+
+	list_for_each(pos, transport_list) {
+		transport  = list_entry(pos, struct sctp_transport,
+					transports);
+		sctp_mark_missing(q, &transport->transmitted, transport,
+				  highest_new_tsn, count_of_newacks);
 	}
 
 	/* Move the Cumulative TSN Ack Point if appropriate.  */
@@ -1191,11 +1116,12 @@
 
 	/* Throw away stuff rotting on the sack queue.  */
 	list_for_each(lchunk, &q->sacked) {
-		tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
+		tchunk = list_entry(lchunk, struct sctp_chunk,
+				    transmitted_list);
 		tsn = ntohl(tchunk->subh.data_hdr->tsn);
 		if (TSN_lte(tsn, ctsn)) {
 			lchunk = lchunk->prev;
-			sctp_free_chunk(tchunk);
+			sctp_chunk_free(tchunk);
 		}
 	}
 
@@ -1244,12 +1170,9 @@
  * 2nd Level Abstractions
  ********************************************************************/
 
-/* Go through a transport's transmitted list or the assocication's retransmit
+/* Go through a transport's transmitted list or the association's retransmit
  * list and move chunks that are acked by the Cumulative TSN Ack to q->sacked.
- * The retransmit list will not have an associated transport. In case of a
- * transmitted list with a transport, the transport's congestion, rto and fast
- * retransmit parameters are also updated and if needed a fast retransmit
- * process is started.
+ * The retransmit list will not have an associated transport.
  *
  * I added coherent debug information output.	--xguo
  *
@@ -1260,17 +1183,16 @@
 static void sctp_check_transmitted(struct sctp_outq *q,
 				   struct list_head *transmitted_queue,
 				   struct sctp_transport *transport,
-				   sctp_sackhdr_t *sack,
+				   struct sctp_sackhdr *sack,
 				   __u32 highest_new_tsn_in_sack)
 {
 	struct list_head *lchunk;
-	sctp_chunk_t *tchunk;
+	struct sctp_chunk *tchunk;
 	struct list_head tlist;
 	__u32 tsn;
 	__u32 sack_ctsn;
 	__u32 rtt;
 	__u8 restart_timer = 0;
-	__u8 do_fast_retransmit = 0;
 	int bytes_acked = 0;
 
 	/* These state variables are for coherent debug output. --xguo */
@@ -1294,7 +1216,8 @@
 
 	/* The while loop will skip empty transmitted queues. */
 	while (NULL != (lchunk = sctp_list_dequeue(transmitted_queue))) {
-		tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
+		tchunk = list_entry(lchunk, struct sctp_chunk,
+				    transmitted_list);
 
 		tsn = ntohl(tchunk->subh.data_hdr->tsn);
 		if (sctp_acked(sack, tsn)) {
@@ -1315,9 +1238,9 @@
 				 * first instance of the packet or a later
 				 * instance).
 				 */
-			   	if ((!tchunk->tsn_gap_acked) &&
-				    (1 == tchunk->num_times_sent) &&
-				    (tchunk->rtt_in_progress)) {
+			   	if (!tchunk->tsn_gap_acked &&
+				    !tchunk->resent &&
+				    tchunk->rtt_in_progress) {
 					rtt = jiffies - tchunk->sent_at;
 					sctp_transport_update_rto(transport,
 								  rtt);
@@ -1338,6 +1261,25 @@
 				if (!tchunk->tsn_gap_acked) {
 					tchunk->tsn_gap_acked = 1;
 					bytes_acked += sctp_data_size(tchunk);
+					/*
+					 * SFR-CACC algorithm:
+					 * 2) If the SACK contains gap acks
+					 * and the flag CHANGEOVER_ACTIVE is
+					 * set the receiver of the SACK MUST
+					 * take the following action:
+					 *
+					 * B) For each TSN t being acked that
+					 * has not been acked in any SACK so
+					 * far, set cacc_saw_newack to 1 for
+					 * the destination that the TSN was
+					 * sent to.
+					 */
+					if (transport &&
+					    sack->num_gap_ack_blocks &&
+					    q->asoc->peer.primary_path->cacc.
+					    changeover_active)
+						transport->cacc.cacc_saw_newack
+							= 1;
 				}
 
 				list_add_tail(&tchunk->transmitted_list,
@@ -1524,8 +1466,8 @@
 			 * receiver's advertised window is zero, and there is
 			 * only one data chunk in flight to the receiver.
 			 */
-			if ((0 == q->asoc->peer.rwnd) &&
-			    (!list_empty(&tlist)) &&
+			if (!q->asoc->peer.rwnd &&
+			    !list_empty(&tlist) &&
 			    (sack_ctsn+2 == q->asoc->next_tsn)) {
 				SCTP_DEBUG_PRINTK("%s: SACK received for zero "
 						  "window probe: %u\n",
@@ -1553,12 +1495,26 @@
 		}
 	}
 
-	/* Reconstruct the transmitted list with chunks that are not yet
-	 * acked by the Cumulative TSN Ack.
-	 */
-        while (NULL != (lchunk = sctp_list_dequeue(&tlist))) {
-		tchunk = list_entry(lchunk, sctp_chunk_t, transmitted_list);
-		tsn = ntohl(tchunk->subh.data_hdr->tsn);
+	list_splice(&tlist, transmitted_queue);
+}
+
+/* Mark chunks as missing and consequently may get retransmitted. */
+static void sctp_mark_missing(struct sctp_outq *q,
+			      struct list_head *transmitted_queue,
+			      struct sctp_transport *transport,
+			      __u32 highest_new_tsn_in_sack,
+			      int count_of_newacks)
+{
+	struct sctp_chunk *chunk;
+	struct list_head *pos;
+	__u32 tsn;
+	char do_fast_retransmit = 0;
+	struct sctp_transport *primary = q->asoc->peer.primary_path;
+
+	list_for_each(pos, transmitted_queue) {
+
+		chunk = list_entry(pos, struct sctp_chunk, transmitted_list);
+		tsn = ntohl(chunk->subh.data_hdr->tsn);
 
 		/* RFC 2960 7.2.4, sctpimpguide-05 2.8.2 M3) Examine all
 		 * 'Unacknowledged TSN's', if the TSN number of an
@@ -1566,26 +1522,35 @@
 		 * value, increment the 'TSN.Missing.Report' count on that
 		 * chunk if it has NOT been fast retransmitted or marked for
 		 * fast retransmit already.
-		 *
+		 */
+		if (!chunk->fast_retransmit &&
+		    !chunk->tsn_gap_acked &&
+		    TSN_lt(tsn, highest_new_tsn_in_sack)) {
+
+			/* SFR-CACC may require us to skip marking
+			 * this chunk as missing.
+			 */
+			if (!transport || !sctp_cacc_skip(primary, transport,
+					    count_of_newacks, tsn)) {
+				chunk->tsn_missing_report++;
+
+				SCTP_DEBUG_PRINTK(
+					"%s: TSN 0x%x missing counter: %d\n",
+					__FUNCTION__, tsn,
+					chunk->tsn_missing_report);
+			}
+		}
+		/*
 		 * M4) If any DATA chunk is found to have a
 		 * 'TSN.Missing.Report'
 		 * value larger than or equal to 4, mark that chunk for
 		 * retransmission and start the fast retransmit procedure.
 		 */
-		if ((!tchunk->fast_retransmit) &&
-		    (!tchunk->tsn_gap_acked) &&
-		    (TSN_lt(tsn, highest_new_tsn_in_sack))) {
-			tchunk->tsn_missing_report++;
-			SCTP_DEBUG_PRINTK("%s: TSN 0x%x missing counter: %d\n",
-					  __FUNCTION__, tsn,
-					  tchunk->tsn_missing_report);
-		}
-		if (tchunk->tsn_missing_report >= 4) {
-			tchunk->fast_retransmit = 1;
+
+		if (chunk->tsn_missing_report >= 4) {
+			chunk->fast_retransmit = 1;
 			do_fast_retransmit = 1;
 		}
-
-		list_add_tail(lchunk, transmitted_queue);
 	}
 
 	if (transport) {
@@ -1601,7 +1566,7 @@
 }
 
 /* Is the given TSN acked by this packet?  */
-static int sctp_acked(sctp_sackhdr_t *sack, __u32 tsn)
+static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn)
 {
 	int i;
 	sctp_sack_variable_t *frags;
diff -Nru a/net/sctp/primitive.c b/net/sctp/primitive.c
--- a/net/sctp/primitive.c	Mon Feb 24 12:51:23 2003
+++ b/net/sctp/primitive.c	Wed Apr  9 12:24:28 2003
@@ -55,12 +55,12 @@
 
 #define DECLARE_PRIMITIVE(name) \
 /* This is called in the code as sctp_primitive_ ## name.  */ \
-int sctp_primitive_ ## name(sctp_association_t *asoc, \
+int sctp_primitive_ ## name(struct sctp_association *asoc, \
 			    void *arg) { \
 	int error = 0; \
 	sctp_event_t event_type; sctp_subtype_t subtype; \
 	sctp_state_t state; \
-	sctp_endpoint_t *ep; \
+	struct sctp_endpoint *ep; \
 	\
 	event_type = SCTP_EVENT_T_PRIMITIVE; \
 	subtype = SCTP_ST_PRIMITIVE(SCTP_PRIMITIVE_ ## name); \
diff -Nru a/net/sctp/proc.c b/net/sctp/proc.c
--- a/net/sctp/proc.c	Mon Mar  3 02:12:59 2003
+++ b/net/sctp/proc.c	Sat May 10 11:46:35 2003
@@ -102,6 +102,7 @@
 }
 
 static struct file_operations sctp_snmp_seq_fops = {
+	.owner	 = THIS_MODULE,
 	.open	 = sctp_snmp_seq_open,
 	.read	 = seq_read,
 	.llseek	 = seq_lseek,
diff -Nru a/net/sctp/protocol.c b/net/sctp/protocol.c
--- a/net/sctp/protocol.c	Fri May  2 23:41:46 2003
+++ b/net/sctp/protocol.c	Fri May 16 01:07:43 2003
@@ -56,6 +56,7 @@
 #include <net/sctp/sctp.h>
 #include <net/addrconf.h>
 #include <net/inet_common.h>
+#include <net/inet_ecn.h>
 
 /* Global data structures. */
 struct sctp_protocol sctp_proto;
@@ -203,7 +204,7 @@
 /* Copy the local addresses which are valid for 'scope' into 'bp'.  */
 int sctp_copy_local_addr_list(struct sctp_protocol *proto,
 			      struct sctp_bind_addr *bp, sctp_scope_t scope,
-			      int priority, int copy_flags)
+			      int gfp, int copy_flags)
 {
 	struct sockaddr_storage_list *addr;
 	int error = 0;
@@ -223,8 +224,8 @@
 			    (((AF_INET6 == addr->a.sa.sa_family) &&
 			      (copy_flags & SCTP_ADDR6_ALLOWED) &&
 			      (copy_flags & SCTP_ADDR6_PEERSUPP)))) {
-				error = sctp_add_bind_addr(bp, &addr->a,
-							   priority);
+				error = sctp_add_bind_addr(bp, &addr->a, 
+							   GFP_ATOMIC);
 				if (error)
 					goto end_copy;
 			}
@@ -267,11 +268,16 @@
 }
 
 /* Initialize sk->rcv_saddr from sctp_addr. */
-static void sctp_v4_to_sk(union sctp_addr *addr, struct sock *sk)
+static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
 {
 	inet_sk(sk)->rcv_saddr = addr->v4.sin_addr.s_addr;
 }
 
+/* Initialize sk->daddr from sctp_addr. */
+static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
+{
+	inet_sk(sk)->daddr = addr->v4.sin_addr.s_addr;
+}
 
 /* Initialize a sctp_addr from a dst_entry. */
 static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct dst_entry *dst,
@@ -388,7 +394,7 @@
 {
 	struct rtable *rt;
 	struct flowi fl;
-	sctp_bind_addr_t *bp;
+	struct sctp_bind_addr *bp;
 	rwlock_t *addr_lock;
 	struct sockaddr_storage_list *laddr;
 	struct list_head *pos;
@@ -471,21 +477,33 @@
 /* For v4, the source address is cached in the route entry(dst). So no need
  * to cache it separately and hence this is an empty routine.
  */
-void sctp_v4_get_saddr(sctp_association_t *asoc,
+void sctp_v4_get_saddr(struct sctp_association *asoc,
 		       struct dst_entry *dst,
 		       union sctp_addr *daddr,
 		       union sctp_addr *saddr)
 {
+	struct rtable *rt = (struct rtable *)dst;
 
+	if (rt) {
+		saddr->v4.sin_family = AF_INET;
+		saddr->v4.sin_port = asoc->base.bind_addr.port;  
+		saddr->v4.sin_addr.s_addr = rt->rt_src; 
+	}
 }
 
 /* What interface did this skb arrive on? */
-int sctp_v4_skb_iif(const struct sk_buff *skb) 
+static int sctp_v4_skb_iif(const struct sk_buff *skb)
+{
+     	return ((struct rtable *)skb->dst)->rt_iif;
+}
+
+/* Was this packet marked by Explicit Congestion Notification? */
+static int sctp_v4_is_ce(const struct sk_buff *skb)
 {
-     	return ((struct rtable *)skb->dst)->rt_iif;  
+	return INET_ECN_is_ce(skb->nh.iph->tos);
 }
 
-/* Create and initialize a new sk for the socket returned by accept(). */ 
+/* Create and initialize a new sk for the socket returned by accept(). */
 struct sock *sctp_v4_create_accept_sk(struct sock *sk,
 				      struct sctp_association *asoc)
 {
@@ -506,23 +524,28 @@
 	newsk->prot = sk->prot;
 	newsk->no_check = sk->no_check;
 	newsk->reuse = sk->reuse;
+	newsk->shutdown = sk->shutdown;
 
 	newsk->destruct = inet_sock_destruct;
 	newsk->zapped = 0;
 	newsk->family = PF_INET;
 	newsk->protocol = IPPROTO_SCTP;
 	newsk->backlog_rcv = sk->prot->backlog_rcv;
-	
+
 	newinet = inet_sk(newsk);
+
+	/* Initialize sk's sport, dport, rcv_saddr and daddr for
+	 * getsockname() and getpeername()
+	 */
 	newinet->sport = inet->sport;
 	newinet->saddr = inet->saddr;
-	newinet->rcv_saddr = inet->saddr;
-	newinet->dport = asoc->peer.port;
+	newinet->rcv_saddr = inet->rcv_saddr;
+	newinet->dport = htons(asoc->peer.port);
 	newinet->daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr;
 	newinet->pmtudisc = inet->pmtudisc;
       	newinet->id = 0;
-	
-	newinet->ttl = sysctl_ip_default_ttl;
+
+	newinet->uc_ttl = -1;
 	newinet->mc_loop = 1;
 	newinet->mc_ttl = 1;
 	newinet->mc_index = 0;
@@ -568,7 +591,7 @@
 
 	if (sctp_get_pf_specific(PF_INET6))
 		family = PF_INET6;
-	else 
+	else
 		family = PF_INET;
 
 	err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP,
@@ -579,7 +602,7 @@
 		return err;
 	}
 	sctp_ctl_socket->sk->allocation = GFP_ATOMIC;
-	inet_sk(sctp_ctl_socket->sk)->ttl = MAXTTL;
+	inet_sk(sctp_ctl_socket->sk)->uc_ttl = -1;
 
 	return 0;
 }
@@ -695,7 +718,7 @@
 	return sctp_v4_available(addr);
 }
 
-/* Verify that sockaddr looks sendable.  Common verification has already 
+/* Verify that sockaddr looks sendable.  Common verification has already
  * been taken care of.
  */
 static int sctp_inet_send_verify(struct sctp_opt *opt, union sctp_addr *addr)
@@ -706,7 +729,7 @@
 /* Fill in Supported Address Type information for INIT and INIT-ACK
  * chunks.  Returns number of addresses supported.
  */
-static int sctp_inet_supported_addrs(const struct sctp_opt *opt, 
+static int sctp_inet_supported_addrs(const struct sctp_opt *opt,
 				     __u16 *types)
 {
 	types[0] = SCTP_PARAM_IPV4_ADDRESS;
@@ -805,7 +828,8 @@
 	.copy_addrlist  = sctp_v4_copy_addrlist,
 	.from_skb       = sctp_v4_from_skb,
 	.from_sk        = sctp_v4_from_sk,
-	.to_sk          = sctp_v4_to_sk,
+	.to_sk_saddr    = sctp_v4_to_sk_saddr,
+	.to_sk_daddr    = sctp_v4_to_sk_daddr,
 	.dst_saddr      = sctp_v4_dst_saddr,
 	.cmp_addr       = sctp_v4_cmp_addr,
 	.addr_valid     = sctp_v4_addr_valid,
@@ -814,6 +838,7 @@
 	.available      = sctp_v4_available,
 	.scope          = sctp_v4_scope,
 	.skb_iif        = sctp_v4_skb_iif,
+	.is_ce          = sctp_v4_is_ce,
 	.net_header_len = sizeof(struct iphdr),
 	.sockaddr_len   = sizeof(struct sockaddr_in),
 	.sa_family      = AF_INET,
diff -Nru a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
--- a/net/sctp/sm_make_chunk.c	Tue Apr 29 02:29:48 2003
+++ b/net/sctp/sm_make_chunk.c	Tue May  6 16:40:03 2003
@@ -59,6 +59,8 @@
 #include <linux/ipv6.h>
 #include <linux/net.h>
 #include <linux/inet.h>
+#include <asm/scatterlist.h>
+#include <linux/crypto.h>
 #include <net/sock.h>
 
 #include <linux/skbuff.h>
@@ -95,7 +97,7 @@
  * provided chunk, as most cause codes will be embedded inside an
  * abort chunk.
  */
-void  sctp_init_cause(sctp_chunk_t *chunk, __u16 cause_code,
+void  sctp_init_cause(struct sctp_chunk *chunk, __u16 cause_code,
 		      const void *payload, size_t paylen)
 {
 	sctp_errhdr_t err;
@@ -156,14 +158,14 @@
  * Host Name Address (Note 3)          Optional    11
  * Supported Address Types (Note 4)    Optional    12
  */
-sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc,
-			     const sctp_bind_addr_t *bp,
+struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
+			     const struct sctp_bind_addr *bp,
 			     int gfp, int vparam_len)
 {
 	sctp_inithdr_t init;
 	union sctp_params addrs;
 	size_t chunksize;
-	sctp_chunk_t *retval = NULL;
+	struct sctp_chunk *retval = NULL;
 	int num_types, addrs_len = 0;
 	struct sctp_opt *sp;
 	sctp_supported_addrs_param_t sat;
@@ -175,12 +177,9 @@
 	 * can be IPv4 and/or IPv6 in any combination.
 	 */
 	retval = NULL;
-	addrs.v = NULL;
 
-	/* Convert the provided bind address list to raw format */
+	/* Convert the provided bind address list to raw format. */
 	addrs = sctp_bind_addrs_to_raw(bp, &addrs_len, gfp);
-	if (!addrs.v)
-		goto nodata;
 
 	init.init_tag		   = htonl(asoc->c.my_vtag);
 	init.a_rwnd		   = htonl(asoc->rwnd);
@@ -236,12 +235,12 @@
 	return retval;
 }
 
-sctp_chunk_t *sctp_make_init_ack(const sctp_association_t *asoc,
-				 const sctp_chunk_t *chunk,
+struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
+				 const struct sctp_chunk *chunk,
 				 int gfp, int unkparam_len)
 {
 	sctp_inithdr_t initack;
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	union sctp_params addrs;
 	int addrs_len;
 	sctp_cookie_param_t *cookie;
@@ -250,9 +249,8 @@
 
 	retval = NULL;
 
+	/* Note: there may be no addresses to embed. */
 	addrs = sctp_bind_addrs_to_raw(&asoc->base.bind_addr, &addrs_len, gfp);
-	if (!addrs.v)
-		goto nomem_rawaddr;
 
 	initack.init_tag	        = htonl(asoc->c.my_vtag);
 	initack.a_rwnd			= htonl(asoc->rwnd);
@@ -294,7 +292,7 @@
 		sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param);
 
 	/* We need to remove the const qualifier at this point.  */
-	retval->asoc = (sctp_association_t *) asoc;
+	retval->asoc = (struct sctp_association *) asoc;
 
 	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
 	 *
@@ -311,8 +309,8 @@
 nomem_chunk:
 	kfree(cookie);
 nomem_cookie:
-	kfree(addrs.v);
-nomem_rawaddr:
+	if (addrs.v)
+		kfree(addrs.v);
 	return retval;
 }
 
@@ -350,10 +348,10 @@
  *   An implementation SHOULD make the cookie as small as possible
  *   to insure interoperability.
  */
-sctp_chunk_t *sctp_make_cookie_echo(const sctp_association_t *asoc,
-				    const sctp_chunk_t *chunk)
+struct sctp_chunk *sctp_make_cookie_echo(const struct sctp_association *asoc,
+				    const struct sctp_chunk *chunk)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	void *cookie;
 	int cookie_len;
 
@@ -401,10 +399,10 @@
  *
  *   Set to zero on transmit and ignored on receipt.
  */
-sctp_chunk_t *sctp_make_cookie_ack(const sctp_association_t *asoc,
-				   const sctp_chunk_t *chunk)
+struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *asoc,
+				   const struct sctp_chunk *chunk)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 
 	retval = sctp_make_chunk(asoc, SCTP_CID_COOKIE_ACK, 0, 0);
 
@@ -446,11 +444,11 @@
  *
  *     Note: The CWR is considered a Control chunk.
  */
-sctp_chunk_t *sctp_make_cwr(const sctp_association_t *asoc,
+struct sctp_chunk *sctp_make_cwr(const struct sctp_association *asoc,
 			    const __u32 lowest_tsn,
-			    const sctp_chunk_t *chunk)
+			    const struct sctp_chunk *chunk)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	sctp_cwrhdr_t cwr;
 
 	cwr.lowest_tsn = htonl(lowest_tsn);
@@ -481,10 +479,10 @@
 }
 
 /* Make an ECNE chunk.  This is a congestion experienced report.  */
-sctp_chunk_t *sctp_make_ecne(const sctp_association_t *asoc,
+struct sctp_chunk *sctp_make_ecne(const struct sctp_association *asoc,
 			     const __u32 lowest_tsn)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	sctp_ecnehdr_t ecne;
 
 	ecne.lowest_tsn = htonl(lowest_tsn);
@@ -502,25 +500,27 @@
 /* Make a DATA chunk for the given association from the provided
  * parameters.  However, do not populate the data payload.
  */
-sctp_chunk_t *sctp_make_datafrag_empty(sctp_association_t *asoc,
+struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
 				       const struct sctp_sndrcvinfo *sinfo,
 				       int data_len, __u8 flags, __u16 ssn)
 {
-	sctp_chunk_t *retval;
-	sctp_datahdr_t dp;
+	struct sctp_chunk *retval;
+	struct sctp_datahdr dp;
 	int chunk_len;
 
 	/* We assign the TSN as LATE as possible, not here when
 	 * creating the chunk.
 	 */
-	dp.tsn= 1000000;       /* This marker is a debugging aid. */
+	dp.tsn = 0;
 	dp.stream = htons(sinfo->sinfo_stream);
 	dp.ppid   = htonl(sinfo->sinfo_ppid);
-	dp.ssn    = htons(ssn);
 
 	/* Set the flags for an unordered send.  */
-	if (sinfo->sinfo_flags & MSG_UNORDERED)
+	if (sinfo->sinfo_flags & MSG_UNORDERED) {
 		flags |= SCTP_DATA_UNORDERED;
+		dp.ssn = 0;
+	} else
+		dp.ssn = htons(ssn);
 
 	chunk_len = sizeof(dp) + data_len;
 	retval = sctp_make_chunk(asoc, SCTP_CID_DATA, flags, chunk_len);
@@ -537,12 +537,12 @@
 /* Make a DATA chunk for the given association.  Populate the data
  * payload.
  */
-sctp_chunk_t *sctp_make_datafrag(sctp_association_t *asoc,
+struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc,
 				 const struct sctp_sndrcvinfo *sinfo,
 				 int data_len, const __u8 *data,
 				 __u8 flags, __u16 ssn)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 
 	retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn);
 	if (retval)
@@ -554,11 +554,11 @@
 /* Make a DATA chunk for the given association to ride on stream id
  * 'stream', with a payload id of 'payload', and a body of 'data'.
  */
-sctp_chunk_t *sctp_make_data(sctp_association_t *asoc,
+struct sctp_chunk *sctp_make_data(struct sctp_association *asoc,
 			     const struct sctp_sndrcvinfo *sinfo,
 			     int data_len, const __u8 *data)
 {
-	sctp_chunk_t *retval = NULL;
+	struct sctp_chunk *retval = NULL;
 
 	retval = sctp_make_data_empty(asoc, sinfo, data_len);
 	if (retval)
@@ -571,7 +571,7 @@
  * hold 'data_len' octets of data.  We use this version when we need
  * to build the message AFTER allocating memory.
  */
-sctp_chunk_t *sctp_make_data_empty(sctp_association_t *asoc,
+struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc,
 				   const struct sctp_sndrcvinfo *sinfo,
 				   int data_len)
 {
@@ -584,9 +584,9 @@
  * association.  This reports on which TSN's we've seen to date,
  * including duplicates and gaps.
  */
-sctp_chunk_t *sctp_make_sack(const sctp_association_t *asoc)
+struct sctp_chunk *sctp_make_sack(const struct sctp_association *asoc)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	sctp_sackhdr_t sack;
 	sctp_gap_ack_block_t gab;
 	int length;
@@ -599,11 +599,13 @@
 	SCTP_DEBUG_PRINTK("sackCTSNAck sent is 0x%x.\n", ctsn);
 
 	/* Count the number of Gap Ack Blocks.  */
-	sctp_tsnmap_iter_init(map, &iter);
-	for (num_gabs = 0;
-	     sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end);
-	     num_gabs++) {
-		/* Do nothing. */
+	num_gabs = 0;
+
+	if (sctp_tsnmap_has_gap(map)) {
+		sctp_tsnmap_iter_init(map, &iter);
+		while (sctp_tsnmap_next_gap_ack(map, &iter,
+						&gab.start, &gab.end))
+			num_gabs++;
 	}
 
 	num_dup_tsns = sctp_tsnmap_num_dups(map);
@@ -659,11 +661,15 @@
 		sctp_addto_chunk(retval, sizeof(sack), &sack);
 
 	/* Put the Gap Ack Blocks into the chunk.  */
-	sctp_tsnmap_iter_init(map, &iter);
-	while(sctp_tsnmap_next_gap_ack(map, &iter, &gab.start, &gab.end)) {
-		gab.start = htons(gab.start);
-		gab.end = htons(gab.end);
-		sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t), &gab);
+	if (num_gabs) {
+		sctp_tsnmap_iter_init(map, &iter);
+		while(sctp_tsnmap_next_gap_ack(map, &iter,
+					       &gab.start, &gab.end)) {
+			gab.start = htons(gab.start);
+			gab.end = htons(gab.end);
+			sctp_addto_chunk(retval, sizeof(sctp_gap_ack_block_t),
+					 &gab);
+		}
 	}
 
 	/* Register the duplicates.  */
@@ -675,9 +681,9 @@
 }
 
 /* Make a SHUTDOWN chunk. */
-sctp_chunk_t *sctp_make_shutdown(const sctp_association_t *asoc)
+struct sctp_chunk *sctp_make_shutdown(const struct sctp_association *asoc)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	sctp_shutdownhdr_t shut;
 	__u32 ctsn;
 
@@ -695,10 +701,10 @@
 	return retval;
 }
 
-sctp_chunk_t *sctp_make_shutdown_ack(const sctp_association_t *asoc,
-				     const sctp_chunk_t *chunk)
+struct sctp_chunk *sctp_make_shutdown_ack(const struct sctp_association *asoc,
+				     const struct sctp_chunk *chunk)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 
 	retval = sctp_make_chunk(asoc, SCTP_CID_SHUTDOWN_ACK, 0, 0);
 
@@ -717,10 +723,11 @@
 	return retval;
 }
 
-sctp_chunk_t *sctp_make_shutdown_complete(const sctp_association_t *asoc,
-					  const sctp_chunk_t *chunk)
+struct sctp_chunk *sctp_make_shutdown_complete(
+	const struct sctp_association *asoc,
+	const struct sctp_chunk *chunk)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	__u8 flags = 0;
 
 	/* Maybe set the T-bit if we have no association. */
@@ -747,11 +754,11 @@
 /* Create an ABORT.  Note that we set the T bit if we have no
  * association.
  */
-sctp_chunk_t *sctp_make_abort(const sctp_association_t *asoc,
-			      const sctp_chunk_t *chunk,
+struct sctp_chunk *sctp_make_abort(const struct sctp_association *asoc,
+			      const struct sctp_chunk *chunk,
 			      const size_t hint)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	__u8 flags = 0;
 
 	/* Maybe set the T-bit if we have no association.  */
@@ -775,10 +782,11 @@
 }
 
 /* Helper to create ABORT with a NO_USER_DATA error.  */
-sctp_chunk_t *sctp_make_abort_no_data(const sctp_association_t *asoc,
-				      const sctp_chunk_t *chunk, __u32 tsn)
+struct sctp_chunk *sctp_make_abort_no_data(
+	const struct sctp_association *asoc,
+	const struct sctp_chunk *chunk, __u32 tsn)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	__u32 payload;
 
 	retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t)
@@ -809,17 +817,22 @@
 }
 
 /* Helper to create ABORT with a SCTP_ERROR_USER_ABORT error.  */
-sctp_chunk_t *sctp_make_abort_user(const sctp_association_t *asoc,
-				   const sctp_chunk_t *chunk,
+struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc,
+				   const struct sctp_chunk *chunk,
 				   const struct msghdr *msg)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	void *payload = NULL, *payoff;
-	size_t paylen;
-	struct iovec *iov = msg->msg_iov;
-	int iovlen = msg->msg_iovlen;
+	size_t paylen = 0;
+	struct iovec *iov = NULL;
+	int iovlen = 0;
+
+	if (msg) {
+		iov = msg->msg_iov;
+		iovlen = msg->msg_iovlen;
+		paylen = get_user_iov_size(iov, iovlen);
+	}
 
-	paylen = get_user_iov_size(iov, iovlen);
 	retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen);
 	if (!retval)
 		goto err_chunk;
@@ -832,7 +845,7 @@
 		payoff = payload;
 
 		for (; iovlen > 0; --iovlen) {
-			if (copy_from_user(payoff, iov->iov_base, iov->iov_len))
+			if (copy_from_user(payoff, iov->iov_base,iov->iov_len))
 				goto err_copy;
 			payoff += iov->iov_len;
 			iov++;
@@ -849,18 +862,18 @@
 err_copy:
 	kfree(payload);
 err_payload:
-	sctp_free_chunk(retval);
+	sctp_chunk_free(retval);
 	retval = NULL;
 err_chunk:
 	return retval;
 }
 
 /* Make a HEARTBEAT chunk.  */
-sctp_chunk_t *sctp_make_heartbeat(const sctp_association_t *asoc,
+struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
 				  const struct sctp_transport *transport,
 				  const void *payload, const size_t paylen)
 {
-	sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT,
+	struct sctp_chunk *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT,
 					       0, paylen);
 
 	if (!retval)
@@ -876,15 +889,16 @@
 	return retval;
 }
 
-sctp_chunk_t *sctp_make_heartbeat_ack(const sctp_association_t *asoc,
-				      const sctp_chunk_t *chunk,
+struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
+				      const struct sctp_chunk *chunk,
 				      const void *payload, const size_t paylen)
 {
-	sctp_chunk_t *retval = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK,
-					       0, paylen);
+	struct sctp_chunk *retval;
 
+	retval  = sctp_make_chunk(asoc, SCTP_CID_HEARTBEAT_ACK, 0, paylen);
 	if (!retval)
 		goto nodata;
+
 	retval->subh.hbs_hdr = sctp_addto_chunk(retval, paylen, payload);
 
 	/* RFC 2960 6.4 Multi-homed SCTP Endpoints
@@ -906,11 +920,12 @@
 /* Create an Operation Error chunk with the specified space reserved.
  * This routine can be used for containing multiple causes in the chunk.
  */
-sctp_chunk_t *sctp_make_op_error_space(const sctp_association_t *asoc,
-				       const sctp_chunk_t *chunk,
-				       size_t size)
+struct sctp_chunk *sctp_make_op_error_space(
+	const struct sctp_association *asoc,
+	const struct sctp_chunk *chunk,
+	size_t size)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 
 	retval = sctp_make_chunk(asoc, SCTP_CID_ERROR, 0,
 				 sizeof(sctp_errhdr_t) + size);
@@ -933,13 +948,14 @@
 }
 
 /* Create an Operation Error chunk.  */
-sctp_chunk_t *sctp_make_op_error(const sctp_association_t *asoc,
-				 const sctp_chunk_t *chunk,
+struct sctp_chunk *sctp_make_op_error(const struct sctp_association *asoc,
+				 const struct sctp_chunk *chunk,
 				 __u16 cause_code, const void *payload,
 				 size_t paylen)
 {
-	sctp_chunk_t *retval = sctp_make_op_error_space(asoc, chunk, paylen);
+	struct sctp_chunk *retval;
 
+	retval = sctp_make_op_error_space(asoc, chunk, paylen);
 	if (!retval)
 		goto nodata;
 
@@ -956,26 +972,27 @@
 /* Turn an skb into a chunk.
  * FIXME: Eventually move the structure directly inside the skb->cb[].
  */
-sctp_chunk_t *sctp_chunkify(struct sk_buff *skb, const sctp_association_t *asoc,
+struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
+			    const struct sctp_association *asoc,
 			    struct sock *sk)
 {
-	sctp_chunk_t *retval = t_new(sctp_chunk_t, GFP_ATOMIC);
+	struct sctp_chunk *retval = t_new(struct sctp_chunk, GFP_ATOMIC);
 
 	if (!retval)
 		goto nodata;
-	memset(retval, 0, sizeof(sctp_chunk_t));
+	memset(retval, 0, sizeof(struct sctp_chunk));
 
 	if (!sk) {
 		SCTP_DEBUG_PRINTK("chunkifying skb %p w/o an sk\n", skb);
 	}
 
 	retval->skb		= skb;
-	retval->asoc		= (sctp_association_t *) asoc;
-	retval->num_times_sent	= 0;
+	retval->asoc		= (struct sctp_association *)asoc;
+	retval->resent  	= 0;
 	retval->has_tsn		= 0;
 	retval->has_ssn         = 0;
 	retval->rtt_in_progress	= 0;
-	retval->sent_at	= jiffies;
+	retval->sent_at		= 0;
 	retval->singleton	= 1;
 	retval->end_of_packet	= 0;
 	retval->ecn_ce_done	= 0;
@@ -991,17 +1008,24 @@
 	retval->tsn_gap_acked = 0;
 	retval->fast_retransmit = 0;
 
+	/* If this is a fragmented message, track all fragments
+	 * of the message (for SEND_FAILED).
+	 */
+	retval->msg = NULL;
+
 	/* Polish the bead hole.  */
 	INIT_LIST_HEAD(&retval->transmitted_list);
 	INIT_LIST_HEAD(&retval->frag_list);
 	SCTP_DBG_OBJCNT_INC(chunk);
+	atomic_set(&retval->refcnt, 1);
+
 
 nodata:
 	return retval;
 }
 
 /* Set chunk->source and dest based on the IP header in chunk->skb.  */
-void sctp_init_addrs(sctp_chunk_t *chunk, union sctp_addr *src,
+void sctp_init_addrs(struct sctp_chunk *chunk, union sctp_addr *src,
 		     union sctp_addr *dest)
 {
 	memcpy(&chunk->source, src, sizeof(union sctp_addr));
@@ -1009,7 +1033,7 @@
 }
 
 /* Extract the source address from a chunk.  */
-const union sctp_addr *sctp_source(const sctp_chunk_t *chunk)
+const union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
 {
 	/* If we have a known transport, use that.  */
 	if (chunk->transport) {
@@ -1023,16 +1047,16 @@
 /* Create a new chunk, setting the type and flags headers from the
  * arguments, reserving enough space for a 'paylen' byte payload.
  */
-sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc,
+struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
 			      __u8 type, __u8 flags, int paylen)
 {
-	sctp_chunk_t *retval;
+	struct sctp_chunk *retval;
 	sctp_chunkhdr_t *chunk_hdr;
 	struct sk_buff *skb;
 	struct sock *sk;
 
 	/* No need to allocate LL here, as this is only a chunk. */
-	skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen), 
+	skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen),
 			GFP_ATOMIC);
 	if (!skb)
 		goto nodata;
@@ -1046,7 +1070,7 @@
 	sk = asoc ? asoc->base.sk : NULL;
 	retval = sctp_chunkify(skb, asoc, sk);
 	if (!retval) {
-		dev_kfree_skb(skb);
+		kfree_skb(skb);
 		goto nodata;
 	}
 
@@ -1062,12 +1086,10 @@
 	return NULL;
 }
 
+
 /* Release the memory occupied by a chunk.  */
-void sctp_free_chunk(sctp_chunk_t *chunk)
+static void sctp_chunk_destroy(struct sctp_chunk *chunk)
 {
-	/* Make sure that we are not on any list.  */
-	skb_unlink((struct sk_buff *) chunk);
-	list_del(&chunk->transmitted_list);
 
 	/* Free the chunk skb data and the SCTP_chunk stub itself. */
 	dev_kfree_skb(chunk->skb);
@@ -1076,11 +1098,37 @@
 	SCTP_DBG_OBJCNT_DEC(chunk);
 }
 
+/* Possibly, free the chunk.  */
+void sctp_chunk_free(struct sctp_chunk *chunk)
+{
+	/* Make sure that we are not on any list.  */
+	skb_unlink((struct sk_buff *) chunk);
+	list_del(&chunk->transmitted_list);
+
+	/* Release our reference on the message tracker. */
+	if (chunk->msg)
+		sctp_datamsg_put(chunk->msg);
+
+	sctp_chunk_put(chunk);
+}
+
+/* Grab a reference to the chunk. */
+void sctp_chunk_hold(struct sctp_chunk *ch)
+{
+	atomic_inc(&ch->refcnt);
+}
+
+/* Release a reference to the chunk. */
+void sctp_chunk_put(struct sctp_chunk *ch)
+{
+	if (atomic_dec_and_test(&ch->refcnt))
+		sctp_chunk_destroy(ch);
+}
 
 /* Append bytes to the end of a chunk.  Will panic if chunk is not big
  * enough.
  */
-void *sctp_addto_chunk(sctp_chunk_t *chunk, int len, const void *data)
+void *sctp_addto_chunk(struct sctp_chunk *chunk, int len, const void *data)
 {
 	void *target;
 	void *padding;
@@ -1104,8 +1152,8 @@
  * chunk is not big enough.
  * Returns a kernel err value.
  */
-static int sctp_user_addto_chunk(sctp_chunk_t *chunk, int off, int len,
-				 struct iovec *data)
+int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
+			  struct iovec *data)
 {
 	__u8 *target;
 	int err = 0;
@@ -1126,132 +1174,10 @@
 	return err;
 }
 
-/* A data chunk can have a maximum payload of (2^16 - 20).  Break
- * down any such message into smaller chunks.  Opportunistically, fragment
- * the chunks down to the current MTU constraints.  We may get refragmented
- * later if the PMTU changes, but it is _much better_ to fragment immediately
- * with a reasonable guess than always doing our fragmentation on the
- * soft-interrupt.
- */
-
-
-int sctp_datachunks_from_user(sctp_association_t *asoc,
-			      const struct sctp_sndrcvinfo *sinfo,
-			      struct msghdr *msg, int msg_len,
-			      struct sk_buff_head *chunks)
-{
-	int max, whole, i, offset, over, err;
-	int len, first_len;
-	sctp_chunk_t *chunk;
-	__u8 frag;
-
-	/* What is a reasonable fragmentation point right now? */
-	max = asoc->pmtu;
-	if (max < SCTP_MIN_PMTU)
-		max = SCTP_MIN_PMTU;
-	max -= SCTP_IP_OVERHEAD;
-
-	/* Make sure not beyond maximum chunk size. */
-	if (max > SCTP_MAX_CHUNK_LEN)
-		max = SCTP_MAX_CHUNK_LEN;
-
-	/* Subtract out the overhead of a data chunk header. */
-	max -= sizeof(struct sctp_data_chunk);
-
-	whole = 0;
-	first_len = max;
-
-	/* Encourage Cookie-ECHO bundling. */
-	if (asoc->state < SCTP_STATE_COOKIE_ECHOED) {
-		whole = msg_len / (max - SCTP_ARBITRARY_COOKIE_ECHO_LEN);
-
-		/* Account for the DATA to be bundled with the COOKIE-ECHO. */
-		if (whole) {
-			first_len = max - SCTP_ARBITRARY_COOKIE_ECHO_LEN;
-			msg_len -= first_len;
-			whole = 1;
-		}
-	}
-
-	/* How many full sized?  How many bytes leftover? */
-	whole += msg_len / max;
-	over = msg_len % max;
-	offset = 0;
-
-	if (whole && over)
-		SCTP_INC_STATS_USER(SctpFragUsrMsgs);
-
-	/* Create chunks for all the full sized DATA chunks. */
-	for (i=0, len=first_len; i < whole; i++) {
-		frag = SCTP_DATA_MIDDLE_FRAG;
-
-		if (0 == i)
-			frag |= SCTP_DATA_FIRST_FRAG;
-
-		if ((i == (whole - 1)) && !over)
-			frag |= SCTP_DATA_LAST_FRAG;
-
-		chunk = sctp_make_datafrag_empty(asoc, sinfo, len, frag, 0);
-
-		if (!chunk)
-			goto nomem;
-		err = sctp_user_addto_chunk(chunk, offset, len, msg->msg_iov);
-		if (err < 0)
-			goto errout;
-
-		offset += len;
-
-		/* Put the chunk->skb back into the form expected by send.  */
-		__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
-			   - (__u8 *)chunk->skb->data);
-
-		__skb_queue_tail(chunks, (struct sk_buff *)chunk);
-
-		/* The first chunk, the first chunk was likely short
-		 * to allow bundling, so reset to full size.
-		 */
-		if (0 == i)
-			len = max;
-	}
-
-	/* .. now the leftover bytes. */
-	if (over) {
-		if (!whole)
-			frag = SCTP_DATA_NOT_FRAG;
-		else
-			frag = SCTP_DATA_LAST_FRAG;
-
-		chunk = sctp_make_datafrag_empty(asoc, sinfo, over, frag, 0);
-
-		if (!chunk)
-			goto nomem;
-
-		err = sctp_user_addto_chunk(chunk, offset, over, msg->msg_iov);
-
-		/* Put the chunk->skb back into the form expected by send.  */
-		__skb_pull(chunk->skb, (__u8 *)chunk->chunk_hdr
-			   - (__u8 *)chunk->skb->data);
-		if (err < 0)
-			goto errout;
-
-		__skb_queue_tail(chunks, (struct sk_buff *)chunk);
-	}
-	err = 0;
-	goto out;
-
-nomem:
-	err = -ENOMEM;
-errout:
-	while ((chunk = (sctp_chunk_t *)__skb_dequeue(chunks)))
-		sctp_free_chunk(chunk);
-out:
-	return err;
-}
-
 /* Helper function to assign a TSN if needed.  This assumes that both
  * the data_hdr and association have already been assigned.
  */
-void sctp_chunk_assign_ssn(sctp_chunk_t *chunk)
+void sctp_chunk_assign_ssn(struct sctp_chunk *chunk)
 {
 	__u16 ssn;
 	__u16 sid;
@@ -1278,7 +1204,7 @@
 /* Helper function to assign a TSN if needed.  This assumes that both
  * the data_hdr and association have already been assigned.
  */
-void sctp_chunk_assign_tsn(sctp_chunk_t *chunk)
+void sctp_chunk_assign_tsn(struct sctp_chunk *chunk)
 {
 	if (!chunk->has_tsn) {
 		/* This is the last possible instant to
@@ -1291,10 +1217,10 @@
 }
 
 /* Create a CLOSED association to use with an incoming packet.  */
-sctp_association_t *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
+struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
 					struct sctp_chunk *chunk, int gfp)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	struct sk_buff *skb;
 	sctp_scope_t scope;
 
@@ -1303,6 +1229,7 @@
 	asoc = sctp_association_new(ep, ep->base.sk, scope, gfp);
 	if (!asoc)
 		goto nodata;
+	asoc->temp = 1;
 	skb = chunk->skb;
 	/* Create an entry for the source address of the packet.  */
 	/* FIXME: Use the af specific helpers. */
@@ -1339,15 +1266,18 @@
 /* Build a cookie representing asoc.
  * This INCLUDES the param header needed to put the cookie in the INIT ACK.
  */
-sctp_cookie_param_t *sctp_pack_cookie(const sctp_endpoint_t *ep,
-				      const sctp_association_t *asoc,
-				      const sctp_chunk_t *init_chunk,
+sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
+				      const struct sctp_association *asoc,
+				      const struct sctp_chunk *init_chunk,
 				      int *cookie_len,
 				      const __u8 *raw_addrs, int addrs_len)
 {
 	sctp_cookie_param_t *retval;
 	sctp_signed_cookie_t *cookie;
+	struct scatterlist sg;
 	int headersize, bodysize;
+	unsigned int keylen;
+	char *key;
 
 	headersize = sizeof(sctp_paramhdr_t) + SCTP_SECRET_SIZE;
 	bodysize = sizeof(sctp_cookie_t)
@@ -1361,8 +1291,8 @@
 			- (bodysize % SCTP_COOKIE_MULTIPLE);
 	*cookie_len = headersize + bodysize;
 
-	retval = (sctp_cookie_param_t *)
-		kmalloc(*cookie_len, GFP_ATOMIC);
+	retval = (sctp_cookie_param_t *)kmalloc(*cookie_len, GFP_ATOMIC);
+
 	if (!retval) {
 		*cookie_len = 0;
 		goto nodata;
@@ -1393,30 +1323,39 @@
 
 	/* Copy the raw local address list of the association. */
 	memcpy((__u8 *)&cookie->c.peer_init[0] +
-	       ntohs(init_chunk->chunk_hdr->length), raw_addrs,
-	       addrs_len);
+	       ntohs(init_chunk->chunk_hdr->length), raw_addrs, addrs_len);
 
-	/* Sign the message.  */
-	sctp_hash_digest(ep->secret_key[ep->current_key], SCTP_SECRET_SIZE,
-			 (__u8 *) &cookie->c, bodysize, cookie->signature);
+  	if (sctp_sk(ep->base.sk)->hmac) {
+		/* Sign the message.  */
+		sg.page = virt_to_page(&cookie->c);
+		sg.offset = (unsigned long)(&cookie->c) % PAGE_SIZE;
+		sg.length = bodysize;
+		keylen = SCTP_SECRET_SIZE;
+		key = (char *)ep->secret_key[ep->current_key];
+
+		sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
+				 &sg, 1, cookie->signature);
+	}
 
 nodata:
 	return retval;
 }
 
 /* Unpack the cookie from COOKIE ECHO chunk, recreating the association.  */
-sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *ep,
-				       const sctp_association_t *asoc,
-				       sctp_chunk_t *chunk, int gfp,
-				       int *error, sctp_chunk_t **err_chk_p)
+struct sctp_association *sctp_unpack_cookie(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	struct sctp_chunk *chunk, int gfp,
+	int *error, struct sctp_chunk **errp)
 {
-	sctp_association_t *retval = NULL;
+	struct sctp_association *retval = NULL;
 	sctp_signed_cookie_t *cookie;
 	sctp_cookie_t *bear_cookie;
-	int headersize, bodysize;
-	int fixed_size;
-	__u8 digest_buf[SCTP_SIGNATURE_SIZE];
-	int secret;
+	int headersize, bodysize, fixed_size;
+	__u8 digest[SCTP_SIGNATURE_SIZE];
+	struct scatterlist sg;
+	unsigned int keylen;
+	char *key;
 	sctp_scope_t scope;
 	struct sk_buff *skb = chunk->skb;
 
@@ -1440,23 +1379,35 @@
 	cookie = chunk->subh.cookie_hdr;
 	bear_cookie = &cookie->c;
 
+	if (!sctp_sk(ep->base.sk)->hmac)
+		goto no_hmac;
+
 	/* Check the signature.  */
-	secret = ep->current_key;
-	sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE,
-			 (__u8 *) bear_cookie, bodysize,
-			 digest_buf);
-	if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) {
+	keylen = SCTP_SECRET_SIZE;
+	sg.page = virt_to_page(bear_cookie);
+	sg.offset = (unsigned long)(bear_cookie) % PAGE_SIZE;
+	sg.length = bodysize;
+	key = (char *)ep->secret_key[ep->current_key];
+
+	memset(digest, 0x00, sizeof(digest));
+	sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen, &sg,
+			 1, digest);
+
+	if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
 		/* Try the previous key. */
-		secret = ep->last_key;
-		sctp_hash_digest(ep->secret_key[secret], SCTP_SECRET_SIZE,
-				 (__u8 *) bear_cookie, bodysize, digest_buf);
-		if (memcmp(digest_buf, cookie->signature, SCTP_SIGNATURE_SIZE)) {
+		key = (char *)ep->secret_key[ep->last_key];
+		memset(digest, 0x00, sizeof(digest));
+		sctp_crypto_hmac(sctp_sk(ep->base.sk)->hmac, key, &keylen,
+				 &sg, 1, digest);
+
+		if (memcmp(digest, cookie->signature, SCTP_SIGNATURE_SIZE)) {
 			/* Yikes!  Still bad signature! */
 			*error = -SCTP_IERROR_BAD_SIG;
 			goto fail;
 		}
 	}
 
+no_hmac:
 	/* Check to see if the cookie is stale.  If there is already
 	 * an association, there is no need to check cookie's expiration
 	 * for init collision case of lost COOKIE ACK.
@@ -1472,15 +1423,15 @@
 		 * Cookie that has expired.
 		 */
 		len = ntohs(chunk->chunk_hdr->length);
-		*err_chk_p = sctp_make_op_error_space(asoc, chunk, len);
-		if (*err_chk_p) {
+		*errp = sctp_make_op_error_space(asoc, chunk, len);
+		if (*errp) {
 			suseconds_t usecs = (skb->stamp.tv_sec -
 				bear_cookie->expiration.tv_sec) * 1000000L +
 				skb->stamp.tv_usec -
 				bear_cookie->expiration.tv_usec;
 
 			usecs = htonl(usecs);
-			sctp_init_cause(*err_chk_p, SCTP_ERROR_STALE_COOKIE,
+			sctp_init_cause(*errp, SCTP_ERROR_STALE_COOKIE,
 					&usecs, sizeof(usecs));
 			*error = -SCTP_IERROR_STALE_COOKIE;
 		} else
@@ -1509,6 +1460,12 @@
 		goto fail;
 	}
 
+	/* Also, add the destination address. */
+	if (list_empty(&retval->base.bind_addr.address_list)) {
+		sctp_add_bind_addr(&retval->base.bind_addr, &chunk->dest,
+				   GFP_ATOMIC);
+	}
+
 	retval->next_tsn = retval->c.initial_tsn;
 	retval->ctsn_ack_point = retval->next_tsn - 1;
 
@@ -1541,10 +1498,10 @@
 /*
  * Report a missing mandatory parameter.
  */
-static int sctp_process_missing_param(const sctp_association_t *asoc,
+static int sctp_process_missing_param(const struct sctp_association *asoc,
 				      sctp_param_t paramtype,
-				      sctp_chunk_t *chunk,
-				      sctp_chunk_t **err_chk_p)
+				      struct sctp_chunk *chunk,
+				      struct sctp_chunk **errp)
 {
 	struct __sctp_missing report;
 	__u16 len;
@@ -1554,13 +1511,13 @@
 	/* Make an ERROR chunk, preparing enough room for
 	 * returning multiple unknown parameters.
 	 */
-	if (!*err_chk_p)
-		*err_chk_p = sctp_make_op_error_space(asoc, chunk, len);
+	if (!*errp)
+		*errp = sctp_make_op_error_space(asoc, chunk, len);
 
-	if (*err_chk_p) {
+	if (*errp) {
 		report.num_missing = htonl(1);
 		report.type = paramtype;
-		sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM,
+		sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM,
 				&report, sizeof(report));
 	}
 
@@ -1569,17 +1526,17 @@
 }
 
 /* Report an Invalid Mandatory Parameter.  */
-static int sctp_process_inv_mandatory(const sctp_association_t *asoc,
-				      sctp_chunk_t *chunk,
-				      sctp_chunk_t **err_chk_p)
+static int sctp_process_inv_mandatory(const struct sctp_association *asoc,
+				      struct sctp_chunk *chunk,
+				      struct sctp_chunk **errp)
 {
 	/* Invalid Mandatory Parameter Error has no payload. */
 
-	if (!*err_chk_p)
-		*err_chk_p = sctp_make_op_error_space(asoc, chunk, 0);
+	if (!*errp)
+		*errp = sctp_make_op_error_space(asoc, chunk, 0);
 
-	if (*err_chk_p)
-		sctp_init_cause(*err_chk_p, SCTP_ERROR_INV_PARAM, NULL, 0);
+	if (*errp)
+		sctp_init_cause(*errp, SCTP_ERROR_INV_PARAM, NULL, 0);
 
 	/* Stop processing this chunk. */
 	return 0;
@@ -1588,19 +1545,19 @@
 /* Do not attempt to handle the HOST_NAME parm.  However, do
  * send back an indicator to the peer.
  */
-static int sctp_process_hn_param(const sctp_association_t *asoc,
+static int sctp_process_hn_param(const struct sctp_association *asoc,
 				 union sctp_params param,
-				 sctp_chunk_t *chunk,
-				 sctp_chunk_t **err_chk_p)
+				 struct sctp_chunk *chunk,
+				 struct sctp_chunk **errp)
 {
 	__u16 len = ntohs(param.p->length);
 
 	/* Make an ERROR chunk. */
-	if (!*err_chk_p)
-		*err_chk_p = sctp_make_op_error_space(asoc, chunk, len);
+	if (!*errp)
+		*errp = sctp_make_op_error_space(asoc, chunk, len);
 
-	if (*err_chk_p)
-		sctp_init_cause(*err_chk_p, SCTP_ERROR_DNS_FAILED,
+	if (*errp)
+		sctp_init_cause(*errp, SCTP_ERROR_DNS_FAILED,
 				param.v, len);
 
 	/* Stop processing this chunk. */
@@ -1633,10 +1590,10 @@
  * 	0 - discard the chunk
  * 	1 - continue with the chunk
  */
-static int sctp_process_unk_param(const sctp_association_t *asoc,
+static int sctp_process_unk_param(const struct sctp_association *asoc,
 				  union sctp_params param,
-				  sctp_chunk_t *chunk,
-				  sctp_chunk_t **err_chk_p)
+				  struct sctp_chunk *chunk,
+				  struct sctp_chunk **errp)
 {
 	int retval = 1;
 
@@ -1649,12 +1606,12 @@
 		/* Make an ERROR chunk, preparing enough room for
 		 * returning multiple unknown parameters.
 		 */
-		if (NULL == *err_chk_p)
-			*err_chk_p = sctp_make_op_error_space(asoc, chunk,
+		if (NULL == *errp)
+			*errp = sctp_make_op_error_space(asoc, chunk,
 					ntohs(chunk->chunk_hdr->length));
 
-		if (*err_chk_p)
-			sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM,
+		if (*errp)
+			sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
 					param.v,
 					WORD_ROUND(ntohs(param.p->length)));
 
@@ -1665,12 +1622,12 @@
 		/* Make an ERROR chunk, preparing enough room for
 		 * returning multiple unknown parameters.
 		 */
-		if (NULL == *err_chk_p)
-			*err_chk_p = sctp_make_op_error_space(asoc, chunk,
+		if (NULL == *errp)
+			*errp = sctp_make_op_error_space(asoc, chunk,
 					ntohs(chunk->chunk_hdr->length));
 
-		if (*err_chk_p) {
-			sctp_init_cause(*err_chk_p, SCTP_ERROR_UNKNOWN_PARAM,
+		if (*errp) {
+			sctp_init_cause(*errp, SCTP_ERROR_UNKNOWN_PARAM,
 					param.v,
 					WORD_ROUND(ntohs(param.p->length)));
 		} else {
@@ -1695,11 +1652,11 @@
  * 	0 - discard the chunk
  * 	1 - continue with the chunk
  */
-static int sctp_verify_param(const sctp_association_t *asoc,
+static int sctp_verify_param(const struct sctp_association *asoc,
 			     union sctp_params param,
 			     sctp_cid_t cid,
-			     sctp_chunk_t *chunk,
-			     sctp_chunk_t **err_chunk)
+			     struct sctp_chunk *chunk,
+			     struct sctp_chunk **err_chunk)
 {
 	int retval = 1;
 
@@ -1733,11 +1690,11 @@
 }
 
 /* Verify the INIT packet before we process it.  */
-int sctp_verify_init(const sctp_association_t *asoc,
+int sctp_verify_init(const struct sctp_association *asoc,
 		     sctp_cid_t cid,
 		     sctp_init_chunk_t *peer_init,
-		     sctp_chunk_t *chunk,
-		     sctp_chunk_t **err_chk_p)
+		     struct sctp_chunk *chunk,
+		     struct sctp_chunk **errp)
 {
 	union sctp_params param;
 	int has_cookie = 0;
@@ -1746,7 +1703,7 @@
 	if ((0 == peer_init->init_hdr.num_outbound_streams) ||
 	    (0 == peer_init->init_hdr.num_inbound_streams)) {
 
-		sctp_process_inv_mandatory(asoc, chunk, err_chk_p);
+		sctp_process_inv_mandatory(asoc, chunk, errp);
 		return 0;
 	}
 
@@ -1762,9 +1719,8 @@
 	 * the state cookie for an INIT-ACK chunk.
 	 */
 	if ((SCTP_CID_INIT_ACK == cid) && !has_cookie) {
-
 		sctp_process_missing_param(asoc, SCTP_PARAM_STATE_COOKIE,
-					   chunk, err_chk_p);
+					   chunk, errp);
 		return 0;
 	}
 
@@ -1772,7 +1728,7 @@
 
 	sctp_walk_params(param, peer_init, init_hdr.params) {
 
-		if (!sctp_verify_param(asoc, param, cid, chunk, err_chk_p))
+		if (!sctp_verify_param(asoc, param, cid, chunk, errp))
 			return 0;
 
 	} /* for (loop through all parameters) */
@@ -1784,7 +1740,7 @@
  * Returns 0 on failure, else success.
  * FIXME:  This is an association method.
  */
-int sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
+int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
 		      const union sctp_addr *peer_addr,
 		      sctp_init_chunk_t *peer_init, int gfp)
 {
@@ -1923,7 +1879,7 @@
  * work we do.  In particular, we should not build transport
  * structures for the addresses.
  */
-int sctp_process_param(sctp_association_t *asoc, union sctp_params param,
+int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
 		       const union sctp_addr *peer_addr, int gfp)
 {
 	union sctp_addr addr;
@@ -2032,7 +1988,7 @@
 }
 
 /* Select a new verification tag.  */
-__u32 sctp_generate_tag(const sctp_endpoint_t *ep)
+__u32 sctp_generate_tag(const struct sctp_endpoint *ep)
 {
 	/* I believe that this random number generator complies with RFC1750.
 	 * A tag of 0 is reserved for special cases (e.g. INIT).
@@ -2047,7 +2003,7 @@
 }
 
 /* Select an initial TSN to send during startup.  */
-__u32 sctp_generate_tsn(const sctp_endpoint_t *ep)
+__u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
 {
 	__u32 retval;
 
diff -Nru a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c
--- a/net/sctp/sm_sideeffect.c	Tue Apr 29 02:29:48 2003
+++ b/net/sctp/sm_sideeffect.c	Tue May  6 16:52:03 2003
@@ -60,7 +60,8 @@
  ********************************************************************/
 
 /* A helper function for delayed processing of INET ECN CE bit. */
-static void sctp_do_ecn_ce_work(sctp_association_t *asoc, __u32 lowest_tsn)
+static void sctp_do_ecn_ce_work(struct sctp_association *asoc, 
+				__u32 lowest_tsn)
 {
 	/* Save the TSN away for comparison when we receive CWR */
 
@@ -80,11 +81,11 @@
  * This element represents the lowest TSN number in the datagram
  * that was originally marked with the CE bit.
  */
-static sctp_chunk_t *sctp_do_ecn_ecne_work(sctp_association_t *asoc,
+static struct sctp_chunk *sctp_do_ecn_ecne_work(struct sctp_association *asoc,
 					   __u32 lowest_tsn,
-					   sctp_chunk_t *chunk)
+					   struct sctp_chunk *chunk)
 {
-	sctp_chunk_t *repl;
+	struct sctp_chunk *repl;
 
 	/* Our previously transmitted packet ran into some congestion
 	 * so we should take action by reducing cwnd and ssthresh
@@ -123,7 +124,7 @@
 }
 
 /* Helper function to do delayed processing of ECN CWR chunk.  */
-static void sctp_do_ecn_cwr_work(sctp_association_t *asoc,
+static void sctp_do_ecn_cwr_work(struct sctp_association *asoc,
 				 __u32 lowest_tsn)
 {
 	/* Turn off ECNE getting auto-prepended to every outgoing
@@ -200,7 +201,7 @@
 {
 	int error;
 	struct sctp_transport *transport = (struct sctp_transport *) peer;
-	sctp_association_t *asoc = transport->asoc;
+	struct sctp_association *asoc = transport->asoc;
 
 	/* Check whether a task is in the sock.  */
 
@@ -238,7 +239,7 @@
 /* This is a sa interface for producing timeout events.  It works
  * for timeouts which use the association as their parameter.
  */
-static void sctp_generate_timeout_event(sctp_association_t *asoc,
+static void sctp_generate_timeout_event(struct sctp_association *asoc,
 					sctp_event_timeout_t timeout_type)
 {
 	int error = 0;
@@ -265,8 +266,7 @@
 	error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
 			   SCTP_ST_TIMEOUT(timeout_type),
 			   asoc->state, asoc->ep, asoc,
-			   (void *)timeout_type,
-			   GFP_ATOMIC);
+			   (void *)timeout_type, GFP_ATOMIC);
 
 	if (error)
 		asoc->base.sk->err = -error;
@@ -278,25 +278,25 @@
 
 void sctp_generate_t1_cookie_event(unsigned long data)
 {
-	sctp_association_t *asoc = (sctp_association_t *) data;
+	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE);
 }
 
 void sctp_generate_t1_init_event(unsigned long data)
 {
-	sctp_association_t *asoc = (sctp_association_t *) data;
+	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT);
 }
 
 void sctp_generate_t2_shutdown_event(unsigned long data)
 {
-	sctp_association_t *asoc = (sctp_association_t *) data;
+	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
 }
 
 void sctp_generate_t5_shutdown_guard_event(unsigned long data)
 {
-        sctp_association_t *asoc = (sctp_association_t *)data;
+        struct sctp_association *asoc = (struct sctp_association *)data;
         sctp_generate_timeout_event(asoc,
 				    SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD);
 
@@ -304,7 +304,7 @@
 
 void sctp_generate_autoclose_event(unsigned long data)
 {
-	sctp_association_t *asoc = (sctp_association_t *) data;
+	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE);
 }
 
@@ -315,7 +315,7 @@
 {
 	int error = 0;
 	struct sctp_transport *transport = (struct sctp_transport *) data;
-	sctp_association_t *asoc = transport->asoc;
+	struct sctp_association *asoc = transport->asoc;
 
 	sctp_bh_lock_sock(asoc->base.sk);
 	if (sock_owned_by_user(asoc->base.sk)) {
@@ -335,8 +335,7 @@
 
 	error = sctp_do_sm(SCTP_EVENT_T_TIMEOUT,
 			   SCTP_ST_TIMEOUT(SCTP_EVENT_TIMEOUT_HEARTBEAT),
-			   asoc->state,
-			   asoc->ep, asoc,
+			   asoc->state, asoc->ep, asoc,
 			   transport, GFP_ATOMIC);
 
          if (error)
@@ -350,7 +349,7 @@
 /* Inject a SACK Timeout event into the state machine.  */
 void sctp_generate_sack_event(unsigned long data)
 {
-	sctp_association_t *asoc = (sctp_association_t *) data;
+	struct sctp_association *asoc = (struct sctp_association *) data;
 	sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK);
 }
 
@@ -382,7 +381,7 @@
  * notification SHOULD be sent to the upper layer.
  *
  */
-static void sctp_do_8_2_transport_strike(sctp_association_t *asoc,
+static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
 					 struct sctp_transport *transport)
 {
 	/* The check for association's overall error counter exceeding the
@@ -410,7 +409,7 @@
 
 /* Worker routine to handle INIT command failure.  */
 static void sctp_cmd_init_failed(sctp_cmd_seq_t *commands,
-				 sctp_association_t *asoc,
+				 struct sctp_association *asoc,
 				 unsigned error)
 {
 	struct sctp_ulpevent *event;
@@ -483,7 +482,7 @@
 
 /* Helper function to break out starting up of heartbeat timers.  */
 static void sctp_cmd_hb_timers_start(sctp_cmd_seq_t *cmds,
-				     sctp_association_t *asoc)
+				     struct sctp_association *asoc)
 {
 	struct sctp_transport *t;
 	struct list_head *pos;
@@ -501,7 +500,7 @@
 }
 
 static void sctp_cmd_hb_timers_stop(sctp_cmd_seq_t *cmds,
-				    sctp_association_t *asoc)
+				    struct sctp_association *asoc)
 {
 	struct sctp_transport *t;
 	struct list_head *pos;
@@ -517,7 +516,7 @@
 
 /* Helper function to update the heartbeat timer. */
 static void sctp_cmd_hb_timer_update(sctp_cmd_seq_t *cmds,
-				     sctp_association_t *asoc,
+				     struct sctp_association *asoc,
 				     struct sctp_transport *t)
 {
 	/* Update the heartbeat timer.  */
@@ -527,9 +526,9 @@
 
 /* Helper function to handle the reception of an HEARTBEAT ACK.  */
 static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
-				  sctp_association_t *asoc,
+				  struct sctp_association *asoc,
 				  struct sctp_transport *t,
-				  sctp_chunk_t *chunk)
+				  struct sctp_chunk *chunk)
 {
 	sctp_sender_hb_info_t *hbinfo;
 
@@ -560,7 +559,7 @@
  * timer.
  */
 static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
-				     sctp_association_t *asoc,
+				     struct sctp_association *asoc,
 				     struct sctp_transport *t)
 {
 	sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE);
@@ -571,7 +570,7 @@
 
 /* Helper function to process the process SACK command.  */
 static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
-				 sctp_association_t *asoc,
+				 struct sctp_association *asoc,
 				 sctp_sackhdr_t *sackh)
 {
 	int err;
@@ -595,8 +594,9 @@
 /* Helper function to set the timeout value for T2-SHUTDOWN timer and to set
  * the transport for a shutdown chunk.
  */
-static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
-			      sctp_chunk_t *chunk)
+static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, 
+			      struct sctp_association *asoc,
+			      struct sctp_chunk *chunk)
 {
 	struct sctp_transport *t;
 
@@ -607,18 +607,30 @@
 }
 
 /* Helper function to change the state of an association. */
-static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
+static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, struct sctp_association *asoc,
 			       sctp_state_t state)
 {
-
 	struct sock *sk = asoc->base.sk;
-	struct sctp_opt *sp = sctp_sk(sk);
 
 	asoc->state = state;
 	asoc->state_timestamp = jiffies;
 
-	if ((SCTP_STATE_ESTABLISHED == asoc->state) ||
-	    (SCTP_STATE_CLOSED == asoc->state)) {
+	if (sctp_style(sk, TCP)) {
+		/* Change the sk->state of a TCP-style socket that has 
+		 * sucessfully completed a connect() call.
+		 */
+		if (sctp_state(asoc, ESTABLISHED) && sctp_sstate(sk, CLOSED))
+			sk->state = SCTP_SS_ESTABLISHED;
+
+		/* Set the RCV_SHUTDOWN flag when a SHUTDOWN is received. */
+		if (sctp_state(asoc, SHUTDOWN_RECEIVED) &&
+		    sctp_sstate(sk, ESTABLISHED))
+			sk->shutdown |= RCV_SHUTDOWN;
+	}
+
+	if (sctp_state(asoc, ESTABLISHED) ||
+	    sctp_state(asoc, CLOSED) ||
+	    sctp_state(asoc, SHUTDOWN_RECEIVED)) {
 		/* Wake up any processes waiting in the asoc's wait queue in
 		 * sctp_wait_for_connect() or sctp_wait_for_sndbuf().
 	 	 */
@@ -631,16 +643,26 @@
 		 * For a UDP-style socket, the waiters are woken up by the
 		 * notifications.
 		 */
-		if (SCTP_SOCKET_UDP != sp->type)
+		if (!sctp_style(sk, UDP))
 			sk->state_change(sk);
 	}
+}
 
-	/* Change the sk->state of a TCP-style socket that has successfully
-	 * completed a connect() call.
-	 */
-	if ((SCTP_STATE_ESTABLISHED == asoc->state) &&
-	    (SCTP_SOCKET_TCP == sp->type) && (SCTP_SS_CLOSED == sk->state))
-	    sk->state = SCTP_SS_ESTABLISHED;
+/* Helper function to delete an association. */
+static void sctp_cmd_delete_tcb(sctp_cmd_seq_t *cmds,
+				struct sctp_association *asoc)
+{
+	struct sock *sk = asoc->base.sk;
+
+	/* If it is a non-temporary association belonging to a TCP-style
+	 * listening socket, do not free it so that accept() can pick it
+	 * up later.
+	 */ 
+	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING) && (!asoc->temp))
+		return;
+
+	sctp_unhash_established(asoc);
+	sctp_association_free(asoc);
 }
 
 /* These three macros allow us to pull the debugging code out of the
@@ -673,10 +695,10 @@
  */
 int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
 	       sctp_state_t state,
-	       sctp_endpoint_t *ep,
-	       sctp_association_t *asoc,
+	       struct sctp_endpoint *ep,
+	       struct sctp_association *asoc,
 	       void *event_arg,
-	       int priority)
+	       int gfp)
 {
 	sctp_cmd_seq_t commands;
 	sctp_sm_table_entry_t *state_fn;
@@ -701,9 +723,8 @@
 	DEBUG_POST;
 
 	error = sctp_side_effects(event_type, subtype, state,
-				  ep, asoc, event_arg,
-				  status, &commands,
-				  priority);
+				  ep, asoc, event_arg, status, 
+				  &commands, gfp);
 	DEBUG_POST_SFX;
 
 	return error;
@@ -717,12 +738,12 @@
  *****************************************************************/
 int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
 		      sctp_state_t state,
-		      sctp_endpoint_t *ep,
-		      sctp_association_t *asoc,
+		      struct sctp_endpoint *ep,
+		      struct sctp_association *asoc,
 		      void *event_arg,
 		      sctp_disposition_t status,
 		      sctp_cmd_seq_t *commands,
-		      int priority)
+		      int gfp)
 {
 	int error;
 
@@ -735,7 +756,7 @@
 	if (0 != (error = sctp_cmd_interpreter(event_type, subtype, state,
 					       ep, asoc,
 					       event_arg, status,
-					       commands, priority)))
+					       commands, gfp)))
 		goto bail;
 
 	switch (status) {
@@ -803,25 +824,26 @@
 
 /* This is the side-effect interpreter.  */
 int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
-			 sctp_state_t state, sctp_endpoint_t *ep,
-			 sctp_association_t *asoc, void *event_arg,
+			 sctp_state_t state, struct sctp_endpoint *ep,
+			 struct sctp_association *asoc, void *event_arg,
 			 sctp_disposition_t status, sctp_cmd_seq_t *commands,
-			 int priority)
+			 int gfp)
 {
 	int error = 0;
 	int force;
 	sctp_cmd_t *cmd;
-	sctp_chunk_t *new_obj;
-	sctp_chunk_t *chunk = NULL;
+	struct sctp_chunk *new_obj;
+	struct sctp_chunk *chunk = NULL;
 	struct sctp_packet *packet;
 	struct list_head *pos;
 	struct timer_list *timer;
 	unsigned long timeout;
 	struct sctp_transport *t;
 	sctp_sackhdr_t sackh;
+	int local_cork = 0;
 
-	if(SCTP_EVENT_T_TIMEOUT != event_type)
-		chunk = (sctp_chunk_t *) event_arg;
+	if (SCTP_EVENT_T_TIMEOUT != event_type)
+		chunk = (struct sctp_chunk *) event_arg;
 
 	/* Note:  This whole file is a huge candidate for rework.
 	 * For example, each command could either have its own handler, so
@@ -838,6 +860,10 @@
 
 		case SCTP_CMD_NEW_ASOC:
 			/* Register a new association.  */
+			if (local_cork) {
+				sctp_outq_uncork(&asoc->outqueue); 
+				local_cork = 0;
+			}
 			asoc = cmd->obj.ptr;
 			/* Register with the endpoint.  */
 			sctp_endpoint_add_asoc(ep, asoc);
@@ -852,10 +878,13 @@
 		       sctp_outq_teardown(&asoc->outqueue);
 		       break;
 
-		case SCTP_CMD_DELETE_TCB:
+		case SCTP_CMD_DELETE_TCB:			
+			if (local_cork) {
+				sctp_outq_uncork(&asoc->outqueue);
+				local_cork = 0;
+			}
 			/* Delete the current association.  */
-			sctp_unhash_established(asoc);
-			sctp_association_free(asoc);
+			sctp_cmd_delete_tcb(commands, asoc);
 			asoc = NULL;
 			break;
 
@@ -903,7 +932,7 @@
 			 * layer which will bail.
 			 */
 			error = sctp_cmd_process_init(commands, asoc, chunk,
-						      cmd->obj.ptr, priority);
+						      cmd->obj.ptr, gfp);
 			break;
 
 		case SCTP_CMD_GEN_COOKIE_ECHO:
@@ -911,7 +940,7 @@
 			new_obj = sctp_make_cookie_echo(asoc, chunk);
 			if (!new_obj) {
 				if (cmd->obj.ptr)
-					sctp_free_chunk(cmd->obj.ptr);
+					sctp_chunk_free(cmd->obj.ptr);
 				goto nomem;
 			}
 			sctp_add_cmd_sf(commands, SCTP_CMD_REPLY,
@@ -957,9 +986,13 @@
 			break;
 
 		case SCTP_CMD_REPLY:
+			/* If an caller has not already corked, do cork. */
+			if (!asoc->outqueue.cork) {
+				sctp_outq_cork(&asoc->outqueue);
+				local_cork = 1;
+			}
 			/* Send a chunk to our peer.  */
-			error = sctp_outq_tail(&asoc->outqueue,
-					       cmd->obj.ptr);
+			error = sctp_outq_tail(&asoc->outqueue, cmd->obj.ptr);
 			break;
 
 		case SCTP_CMD_SEND_PKT:
@@ -977,7 +1010,8 @@
 
 		case SCTP_CMD_TRANSMIT:
 			/* Kick start transmission. */
-			error = sctp_outq_flush(&asoc->outqueue, 0);
+			error = sctp_outq_uncork(&asoc->outqueue);
+			local_cork = 0;
 			break;
 
 		case SCTP_CMD_ECN_CE:
@@ -1148,13 +1182,15 @@
 			break;
 		};
 		if (error)
-			return error;
+			break;
 	}
 
+out:
+	if (local_cork)
+		sctp_outq_uncork(&asoc->outqueue);
 	return error;
-
 nomem:
 	error = -ENOMEM;
-	return error;
+	goto out;
 }
 
diff -Nru a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
--- a/net/sctp/sm_statefuns.c	Tue Apr 29 02:29:48 2003
+++ b/net/sctp/sm_statefuns.c	Tue May  6 16:40:03 2003
@@ -95,13 +95,13 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_4_C(const sctp_endpoint_t *ep,
-				  const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
+				  const struct sctp_association *asoc,
 				  const sctp_subtype_t type,
 				  void *arg,
 				  sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	struct sctp_ulpevent *ev;
 
 	/* RFC 2960 6.10 Bundling
@@ -179,16 +179,16 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
-	sctp_chunk_t *repl;
-	sctp_association_t *new_asoc;
-	sctp_chunk_t *err_chunk;
+	struct sctp_chunk *chunk = arg;
+	struct sctp_chunk *repl;
+	struct sctp_association *new_asoc;
+	struct sctp_chunk *err_chunk;
 	struct sctp_packet *packet;
 	sctp_unrecognized_param_t *unk_param;
 	struct sock *sk;
@@ -212,9 +212,8 @@
 	 * on the TCP-style socket exceed the max backlog, respond with an
 	 * ABORT.
 	 */
-	if ((SCTP_SS_LISTENING != sk->state) ||
-	    ((SCTP_SOCKET_TCP == sctp_sk(sk)->type) &&
-	     (sk->ack_backlog >= sk->max_ack_backlog)))
+	if (!sctp_sstate(sk, LISTENING) ||
+	    (sctp_style(sk, TCP) && (sk->ack_backlog >= sk->max_ack_backlog)))
 		return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
 
 	/* Verify the INIT chunk before processing it. */
@@ -232,7 +231,7 @@
 					ntohs(err_chunk->chunk_hdr->length) -
 					sizeof(sctp_chunkhdr_t));
 
-			sctp_free_chunk(err_chunk);
+			sctp_chunk_free(err_chunk);
 
 			if (packet) {
 				sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
@@ -260,8 +259,8 @@
 
 	/* The call, sctp_process_init(), can fail on memory allocation.  */
 	if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-			       sctp_source(chunk), 
-			       (sctp_init_chunk_t *)chunk->chunk_hdr, 
+			       sctp_source(chunk),
+			       (sctp_init_chunk_t *)chunk->chunk_hdr,
 			       GFP_ATOMIC))
 		goto nomem_init;
 
@@ -303,7 +302,7 @@
 		 * parameter type.
 		 */
 		sctp_addto_chunk(repl, len, unk_param);
-		sctp_free_chunk(err_chunk);
+		sctp_chunk_free(err_chunk);
 	}
 
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
@@ -320,7 +319,7 @@
 
 nomem_ack:
 	if (err_chunk)
-		sctp_free_chunk(err_chunk);
+		sctp_chunk_free(err_chunk);
 nomem_init:
 	sctp_association_free(new_asoc);
 nomem:
@@ -355,16 +354,16 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep,
-				       const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
+				       const struct sctp_association *asoc,
 				       const sctp_subtype_t type,
 				       void *arg,
 				       sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	sctp_init_chunk_t *initchunk;
 	__u32 init_tag;
-	sctp_chunk_t *err_chunk;
+	struct sctp_chunk *err_chunk;
 	struct sctp_packet *packet;
 	sctp_disposition_t ret;
 
@@ -386,7 +385,7 @@
 	 *   error and close the association by transmitting an ABORT.
 	 */
 	if (!init_tag) {
-		sctp_chunk_t *reply = sctp_make_abort(asoc, chunk, 0);
+		struct sctp_chunk *reply = sctp_make_abort(asoc, chunk, 0);
 		if (!reply)
 			goto nomem;
 
@@ -416,7 +415,7 @@
 					ntohs(err_chunk->chunk_hdr->length) -
 					sizeof(sctp_chunkhdr_t));
 
-			sctp_free_chunk(err_chunk);
+			sctp_chunk_free(err_chunk);
 
 			if (packet) {
 				sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
@@ -514,18 +513,18 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_1D_ce(const sctp_endpoint_t *ep,
-				      const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
+				      const struct sctp_association *asoc,
 				      const sctp_subtype_t type, void *arg,
 				      sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
-	sctp_association_t *new_asoc;
+	struct sctp_chunk *chunk = arg;
+	struct sctp_association *new_asoc;
 	sctp_init_chunk_t *peer_init;
-	sctp_chunk_t *repl;
+	struct sctp_chunk *repl;
 	struct sctp_ulpevent *ev;
 	int error = 0;
-	sctp_chunk_t *err_chk_p;
+	struct sctp_chunk *err_chk_p;
 
 	/* If the packet is an OOTB packet which is temporarily on the
 	 * control endpoint, respond with an ABORT.
@@ -623,7 +622,7 @@
 	return SCTP_DISPOSITION_CONSUME;
 
 nomem_ev:
-	sctp_free_chunk(repl);
+	sctp_chunk_free(repl);
 nomem_repl:
 nomem_init:
 	sctp_association_free(new_asoc);
@@ -652,8 +651,8 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_1E_ca(const sctp_endpoint_t *ep,
-				      const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
+				      const struct sctp_association *asoc,
 				      const sctp_subtype_t type, void *arg,
 				      sctp_cmd_seq_t *commands)
 {
@@ -697,14 +696,14 @@
 }
 
 /* Generate and sendout a heartbeat packet.  */
-sctp_disposition_t sctp_sf_heartbeat(const sctp_endpoint_t *ep,
-				     const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
+				     const struct sctp_association *asoc,
 				     const sctp_subtype_t type,
 				     void *arg,
 				     sctp_cmd_seq_t *commands)
 {
 	struct sctp_transport *transport = (struct sctp_transport *) arg;
-	sctp_chunk_t *reply;
+	struct sctp_chunk *reply;
 	sctp_sender_hb_info_t hbinfo;
 	size_t paylen = 0;
 
@@ -730,8 +729,8 @@
 }
 
 /* Generate a HEARTBEAT packet on the given transport.  */
-sctp_disposition_t sctp_sf_sendbeat_8_3(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
@@ -740,7 +739,7 @@
 
 	if (asoc->overall_error_count >= asoc->overall_error_threshold) {
 		/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
 				SCTP_U32(SCTP_ERROR_NO_ERROR));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
@@ -795,14 +794,14 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_beat_8_3(const sctp_endpoint_t *ep,
-				    const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep,
+				    const struct sctp_association *asoc,
 				    const sctp_subtype_t type,
 				    void *arg,
 				    sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
-	sctp_chunk_t *reply;
+	struct sctp_chunk *chunk = arg;
+	struct sctp_chunk *reply;
 	size_t paylen = 0;
 
 	/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
@@ -862,13 +861,13 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_backbeat_8_3(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	union sctp_addr from_addr;
 	struct sctp_transport *link;
 	sctp_sender_hb_info_t *hbinfo;
@@ -919,14 +918,14 @@
  * condition.
  */
 static int sctp_sf_send_restart_abort(union sctp_addr *ssa,
-				      sctp_chunk_t *init,
+				      struct sctp_chunk *init,
 				      sctp_cmd_seq_t *commands)
 {
 	int len;
 	struct sctp_packet *pkt;
 	sctp_addr_param_t *addrparm;
 	sctp_errhdr_t *errhdr;
-	sctp_endpoint_t *ep;
+	struct sctp_endpoint *ep;
 	char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)];
 
 	/* Build the error on the stack.   We are way to malloc crazy
@@ -969,9 +968,9 @@
 /* A restart is occurring, check to make sure no new addresses
  * are being added as we may be under a takeover attack.
  */
-static int sctp_sf_check_restart_addrs(const sctp_association_t *new_asoc,
-				       const sctp_association_t *asoc,
-				       sctp_chunk_t *init,
+static int sctp_sf_check_restart_addrs(const struct sctp_association *new_asoc,
+				       const struct sctp_association *asoc,
+				       struct sctp_chunk *init,
 				       sctp_cmd_seq_t *commands)
 {
 	struct sctp_transport *new_addr, *addr;
@@ -1022,8 +1021,8 @@
  *
  * Note: Do not use in CLOSED or SHUTDOWN-ACK-SENT state.
  */
-static void sctp_tietags_populate(sctp_association_t *new_asoc,
-				  const sctp_association_t *asoc)
+static void sctp_tietags_populate(struct sctp_association *new_asoc,
+				  const struct sctp_association *asoc)
 {
 	switch (asoc->state) {
 
@@ -1069,8 +1068,8 @@
  * Returns value representing action to be taken.   These action values
  * correspond to Action/Description values in RFC 2960, Table 2.
  */
-static char sctp_tietags_compare(sctp_association_t *new_asoc,
-				 const sctp_association_t *asoc)
+static char sctp_tietags_compare(struct sctp_association *new_asoc,
+				 const struct sctp_association *asoc)
 {
 	/* In this case, the peer may have restarted.  */
 	if ((asoc->c.my_vtag != new_asoc->c.my_vtag) &&
@@ -1106,16 +1105,16 @@
  * chunk handling.
  */
 static sctp_disposition_t sctp_sf_do_unexpected_init(
-	const sctp_endpoint_t *ep,
-	const sctp_association_t *asoc,
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
 	const sctp_subtype_t type,
 	void *arg, sctp_cmd_seq_t *commands)
 {
 	sctp_disposition_t retval;
-	sctp_chunk_t *chunk = arg;
-	sctp_chunk_t *repl;
-	sctp_association_t *new_asoc;
-	sctp_chunk_t *err_chunk;
+	struct sctp_chunk *chunk = arg;
+	struct sctp_chunk *repl;
+	struct sctp_association *new_asoc;
+	struct sctp_chunk *err_chunk;
 	struct sctp_packet *packet;
 	sctp_unrecognized_param_t *unk_param;
 	int len;
@@ -1191,7 +1190,7 @@
 	 * since there are no peer addresses to check against.
 	 * Upon return an ABORT will have been sent if needed.
 	 */
-	if (asoc->state != SCTP_STATE_COOKIE_WAIT) {
+	if (!sctp_state(asoc, COOKIE_WAIT)) {
 		if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk,
 						 commands)) {
 			retval = SCTP_DISPOSITION_CONSUME;
@@ -1238,7 +1237,7 @@
 		 * parameter type.
 		 */
 		sctp_addto_chunk(repl, len, unk_param);
-		sctp_free_chunk(err_chunk);
+		sctp_chunk_free(err_chunk);
 	}
 
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC, SCTP_ASOC(new_asoc));
@@ -1254,7 +1253,7 @@
 
 cleanup:
 	if (err_chunk)
-		sctp_free_chunk(err_chunk);
+		sctp_chunk_free(err_chunk);
 	return retval;
 nomem:
 	retval = SCTP_DISPOSITION_NOMEM;
@@ -1303,11 +1302,11 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_1_siminit(const sctp_endpoint_t *ep,
-					    const sctp_association_t *asoc,
-					    const sctp_subtype_t type,
-					    void *arg,
-					    sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_do_5_2_1_siminit(const struct sctp_endpoint *ep,
+				    const struct sctp_association *asoc,
+				    const sctp_subtype_t type,
+				    void *arg,
+				    sctp_cmd_seq_t *commands)
 {
 	/* Call helper to do the real work for both simulataneous and
 	 * duplicate INIT chunk handling.
@@ -1356,11 +1355,11 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const sctp_endpoint_t *ep,
-					    const sctp_association_t *asoc,
-					    const sctp_subtype_t type,
-					    void *arg,
-					    sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_do_5_2_2_dupinit(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					const sctp_subtype_t type,
+					void *arg,
+					sctp_cmd_seq_t *commands)
 {
 	/* Call helper to do the real work for both simulataneous and
 	 * duplicate INIT chunk handling.
@@ -1375,15 +1374,15 @@
  * Section 5.2.4
  *  A)  In this case, the peer may have restarted.
  */
-static sctp_disposition_t sctp_sf_do_dupcook_a(const sctp_endpoint_t *ep,
-					       const sctp_association_t *asoc,
-					       sctp_chunk_t *chunk,
-					       sctp_cmd_seq_t *commands,
-					       sctp_association_t *new_asoc)
+static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					struct sctp_chunk *chunk,
+					sctp_cmd_seq_t *commands,
+					struct sctp_association *new_asoc)
 {
 	sctp_init_chunk_t *peer_init;
 	struct sctp_ulpevent *ev;
-	sctp_chunk_t *repl;
+	struct sctp_chunk *repl;
 
 	/* new_asoc is a brand-new association, so these are not yet
 	 * side effects--it is safe to run them here.
@@ -1391,7 +1390,7 @@
 	peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
 
 	if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-			       sctp_source(chunk), peer_init, 
+			       sctp_source(chunk), peer_init,
 			       GFP_ATOMIC))
 		goto nomem;
 
@@ -1429,7 +1428,7 @@
 	return SCTP_DISPOSITION_CONSUME;
 
 nomem_ev:
-	sctp_free_chunk(repl);
+	sctp_chunk_free(repl);
 nomem:
 	return SCTP_DISPOSITION_NOMEM;
 }
@@ -1442,22 +1441,22 @@
  *      after responding to the local endpoint's INIT
  */
 /* This case represents an initialization collision.  */
-static sctp_disposition_t sctp_sf_do_dupcook_b(const sctp_endpoint_t *ep,
-					       const sctp_association_t *asoc,
-					       sctp_chunk_t *chunk,
-					       sctp_cmd_seq_t *commands,
-					       sctp_association_t *new_asoc)
+static sctp_disposition_t sctp_sf_do_dupcook_b(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					struct sctp_chunk *chunk,
+					sctp_cmd_seq_t *commands,
+					struct sctp_association *new_asoc)
 {
 	sctp_init_chunk_t *peer_init;
 	struct sctp_ulpevent *ev;
-	sctp_chunk_t *repl;
+	struct sctp_chunk *repl;
 
 	/* new_asoc is a brand-new association, so these are not yet
 	 * side effects--it is safe to run them here.
 	 */
 	peer_init = &chunk->subh.cookie_hdr->c.peer_init[0];
 	if (!sctp_process_init(new_asoc, chunk->chunk_hdr->type,
-			       sctp_source(chunk), peer_init, 
+			       sctp_source(chunk), peer_init,
 			       GFP_ATOMIC))
 		goto nomem;
 
@@ -1492,7 +1491,7 @@
 	return SCTP_DISPOSITION_CONSUME;
 
 nomem_ev:
-	sctp_free_chunk(repl);
+	sctp_chunk_free(repl);
 nomem:
 	return SCTP_DISPOSITION_NOMEM;
 }
@@ -1506,11 +1505,11 @@
  *     but a new tag of its own.
  */
 /* This case represents an initialization collision.  */
-static sctp_disposition_t sctp_sf_do_dupcook_c(const sctp_endpoint_t *ep,
-					       const sctp_association_t *asoc,
-					       sctp_chunk_t *chunk,
-					       sctp_cmd_seq_t *commands,
-					       sctp_association_t *new_asoc)
+static sctp_disposition_t sctp_sf_do_dupcook_c(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					struct sctp_chunk *chunk,
+					sctp_cmd_seq_t *commands,
+					struct sctp_association *new_asoc)
 {
 	/* The cookie should be silently discarded.
 	 * The endpoint SHOULD NOT change states and should leave
@@ -1527,14 +1526,14 @@
  *    enter the ESTABLISHED state, if it has not already done so.
  */
 /* This case represents an initialization collision.  */
-static sctp_disposition_t sctp_sf_do_dupcook_d(const sctp_endpoint_t *ep,
-					       const sctp_association_t *asoc,
-					       sctp_chunk_t *chunk,
-					       sctp_cmd_seq_t *commands,
-					       sctp_association_t *new_asoc)
+static sctp_disposition_t sctp_sf_do_dupcook_d(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					struct sctp_chunk *chunk,
+					sctp_cmd_seq_t *commands,
+					struct sctp_association *new_asoc)
 {
 	struct sctp_ulpevent *ev = NULL;
-	sctp_chunk_t *repl;
+	struct sctp_chunk *repl;
 
 	/* Clarification from Implementor's Guide:
 	 * D) When both local and remote tags match the endpoint should
@@ -1603,18 +1602,18 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const sctp_endpoint_t *ep,
-					    const sctp_association_t *asoc,
-					    const sctp_subtype_t type,
-					    void *arg,
-					    sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					const sctp_subtype_t type,
+					void *arg,
+					sctp_cmd_seq_t *commands)
 {
 	sctp_disposition_t retval;
-	sctp_chunk_t *chunk = arg;
-	sctp_association_t *new_asoc;
+	struct sctp_chunk *chunk = arg;
+	struct sctp_association *new_asoc;
 	int error = 0;
 	char action;
-	sctp_chunk_t *err_chk_p;
+	struct sctp_chunk *err_chk_p;
 
 	/* "Decode" the chunk.  We have no optional parameters so we
 	 * are in good shape.
@@ -1701,13 +1700,14 @@
  *
  * See sctp_sf_do_9_1_abort().
  */
-sctp_disposition_t sctp_sf_shutdown_pending_abort(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
-					const sctp_subtype_t type,
-					void *arg,
-					sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_shutdown_pending_abort(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -1724,13 +1724,13 @@
  *
  * See sctp_sf_do_9_1_abort().
  */
-sctp_disposition_t sctp_sf_shutdown_sent_abort(const sctp_endpoint_t *ep,
-					       const sctp_association_t *asoc,
-					       const sctp_subtype_t type,
-					       void *arg,
-					       sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					const sctp_subtype_t type,
+					void *arg,
+					sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -1751,11 +1751,12 @@
  *
  * See sctp_sf_do_9_1_abort().
  */
-sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(const sctp_endpoint_t *ep,
-						const sctp_association_t *asoc,
-						const sctp_subtype_t type,
-						void *arg,
-						sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_shutdown_ack_sent_abort(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
 	/* The same T2 timer, so we should be able to use
 	 * common function with the SHUTDOWN-SENT state.
@@ -1777,13 +1778,13 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_cookie_echoed_err(const sctp_endpoint_t *ep,
-					     const sctp_association_t *asoc,
-					     const sctp_subtype_t type,
-					     void *arg,
-					     sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
+					const sctp_subtype_t type,
+					void *arg,
+					sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	sctp_errhdr_t *err;
 
 	err = (sctp_errhdr_t *)(chunk->skb->data);
@@ -1792,7 +1793,7 @@
 	if (1 + asoc->counters[SCTP_COUNTER_INIT_ERROR] >
 					 asoc->max_init_attempts) {
 		/* INIT_FAILED will issue an ulpevent.  */
-		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, 
+		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
 				SCTP_U32(err->cause));
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
@@ -1831,26 +1832,26 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_5_2_6_stale(const sctp_endpoint_t *ep,
-					  const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
+					  const struct sctp_association *asoc,
 					  const sctp_subtype_t type,
 					  void *arg,
 					  sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	time_t stale;
 	sctp_cookie_preserve_param_t bht;
 	sctp_errhdr_t *err;
 	struct list_head *pos;
 	struct sctp_transport *t;
-	sctp_chunk_t *reply;
-	sctp_bind_addr_t *bp;
+	struct sctp_chunk *reply;
+	struct sctp_bind_addr *bp;
 	int attempts;
 
 	attempts = asoc->counters[SCTP_COUNTER_INIT_ERROR] + 1;
 
 	if (attempts >= asoc->max_init_attempts) {
-		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, 
+		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
 				SCTP_U32(SCTP_ERROR_STALE_COOKIE));
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
@@ -1879,7 +1880,7 @@
 	bht.lifespan_increment = htonl(stale);
 
 	/* Build that new INIT chunk.  */
-	bp = (sctp_bind_addr_t *) &asoc->base.bind_addr;
+	bp = (struct sctp_bind_addr *) &asoc->base.bind_addr;
 	reply = sctp_make_init(asoc, bp, GFP_ATOMIC, sizeof(bht));
 	if (!reply)
 		goto nomem;
@@ -1946,20 +1947,20 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_9_1_abort(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	__u16 error = SCTP_ERROR_NO_ERROR;
 
 	if (!sctp_vtag_verify_either(chunk, asoc))
 		return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
 
 	if (chunk && (ntohs(chunk->chunk_hdr->length) >=
-			(sizeof(struct sctp_chunkhdr) + 
+			(sizeof(struct sctp_chunkhdr) +
 			sizeof(struct sctp_errhdr))))
 		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
 
@@ -1977,13 +1978,13 @@
  *
  * See sctp_sf_do_9_1_abort() above.
  */
-sctp_disposition_t sctp_sf_cookie_wait_abort(const sctp_endpoint_t *ep,
-					     const sctp_association_t *asoc,
-					     const sctp_subtype_t type,
-					     void *arg,
-					     sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
+				     const struct sctp_association *asoc,
+				     const sctp_subtype_t type,
+				     void *arg,
+				     sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	__u16 error = SCTP_ERROR_NO_ERROR;
 
 	if (!sctp_vtag_verify_either(chunk, asoc))
@@ -1996,7 +1997,7 @@
 			SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
 
 	if (chunk && (ntohs(chunk->chunk_hdr->length) >=
-			(sizeof(struct sctp_chunkhdr) + 
+			(sizeof(struct sctp_chunkhdr) +
 			sizeof(struct sctp_errhdr))))
 		error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
 
@@ -2011,8 +2012,8 @@
  *
  * See sctp_sf_do_9_1_abort() above.
  */
-sctp_disposition_t sctp_sf_cookie_echoed_abort(const sctp_endpoint_t *ep,
-					       const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
+					       const struct sctp_association *asoc,
 					       const sctp_subtype_t type,
 					       void *arg,
 					       sctp_cmd_seq_t *commands)
@@ -2056,13 +2057,13 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_9_2_shutdown(const sctp_endpoint_t *ep,
-					   const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
+					   const struct sctp_association *asoc,
 					   const sctp_subtype_t type,
 					   void *arg,
 					   sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	sctp_shutdownhdr_t *sdh;
 	sctp_disposition_t disposition;
 
@@ -2111,14 +2112,14 @@
  * that belong to this association, it should discard the INIT chunk and
  * retransmit the SHUTDOWN ACK chunk.
  */
-sctp_disposition_t sctp_sf_do_9_2_reshutack(const sctp_endpoint_t *ep,
-					    const sctp_association_t *asoc,
-					    const sctp_subtype_t type,
-					    void *arg,
-					    sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep,
+				    const struct sctp_association *asoc,
+				    const sctp_subtype_t type,
+				    void *arg,
+				    sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = (sctp_chunk_t *) arg;
-	sctp_chunk_t *reply;
+	struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
+	struct sctp_chunk *reply;
 
 	reply = sctp_make_shutdown_ack(asoc, chunk);
 	if (NULL == reply)
@@ -2165,14 +2166,14 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_ecn_cwr(const sctp_endpoint_t *ep,
-				      const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep,
+				      const struct sctp_association *asoc,
 				      const sctp_subtype_t type,
 				      void *arg,
 				      sctp_cmd_seq_t *commands)
 {
 	sctp_cwrhdr_t *cwr;
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 
 	/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
 	 * that the value in the Verification Tag field of the
@@ -2221,14 +2222,14 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_ecne(const sctp_endpoint_t *ep,
-				   const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_ecne(const struct sctp_endpoint *ep,
+				   const struct sctp_association *asoc,
 				   const sctp_subtype_t type,
 				   void *arg,
 				   sctp_cmd_seq_t *commands)
 {
 	sctp_ecnehdr_t *ecne;
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 
 	/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
 	 * that the value in the Verification Tag field of the
@@ -2279,15 +2280,15 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	sctp_datahdr_t *data_hdr;
-	sctp_chunk_t *err;
+	struct sctp_chunk *err;
 	size_t datalen;
 	sctp_verb_t deliver;
 	int tmp;
@@ -2309,9 +2310,7 @@
 	skb_pull(chunk->skb, sizeof(sctp_datahdr_t));
 
 	tsn = ntohl(data_hdr->tsn);
-
 	SCTP_DEBUG_PRINTK("eat_data: TSN 0x%x.\n", tsn);
-	SCTP_DEBUG_PRINTK("eat_data: skb->head %p.\n", chunk->skb->head);
 
 	/* ASSERT:  Now skb->data is really the user data.  */
 
@@ -2326,11 +2325,15 @@
 	 */
 
 	if (!chunk->ecn_ce_done) {
+		struct sctp_af *af;
 		chunk->ecn_ce_done = 1;
-		if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) &&
-		    asoc->peer.ecn_capable) {
+
+		af = sctp_get_af_specific(
+			ipver2af(chunk->skb->nh.iph->version));
+
+		if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
 			/* Do real work as sideffect. */
-			sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
+			sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, 
 					SCTP_U32(tsn));
 		}
 	}
@@ -2371,7 +2374,8 @@
 	 * PMTU.  In cases, such as loopback, this might be a rather
 	 * large spill over.
 	 */
-	if (asoc->rwnd_over || (datalen > asoc->rwnd + asoc->frag_point)) {
+	if (!asoc->rwnd || asoc->rwnd_over || 
+	    (datalen > asoc->rwnd + asoc->frag_point)) {
 
 		/* If this is the next TSN, consider reneging to make
 		 * room.   Note: Playing nice with a confused sender.  A
@@ -2409,7 +2413,7 @@
 		 * processing the rest of the chunks in the packet.
 		 */
 		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
 				SCTP_U32(SCTP_ERROR_NO_DATA));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
@@ -2537,15 +2541,15 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_eat_data_fast_4_4(const sctp_endpoint_t *ep,
-					     const sctp_association_t *asoc,
-					     const sctp_subtype_t type,
-					     void *arg,
-					     sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
+				     const struct sctp_association *asoc,
+				     const sctp_subtype_t type,
+				     void *arg,
+				     sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	sctp_datahdr_t *data_hdr;
-	sctp_chunk_t *err;
+	struct sctp_chunk *err;
 	size_t datalen;
 	int tmp;
 	__u32 tsn;
@@ -2581,11 +2585,15 @@
 	 * chunk later.
 	 */
 	if (!chunk->ecn_ce_done) {
+		struct sctp_af *af;
 		chunk->ecn_ce_done = 1;
-		if (INET_ECN_is_ce(chunk->skb->nh.iph->tos) &&
-		    asoc->peer.ecn_capable) {
+
+		af = sctp_get_af_specific(
+			ipver2af(chunk->skb->nh.iph->version));
+
+		if (af && af->is_ce(chunk->skb) && asoc->peer.ecn_capable) {
 			/* Do real work as sideffect. */
-			sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE,
+			sctp_add_cmd_sf(commands, SCTP_CMD_ECN_CE, 
 					SCTP_U32(tsn));
 		}
 	}
@@ -2625,7 +2633,7 @@
 		 * processing the rest of the chunks in the packet.
 		 */
 		sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET,SCTP_NULL());
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
 				SCTP_U32(SCTP_ERROR_NO_DATA));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
@@ -2712,13 +2720,13 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_eat_sack_6_2(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	sctp_sackhdr_t *sackh;
 	__u32 ctsn;
 
@@ -2773,15 +2781,15 @@
  *
  * The return value is the disposition of the chunk.
 */
-sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
 	struct sctp_packet *packet = NULL;
-	sctp_chunk_t *chunk = arg;
-	sctp_chunk_t *abort;
+	struct sctp_chunk *chunk = arg;
+	struct sctp_chunk *abort;
 
 	packet = sctp_ootb_pkt_new(asoc, chunk);
 
@@ -2819,13 +2827,13 @@
  *
  * The return value is the disposition of the chunk.
 */
-sctp_disposition_t sctp_sf_operr_notify(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	struct sctp_ulpevent *ev;
 
 	while (chunk->chunk_end > chunk->skb->data) {
@@ -2856,14 +2864,14 @@
  *
  * The return value is the disposition.
  */
-sctp_disposition_t sctp_sf_do_9_2_final(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
-	sctp_chunk_t *reply;
+	struct sctp_chunk *chunk = arg;
+	struct sctp_chunk *reply;
 	struct sctp_ulpevent *ev;
 
 	/* 10.2 H) SHUTDOWN COMPLETE notification
@@ -2924,13 +2932,13 @@
  *    TCB was found.  After sending this ABORT, the receiver of the OOTB
  *    packet shall discard the OOTB packet and take no further action.
  */
-sctp_disposition_t sctp_sf_ootb(const sctp_endpoint_t *ep,
-				const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
+				const struct sctp_association *asoc,
 				const sctp_subtype_t type,
 				void *arg,
 				sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 	struct sk_buff *skb = chunk->skb;
 	sctp_chunkhdr_t *ch;
 	__u8 *ch_end;
@@ -2975,15 +2983,15 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep,
-				      const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
+				      const struct sctp_association *asoc,
 				      const sctp_subtype_t type,
 				      void *arg,
 				      sctp_cmd_seq_t *commands)
 {
 	struct sctp_packet *packet = NULL;
-	sctp_chunk_t *chunk = arg;
-	sctp_chunk_t *shut;
+	struct sctp_chunk *chunk = arg;
+	struct sctp_chunk *shut;
 
 	packet = sctp_ootb_pkt_new(asoc, chunk);
 
@@ -3024,8 +3032,8 @@
  *   chunks. --piggy ]
  *
  */
-sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const sctp_endpoint_t *ep,
-				      const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
+				      const struct sctp_association *asoc,
 				      const sctp_subtype_t type,
 				      void *arg,
 				      sctp_cmd_seq_t *commands)
@@ -3061,14 +3069,14 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_unk_chunk(const sctp_endpoint_t *ep,
-				     const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
+				     const struct sctp_association *asoc,
 				     const sctp_subtype_t type,
 				     void *arg,
 				     sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *unk_chunk = arg;
-	sctp_chunk_t *err_chunk;
+	struct sctp_chunk *unk_chunk = arg;
+	struct sctp_chunk *err_chunk;
 	sctp_chunkhdr_t *hdr;
 
 	SCTP_DEBUG_PRINTK("Processing the unknown chunk id %d.\n", type.chunk);
@@ -3140,8 +3148,8 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_discard_chunk(const sctp_endpoint_t *ep,
-					 const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep,
+					 const struct sctp_association *asoc,
 					 const sctp_subtype_t type,
 					 void *arg,
 					 sctp_cmd_seq_t *commands)
@@ -3169,8 +3177,8 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_pdiscard(const sctp_endpoint_t *ep,
-				    const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_pdiscard(const struct sctp_endpoint *ep,
+				    const struct sctp_association *asoc,
 				    const sctp_subtype_t type,
 				    void *arg,
 				    sctp_cmd_seq_t *commands)
@@ -3198,13 +3206,13 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t lucky(const sctp_endpoint_t *ep,
-			 const sctp_association_t *asoc,
+sctp_disposition_t lucky(const struct sctp_endpoint *ep,
+			 const struct sctp_association *asoc,
 			 const sctp_subtype_t type,
 			 void *arg,
 			 sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 
 	/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
 	 * that the value in the Verification Tag field of the
@@ -3235,13 +3243,13 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t other_stupid(const sctp_endpoint_t *ep,
-				const sctp_association_t *asoc,
+sctp_disposition_t other_stupid(const struct sctp_endpoint *ep,
+				const struct sctp_association *asoc,
 				const sctp_subtype_t type,
 				void *arg,
 				sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 
 	/* 8.5 When receiving an SCTP packet, the endpoint MUST ensure
 	 * that the value in the Verification Tag field of the
@@ -3271,8 +3279,8 @@
  * We simply tag the chunk as a violation.  The state machine will log
  * the violation and continue.
  */
-sctp_disposition_t sctp_sf_violation(const sctp_endpoint_t *ep,
-				     const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
+				     const struct sctp_association *asoc,
 				     const sctp_subtype_t type,
 				     void *arg,
 				     sctp_cmd_seq_t *commands)
@@ -3309,7 +3317,7 @@
  * will be returned on successful establishment of the association. If
  * SCTP is not able to open an SCTP association with the peer endpoint,
  * an error is returned.
- * [In the kernel implementation, the sctp_association_t needs to
+ * [In the kernel implementation, the struct sctp_association needs to
  * be created BEFORE causing this primitive to run.]
  *
  * Other association parameters may be returned, including the
@@ -3340,13 +3348,13 @@
  *
  * The return value is a disposition.
  */
-sctp_disposition_t sctp_sf_do_prm_asoc(const sctp_endpoint_t *ep,
-				       const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_prm_asoc(const struct sctp_endpoint *ep,
+				       const struct sctp_association *asoc,
 				       const sctp_subtype_t type,
 				       void *arg,
 				       sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *repl;
+	struct sctp_chunk *repl;
 
 	/* The comment below says that we enter COOKIE-WAIT AFTER
 	 * sending the INIT, but that doesn't actually work in our
@@ -3371,7 +3379,7 @@
 	 * rerun it through as a sideffect.
 	 */
 	sctp_add_cmd_sf(commands, SCTP_CMD_NEW_ASOC,
-			SCTP_ASOC((sctp_association_t *) asoc));
+			SCTP_ASOC((struct sctp_association *) asoc));
 
 	/* After sending the INIT, "A" starts the T1-init timer and
 	 * enters the COOKIE-WAIT state.
@@ -3446,13 +3454,13 @@
  *
  * The return value is the disposition.
  */
-sctp_disposition_t sctp_sf_do_prm_send(const sctp_endpoint_t *ep,
-				       const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_prm_send(const struct sctp_endpoint *ep,
+				       const struct sctp_association *asoc,
 				       const sctp_subtype_t type,
 				       void *arg,
 				       sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = arg;
+	struct sctp_chunk *chunk = arg;
 
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(chunk));
 	return SCTP_DISPOSITION_CONSUME;
@@ -3484,11 +3492,12 @@
  *
  * The return value is the disposition.
  */
-sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(const sctp_endpoint_t *ep,
-					       const sctp_association_t *asoc,
-					       const sctp_subtype_t type,
-					       void *arg,
-					       sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_do_9_2_prm_shutdown(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
 	int disposition;
 
@@ -3545,11 +3554,12 @@
  *
  * The return value is the disposition.
  */
-sctp_disposition_t sctp_sf_do_9_1_prm_abort(const sctp_endpoint_t *ep,
-					    const sctp_association_t *asoc,
-					    const sctp_subtype_t type,
-					    void *arg,
-					    sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_do_9_1_prm_abort(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
 	/* From 9.1 Abort of an Association
 	 * Upon receipt of the ABORT primitive from its upper
@@ -3560,7 +3570,7 @@
 	 * if necessary to fill gaps.
 	 */
 	struct msghdr *msg = arg;
-	sctp_chunk_t *abort;
+	struct sctp_chunk *abort;
 	sctp_disposition_t retval;
 
 	retval = SCTP_DISPOSITION_CONSUME;
@@ -3577,7 +3587,7 @@
 	 */
 
 	/* Delete the established association. */
-	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
 			SCTP_U32(SCTP_ERROR_USER_ABORT));
 
 	SCTP_INC_STATS(SctpAborteds);
@@ -3587,8 +3597,8 @@
 }
 
 /* We tried an illegal operation on an association which is closed.  */
-sctp_disposition_t sctp_sf_error_closed(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_error_closed(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
@@ -3600,8 +3610,8 @@
 /* We tried an illegal operation on an association which is shutting
  * down.
  */
-sctp_disposition_t sctp_sf_error_shutdown(const sctp_endpoint_t *ep,
-					  const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_error_shutdown(const struct sctp_endpoint *ep,
+					  const struct sctp_association *asoc,
 					  const sctp_subtype_t type,
 					  void *arg,
 					  sctp_cmd_seq_t *commands)
@@ -3626,8 +3636,8 @@
  * (timers)
  */
 sctp_disposition_t sctp_sf_cookie_wait_prm_shutdown(
-	const sctp_endpoint_t *ep,
-	const sctp_association_t *asoc,
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
 	const sctp_subtype_t type,
 	void *arg,
 	sctp_cmd_seq_t *commands)
@@ -3660,8 +3670,8 @@
  * (timers)
  */
 sctp_disposition_t sctp_sf_cookie_echoed_prm_shutdown(
-	const sctp_endpoint_t *ep,
-	const sctp_association_t *asoc,
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
 	const sctp_subtype_t type,
 	void *arg, sctp_cmd_seq_t *commands)
 {
@@ -3685,14 +3695,15 @@
  * Outputs
  * (timers)
  */
-sctp_disposition_t sctp_sf_cookie_wait_prm_abort(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
-					const sctp_subtype_t type,
-					void *arg,
-					sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_cookie_wait_prm_abort(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
 	struct msghdr *msg = arg;
-	sctp_chunk_t *abort;
+	struct sctp_chunk *abort;
 	sctp_disposition_t retval;
 
 	/* Stop T1-init timer */
@@ -3717,7 +3728,7 @@
 	 */
 
 	/* Delete the established association. */
-	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, 
+	sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
 			SCTP_U32(SCTP_ERROR_USER_ABORT));
 
 	return retval;
@@ -3737,11 +3748,12 @@
  * Outputs
  * (timers)
  */
-sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(const sctp_endpoint_t *ep,
-						const sctp_association_t *asoc,
-						const sctp_subtype_t type,
-						void *arg,
-						sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_cookie_echoed_prm_abort(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
 	/* There is a single T1 timer, so we should be able to use
 	 * common function with the COOKIE-WAIT state.
@@ -3762,8 +3774,8 @@
  * (timers)
  */
 sctp_disposition_t sctp_sf_shutdown_pending_prm_abort(
-	const sctp_endpoint_t *ep,
-	const sctp_association_t *asoc,
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
 	const sctp_subtype_t type,
 	void *arg,
 	sctp_cmd_seq_t *commands)
@@ -3788,8 +3800,8 @@
  * (timers)
  */
 sctp_disposition_t sctp_sf_shutdown_sent_prm_abort(
-	const sctp_endpoint_t *ep,
-	const sctp_association_t *asoc,
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
 	const sctp_subtype_t type,
 	void *arg,
 	sctp_cmd_seq_t *commands)
@@ -3818,8 +3830,8 @@
  * (timers)
  */
 sctp_disposition_t sctp_sf_shutdown_ack_sent_prm_abort(
-	const sctp_endpoint_t *ep,
-	const sctp_association_t *asoc,
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
 	const sctp_subtype_t type,
 	void *arg,
 	sctp_cmd_seq_t *commands)
@@ -3853,8 +3865,8 @@
  *   association on which a heartbeat should be issued.
  */
 sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
-					const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+					const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
@@ -3868,11 +3880,12 @@
  *
  * The return value is the disposition of the primitive.
  */
-sctp_disposition_t sctp_sf_ignore_primitive(const sctp_endpoint_t *ep,
-					    const sctp_association_t *asoc,
-					    const sctp_subtype_t type,
-					    void *arg,
-					    sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_ignore_primitive(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
 	SCTP_DEBUG_PRINTK("Primitive type %d is ignored.\n", type.primitive);
 	return SCTP_DISPOSITION_DISCARD;
@@ -3895,13 +3908,14 @@
  *
  * The return value is the disposition.
  */
-sctp_disposition_t sctp_sf_do_9_2_start_shutdown(const sctp_endpoint_t *ep,
-						const sctp_association_t *asoc,
-						const sctp_subtype_t type,
-						void *arg,
-						sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_do_9_2_start_shutdown(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *reply;
+	struct sctp_chunk *reply;
 
 	/* Once all its outstanding data has been acknowledged, the
 	 * endpoint shall send a SHUTDOWN chunk to its peer including
@@ -3956,14 +3970,15 @@
  *
  * The return value is the disposition.
  */
-sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(const sctp_endpoint_t *ep,
-					       const sctp_association_t *asoc,
-					       const sctp_subtype_t type,
-					       void *arg,
-					       sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *chunk = (sctp_chunk_t *) arg;
-	sctp_chunk_t *reply;
+	struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
+	struct sctp_chunk *reply;
 
 	/* If it has no more outstanding DATA chunks, the SHUTDOWN receiver
 	 * shall send a SHUTDOWN ACK ...
@@ -4009,8 +4024,8 @@
  *
  * The return value is the disposition of the event.
  */
-sctp_disposition_t sctp_sf_ignore_other(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_ignore_other(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
@@ -4034,8 +4049,8 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_do_6_3_3_rtx(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_6_3_3_rtx(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
@@ -4044,7 +4059,7 @@
 
 	if (asoc->overall_error_count >= asoc->overall_error_threshold) {
 		/* CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
 				SCTP_U32(SCTP_ERROR_NO_ERROR));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
@@ -4102,8 +4117,8 @@
  * allow. However, an SCTP transmitter MUST NOT be more aggressive than
  * the following algorithms allow.
  */
-sctp_disposition_t sctp_sf_do_6_2_sack(const sctp_endpoint_t *ep,
-				       const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_do_6_2_sack(const struct sctp_endpoint *ep,
+				       const struct sctp_association *asoc,
 				       const sctp_subtype_t type,
 				       void *arg,
 				       sctp_cmd_seq_t *commands)
@@ -4137,14 +4152,14 @@
  * (timers, events)
  *
  */
-sctp_disposition_t sctp_sf_t1_timer_expire(const sctp_endpoint_t *ep,
-					   const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_t1_timer_expire(const struct sctp_endpoint *ep,
+					   const struct sctp_association *asoc,
 					   const sctp_subtype_t type,
 					   void *arg,
 					   sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *repl;
-	sctp_bind_addr_t *bp;
+	struct sctp_chunk *repl;
+	struct sctp_bind_addr *bp;
 	sctp_event_timeout_t timer = (sctp_event_timeout_t) arg;
 	int timeout;
 	int attempts;
@@ -4159,7 +4174,7 @@
 	    (attempts < asoc->max_init_attempts)) {
 		switch (timer) {
 		case SCTP_EVENT_TIMEOUT_T1_INIT:
-			bp = (sctp_bind_addr_t *) &asoc->base.bind_addr;
+			bp = (struct sctp_bind_addr *) &asoc->base.bind_addr;
 			repl = sctp_make_init(asoc, bp, GFP_ATOMIC, 0);
 			break;
 
@@ -4180,7 +4195,7 @@
 				SCTP_TO(timer));
 		sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(repl));
 	} else {
-		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, 
+		sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
 				SCTP_U32(SCTP_ERROR_NO_ERROR));
 		return SCTP_DISPOSITION_DELETE_TCB;
 	}
@@ -4204,18 +4219,18 @@
  * the T2-Shutdown timer,  giving its peer ample opportunity to transmit
  * all of its queued DATA chunks that have not yet been sent.
  */
-sctp_disposition_t sctp_sf_t2_timer_expire(const sctp_endpoint_t *ep,
-					   const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_t2_timer_expire(const struct sctp_endpoint *ep,
+					   const struct sctp_association *asoc,
 					   const sctp_subtype_t type,
 					   void *arg,
 					   sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *reply = NULL;
+	struct sctp_chunk *reply = NULL;
 
 	SCTP_DEBUG_PRINTK("Timer T2 expired.\n");
 	if (asoc->overall_error_count >= asoc->overall_error_threshold) {
 		/* Note:  CMD_ASSOC_FAILED calls CMD_DELETE_TCB. */
-		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+		sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
 				SCTP_U32(SCTP_ERROR_NO_ERROR));
 		SCTP_INC_STATS(SctpAborteds);
 		SCTP_DEC_STATS(SctpCurrEstab);
@@ -4264,13 +4279,13 @@
  * At the expiration of this timer the sender SHOULD abort the association
  * by sending an ABORT chunk.
  */
-sctp_disposition_t sctp_sf_t5_timer_expire(const sctp_endpoint_t *ep,
-					   const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_t5_timer_expire(const struct sctp_endpoint *ep,
+					   const struct sctp_association *asoc,
 					   const sctp_subtype_t type,
 					   void *arg,
 					   sctp_cmd_seq_t *commands)
 {
-	sctp_chunk_t *reply = NULL;
+	struct sctp_chunk *reply = NULL;
 
 	SCTP_DEBUG_PRINTK("Timer T5 expired.\n");
 
@@ -4279,7 +4294,7 @@
 		goto nomem;
 
 	sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(reply));
-	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, 
+	sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
 			SCTP_U32(SCTP_ERROR_NO_ERROR));
 
 	return SCTP_DISPOSITION_DELETE_TCB;
@@ -4292,11 +4307,12 @@
  * The work that needs to be done is same as when SHUTDOWN is initiated by
  * the user.  So this routine looks same as sctp_sf_do_9_2_prm_shutdown().
  */
-sctp_disposition_t sctp_sf_autoclose_timer_expire(const sctp_endpoint_t *ep,
-						const sctp_association_t *asoc,
-						const sctp_subtype_t type,
-						void *arg,
-						sctp_cmd_seq_t *commands)
+sctp_disposition_t sctp_sf_autoclose_timer_expire(
+	const struct sctp_endpoint *ep,
+	const struct sctp_association *asoc,
+	const sctp_subtype_t type,
+	void *arg,
+	sctp_cmd_seq_t *commands)
 {
 	int disposition;
 
@@ -4337,8 +4353,8 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_not_impl(const sctp_endpoint_t *ep,
-				    const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_not_impl(const struct sctp_endpoint *ep,
+				    const struct sctp_association *asoc,
 				    const sctp_subtype_t type,
 				    void *arg,
 				    sctp_cmd_seq_t *commands)
@@ -4354,8 +4370,8 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_bug(const sctp_endpoint_t *ep,
-			       const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_bug(const struct sctp_endpoint *ep,
+			       const struct sctp_association *asoc,
 			       const sctp_subtype_t type,
 			       void *arg,
 			       sctp_cmd_seq_t *commands)
@@ -4374,8 +4390,8 @@
  *
  * The return value is the disposition of the chunk.
  */
-sctp_disposition_t sctp_sf_timer_ignore(const sctp_endpoint_t *ep,
-					const sctp_association_t *asoc,
+sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep,
+					const struct sctp_association *asoc,
 					const sctp_subtype_t type,
 					void *arg,
 					sctp_cmd_seq_t *commands)
@@ -4389,7 +4405,7 @@
  ********************************************************************/
 
 /* Pull the SACK chunk based on the SACK header. */
-sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk)
+sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *chunk)
 {
 	sctp_sackhdr_t *sack;
 	__u16 num_blocks;
@@ -4411,14 +4427,14 @@
 /* Create an ABORT packet to be sent as a response, with the specified
  * error causes.
  */
-struct sctp_packet *sctp_abort_pkt_new(const sctp_endpoint_t *ep,
-				  const sctp_association_t *asoc,
-				  sctp_chunk_t *chunk,
+struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
+				  const struct sctp_association *asoc,
+				  struct sctp_chunk *chunk,
 				  const void *payload,
 				  size_t paylen)
 {
 	struct sctp_packet *packet;
-	sctp_chunk_t *abort;
+	struct sctp_chunk *abort;
 
 	packet = sctp_ootb_pkt_new(asoc, chunk);
 
@@ -4447,8 +4463,8 @@
 }
 
 /* Allocate a packet for responding in the OOTB conditions.  */
-struct sctp_packet *sctp_ootb_pkt_new(const sctp_association_t *asoc,
-				 const sctp_chunk_t *chunk)
+struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
+				 const struct sctp_chunk *chunk)
 {
 	struct sctp_packet *packet;
 	struct sctp_transport *transport;
@@ -4512,11 +4528,11 @@
 }
 
 /* Send a stale cookie error when a invalid COOKIE ECHO chunk is found  */
-void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep,
-				const sctp_association_t *asoc,
-				const sctp_chunk_t *chunk,
+void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
+				const struct sctp_association *asoc,
+				const struct sctp_chunk *chunk,
 				sctp_cmd_seq_t *commands,
-				sctp_chunk_t *err_chunk)
+				struct sctp_chunk *err_chunk)
 {
 	struct sctp_packet *packet;
 
@@ -4530,6 +4546,6 @@
 					SCTP_PACKET(packet));
 			SCTP_INC_STATS(SctpOutCtrlChunks);
 		} else
-			sctp_free_chunk (err_chunk);
+			sctp_chunk_free (err_chunk);
 	}
 }
diff -Nru a/net/sctp/socket.c b/net/sctp/socket.c
--- a/net/sctp/socket.c	Tue Apr 29 02:29:48 2003
+++ b/net/sctp/socket.c	Mon May 12 18:59:25 2003
@@ -55,7 +55,6 @@
 
 #include <linux/config.h>
 #include <linux/types.h>
-#include <linux/compiler.h>
 #include <linux/kernel.h>
 #include <linux/wait.h>
 #include <linux/time.h>
@@ -63,6 +62,7 @@
 #include <linux/fcntl.h>
 #include <linux/poll.h>
 #include <linux/init.h>
+#include <linux/crypto.h>
 
 #include <net/ip.h>
 #include <net/icmp.h>
@@ -82,13 +82,14 @@
 /* Forward declarations for internal helper functions. */
 static int sctp_writeable(struct sock *sk);
 static inline int sctp_wspace(struct sctp_association *asoc);
-static inline void sctp_set_owner_w(sctp_chunk_t *chunk);
+static inline void sctp_set_owner_w(struct sctp_chunk *chunk);
 static void sctp_wfree(struct sk_buff *skb);
 static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
 				int msg_len);
 static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p);
 static int sctp_wait_for_connect(struct sctp_association *, long *timeo_p);
 static int sctp_wait_for_accept(struct sock *sk, long timeo);
+static void sctp_wait_for_close(struct sock *sk, long timeo);
 static inline int sctp_verify_addr(struct sock *, union sctp_addr *, int);
 static int sctp_bindx_add(struct sock *, struct sockaddr_storage *, int);
 static int sctp_bindx_rem(struct sock *, struct sockaddr_storage *, int);
@@ -96,31 +97,33 @@
 static int sctp_autobind(struct sock *sk);
 static void sctp_sock_migrate(struct sock *, struct sock *,
 			      struct sctp_association *, sctp_socket_type_t);
+static char *sctp_hmac_alg = SCTP_COOKIE_HMAC_ALG;
 
 /* Look up the association by its id.  If this is not a UDP-style
  * socket, the ID field is always ignored.
  */
-sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
+struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
 {
-	sctp_association_t *asoc = NULL;
+	struct sctp_association *asoc = NULL;
 
-	/* If this is not a UDP-style socket, assoc id should be 
+	/* If this is not a UDP-style socket, assoc id should be
 	 * ignored.
 	 */
-	if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) {
+	if (!sctp_style(sk, UDP)) {
 		if (!list_empty(&sctp_sk(sk)->ep->asocs))
 			asoc = list_entry(sctp_sk(sk)->ep->asocs.next,
-					  sctp_association_t, asocs);
+					  struct sctp_association, asocs);
 		return asoc;
 	}
 
 	/* First, verify that this is a kernel address. */
 	if (sctp_is_valid_kaddr((unsigned long) id)) {
-		sctp_association_t *temp = (sctp_association_t *) id;
+		struct sctp_association *temp;
 
-		/* Verify that this _is_ an sctp_association_t
+		/* Verify that this _is_ an sctp_association
 		 * data structure and if so, that the socket matches.
 		 */
+		temp = (struct sctp_association *)id;
 		if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) &&
 		    (temp->base.sk == sk))
 			asoc = temp;
@@ -188,13 +191,12 @@
 	return af;
 }
 
-
 /* Bind a local address either to an endpoint or to an association.  */
 SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
 {
 	struct sctp_opt *sp = sctp_sk(sk);
-	sctp_endpoint_t *ep = sp->ep;
-	sctp_bind_addr_t *bp = &ep->base.bind_addr;
+	struct sctp_endpoint *ep = sp->ep;
+	struct sctp_bind_addr *bp = &ep->base.bind_addr;
 	struct sctp_af *af;
 	unsigned short snum;
 	int ret = 0;
@@ -260,7 +262,7 @@
 	/* Copy back into socket for getsockname() use. */
 	if (!ret) {
 		inet_sk(sk)->sport = htons(inet_sk(sk)->num);
-		af->to_sk(addr, sk);
+		af->to_sk_saddr(addr, sk);
 	}
 
 	return ret;
@@ -446,16 +448,16 @@
 	 * 							--daisy
 	 */
 
-#if CONFIG_IP_SCTP_ADDIP
+#ifdef CONFIG_IP_SCTP_ADDIP
 	/* Add these addresses to all associations on this endpoint.  */
 	if (retval >= 0) {
 		struct list_head *pos;
-		sctp_endpoint_t *ep;
-		sctp_association_t *asoc;
+		struct sctp_endpoint *ep;
+		struct sctp_association *asoc;
 		ep = sctp_sk(sk)->ep;
 
 		list_for_each(pos, &ep->asocs) {
-			asoc = list_entry(pos, sctp_association_t, asocs);
+			asoc = list_entry(pos, struct sctp_association, asocs);
 
 			sctp_addip_addr_config(asoc,
 					       SCTP_PARAM_ADD_IP,
@@ -485,9 +487,9 @@
 int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
 {
 	struct sctp_opt *sp = sctp_sk(sk);
-	sctp_endpoint_t *ep = sp->ep;
+	struct sctp_endpoint *ep = sp->ep;
 	int cnt;
-	sctp_bind_addr_t *bp = &ep->base.bind_addr;
+	struct sctp_bind_addr *bp = &ep->base.bind_addr;
 	int retval = 0;
 	union sctp_addr saveaddr;
 
@@ -566,16 +568,16 @@
 	 * ADDIP code.
 	 * 							--daisy
 	 */
-#if CONFIG_IP_SCTP_ADDIP
+#ifdef CONFIG_IP_SCTP_ADDIP
 	/* Remove these addresses from all associations on this endpoint.  */
 	if (retval >= 0) {
 		struct list_head *pos;
-		sctp_endpoint_t *ep;
-		sctp_association_t *asoc;
+		struct sctp_endpoint *ep;
+		struct sctp_association *asoc;
 
 		ep = sctp_sk(sk)->ep;
 		list_for_each(pos, &ep->asocs) {
-			asoc = list_entry(pos, sctp_association_t, asocs);
+			asoc = list_entry(pos, struct sctp_association, asocs);
 			sctp_addip_addr_config(asoc, SCTP_PARAM_DEL_IP,
 					       addrs, addrcnt);
 		}
@@ -637,7 +639,7 @@
 
 	/* Alloc space for the address array in kernel memory.  */
 	kaddrs = (struct sockaddr_storage *) kmalloc(addrssize, GFP_KERNEL);
-	if (unlikely(NULL == kaddrs))
+	if (unlikely(!kaddrs))
 		return -ENOMEM;
 
 	if (copy_from_user(kaddrs, addrs, addrssize)) {
@@ -670,14 +672,45 @@
  *
  * If sd in the close() call is a branched-off socket representing only
  * one association, the shutdown is performed on that association only.
+ *
+ * 4.1.6 close() - TCP Style Syntax
+ *
+ * Applications use close() to gracefully close down an association.
+ *
+ * The syntax is:
+ *
+ *    int close(int sd);
+ *
+ *      sd      - the socket descriptor of the association to be closed.
+ *
+ * After an application calls close() on a socket descriptor, no further
+ * socket operations will succeed on that descriptor.
+ *
+ * API 7.1.4 SO_LINGER
+ *
+ * An application using the TCP-style socket can use this option to
+ * perform the SCTP ABORT primitive.  The linger option structure is:
+ *
+ *  struct  linger {
+ *     int     l_onoff;                // option on/off
+ *     int     l_linger;               // linger time
+ * };
+ *
+ * To enable the option, set l_onoff to 1.  If the l_linger value is set
+ * to 0, calling close() is the same as the ABORT primitive.  If the
+ * value is set to a negative value, the setsockopt() call will return
+ * an error.  If the value is set to a positive value linger_time, the
+ * close() can be blocked for at most linger_time ms.  If the graceful
+ * shutdown phase does not finish during this period, close() will
+ * return but the graceful shutdown phase continues in the system.
  */
 SCTP_STATIC void sctp_close(struct sock *sk, long timeout)
 {
-	sctp_endpoint_t *ep;
-	sctp_association_t *asoc;
+	struct sctp_endpoint *ep;
+	struct sctp_association *asoc;
 	struct list_head *pos, *temp;
 
-	SCTP_DEBUG_PRINTK("sctp_close(sk: 0x%p...)\n", sk);
+	printk("sctp_close(sk: 0x%p, timeout:%ld)\n", sk, timeout);
 
 	sctp_lock_sock(sk);
 	sk->shutdown = SHUTDOWN_MASK;
@@ -686,14 +719,35 @@
 
 	/* Walk all associations on a socket, not on an endpoint.  */
 	list_for_each_safe(pos, temp, &ep->asocs) {
-		asoc = list_entry(pos, sctp_association_t, asocs);
-		sctp_primitive_SHUTDOWN(asoc, NULL);
+		asoc = list_entry(pos, struct sctp_association, asocs);
+
+		if (sctp_style(sk, TCP)) {
+			/* A closed association can still be in the list if
+			 * it belongs to a TCP-style listening socket that is
+			 * not yet accepted. If so, free it. If not, send an
+			 * ABORT or SHUTDOWN based on the linger options.
+			 */
+			if (sctp_state(asoc, CLOSED)) {
+				sctp_unhash_established(asoc);
+				sctp_association_free(asoc);
+
+			} else if (test_bit(SOCK_LINGER, &sk->flags) &&
+				   !sk->lingertime)
+				sctp_primitive_ABORT(asoc, NULL);
+			else
+				sctp_primitive_SHUTDOWN(asoc, NULL);
+		} else
+			sctp_primitive_SHUTDOWN(asoc, NULL);
 	}
 
 	/* Clean up any skbs sitting on the receive queue.  */
 	skb_queue_purge(&sk->receive_queue);
 	skb_queue_purge(&sctp_sk(sk)->pd_lobby);
 
+	/* On a TCP-style socket, block for at most linger_time if set. */
+	if (sctp_style(sk, TCP) && timeout)
+		sctp_wait_for_close(sk, timeout);
+
 	/* This will run the backlog queue.  */
 	sctp_release_sock(sk);
 
@@ -717,6 +771,16 @@
 	SCTP_DBG_OBJCNT_DEC(sock);
 }
 
+/* Handle EPIPE error. */
+static int sctp_error(struct sock *sk, int flags, int err)
+{
+	if (err == -EPIPE)
+		err = sock_error(sk) ? : -EPIPE;
+	if (err == -EPIPE && !(flags & MSG_NOSIGNAL))
+		send_sig(SIGPIPE, current, 0);
+	return err;
+}
+
 /* API 3.1.3 sendmsg() - UDP Style Syntax
  *
  * An application uses sendmsg() and recvmsg() calls to transmit data to
@@ -746,10 +810,10 @@
 			     struct msghdr *msg, int msg_len)
 {
 	struct sctp_opt *sp;
-	sctp_endpoint_t *ep;
-	sctp_association_t *new_asoc=NULL, *asoc=NULL;
-	struct sctp_transport *transport;
-	sctp_chunk_t *chunk = NULL;
+	struct sctp_endpoint *ep;
+	struct sctp_association *new_asoc=NULL, *asoc=NULL;
+	struct sctp_transport *transport, *chunk_tp;
+	struct sctp_chunk *chunk;
 	union sctp_addr to;
 	struct sockaddr *msg_name = NULL;
 	struct sctp_sndrcvinfo default_sinfo = { 0 };
@@ -761,7 +825,9 @@
 	sctp_scope_t scope;
 	long timeo;
 	__u16 sinfo_flags = 0;
-	struct sk_buff_head chunks;
+	struct sctp_datamsg *datamsg;
+	struct list_head *pos;
+	int msg_flags = msg->msg_flags;
 
 	SCTP_DEBUG_PRINTK("sctp_sendmsg(sk: %p, msg: %p, msg_len: %d)\n",
 			  sk, msg, msg_len);
@@ -772,6 +838,12 @@
 
 	SCTP_DEBUG_PRINTK("Using endpoint: %s.\n", ep->debug_name);
 
+	/* We cannot send a message over a TCP-style listening socket. */
+	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING)) {
+		err = -EPIPE;
+		goto out_nounlock;
+	}
+
 	/* Parse out the SCTP CMSGs.  */
 	err = sctp_msghdr_parse(msg, &cmsgs);
 
@@ -785,7 +857,7 @@
 	 * the address we will send to.
 	 * For a peeled-off socket, msg_name is ignored.
 	 */
-	if ((SCTP_SOCKET_UDP_HIGH_BANDWIDTH != sp->type) && msg->msg_name) {
+	if (!sctp_style(sk, UDP_HIGH_BANDWIDTH) && msg->msg_name) {
 		int msg_namelen = msg->msg_namelen;
 
 		err = sctp_verify_addr(sk, (union sctp_addr *)msg->msg_name,
@@ -816,6 +888,12 @@
 	SCTP_DEBUG_PRINTK("msg_len: %Zd, sinfo_flags: 0x%x\n",
 			  msg_len, sinfo_flags);
 
+	/* MSG_EOF or MSG_ABORT cannot be set on a TCP-style socket. */
+	if (sctp_style(sk, TCP) && (sinfo_flags & (MSG_EOF | MSG_ABORT))) {
+		err = -EINVAL;
+		goto out_nounlock;
+	}
+
 	/* If MSG_EOF is set, no data can be sent. Disallow sending zero
 	 * length messages when MSG_EOF|MSG_ABORT is not set.
 	 * If MSG_ABORT is set, the message length could be non zero with
@@ -827,22 +905,33 @@
 		goto out_nounlock;
 	}
 
-	sctp_lock_sock(sk);
+	/* If MSG_ADDR_OVER is set, there must be an address
+	 * specified in msg_name.
+	 */
+	if ((sinfo_flags & MSG_ADDR_OVER) && (!msg->msg_name)) {
+		err = -EINVAL;
+		goto out_nounlock;
+	}
 
 	transport = NULL;
 
 	SCTP_DEBUG_PRINTK("About to look up association.\n");
 
+	sctp_lock_sock(sk);
+
 	/* If a msg_name has been specified, assume this is to be used.  */
 	if (msg_name) {
 		/* Look for a matching association on the endpoint. */
 		asoc = sctp_endpoint_lookup_assoc(ep, &to, &transport);
 		if (!asoc) {
 			/* If we could not find a matching association on the
-			 * endpoint, make sure that there is no peeled-off
-			 * association on another socket.
+			 * endpoint, make sure that it is not a TCP-style
+			 * socket that already has an association or there is
+			 * no peeled-off association on another socket.
 			 */
-			if (sctp_endpoint_is_peeled_off(ep, &to)) {
+			if ((sctp_style(sk, TCP) &&
+			     sctp_sstate(sk, ESTABLISHED)) ||
+			    sctp_endpoint_is_peeled_off(ep, &to)) {
 				err = -EADDRNOTAVAIL;
 				goto out_unlock;
 			}
@@ -850,14 +939,24 @@
 	} else {
 		asoc = sctp_id2assoc(sk, associd);
 		if (!asoc) {
-			err = -EINVAL;
+			err = -EPIPE;
 			goto out_unlock;
 		}
 	}
 
 	if (asoc) {
-		SCTP_DEBUG_PRINTK("Just looked up association: "
-				  "%s. \n", asoc->debug_name);
+		SCTP_DEBUG_PRINTK("Just looked up association: %p.\n", asoc);
+
+		/* We cannot send a message on a TCP-style SCTP_SS_ESTABLISHED
+		 * socket that has an association in CLOSED state. This can
+		 * happen when an accepted socket has an association that is
+		 * already CLOSED.
+		 */
+		if (sctp_state(asoc, CLOSED) && sctp_style(sk, TCP)) {
+			err = -EPIPE;
+			goto out_unlock;
+		}
+
 		if (sinfo_flags & MSG_EOF) {
 			SCTP_DEBUG_PRINTK("Shutting down association: %p\n",
 					  asoc);
@@ -1004,69 +1103,76 @@
 			goto out_free;
 	}
 
-	/* Break the message into multiple chunks of maximum size. */
-	skb_queue_head_init(&chunks);
-	err = sctp_datachunks_from_user(asoc, sinfo, msg, msg_len, &chunks);
-	if (err)
-		goto out_free;
+	/* If an address is passed with the sendto/sendmsg call, it is used
+	 * to override the primary destination address in the TCP model, or
+	 * when MSG_ADDR_OVER flag is set in the UDP model.
+	 */
+	if ((sctp_style(sk, TCP) && msg_name) ||
+	    (sinfo_flags & MSG_ADDR_OVER)) {
+		chunk_tp = sctp_assoc_lookup_paddr(asoc, &to);
+		if (!chunk_tp) {
+			err = -EINVAL;
+			goto out_free;
+		}
+	} else
+		chunk_tp = NULL;
 
 	/* Auto-connect, if we aren't connected already. */
-	if (SCTP_STATE_CLOSED == asoc->state) {
+	if (sctp_state(asoc, CLOSED)) {
 		err = sctp_primitive_ASSOCIATE(asoc, NULL);
 		if (err < 0)
 			goto out_free;
 		SCTP_DEBUG_PRINTK("We associated primitively.\n");
 	}
 
+	/* Break the message into multiple chunks of maximum size. */
+	datamsg = sctp_datamsg_from_user(asoc, sinfo, msg, msg_len);
+	if (!datamsg) {
+		err = -ENOMEM;
+		goto out_free;
+	}
+
 	/* Now send the (possibly) fragmented message. */
-	while ((chunk = (sctp_chunk_t *)__skb_dequeue(&chunks))) {
+	list_for_each(pos, &datamsg->chunks) {
+		chunk = list_entry(pos, struct sctp_chunk, frag_list);
+		sctp_datamsg_track(chunk);
 
 		/* Do accounting for the write space.  */
 		sctp_set_owner_w(chunk);
 
-		/* This flag, in the UDP model, requests the SCTP stack to
-		 * override the primary destination address with the
-		 * address found with the sendto/sendmsg call.
-		 */
-		if (sinfo_flags & MSG_ADDR_OVER) {
-			if (!msg->msg_name) {
-				err = -EINVAL;
-				goto out_free;
-			}
-			chunk->transport = sctp_assoc_lookup_paddr(asoc, &to);
-			if (!chunk->transport) {
-				err = -EINVAL;
-				goto out_free;
-			}
-		}
+		chunk->transport = chunk_tp;
 
-		/* Send it to the lower layers.  */
-		sctp_primitive_SEND(asoc, chunk);
+		/* Send it to the lower layers.  Note:  all chunks
+		 * must either fail or succeed.   The lower layer
+		 * works that way today.  Keep it that way or this
+		 * breaks.
+		 */
+		err = sctp_primitive_SEND(asoc, chunk);
+		/* Did the lower layer accept the chunk? */
+		if (err)
+			sctp_chunk_free(chunk);
 		SCTP_DEBUG_PRINTK("We sent primitively.\n");
 	}
 
-	if (!err) {
+	sctp_datamsg_free(datamsg);
+	if (err)
+		goto out_free;
+	else
 		err = msg_len;
-		goto out_unlock;
-	}
+
 	/* If we are already past ASSOCIATE, the lower
 	 * layers are responsible for association cleanup.
 	 */
-	goto out_free_chunk;
+	goto out_unlock;
 
 out_free:
 	if (new_asoc)
 		sctp_association_free(asoc);
-
-out_free_chunk:
-	if (chunk)
-		sctp_free_chunk(chunk);
-
 out_unlock:
 	sctp_release_sock(sk);
 
 out_nounlock:
-	return err;
+	return sctp_error(sk, msg_flags, err);
 
 #if 0
 do_sock_err:
@@ -1134,8 +1240,9 @@
  */
 static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
 
-SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
-			     int len, int noblock, int flags, int *addr_len)
+SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
+			     struct msghdr *msg, int len, int noblock,
+			     int flags, int *addr_len)
 {
 	struct sctp_ulpevent *event = NULL;
 	struct sctp_opt *sp = sctp_sk(sk);
@@ -1151,12 +1258,11 @@
 
 	sctp_lock_sock(sk);
 
-	if ((SCTP_SOCKET_TCP == sp->type) &&
-	    (SCTP_SS_ESTABLISHED != sk->state)) {
+	if (sctp_style(sk, TCP) && !sctp_sstate(sk, ESTABLISHED)) {
 		err = -ENOTCONN;
 		goto out;
 	}
-	
+
 	skb = sctp_skb_recv_datagram(sk, flags, noblock, &err);
 	if (!skb)
 		goto out;
@@ -1259,7 +1365,7 @@
 	struct sctp_opt *sp = sctp_sk(sk);
 
 	/* Applicable to UDP-style socket only */
-	if (SCTP_SOCKET_TCP == sp->type)
+	if (sctp_style(sk, TCP))
 		return -EOPNOTSUPP;
 	if (optlen != sizeof(int))
 		return -EINVAL;
@@ -1271,10 +1377,10 @@
 }
 
 static int sctp_setsockopt_peer_addr_params(struct sock *sk,
-						   char *optval, int optlen)
+					    char *optval, int optlen)
 {
 	struct sctp_paddrparams params;
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	union sctp_addr *addr;
 	struct sctp_transport *trans;
 	int error;
@@ -1329,8 +1435,7 @@
 	return 0;
 }
 
-static int sctp_setsockopt_initmsg(struct sock *sk, char *optval,
-					  int optlen)
+static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen)
 {
 	if (optlen != sizeof(struct sctp_initmsg))
 		return -EINVAL;
@@ -1340,7 +1445,6 @@
 }
 
 /*
- *
  * 7.1.15 Set default send parameters (SET_DEFAULT_SEND_PARAM)
  *
  *   Applications that wish to use the sendto() system call may wish to
@@ -1358,7 +1462,7 @@
 						char *optval, int optlen)
 {
 	struct sctp_sndrcvinfo info;
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
 	if (optlen != sizeof(struct sctp_sndrcvinfo))
 		return -EINVAL;
@@ -1413,7 +1517,6 @@
 }
 
 /*
- *
  * 7.1.5 SCTP_NODELAY
  *
  * Turn on/off any Nagle-like algorithm.  This means that packets are
@@ -1424,15 +1527,61 @@
 static int sctp_setsockopt_nodelay(struct sock *sk, char *optval,
 					int optlen)
 {
-	__u8 val;
+	int val;
 
-	if (optlen < sizeof(__u8))
+	if (optlen < sizeof(int))
 		return -EINVAL;
-
-	if (get_user(val, (__u8 *)optval))
+	if (get_user(val, (int *)optval))
 		return -EFAULT;
 
 	sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1;
+	return 0;
+}
+
+/*
+ * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
+ *
+ * This socket option is a boolean flag which turns on or off mapped V4
+ * addresses.  If this option is turned on and the socket is type
+ * PF_INET6, then IPv4 addresses will be mapped to V6 representation.
+ * If this option is turned off, then no mapping will be done of V4
+ * addresses and a user will receive both PF_INET6 and PF_INET type
+ * addresses on the socket.
+ */
+static int sctp_setsockopt_mappedv4(struct sock *sk, char *optval, int optlen)
+{
+	int val;
+
+	if (optlen < sizeof(int))
+		return -EINVAL;
+	if (get_user(val, (int *)optval))
+		return -EFAULT;
+	/* FIXME: Put real support here. */
+
+	return -ENOPROTOOPT;
+}
+
+/*
+ * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
+ *
+ * This socket option specifies the maximum size to put in any outgoing
+ * SCTP chunk.  If a message is larger than this size it will be
+ * fragmented by SCTP into the specified size.  Note that the underlying
+ * SCTP implementation may fragment into smaller sized chunks when the
+ * PMTU of the underlying association is smaller than the value set by
+ * the user.
+ */
+static int sctp_setsockopt_maxseg(struct sock *sk, char *optval, int optlen)
+{
+	int val;
+
+	if (optlen < sizeof(int))
+		return -EINVAL;
+	if (get_user(val, (int *)optval))
+		return -EFAULT;
+	if ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))
+		return -EINVAL;
+	sctp_sk(sk)->user_frag = val;
 
 	return 0;
 }
@@ -1526,20 +1675,22 @@
 	case SCTP_INITMSG:
 		retval = sctp_setsockopt_initmsg(sk, optval, optlen);
 		break;
-
 	case SCTP_SET_DEFAULT_SEND_PARAM:
 		retval = sctp_setsockopt_default_send_param(sk, optval,
 							    optlen);
 		break;
-
 	case SCTP_SET_PEER_PRIMARY_ADDR:
 		retval = sctp_setsockopt_peer_prim(sk, optval, optlen);
 		break;
-
 	case SCTP_NODELAY:
 		retval = sctp_setsockopt_nodelay(sk, optval, optlen);
 		break;
-
+	case SCTP_I_WANT_MAPPED_V4_ADDR:
+		retval = sctp_setsockopt_mappedv4(sk, optval, optlen);
+		break;
+	case SCTP_MAXSEG:
+		retval = sctp_setsockopt_maxseg(sk, optval, optlen);
+		break;
 	default:
 		retval = -ENOPROTOOPT;
 		break;
@@ -1572,10 +1723,11 @@
 			     int addr_len)
 {
 	struct sctp_opt *sp;
-	sctp_endpoint_t *ep;
-	sctp_association_t *asoc;
+	struct sctp_endpoint *ep;
+	struct sctp_association *asoc;
 	struct sctp_transport *transport;
 	union sctp_addr to;
+	struct sctp_af *af;
 	sctp_scope_t scope;
 	long timeo;
 	int err = 0;
@@ -1590,12 +1742,11 @@
 
 	/* connect() cannot be done on a socket that is already in ESTABLISHED
 	 * state - UDP-style peeled off socket or a TCP-style socket that
-	 * is already connected. 
+	 * is already connected.
 	 * It cannot be done even on a TCP-style listening socket.
 	 */
-	if ((SCTP_SS_ESTABLISHED == sk->state) ||
-	    ((SCTP_SOCKET_TCP == sp->type) &&
-	     (SCTP_SS_LISTENING == sk->state))) {
+	if (sctp_sstate(sk, ESTABLISHED) ||
+	    (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))) {
 		err = -EISCONN;
 		goto out_unlock;
 	}
@@ -1663,6 +1814,11 @@
 		goto out_unlock;
 	}
 
+	/* Initialize sk's dport and daddr for getpeername() */
+	inet_sk(sk)->dport = htons(asoc->peer.port);
+	af = sctp_get_af_specific(to.sa.sa_family);
+	af->to_sk_daddr(&to, sk);
+
 	timeo = sock_sndtimeo(sk, sk->socket->file->f_flags & O_NONBLOCK);
 	err = sctp_wait_for_connect(asoc, &timeo);
 
@@ -1690,21 +1846,21 @@
 	struct sctp_opt *sp;
 	struct sctp_endpoint *ep;
 	struct sock *newsk = NULL;
-	struct sctp_association *assoc;
+	struct sctp_association *asoc;
 	long timeo;
 	int error = 0;
- 
+
 	sctp_lock_sock(sk);
 
 	sp = sctp_sk(sk);
 	ep = sp->ep;
 
-	if (SCTP_SOCKET_TCP != sp->type) {
+	if (!sctp_style(sk, TCP)) {
 		error = -EOPNOTSUPP;
 		goto out;
 	}
 
-	if (SCTP_SS_LISTENING != sk->state) {
+	if (!sctp_sstate(sk, LISTENING)) {
 		error = -EINVAL;
 		goto out;
 	}
@@ -1715,21 +1871,21 @@
 	if (error)
 		goto out;
 
-	/* We treat the list of associations on the endpoint as the accept 
-	 * queue and pick the first association on the list. 
+	/* We treat the list of associations on the endpoint as the accept
+	 * queue and pick the first association on the list.
 	 */
-	assoc = list_entry(ep->asocs.next, struct sctp_association, asocs);
+	asoc = list_entry(ep->asocs.next, struct sctp_association, asocs);
 
-	newsk = sp->pf->create_accept_sk(sk, assoc); 
+	newsk = sp->pf->create_accept_sk(sk, asoc);
 	if (!newsk) {
 		error = -ENOMEM;
 		goto out;
 	}
 
 	/* Populate the fields of the newsk from the oldsk and migrate the
-	 * assoc to the newsk.
-	 */ 
-	sctp_sock_migrate(sk, newsk, assoc, SCTP_SOCKET_TCP);
+	 * asoc to the newsk.
+	 */
+	sctp_sock_migrate(sk, newsk, asoc, SCTP_SOCKET_TCP);
 
 out:
 	sctp_release_sock(sk);
@@ -1737,10 +1893,10 @@
 	return newsk;
 }
 
-/* FIXME: Write Comments. */
+/* The SCTP ioctl handler. */
 SCTP_STATIC int sctp_ioctl(struct sock *sk, int cmd, unsigned long arg)
 {
-	return -EOPNOTSUPP; /* STUB */
+	return -ENOIOCTLCMD;
 }
 
 /* This is the function which gets called during socket creation to
@@ -1749,7 +1905,7 @@
  */
 SCTP_STATIC int sctp_init_sock(struct sock *sk)
 {
-	sctp_endpoint_t *ep;
+	struct sctp_endpoint *ep;
 	struct sctp_protocol *proto;
 	struct sctp_opt *sp;
 
@@ -1800,7 +1956,7 @@
 	 * enable the events needed.  By default, UDP-style
 	 * sockets enable io and association change notifications.
 	 */
-	if (SCTP_SOCKET_UDP == sp->type) {
+	if (sctp_style(sk, UDP)) {
 		sp->subscribe.sctp_data_io_event     = 1;
 		sp->subscribe.sctp_association_event = 1;
 	}
@@ -1819,12 +1975,19 @@
 	/* Turn on/off any Nagle-like algorithm.  */
 	sp->nodelay           = 1;
 
+	/* Enable by default. */
+	sp->v4mapped          = 1;
+
 	/* Auto-close idle associations after the configured
 	 * number of seconds.  A value of 0 disables this
 	 * feature.  Configure through the SCTP_AUTOCLOSE socket option,
 	 * for UDP-style sockets only.
 	 */
 	sp->autoclose         = 0;
+
+	/* User specified fragmentation limit. */
+	sp->user_frag         = 0;
+
 	sp->pf = sctp_get_pf_specific(sk->family);
 
 	/* Control variables for partial data delivery. */
@@ -1835,11 +1998,12 @@
 	 * change the data structure relationships, this may still
 	 * be useful for storing pre-connect address information.
 	 */
-	ep = sctp_endpoint_new(proto, sk, GFP_KERNEL);
-	if (NULL == ep)
+	ep = sctp_endpoint_new(sk, GFP_KERNEL);
+	if (!ep)
 		return -ENOMEM;
 
 	sp->ep = ep;
+	sp->hmac = NULL;
 
 	SCTP_DBG_OBJCNT_INC(sock);
 	return 0;
@@ -1848,7 +2012,7 @@
 /* Cleanup any SCTP per socket resources.  */
 SCTP_STATIC int sctp_destroy_sock(struct sock *sk)
 {
-	sctp_endpoint_t *ep;
+	struct sctp_endpoint *ep;
 
 	SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk);
 
@@ -1859,11 +2023,38 @@
 	return 0;
 }
 
-/* FIXME: Comments needed.  */
+/* API 4.1.7 shutdown() - TCP Style Syntax
+ *     int shutdown(int socket, int how);
+ *
+ *     sd      - the socket descriptor of the association to be closed.
+ *     how     - Specifies the type of shutdown.  The  values  are
+ *               as follows:
+ *               SHUT_RD
+ *                     Disables further receive operations. No SCTP
+ *                     protocol action is taken.
+ *               SHUT_WR
+ *                     Disables further send operations, and initiates
+ *                     the SCTP shutdown sequence.
+ *               SHUT_RDWR
+ *                     Disables further send  and  receive  operations
+ *                     and initiates the SCTP shutdown sequence.
+ */
 SCTP_STATIC void sctp_shutdown(struct sock *sk, int how)
 {
-	/* UDP-style sockets do not support shutdown. */
-	/* STUB */
+	struct sctp_endpoint *ep;
+	struct sctp_association *asoc;
+
+	if (!sctp_style(sk, TCP))
+		return;
+
+	if (how & SEND_SHUTDOWN) {
+		ep = sctp_sk(sk)->ep;
+		if (!list_empty(&ep->asocs)) {
+			asoc = list_entry(ep->asocs.next,
+					  struct sctp_association, asocs);
+			sctp_primitive_SHUTDOWN(asoc, NULL);
+		}
+	}
 }
 
 /* 7.2.1 Association Status (SCTP_STATUS)
@@ -1877,7 +2068,7 @@
 				       int *optlen)
 {
 	struct sctp_status status;
-	sctp_association_t *assoc = NULL;
+	struct sctp_association *asoc = NULL;
 	struct sctp_transport *transport;
 	sctp_assoc_t associd;
 	int retval = 0;
@@ -1893,22 +2084,26 @@
 	}
 
 	associd = status.sstat_assoc_id;
-	assoc = sctp_id2assoc(sk, associd);
-	if (!assoc) {
+	asoc = sctp_id2assoc(sk, associd);
+	if (!asoc) {
 		retval = -EINVAL;
 		goto out;
 	}
 
-	transport = assoc->peer.primary_path;
+	transport = asoc->peer.primary_path;
 
-	status.sstat_assoc_id = sctp_assoc2id(assoc);
-	status.sstat_state = assoc->state;
-	status.sstat_rwnd =  assoc->peer.rwnd;
-	status.sstat_unackdata = assoc->unack_data;
-	status.sstat_penddata = assoc->peer.tsn_map.pending_data;
-	status.sstat_instrms = assoc->c.sinit_max_instreams;
-	status.sstat_outstrms = assoc->c.sinit_num_ostreams;
-	status.sstat_fragmentation_point = assoc->frag_point;
+	status.sstat_assoc_id = sctp_assoc2id(asoc);
+	status.sstat_state = asoc->state;
+	status.sstat_rwnd =  asoc->peer.rwnd;
+	status.sstat_unackdata = asoc->unack_data;
+	status.sstat_penddata = asoc->peer.tsn_map.pending_data;
+	status.sstat_instrms = asoc->c.sinit_max_instreams;
+	status.sstat_outstrms = asoc->c.sinit_num_ostreams;
+	/* Just in time frag_point update. */
+	if (sctp_sk(sk)->user_frag)
+		asoc->frag_point
+			= min_t(int, asoc->frag_point, sctp_sk(sk)->user_frag);
+	status.sstat_fragmentation_point = asoc->frag_point;
 	status.sstat_primary.spinfo_assoc_id = sctp_assoc2id(transport->asoc);
 	memcpy(&status.sstat_primary.spinfo_address,
 	       &(transport->ipaddr), sizeof(union sctp_addr));
@@ -1965,7 +2160,7 @@
 static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen)
 {
 	/* Applicable to UDP-style socket only */
-	if (SCTP_SOCKET_TCP == sctp_sk(sk)->type)
+	if (sctp_style(sk, TCP))
 		return -EOPNOTSUPP;
 	if (len != sizeof(int))
 		return -EINVAL;
@@ -1975,33 +2170,29 @@
 }
 
 /* Helper routine to branch off an association to a new socket.  */
-SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newsock)
+SCTP_STATIC int sctp_do_peeloff(struct sctp_association *asoc,
+				struct socket **sockp)
 {
-	struct sock *oldsk = assoc->base.sk;
-	struct sock *newsk;
-	struct socket *tmpsock;
+	struct sock *sk = asoc->base.sk;
+	struct socket *sock;
 	int err = 0;
 
 	/* An association cannot be branched off from an already peeled-off
 	 * socket, nor is this supported for tcp style sockets.
 	 */
-	if (SCTP_SOCKET_UDP != sctp_sk(oldsk)->type)
-		return -EOPNOTSUPP;
+	if (!sctp_style(sk, UDP))
+		return -EINVAL;
 
 	/* Create a new socket.  */
-	err = sock_create(oldsk->family, SOCK_SEQPACKET, IPPROTO_SCTP,
-			  &tmpsock);
+	err = sock_create(sk->family, SOCK_SEQPACKET, IPPROTO_SCTP, &sock);
 	if (err < 0)
 		return err;
 
-	newsk = tmpsock->sk;
-
 	/* Populate the fields of the newsk from the oldsk and migrate the
-	 * assoc to the newsk.
-	 */ 
-	sctp_sock_migrate(oldsk, newsk, assoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
-
-	*newsock = tmpsock;
+	 * asoc to the newsk.
+	 */
+	sctp_sock_migrate(sk, sock->sk, asoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH);
+	*sockp = sock;
 
 	return err;
 }
@@ -2011,22 +2202,22 @@
 	sctp_peeloff_arg_t peeloff;
 	struct socket *newsock;
 	int retval = 0;
-	sctp_association_t *assoc;
+	struct sctp_association *asoc;
 
 	if (len != sizeof(sctp_peeloff_arg_t))
 		return -EINVAL;
 	if (copy_from_user(&peeloff, optval, len))
 		return -EFAULT;
 
-	assoc = sctp_id2assoc(sk, peeloff.associd);
-	if (NULL == assoc) {
+	asoc = sctp_id2assoc(sk, peeloff.associd);
+	if (!asoc) {
 		retval = -EINVAL;
 		goto out;
 	}
 
-	SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p\n", __FUNCTION__, sk, assoc);
+	SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p\n", __FUNCTION__, sk, asoc);
 
-	retval = sctp_do_peeloff(assoc, &newsock);
+	retval = sctp_do_peeloff(asoc, &newsock);
 	if (retval < 0)
 		goto out;
 
@@ -2037,8 +2228,8 @@
 		goto out;
 	}
 
-	SCTP_DEBUG_PRINTK("%s: sk: %p assoc: %p newsk: %p sd: %d\n",
-			  __FUNCTION__, sk, assoc, newsock->sk, retval);
+	SCTP_DEBUG_PRINTK("%s: sk: %p asoc: %p newsk: %p sd: %d\n",
+			  __FUNCTION__, sk, asoc, newsock->sk, retval);
 
 	/* Return the fd mapped to the new socket.  */
 	peeloff.sd = retval;
@@ -2049,11 +2240,11 @@
 	return retval;
 }
 
-static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, 
+static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
 						char *optval, int *optlen)
 {
 	struct sctp_paddrparams params;
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	union sctp_addr *addr;
 	struct sctp_transport *trans;
 
@@ -2088,7 +2279,9 @@
 
 	if (copy_to_user(optval, &params, len))
 		return -EFAULT;
-	*optlen = len;
+
+	if (put_user(len, optlen))
+		return -EFAULT;
 
 	return 0;
 }
@@ -2102,11 +2295,11 @@
 	return 0;
 }
 
-static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len, 
+static int sctp_getsockopt_peer_addrs_num(struct sock *sk, int len,
 					char *optval, int *optlen)
 {
 	sctp_assoc_t id;
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	struct list_head *pos;
 	int cnt = 0;
 
@@ -2135,7 +2328,7 @@
 static int sctp_getsockopt_peer_addrs(struct sock *sk, int len,
 				char *optval, int *optlen)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	struct list_head *pos;
 	int cnt = 0;
 	struct sctp_getaddrs getaddrs;
@@ -2176,8 +2369,8 @@
 						char *optval, int *optlen)
 {
 	sctp_assoc_t id;
-	sctp_bind_addr_t *bp;
-	sctp_association_t *asoc;
+	struct sctp_bind_addr *bp;
+	struct sctp_association *asoc;
 	struct list_head *pos;
 	int cnt = 0;
 
@@ -2214,8 +2407,8 @@
 static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
 					char *optval, int *optlen)
 {
-	sctp_bind_addr_t *bp;
-	sctp_association_t *asoc;
+	struct sctp_bind_addr *bp;
+	struct sctp_association *asoc;
 	struct list_head *pos;
 	int cnt = 0;
 	struct sctp_getaddrs getaddrs;
@@ -2317,7 +2510,7 @@
 					int len, char *optval, int *optlen)
 {
 	struct sctp_sndrcvinfo info;
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 
 	if (len != sizeof(struct sctp_sndrcvinfo))
 		return -EINVAL;
@@ -2350,15 +2543,15 @@
  * integer boolean flag.
  */
 
-static int sctp_getsockopt_nodelay(struct sock *sk, int len, 
-					char *optval, int *optlen)
+static int sctp_getsockopt_nodelay(struct sock *sk, int len,
+				   char *optval, int *optlen)
 {
-	__u8 val;
+	int val;
 
-	if (len < sizeof(__u8))
+	if (len < sizeof(int))
 		return -EINVAL;
 
-	len = sizeof(__u8);
+	len = sizeof(int);
 	val = (sctp_sk(sk)->nodelay == 1);
 	if (put_user(len, optlen))
 		return -EFAULT;
@@ -2366,6 +2559,62 @@
 		return -EFAULT;
 	return 0;
 }
+/*
+ * 7.1.16 Set/clear IPv4 mapped addresses (SCTP_I_WANT_MAPPED_V4_ADDR)
+ *
+ * This socket option is a boolean flag which turns on or off mapped V4
+ * addresses.  If this option is turned on and the socket is type
+ * PF_INET6, then IPv4 addresses will be mapped to V6 representation.
+ * If this option is turned off, then no mapping will be done of V4
+ * addresses and a user will receive both PF_INET6 and PF_INET type
+ * addresses on the socket.
+ */
+static int sctp_getsockopt_mappedv4(struct sock *sk, int len,
+				    char *optval, int *optlen)
+{
+	int val;
+	if (len < sizeof(int))
+		return -EINVAL;
+
+	len = sizeof(int);
+	/* FIXME: Until we have support, return disabled. */
+	val = 0;
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, &val, len))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG)
+ *
+ * This socket option specifies the maximum size to put in any outgoing
+ * SCTP chunk.  If a message is larger than this size it will be
+ * fragmented by SCTP into the specified size.  Note that the underlying
+ * SCTP implementation may fragment into smaller sized chunks when the
+ * PMTU of the underlying association is smaller than the value set by
+ * the user.
+ */
+static int sctp_getsockopt_maxseg(struct sock *sk, int len,
+				  char *optval, int *optlen)
+{
+	int val;
+
+	if (len < sizeof(int))
+		return -EINVAL;
+
+	len = sizeof(int);
+
+	val = sctp_sk(sk)->user_frag;
+	if (put_user(len, optlen))
+		return -EFAULT;
+	if (copy_to_user(optval, &val, len))
+		return -EFAULT;
+
+	return 0;
+}
 
 SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
 				char *optval, int *optlen)
@@ -2418,7 +2667,7 @@
 		retval = sctp_getsockopt_initmsg(sk, len, optval, optlen);
 		break;
 	case SCTP_GET_PEER_ADDRS_NUM:
-		retval = sctp_getsockopt_peer_addrs_num(sk, len, optval, 
+		retval = sctp_getsockopt_peer_addrs_num(sk, len, optval,
 							optlen);
 		break;
 	case SCTP_GET_LOCAL_ADDRS_NUM:
@@ -2443,6 +2692,12 @@
 	case SCTP_NODELAY:
 		retval = sctp_getsockopt_nodelay(sk, len, optval, optlen);
 		break;
+	case SCTP_I_WANT_MAPPED_V4_ADDR:
+		retval = sctp_getsockopt_mappedv4(sk, len, optval, optlen);
+		break;
+	case SCTP_MAXSEG:
+		retval = sctp_getsockopt_maxseg(sk, len, optval, optlen);
+		break;
 	default:
 		retval = -ENOPROTOOPT;
 		break;
@@ -2553,7 +2808,7 @@
 	}
 
 
-	if (pp != NULL && pp->sk != NULL) {
+	if (pp && pp->sk) {
 		/* We had a port hash table hit - there is an
 		 * available port (pp != NULL) and it is being
 		 * used by other socket (pp->sk != NULL); that other
@@ -2578,7 +2833,7 @@
 		 * in an endpoint.
 		 */
 		for ( ; sk2 != NULL; sk2 = sk2->bind_next) {
-			sctp_endpoint_t *ep2;
+			struct sctp_endpoint *ep2;
 			ep2 = sctp_sk(sk2)->ep;
 
 			if (sk_reuse && sk2->reuse)
@@ -2601,18 +2856,17 @@
 	/* If there was a hash table miss, create a new port.  */
 	ret = 1;
 
-	if (pp == NULL && (pp = sctp_bucket_create(head, snum)) == NULL)
+	if (!pp && !(pp = sctp_bucket_create(head, snum)))
 		goto fail_unlock;
 
 	/* In either case (hit or miss), make sure fastreuse is 1 only
 	 * if sk->reuse is too (that is, if the caller requested
 	 * SO_REUSEADDR on this socket -sk-).
 	 */
-	if (pp->sk == NULL) {
+	if (!pp->sk)
 		pp->fastreuse = sk->reuse ? 1 : 0;
-	} else if (pp->fastreuse && sk->reuse == 0) {
+	else if (pp->fastreuse && sk->reuse == 0)
 		pp->fastreuse = 0;
-	}
 
 	/* We are set, so fill up all the data in the hash table
 	 * entry, tie the socket list information with the rest of the
@@ -2669,15 +2923,15 @@
 SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
 {
 	struct sctp_opt *sp = sctp_sk(sk);
-	sctp_endpoint_t *ep = sp->ep;
+	struct sctp_endpoint *ep = sp->ep;
 
 	/* Only UDP style sockets that are not peeled off are allowed to
 	 * listen().
 	 */
-	if (SCTP_SOCKET_UDP != sp->type)
+	if (!sctp_style(sk, UDP))
 		return -EINVAL;
 
-	if (sk->state == SCTP_SS_LISTENING)
+	if (sctp_sstate(sk, LISTENING))
 		return 0;
 
 	/*
@@ -2702,15 +2956,15 @@
 /*
  * 4.1.3 listen() - TCP Style Syntax
  *
- *   Applications uses listen() to ready the SCTP endpoint for accepting 
+ *   Applications uses listen() to ready the SCTP endpoint for accepting
  *   inbound associations.
  */
 SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
 {
 	struct sctp_opt *sp = sctp_sk(sk);
-	sctp_endpoint_t *ep = sp->ep;
+	struct sctp_endpoint *ep = sp->ep;
 
-	if (sk->state == SCTP_SS_LISTENING)
+	if (sctp_sstate(sk, LISTENING))
 		return 0;
 
 	/*
@@ -2739,15 +2993,25 @@
 int sctp_inet_listen(struct socket *sock, int backlog)
 {
 	struct sock *sk = sock->sk;
-	int err;
+	struct crypto_tfm *tfm=NULL;
+	int err = -EINVAL;
+
+	if (unlikely(backlog < 0))
+		goto out;
 
 	sctp_lock_sock(sk);
 
-	err = -EINVAL;
 	if (sock->state != SS_UNCONNECTED)
 		goto out;
-	if (unlikely(backlog < 0))
-		goto out;
+
+	/* Allocate HMAC for generating cookie. */
+	if (sctp_hmac_alg) {
+		tfm = sctp_crypto_alloc_tfm(sctp_hmac_alg, 0);
+		if (!tfm) {
+			err = -ENOSYS;
+			goto out;
+		}
+	}
 
 	switch (sock->type) {
 	case SOCK_SEQPACKET:
@@ -2756,14 +3020,21 @@
 	case SOCK_STREAM:
 		err = sctp_stream_listen(sk, backlog);
 		break;
-
 	default:
-		goto out;
+		break;
 	};
+	if (err)
+		goto cleanup;
 
+	/* Store away the transform reference. */
+	sctp_sk(sk)->hmac = tfm;
 out:
 	sctp_release_sock(sk);
 	return err;
+cleanup:
+	if (tfm)
+		sctp_crypto_free_tfm(tfm);
+	goto out;
 }
 
 /*
@@ -2782,9 +3053,18 @@
 unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait)
 {
 	struct sock *sk = sock->sk;
+	struct sctp_opt *sp = sctp_sk(sk);
 	unsigned int mask;
 
 	poll_wait(file, sk->sleep, wait);
+
+	/* A TCP-style listening socket becomes readable when the accept queue
+	 * is not empty.
+	 */
+	if (sctp_style(sk, TCP) && sctp_sstate(sk, LISTENING))
+		return (!list_empty(&sp->ep->asocs)) ?
+		       	(POLLIN | POLLRDNORM) : 0;
+
 	mask = 0;
 
 	/* Is there any exceptional events?  */
@@ -2798,19 +3078,9 @@
 	    (sk->shutdown & RCV_SHUTDOWN))
 		mask |= POLLIN | POLLRDNORM;
 
-	/*
-	 * FIXME: We need to set SCTP_SS_DISCONNECTING for TCP-style and
-	 * peeled off sockets.  Additionally, TCP-style needs to consider
-	 * other establishment conditions.
-	 */
-	if (SCTP_SOCKET_UDP != sctp_sk(sk)->type) {
-		/* The association is going away.  */
-		if (SCTP_SS_DISCONNECTING == sk->state)
-			mask |= POLLHUP;
-		/* The association is either gone or not ready.  */
-		if (SCTP_SS_CLOSED == sk->state)
-			return mask;
-	}
+	/* The association is either gone or not ready.  */
+	if (!sctp_style(sk, UDP) && sctp_sstate(sk, CLOSED))
+		return mask;
 
 	/* Is it writable?  */
 	if (sctp_writeable(sk)) {
@@ -2967,7 +3237,7 @@
 		/* Strictly check lengths following example in SCM code.  */
 		switch (cmsg->cmsg_type) {
 		case SCTP_INIT:
-			/* SCTP Socket API Extension (draft 1)
+			/* SCTP Socket API Extension
 			 * 5.2.1 SCTP Initiation Structure (SCTP_INIT)
 			 *
 			 * This cmsghdr structure provides information for
@@ -2987,7 +3257,7 @@
 			break;
 
 		case SCTP_SNDRCV:
-			/* SCTP Socket API Extension (draft 1)
+			/* SCTP Socket API Extension
 			 * 5.2.2 SCTP Header Information Structure(SCTP_SNDRCV)
 			 *
 			 * This cmsghdr structure specifies SCTP options for
@@ -3002,7 +3272,8 @@
 			    CMSG_LEN(sizeof(struct sctp_sndrcvinfo)))
 				return -EINVAL;
 
-			cmsgs->info = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+			cmsgs->info =
+				(struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
 
 			/* Minimally, validate the sinfo_flags. */
 			if (cmsgs->info->sinfo_flags &
@@ -3026,10 +3297,9 @@
 static int sctp_wait_for_packet(struct sock * sk, int *err, long *timeo_p)
 {
 	int error;
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
-	__set_current_state(TASK_INTERRUPTIBLE);
-	add_wait_queue_exclusive(sk->sleep, &wait);
+	prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE);
 
 	/* Socket errors? */
 	error = sock_error(sk);
@@ -3049,8 +3319,7 @@
 	error = -ENOTCONN;
 
 	/* Is there a good reason to think that we may receive some data?  */
-	if ((list_empty(&sctp_sk(sk)->ep->asocs)) &&
-	    (sk->state != SCTP_SS_LISTENING))
+	if (list_empty(&sctp_sk(sk)->ep->asocs) && !sctp_sstate(sk, LISTENING))
 		goto out;
 
 	/* Handle signals.  */
@@ -3067,16 +3336,14 @@
 	sctp_lock_sock(sk);
 
 ready:
-	remove_wait_queue(sk->sleep, &wait);
-	__set_current_state(TASK_RUNNING);
+	finish_wait(sk->sleep, &wait);
 	return 0;
 
 interrupted:
 	error = sock_intr_errno(*timeo_p);
 
 out:
-	remove_wait_queue(sk->sleep, &wait);
-	__set_current_state(TASK_RUNNING);
+	finish_wait(sk->sleep, &wait);
 	*err = error;
 	return error;
 }
@@ -3085,13 +3352,14 @@
  * Note: This is pretty much the same routine as in core/datagram.c
  * with a few changes to make lksctp work.
  */
-static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int noblock, int *err)
+static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
+					      int noblock, int *err)
 {
 	int error;
 	struct sk_buff *skb;
 	long timeo;
 
-	/* Caller is allowed not to check sk->err before skb_recv_datagram()  */
+	/* Caller is allowed not to check sk->err before calling.  */
 	error = sock_error(sk);
 	if (error)
 		goto no_packet;
@@ -3126,6 +3394,9 @@
 		if (skb)
 			return skb;
 
+		if (sk->shutdown & RCV_SHUTDOWN)
+			break;
+
 		/* User doesn't want to wait.  */
 		error = -EAGAIN;
 		if (!timeo)
@@ -3140,7 +3411,7 @@
 }
 
 /* Verify that this is a valid address. */
-static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, 
+static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr,
 				   int len)
 {
 	struct sctp_af *af;
@@ -3161,7 +3432,7 @@
 }
 
 /* Get the sndbuf space available at the time on the association.  */
-static inline int sctp_wspace(sctp_association_t *asoc)
+static inline int sctp_wspace(struct sctp_association *asoc)
 {
 	struct sock *sk = asoc->base.sk;
 	int amt = 0;
@@ -3181,9 +3452,9 @@
  * destructor in the data chunk skb for the purpose of the sndbuf space
  * tracking.
  */
-static inline void sctp_set_owner_w(sctp_chunk_t *chunk)
+static inline void sctp_set_owner_w(struct sctp_chunk *chunk)
 {
-	sctp_association_t *asoc = chunk->asoc;
+	struct sctp_association *asoc = chunk->asoc;
 	struct sock *sk = asoc->base.sk;
 
 	/* The sndbuf space is tracked per association.  */
@@ -3191,14 +3462,14 @@
 
 	chunk->skb->destructor = sctp_wfree;
 	/* Save the chunk pointer in skb for sctp_wfree to use later.  */
-	*((sctp_chunk_t **)(chunk->skb->cb)) = chunk;
+	*((struct sctp_chunk **)(chunk->skb->cb)) = chunk;
 
 	asoc->sndbuf_used += SCTP_DATA_SNDSIZE(chunk);
 	sk->wmem_queued += SCTP_DATA_SNDSIZE(chunk);
 }
 
 /* If sndbuf has changed, wake up per association sndbuf waiters.  */
-static void __sctp_write_space(sctp_association_t *asoc)
+static void __sctp_write_space(struct sctp_association *asoc)
 {
 	struct sock *sk = asoc->base.sk;
 	struct socket *sock = sk->socket;
@@ -3228,12 +3499,12 @@
  */
 static void sctp_wfree(struct sk_buff *skb)
 {
-	sctp_association_t *asoc;
-	sctp_chunk_t *chunk;
+	struct sctp_association *asoc;
+	struct sctp_chunk *chunk;
 	struct sock *sk;
 
 	/* Get the saved chunk pointer.  */
-	chunk = *((sctp_chunk_t **)(skb->cb));
+	chunk = *((struct sctp_chunk **)(skb->cb));
 	asoc = chunk->asoc;
 	sk = asoc->base.sk;
 	asoc->sndbuf_used -= SCTP_DATA_SNDSIZE(chunk);
@@ -3244,24 +3515,24 @@
 }
 
 /* Helper function to wait for space in the sndbuf.  */
-static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p,
+static int sctp_wait_for_sndbuf(struct sctp_association *asoc, long *timeo_p,
 				int msg_len)
 {
 	struct sock *sk = asoc->base.sk;
 	int err = 0;
 	long current_timeo = *timeo_p;
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
 	SCTP_DEBUG_PRINTK("wait_for_sndbuf: asoc=%p, timeo=%ld, msg_len=%d\n",
 	                  asoc, (long)(*timeo_p), msg_len);
 
-	/* Wait on the association specific sndbuf space. */
-	add_wait_queue_exclusive(&asoc->wait, &wait);
-
 	/* Increment the association's refcnt.  */
 	sctp_association_hold(asoc);
+
+	/* Wait on the association specific sndbuf space. */
 	for (;;) {
-		set_current_state(TASK_INTERRUPTIBLE);
+		prepare_to_wait_exclusive(&asoc->wait, &wait,
+					  TASK_INTERRUPTIBLE);
 		if (!*timeo_p)
 			goto do_nonblock;
 		if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
@@ -3283,12 +3554,11 @@
 	}
 
 out:
-	remove_wait_queue(&asoc->wait, &wait);
+	finish_wait(&asoc->wait, &wait);
 
 	/* Release the association's refcnt.  */
 	sctp_association_put(asoc);
 
-	__set_current_state(TASK_RUNNING);
 	return err;
 
 do_error:
@@ -3307,12 +3577,12 @@
 /* If socket sndbuf has changed, wake up all per association waiters.  */
 void sctp_write_space(struct sock *sk)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	struct list_head *pos;
 
 	/* Wake up the tasks in each wait queue.  */
 	list_for_each(pos, &((sctp_sk(sk))->ep->asocs)) {
-		asoc = list_entry(pos, sctp_association_t, asocs);
+		asoc = list_entry(pos, struct sctp_association, asocs);
 		__sctp_write_space(asoc);
 	}
 }
@@ -3341,32 +3611,33 @@
 /* Wait for an association to go into ESTABLISHED state. If timeout is 0,
  * returns immediately with EINPROGRESS.
  */
-static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
+static int sctp_wait_for_connect(struct sctp_association *asoc, long *timeo_p)
 {
 	struct sock *sk = asoc->base.sk;
 	int err = 0;
 	long current_timeo = *timeo_p;
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
 	SCTP_DEBUG_PRINTK("%s: asoc=%p, timeo=%ld\n", __FUNCTION__, asoc,
 			  (long)(*timeo_p));
 
-	add_wait_queue_exclusive(&asoc->wait, &wait);
-
 	/* Increment the association's refcnt.  */
 	sctp_association_hold(asoc);
 
 	for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
+		prepare_to_wait_exclusive(&asoc->wait, &wait,
+					  TASK_INTERRUPTIBLE);
 		if (!*timeo_p)
 			goto do_nonblock;
+		if (sk->shutdown & RCV_SHUTDOWN)
+			break;
 		if (sk->err || asoc->state >= SCTP_STATE_SHUTDOWN_PENDING ||
 		    asoc->base.dead)
 			goto do_error;
 		if (signal_pending(current))
 			goto do_interrupted;
 
-		if (asoc->state == SCTP_STATE_ESTABLISHED)
+		if (sctp_state(asoc, ESTABLISHED))
 			break;
 
 		/* Let another process have a go.  Since we are going
@@ -3380,13 +3651,11 @@
 	}
 
 out:
-	remove_wait_queue(&asoc->wait, &wait);
+	finish_wait(&asoc->wait, &wait);
 
 	/* Release the association's refcnt.  */
 	sctp_association_put(asoc);
 
-	__set_current_state(TASK_RUNNING);
-
 	return err;
 
 do_error:
@@ -3406,14 +3675,14 @@
 {
 	struct sctp_endpoint *ep;
 	int err = 0;
-	DECLARE_WAITQUEUE(wait, current);
+	DEFINE_WAIT(wait);
 
 	ep = sctp_sk(sk)->ep;
 
-	add_wait_queue_exclusive(sk->sleep, &wait);
 
 	for (;;) {
-		__set_current_state(TASK_INTERRUPTIBLE);
+		prepare_to_wait_exclusive(sk->sleep, &wait, TASK_INTERRUPTIBLE);
+
 		if (list_empty(&ep->asocs)) {
 			sctp_release_sock(sk);
 			timeo = schedule_timeout(timeo);
@@ -3421,7 +3690,7 @@
 		}
 
 		err = -EINVAL;
-		if (sk->state != SCTP_SS_LISTENING)
+		if (!sctp_sstate(sk, LISTENING))
 			break;
 
 		err = 0;
@@ -3437,21 +3706,37 @@
 			break;
 	}
 
-	remove_wait_queue(sk->sleep, &wait);
-	__set_current_state(TASK_RUNNING);
+	finish_wait(sk->sleep, &wait);
 
 	return err;
 }
 
-/* Populate the fields of the newsk from the oldsk and migrate the assoc 
+void sctp_wait_for_close(struct sock *sk, long timeout)
+{
+	DEFINE_WAIT(wait);
+
+	do {
+		prepare_to_wait(sk->sleep, &wait, TASK_INTERRUPTIBLE);
+		if (list_empty(&sctp_sk(sk)->ep->asocs))
+			break;
+		sctp_release_sock(sk);
+		timeout = schedule_timeout(timeout);
+		sctp_lock_sock(sk);
+	} while (!signal_pending(current) && timeout);
+
+	finish_wait(sk->sleep, &wait);
+}
+
+/* Populate the fields of the newsk from the oldsk and migrate the assoc
  * and its messages to the newsk.
- */ 
-void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
-		  struct sctp_association *assoc, sctp_socket_type_t type)
+ */
+static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
+			      struct sctp_association *assoc,
+			      sctp_socket_type_t type)
 {
 	struct sctp_opt *oldsp = sctp_sk(oldsk);
 	struct sctp_opt *newsp = sctp_sk(newsk);
-	sctp_endpoint_t *newep = newsp->ep;
+	struct sctp_endpoint *newep = newsp->ep;
 	struct sk_buff *skb, *tmp;
 	struct sctp_ulpevent *event;
 
@@ -3466,6 +3751,7 @@
 	 * copy.
 	 */
 	newsp->ep = newep;
+	newsp->hmac = NULL;
 
 	/* Move any messages in the old socket's receive queue that are for the
 	 * peeled off association to the new socket's receive queue.
@@ -3524,9 +3810,15 @@
 	/* Migrate the association to the new socket. */
 	sctp_assoc_migrate(assoc, newsk);
 
+	/* If the association on the newsk is already closed before accept()
+	 * is called, set RCV_SHUTDOWN flag.
+	 */
+	if (sctp_state(assoc, CLOSED) && sctp_style(newsk, TCP))
+		newsk->shutdown |= RCV_SHUTDOWN;
+
 	newsk->state = SCTP_SS_ESTABLISHED;
 }
- 
+
 /* This proto struct describes the ULP interface for SCTP.  */
 struct proto sctp_prot = {
 	.name        =	"SCTP",
diff -Nru a/net/sctp/ssnmap.c b/net/sctp/ssnmap.c
--- a/net/sctp/ssnmap.c	Fri Jan 17 13:35:51 2003
+++ b/net/sctp/ssnmap.c	Wed Apr  9 12:24:29 2003
@@ -53,11 +53,11 @@
 /* Create a new sctp_ssnmap.
  * Allocate room to store at least 'len' contiguous TSNs.
  */
-struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int priority)
+struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp)
 {
 	struct sctp_ssnmap *retval;
 
-	retval = kmalloc(sctp_ssnmap_size(in, out), priority);
+	retval = kmalloc(sctp_ssnmap_size(in, out), gfp);
 
 	if (!retval)
 		goto fail;
diff -Nru a/net/sctp/transport.c b/net/sctp/transport.c
--- a/net/sctp/transport.c	Tue Apr 29 02:29:48 2003
+++ b/net/sctp/transport.c	Tue May  6 16:40:03 2003
@@ -54,16 +54,15 @@
 /* 1st Level Abstractions.  */
 
 /* Allocate and initialize a new transport.  */
-struct sctp_transport *sctp_transport_new(const union sctp_addr *addr,
-					  int priority)
+struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp)
 {
         struct sctp_transport *transport;
 
-        transport = t_new(struct sctp_transport, priority);
+        transport = t_new(struct sctp_transport, gfp);
 	if (!transport)
 		goto fail;
 
-	if (!sctp_transport_init(transport, addr, priority))
+	if (!sctp_transport_init(transport, addr, gfp))
 		goto fail_init;
 
 	transport->malloced = 1;
@@ -81,7 +80,7 @@
 /* Initialize a new transport from provided memory.  */
 struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
 					   const union sctp_addr *addr,
-					   int priority)
+					   int gfp)
 {
 	struct sctp_protocol *proto = sctp_get_protocol();
 
@@ -117,8 +116,6 @@
 	peer->error_threshold = 0;
 	peer->error_count = 0;
 
-	peer->debug_name = "unnamedtransport";
-
 	INIT_LIST_HEAD(&peer->transmitted);
 	INIT_LIST_HEAD(&peer->send_ready);
 	INIT_LIST_HEAD(&peer->transports);
@@ -138,6 +135,13 @@
 	peer->dead = 0;
 
 	peer->malloced = 0;
+
+	/* Initialize the state information for SFR-CACC */
+	peer->cacc.changeover_active = 0;
+	peer->cacc.cycling_changeover = 0;
+	peer->cacc.next_tsn_at_change = 0;
+	peer->cacc.cacc_saw_newack = 0;
+
 	return peer;
 }
 
@@ -199,13 +203,13 @@
  * Register the reference count in the association.
  */
 void sctp_transport_set_owner(struct sctp_transport *transport,
-			      sctp_association_t *asoc)
+			      struct sctp_association *asoc)
 {
 	transport->asoc = asoc;
 	sctp_association_hold(asoc);
 }
 
-/* Initialize the pmtu of a transport. */ 
+/* Initialize the pmtu of a transport. */
 void sctp_transport_pmtu(struct sctp_transport *transport)
 {
 	struct dst_entry *dst;
@@ -225,7 +229,7 @@
 void sctp_transport_route(struct sctp_transport *transport,
 			  union sctp_addr *saddr, struct sctp_opt *opt)
 {
-	sctp_association_t *asoc = transport->asoc;
+	struct sctp_association *asoc = transport->asoc;
 	struct sctp_af *af = transport->af_specific;
 	union sctp_addr *daddr = &transport->ipaddr;
 	struct dst_entry *dst;
@@ -238,9 +242,15 @@
 		af->get_saddr(asoc, dst, daddr, &transport->saddr);
 
 	transport->dst = dst;
-	if (dst)
+	if (dst) {
 		transport->pmtu = dst_pmtu(dst);
-	else
+
+		/* Initialize sk->rcv_saddr, if the transport is the
+		 * association's active path for getsockname().
+		 */ 
+		if (asoc && (transport == asoc->peer.active_path))
+			af->to_sk_saddr(&transport->saddr, asoc->base.sk);
+	} else
 		transport->pmtu = SCTP_DEFAULT_MAXSEGMENT;
 }
 
@@ -359,7 +369,7 @@
 		 * two conditions are met can the cwnd be increased otherwise
 		 * the cwnd MUST not be increased. If these conditions are met
 		 * then cwnd MUST be increased by at most the lesser of
-		 * 1) the total size of the previously outstanding DATA 
+		 * 1) the total size of the previously outstanding DATA
 		 * chunk(s) acknowledged, and 2) the destination's path MTU.
 		 */
 		if (bytes_acked > pmtu)
@@ -373,17 +383,17 @@
 				  transport, bytes_acked, cwnd,
 				  ssthresh, flight_size, pba);
 	} else {
-		/* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh, 
-		 * upon each SACK arrival that advances the Cumulative TSN Ack 
-		 * Point, increase partial_bytes_acked by the total number of 
-		 * bytes of all new chunks acknowledged in that SACK including 
-		 * chunks acknowledged by the new Cumulative TSN Ack and by 
+		/* RFC 2960 7.2.2 Whenever cwnd is greater than ssthresh,
+		 * upon each SACK arrival that advances the Cumulative TSN Ack
+		 * Point, increase partial_bytes_acked by the total number of
+		 * bytes of all new chunks acknowledged in that SACK including
+		 * chunks acknowledged by the new Cumulative TSN Ack and by
 		 * Gap Ack Blocks.
 		 *
-		 * When partial_bytes_acked is equal to or greater than cwnd 
-		 * and before the arrival of the SACK the sender had cwnd or 
-		 * more bytes of data outstanding (i.e., before arrival of the 
-		 * SACK, flightsize was greater than or equal to cwnd), 
+		 * When partial_bytes_acked is equal to or greater than cwnd
+		 * and before the arrival of the SACK the sender had cwnd or
+		 * more bytes of data outstanding (i.e., before arrival of the
+		 * SACK, flightsize was greater than or equal to cwnd),
 		 * increase cwnd by MTU, and reset partial_bytes_acked to
 		 * (partial_bytes_acked - cwnd).
 		 */
diff -Nru a/net/sctp/tsnmap.c b/net/sctp/tsnmap.c
--- a/net/sctp/tsnmap.c	Mon Mar  3 04:52:39 2003
+++ b/net/sctp/tsnmap.c	Wed Apr  9 12:24:29 2003
@@ -55,13 +55,12 @@
 /* Create a new sctp_tsnmap.
  * Allocate room to store at least 'len' contiguous TSNs.
  */
-struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int priority)
+struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int gfp)
 {
 	struct sctp_tsnmap *retval;
 
 	retval = kmalloc(sizeof(struct sctp_tsnmap) +
-			 sctp_tsnmap_storage_size(len),
-			 priority);
+			 sctp_tsnmap_storage_size(len), gfp);
 	if (!retval)
 		goto fail;
 
diff -Nru a/net/sctp/ulpevent.c b/net/sctp/ulpevent.c
--- a/net/sctp/ulpevent.c	Fri Mar 28 12:49:33 2003
+++ b/net/sctp/ulpevent.c	Thu May  1 07:23:56 2003
@@ -52,12 +52,12 @@
 				    const struct sctp_association *asoc);
 
 /* Create a new sctp_ulpevent.  */
-struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int priority)
+struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sk_buff *skb;
 
-	skb = alloc_skb(size, priority);
+	skb = alloc_skb(size, gfp);
 	if (!skb)
 		goto fail;
 
@@ -106,16 +106,16 @@
  * zero'd out.
  */
 struct sctp_ulpevent  *sctp_ulpevent_make_assoc_change(
-	const sctp_association_t *asoc,
+	const struct sctp_association *asoc,
 	__u16 flags, __u16 state, __u16 error, __u16 outbound,
-	__u16 inbound, int priority)
+	__u16 inbound, int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sctp_assoc_change *sac;
 	struct sk_buff *skb;
 
 	event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
-				  MSG_NOTIFICATION, priority);
+				  MSG_NOTIFICATION, gfp);
 	if (!event)
 		goto fail;
 	skb = sctp_event2skb(event);
@@ -207,15 +207,16 @@
  * an interface details event is sent.
  */
 struct sctp_ulpevent *sctp_ulpevent_make_peer_addr_change(
-	const sctp_association_t *asoc, const struct sockaddr_storage *aaddr,
-	int flags, int state, int error, int priority)
+	const struct sctp_association *asoc,
+	const struct sockaddr_storage *aaddr,
+	int flags, int state, int error, int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sctp_paddr_change  *spc;
 	struct sk_buff *skb;
 
 	event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),
-				  MSG_NOTIFICATION, priority);
+				  MSG_NOTIFICATION, gfp);
 	if (!event)
 		goto fail;
 
@@ -315,8 +316,8 @@
  * error formats.
  */
 struct sctp_ulpevent *sctp_ulpevent_make_remote_error(
-	const sctp_association_t *asoc, sctp_chunk_t *chunk,
-	__u16 flags, int priority)
+	const struct sctp_association *asoc, struct sctp_chunk *chunk,
+	__u16 flags, int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sctp_remote_error *sre;
@@ -327,7 +328,7 @@
 
 	ch = (sctp_errhdr_t *)(chunk->skb->data);
 	cause = ch->cause;
-	elen = ntohs(ch->length) - sizeof(sctp_errhdr_t);
+	elen = WORD_ROUND(ntohs(ch->length)) - sizeof(sctp_errhdr_t);
 
 	/* Pull off the ERROR header.  */
 	skb_pull(chunk->skb, sizeof(sctp_errhdr_t));
@@ -335,10 +336,8 @@
 	/* Copy the skb to a new skb with room for us to prepend
 	 * notification with.
 	 */
-	skb = skb_copy_expand(chunk->skb,
-			      sizeof(struct sctp_remote_error), /* headroom */
-			      0,                                /* tailroom */
-			      priority);
+	skb = skb_copy_expand(chunk->skb, sizeof(struct sctp_remote_error), 
+			      0, gfp);
 
 	/* Pull off the rest of the cause TLV from the chunk.  */
 	skb_pull(chunk->skb, elen);
@@ -419,23 +418,27 @@
  * 5.3.1.4 SCTP_SEND_FAILED
  */
 struct sctp_ulpevent *sctp_ulpevent_make_send_failed(
-	const sctp_association_t *asoc, sctp_chunk_t *chunk,
-	__u16 flags, __u32 error, int priority)
+	const struct sctp_association *asoc, struct sctp_chunk *chunk,
+	__u16 flags, __u32 error, int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sctp_send_failed *ssf;
 	struct sk_buff *skb;
 
+	/* Pull off any padding. */
+	int len = ntohs(chunk->chunk_hdr->length);
+
 	/* Make skb with more room so we can prepend notification.  */
 	skb = skb_copy_expand(chunk->skb,
 			      sizeof(struct sctp_send_failed), /* headroom */
 			      0,                               /* tailroom */
-			      priority);
+			      gfp);
 	if (!skb)
 		goto fail;
 
 	/* Pull off the common chunk header and DATA header.  */
-	skb_pull(skb, sizeof(sctp_data_chunk_t));
+	skb_pull(skb, sizeof(struct sctp_data_chunk));
+	len -= sizeof(struct sctp_data_chunk);
 
 	/* Embed the event fields inside the cloned skb.  */
 	event = sctp_skb2event(skb);
@@ -476,7 +479,8 @@
 	 * This field is the total length of the notification data, including
 	 * the notification header.
 	 */
-	ssf->ssf_length = skb->len;
+	ssf->ssf_length = sizeof(struct sctp_send_failed) + len;
+	skb_trim(skb, ssf->ssf_length);
 
 	/* Socket Extensions for SCTP
 	 * 5.3.1.4 SCTP_SEND_FAILED
@@ -497,6 +501,11 @@
 	 */
 	memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
 
+	/* Per TSVWG discussion with Randy. Allow the application to
+	 * ressemble a fragmented message. 
+	 */
+	ssf->ssf_info.sinfo_flags = chunk->chunk_hdr->flags;
+
 	/* Socket Extensions for SCTP
 	 * 5.3.1.4 SCTP_SEND_FAILED
 	 *
@@ -521,15 +530,15 @@
  * 5.3.1.5 SCTP_SHUTDOWN_EVENT
  */
 struct sctp_ulpevent *sctp_ulpevent_make_shutdown_event(
-	const sctp_association_t *asoc,
-	__u16 flags, int priority)
+	const struct sctp_association *asoc,
+	__u16 flags, int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sctp_shutdown_event *sse;
 	struct sk_buff *skb;
 
 	event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
-				  MSG_NOTIFICATION, priority);
+				  MSG_NOTIFICATION, gfp);
 	if (!event)
 		goto fail;
 
@@ -586,8 +595,9 @@
  * Socket Extensions for SCTP
  * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
  */
-struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
-		   sctp_chunk_t *chunk, int priority)
+struct sctp_ulpevent *sctp_ulpevent_make_rcvmsg(struct sctp_association *asoc,
+						struct sctp_chunk *chunk, 
+						int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sctp_sndrcvinfo *info;
@@ -595,7 +605,7 @@
 	size_t padding, len;
 
 	/* Clone the original skb, sharing the data.  */
-	skb = skb_clone(chunk->skb, priority);
+	skb = skb_clone(chunk->skb, gfp);
 	if (!skb)
 		goto fail;
 
@@ -631,7 +641,7 @@
 	event->iif = sctp_chunk_iif(chunk);
 	/* Note:  Not clearing the entire event struct as
 	 * this is just a fragment of the real event.  However,
-	 * we still need to do rwnd accounting. 
+	 * we still need to do rwnd accounting.
 	 */
 	for (list = skb_shinfo(skb)->frag_list; list; list = list->next)
 		sctp_ulpevent_set_owner_r(list, asoc);
@@ -690,16 +700,16 @@
 		info->sinfo_flags |= MSG_UNORDERED;
 
 		/* sinfo_cumtsn: 32 bit (unsigned integer)
-		 *  
-		 * This field will hold the current cumulative TSN as 
-		 * known by the underlying SCTP layer.  Note this field is 
-		 * ignored when sending and only valid for a receive 
+		 *
+		 * This field will hold the current cumulative TSN as
+		 * known by the underlying SCTP layer.  Note this field is
+		 * ignored when sending and only valid for a receive
 		 * operation when sinfo_flags are set to MSG_UNORDERED.
 		 */
 		info->sinfo_cumtsn = sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map);
 	}
 
-	/* Note:  For reassembly, we need to have the fragmentation bits. 
+	/* Note:  For reassembly, we need to have the fragmentation bits.
 	 * For now, merge these into the msg_flags, since those bit
 	 * possitions are not used.
 	 */
@@ -732,7 +742,7 @@
 	return NULL;
 }
 
-/* Create a partial delivery related event. 
+/* Create a partial delivery related event.
  *
  * 5.3.1.7 SCTP_PARTIAL_DELIVERY_EVENT
  *
@@ -741,14 +751,14 @@
  *   various events.
  */
 struct sctp_ulpevent *sctp_ulpevent_make_pdapi(
-	const sctp_association_t *asoc, __u32 indication, int priority)
+	const struct sctp_association *asoc, __u32 indication, int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sctp_rcv_pdapi_event *pd;
 	struct sk_buff *skb;
 
 	event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
-				  MSG_NOTIFICATION, priority);
+				  MSG_NOTIFICATION, gfp);
 	if (!event)
 		goto fail;
 
@@ -780,7 +790,7 @@
 	pd->pdapi_indication = indication;
 
 	/*  pdapi_assoc_id: sizeof (sctp_assoc_t)
-	 * 
+	 *
 	 * The association id field, holds the identifier for the association.
 	 */
 	pd->pdapi_assoc_id = sctp_assoc2id(asoc);
@@ -817,7 +827,7 @@
 /* Do accounting for bytes just read by user.  */
 static void sctp_rcvmsg_rfree(struct sk_buff *skb)
 {
-	sctp_association_t *asoc;
+	struct sctp_association *asoc;
 	struct sctp_ulpevent *event;
 
 	/* Current stack structures assume that the rcv buffer is
@@ -834,7 +844,7 @@
 
 /* Charge receive window for bytes received.  */
 static void sctp_ulpevent_set_owner_r(struct sk_buff *skb,
-				      sctp_association_t *asoc)
+				      struct sctp_association *asoc)
 {
 	struct sctp_ulpevent *event;
 
diff -Nru a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c
--- a/net/sctp/ulpqueue.c	Tue Mar 25 08:05:35 2003
+++ b/net/sctp/ulpqueue.c	Thu Apr 17 06:44:11 2003
@@ -57,11 +57,11 @@
 /* 1st Level Abstractions */
 
 /* Create a new ULP queue.  */
-struct sctp_ulpq *sctp_ulpq_new(sctp_association_t *asoc, int priority)
+struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp)
 {
 	struct sctp_ulpq *ulpq;
 
-	ulpq = kmalloc(sizeof(struct sctp_ulpq), priority);
+	ulpq = kmalloc(sizeof(struct sctp_ulpq), gfp);
 	if (!ulpq)
 		goto fail;
 	if (!sctp_ulpq_init(ulpq, asoc))
@@ -77,7 +77,7 @@
 
 /* Initialize a ULP queue from a block of memory.  */
 struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
-				 sctp_association_t *asoc)
+				 struct sctp_association *asoc)
 {
 	memset(ulpq, sizeof(struct sctp_ulpq), 0x00);
 
@@ -118,8 +118,8 @@
 }
 
 /* Process an incoming DATA chunk.  */
-int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, sctp_chunk_t *chunk,
-			int priority)
+int sctp_ulpq_tail_data(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
+			int gfp)
 {
 	struct sk_buff_head temp;
 	sctp_data_chunk_t *hdr;
@@ -128,7 +128,7 @@
 	hdr = (sctp_data_chunk_t *) chunk->chunk_hdr;
 
 	/* Create an event from the incoming chunk. */
-	event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, priority);
+	event = sctp_ulpevent_make_rcvmsg(chunk->asoc, chunk, gfp);
 	if (!event)
 		return -ENOMEM;
 
@@ -253,6 +253,21 @@
 
 	tsn = event->sndrcvinfo.sinfo_tsn;
 
+	/* See if it belongs at the end. */
+	pos = skb_peek_tail(&ulpq->reasm);
+	if (!pos) {
+		__skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
+		return;
+	}
+
+	/* Short circuit just dropping it at the end. */
+	cevent = sctp_skb2event(pos);
+	ctsn = cevent->sndrcvinfo.sinfo_tsn;
+	if (TSN_lt(ctsn, tsn)) {
+		__skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
+		return;
+	}
+
 	/* Find the right place in this list. We store them by TSN.  */
 	skb_queue_walk(&ulpq->reasm, pos) {
 		cevent = sctp_skb2event(pos);
@@ -262,12 +277,9 @@
 			break;
 	}
 
-	/* If the queue is empty, we have a different function to call.  */
-	if (skb_peek(&ulpq->reasm))
-		__skb_insert(sctp_event2skb(event), pos->prev, pos,
-			     &ulpq->reasm);
-	else
-		__skb_queue_tail(&ulpq->reasm, sctp_event2skb(event));
+	/* Insert before pos. */
+	__skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->reasm);
+
 }
 
 /* Helper function to return an event corresponding to the reassembled
@@ -592,8 +604,27 @@
 	__u16 sid, csid;
 	__u16 ssn, cssn;
 
+	pos = skb_peek_tail(&ulpq->lobby);
+	if (!pos) {
+		__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
+		return;
+	}
+
 	sid = event->sndrcvinfo.sinfo_stream;
 	ssn = event->sndrcvinfo.sinfo_ssn;
+	
+	cevent = (struct sctp_ulpevent *) pos->cb;
+	csid = cevent->sndrcvinfo.sinfo_stream;
+	cssn = cevent->sndrcvinfo.sinfo_ssn;
+	if (sid > csid) {
+		__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
+		return;
+	}
+
+	if ((sid == csid) && SSN_lt(cssn, ssn)) {
+		__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
+		return;
+	}
 
 	/* Find the right place in this list.  We store them by
 	 * stream ID and then by SSN.
@@ -609,12 +640,10 @@
 			break;
 	}
 
-	/* If the queue is empty, we have a different function to call.  */
-	if (skb_peek(&ulpq->lobby))
-		__skb_insert(sctp_event2skb(event), pos->prev, pos,
-			     &ulpq->lobby);
-	else
-		__skb_queue_tail(&ulpq->lobby, sctp_event2skb(event));
+
+	/* Insert before pos. */
+	__skb_insert(sctp_event2skb(event), pos->prev, pos, &ulpq->lobby);
+
 }
 
 static inline struct sctp_ulpevent *sctp_ulpq_order(struct sctp_ulpq *ulpq,
@@ -705,7 +734,7 @@
 
 /* Partial deliver the first message as there is pressure on rwnd. */
 void sctp_ulpq_partial_delivery(struct sctp_ulpq *ulpq,
-				struct sctp_chunk *chunk, int priority)
+				struct sctp_chunk *chunk, int gfp)
 {
 	struct sctp_ulpevent *event;
 	struct sctp_association *asoc;
@@ -729,7 +758,7 @@
 
 /* Renege some packets to make room for an incoming chunk.  */
 void sctp_ulpq_renege(struct sctp_ulpq *ulpq, struct sctp_chunk *chunk,
-		      int priority)
+		      int gfp)
 {
 	struct sctp_association *asoc;
 	__u16 needed, freed;
@@ -755,9 +784,9 @@
 		__u32 tsn;
 		tsn = ntohl(chunk->subh.data_hdr->tsn);
 		sctp_tsnmap_mark(&asoc->peer.tsn_map, tsn);
-		sctp_ulpq_tail_data(ulpq, chunk, priority);
+		sctp_ulpq_tail_data(ulpq, chunk, gfp);
 		
-		sctp_ulpq_partial_delivery(ulpq, chunk, priority);
+		sctp_ulpq_partial_delivery(ulpq, chunk, gfp);
 	}
 
 	return;
@@ -768,7 +797,7 @@
 /* Notify the application if an association is aborted and in
  * partial delivery mode.  Send up any pending received messages.
  */
-void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority)
+void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int gfp)
 {
 	struct sctp_ulpevent *ev = NULL;
 	struct sock *sk;
@@ -781,7 +810,7 @@
 				       &sctp_sk(sk)->subscribe))
 		ev = sctp_ulpevent_make_pdapi(ulpq->asoc,
 					      SCTP_PARTIAL_DELIVERY_ABORTED,
-					      priority);
+					      gfp);
 	if (ev)
 		__skb_queue_tail(&sk->receive_queue, sctp_event2skb(ev));
 
diff -Nru a/net/socket.c b/net/socket.c
--- a/net/socket.c	Fri May  2 22:55:11 2003
+++ b/net/socket.c	Tue May 20 18:56:26 2003
@@ -95,9 +95,9 @@
 #include <linux/netfilter.h>
 
 static int sock_no_open(struct inode *irrelevant, struct file *dontcare);
-static ssize_t sock_aio_read(struct kiocb *iocb, char *buf,
+static ssize_t sock_aio_read(struct kiocb *iocb, char __user *buf,
 			 size_t size, loff_t pos);
-static ssize_t sock_aio_write(struct kiocb *iocb, const char *buf,
+static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *buf,
 			  size_t size, loff_t pos);
 static int sock_mmap(struct file *file, struct vm_area_struct * vma);
 
@@ -121,6 +121,7 @@
  */
 
 static struct file_operations socket_file_ops = {
+	.owner =	THIS_MODULE,
 	.llseek =	no_llseek,
 	.aio_read =	sock_aio_read,
 	.aio_write =	sock_aio_write,
@@ -217,7 +218,7 @@
  *	invalid addresses -EFAULT is returned. On a success 0 is returned.
  */
 
-int move_addr_to_kernel(void *uaddr, int ulen, void *kaddr)
+int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr)
 {
 	if(ulen<0||ulen>MAX_SOCK_ADDR)
 		return -EINVAL;
@@ -245,7 +246,7 @@
  *	specified. Zero is returned for a success.
  */
  
-int move_addr_to_user(void *kaddr, int klen, void *uaddr, int *ulen)
+int move_addr_to_user(void *kaddr, int klen, void __user *uaddr, int __user *ulen)
 {
 	int err;
 	int len;
@@ -490,6 +491,7 @@
 }
 
 struct file_operations bad_sock_fops = {
+	.owner = THIS_MODULE,
 	.open = sock_no_open,
 };
 
@@ -589,7 +591,7 @@
  *	area ubuf...ubuf+size-1 is writable before asking the protocol.
  */
 
-static ssize_t sock_aio_read(struct kiocb *iocb, char *ubuf,
+static ssize_t sock_aio_read(struct kiocb *iocb, char __user *ubuf,
 			 size_t size, loff_t pos)
 {
 	struct sock_iocb *x = kiocb_to_siocb(iocb);
@@ -622,7 +624,7 @@
  *	is readable by the user process.
  */
 
-static ssize_t sock_aio_write(struct kiocb *iocb, const char *ubuf,
+static ssize_t sock_aio_write(struct kiocb *iocb, const char __user *ubuf,
 			  size_t size, loff_t pos)
 {
 	struct sock_iocb *x = kiocb_to_siocb(iocb);
@@ -644,7 +646,7 @@
 	x->async_msg.msg_flags = !(iocb->ki_filp->f_flags & O_NONBLOCK) ? 0 : MSG_DONTWAIT;
 	if (sock->type == SOCK_SEQPACKET)
 		x->async_msg.msg_flags |= MSG_EOR;
-	x->async_iov.iov_base = (void *)ubuf;
+	x->async_iov.iov_base = (void __user *)ubuf;
 	x->async_iov.iov_len = size;
 	
 	return __sock_sendmsg(iocb, sock, &x->async_msg, size);
@@ -731,6 +733,7 @@
 	br_ioctl_hook = hook;
 	up(&br_ioctl_mutex);
 }
+EXPORT_SYMBOL(brioctl_set);
 
 static DECLARE_MUTEX(vlan_ioctl_mutex);
 static int (*vlan_ioctl_hook)(unsigned long arg);
@@ -741,12 +744,18 @@
 	vlan_ioctl_hook = hook;
 	up(&vlan_ioctl_mutex);
 }
+EXPORT_SYMBOL(vlan_ioctl_set);
 
-#ifdef CONFIG_DLCI
-extern int dlci_ioctl(unsigned int, void *);
-#else
-int (*dlci_ioctl_hook)(unsigned int, void *);
-#endif
+static DECLARE_MUTEX(dlci_ioctl_mutex);
+static int (*dlci_ioctl_hook)(unsigned int, void *);
+
+void dlci_ioctl_set(int (*hook)(unsigned int, void *))
+{
+	down(&dlci_ioctl_mutex);
+	dlci_ioctl_hook = hook;
+	up(&dlci_ioctl_mutex);
+}
+EXPORT_SYMBOL(dlci_ioctl_set);
 
 /*
  *	With an ioctl, arg may well be a user mode pointer, but we don't know
@@ -812,32 +821,20 @@
 		case SIOCGIFDIVERT:
 		case SIOCSIFDIVERT:
 		/* Convert this to call through a hook */
-#ifdef CONFIG_NET_DIVERT
 			err = divert_ioctl(cmd, (struct divert_cf *)arg);
-#else
-			err = -ENOPKG;
-#endif	/* CONFIG_NET_DIVERT */
 			break;
 		case SIOCADDDLCI:
 		case SIOCDELDLCI:
-		/* Convert this to always call through a hook */
-#ifdef CONFIG_DLCI
-			lock_kernel();
-			err = dlci_ioctl(cmd, (void *)arg);
-			unlock_kernel();
-			break;
-#else
 			err = -ENOPKG;
 #ifdef CONFIG_KMOD
 			if (!dlci_ioctl_hook)
 				request_module("dlci");
 #endif
 			if (dlci_ioctl_hook) {
-				lock_kernel();
+				down(&dlci_ioctl_mutex);
 				err = dlci_ioctl_hook(cmd, (void *)arg);
-				unlock_kernel();
+				up(&dlci_ioctl_mutex);
 			}
-#endif
 			break;
 		default:
 			err = sock->ops->ioctl(sock, cmd, arg);
@@ -1033,9 +1030,7 @@
 	 */
 	if (net_families[family]==NULL)
 	{
-		char module_name[30];
-		sprintf(module_name,"net-pf-%d",family);
-		request_module(module_name);
+		request_module("net-pf-%d",family);
 	}
 #endif
 
@@ -1123,7 +1118,7 @@
  *	Create a pair of connected sockets.
  */
 
-asmlinkage long sys_socketpair(int family, int type, int protocol, int usockvec[2])
+asmlinkage long sys_socketpair(int family, int type, int protocol, int __user *usockvec)
 {
 	struct socket *sock1, *sock2;
 	int fd1, fd2, err;
@@ -1193,7 +1188,7 @@
  *	the protocol layer (having also checked the address is ok).
  */
 
-asmlinkage long sys_bind(int fd, struct sockaddr *umyaddr, int addrlen)
+asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
@@ -1255,7 +1250,7 @@
  *	clean when we restucture accept also.
  */
 
-asmlinkage long sys_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen)
+asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, int __user *upeer_addrlen)
 {
 	struct socket *sock, *newsock;
 	int err, len;
@@ -1280,26 +1275,26 @@
 	 * We don't need try_module_get here, as the listening socket (sock)
 	 * has the protocol module (sock->ops->owner) held.
 	 */
-	__module_get(sock->ops->owner);
+	__module_get(newsock->ops->owner);
 
 	err = sock->ops->accept(sock, newsock, sock->file->f_flags);
 	if (err < 0)
-		goto out_module_put;
+		goto out_release;
 
 	if (upeer_sockaddr) {
 		if(newsock->ops->getname(newsock, (struct sockaddr *)address, &len, 2)<0) {
 			err = -ECONNABORTED;
-			goto out_module_put;
+			goto out_release;
 		}
 		err = move_addr_to_user(address, len, upeer_sockaddr, upeer_addrlen);
 		if (err < 0)
-			goto out_module_put;
+			goto out_release;
 	}
 
 	/* File flags are not inherited via accept() unlike another OSes. */
 
 	if ((err = sock_map_fd(newsock)) < 0)
-		goto out_module_put;
+		goto out_release;
 
 	security_socket_post_accept(sock, newsock);
 
@@ -1307,8 +1302,6 @@
 	sockfd_put(sock);
 out:
 	return err;
-out_module_put:
-	module_put(sock->ops->owner);
 out_release:
 	sock_release(newsock);
 	goto out_put;
@@ -1327,7 +1320,7 @@
  *	include the -EINPROGRESS status for such sockets.
  */
 
-asmlinkage long sys_connect(int fd, struct sockaddr *uservaddr, int addrlen)
+asmlinkage long sys_connect(int fd, struct sockaddr __user *uservaddr, int addrlen)
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
@@ -1357,7 +1350,7 @@
  *	name to user space.
  */
 
-asmlinkage long sys_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
+asmlinkage long sys_getsockname(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len)
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
@@ -1387,7 +1380,7 @@
  *	name to user space.
  */
 
-asmlinkage long sys_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len)
+asmlinkage long sys_getpeername(int fd, struct sockaddr __user *usockaddr, int __user *usockaddr_len)
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
@@ -1415,8 +1408,8 @@
  *	the protocol.
  */
 
-asmlinkage long sys_sendto(int fd, void * buff, size_t len, unsigned flags,
-			   struct sockaddr *addr, int addr_len)
+asmlinkage long sys_sendto(int fd, void __user * buff, size_t len, unsigned flags,
+			   struct sockaddr __user *addr, int addr_len)
 {
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
@@ -1458,7 +1451,7 @@
  *	Send a datagram down a socket. 
  */
 
-asmlinkage long sys_send(int fd, void * buff, size_t len, unsigned flags)
+asmlinkage long sys_send(int fd, void __user * buff, size_t len, unsigned flags)
 {
 	return sys_sendto(fd, buff, len, flags, NULL, 0);
 }
@@ -1469,8 +1462,8 @@
  *	sender address from kernel to user space.
  */
 
-asmlinkage long sys_recvfrom(int fd, void * ubuf, size_t size, unsigned flags,
-			     struct sockaddr *addr, int *addr_len)
+asmlinkage long sys_recvfrom(int fd, void __user * ubuf, size_t size, unsigned flags,
+			     struct sockaddr __user *addr, int __user *addr_len)
 {
 	struct socket *sock;
 	struct iovec iov;
@@ -1509,7 +1502,7 @@
  *	Receive a datagram from a socket. 
  */
 
-asmlinkage long sys_recv(int fd, void * ubuf, size_t size, unsigned flags)
+asmlinkage long sys_recv(int fd, void __user * ubuf, size_t size, unsigned flags)
 {
 	return sys_recvfrom(fd, ubuf, size, flags, NULL, NULL);
 }
@@ -1519,7 +1512,7 @@
  *	to pass the user mode parameter for the protocols to sort out.
  */
 
-asmlinkage long sys_setsockopt(int fd, int level, int optname, char *optval, int optlen)
+asmlinkage long sys_setsockopt(int fd, int level, int optname, char __user *optval, int optlen)
 {
 	int err;
 	struct socket *sock;
@@ -1549,7 +1542,7 @@
  *	to pass a user mode parameter for the protocols to sort out.
  */
 
-asmlinkage long sys_getsockopt(int fd, int level, int optname, char *optval, int *optlen)
+asmlinkage long sys_getsockopt(int fd, int level, int optname, char __user *optval, int __user *optlen)
 {
 	int err;
 	struct socket *sock;
@@ -1608,9 +1601,9 @@
  *	BSD sendmsg interface
  */
 
-asmlinkage long sys_sendmsg(int fd, struct msghdr *msg, unsigned flags)
+asmlinkage long sys_sendmsg(int fd, struct msghdr __user *msg, unsigned flags)
 {
-	struct compat_msghdr *msg_compat = (struct compat_msghdr *)msg;
+	struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg;
 	struct socket *sock;
 	char address[MAX_SOCK_ADDR];
 	struct iovec iovstack[UIO_FASTIOV], *iov = iovstack;
@@ -1671,7 +1664,12 @@
 				goto out_freeiov;
 		}
 		err = -EFAULT;
-		if (copy_from_user(ctl_buf, msg_sys.msg_control, ctl_len))
+		/*
+		 * Careful! Before this, msg_sys.msg_control contains a user pointer.
+		 * Afterwards, it will be a kernel pointer. Thus the compiler-assisted
+		 * checking falls down on this.
+		 */
+		if (copy_from_user(ctl_buf, (void __user *) msg_sys.msg_control, ctl_len))
 			goto out_freectl;
 		msg_sys.msg_control = ctl_buf;
 	}
@@ -1697,9 +1695,9 @@
  *	BSD recvmsg interface
  */
 
-asmlinkage long sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags)
+asmlinkage long sys_recvmsg(int fd, struct msghdr __user *msg, unsigned int flags)
 {
-	struct compat_msghdr *msg_compat = (struct compat_msghdr *)msg;
+	struct compat_msghdr __user *msg_compat = (struct compat_msghdr __user *)msg;
 	struct socket *sock;
 	struct iovec iovstack[UIO_FASTIOV];
 	struct iovec *iov=iovstack;
@@ -1711,8 +1709,8 @@
 	char addr[MAX_SOCK_ADDR];
 
 	/* user mode address pointers */
-	struct sockaddr *uaddr;
-	int *uaddr_len;
+	struct sockaddr __user *uaddr;
+	int __user *uaddr_len;
 	
 	if (MSG_CMSG_COMPAT & flags) {
 		if (get_compat_msghdr(&msg_sys, msg_compat))
@@ -1743,7 +1741,7 @@
 	 *	kernel msghdr to use the kernel address space)
 	 */
 	 
-	uaddr = msg_sys.msg_name;
+	uaddr = (void __user *) msg_sys.msg_name;
 	uaddr_len = COMPAT_NAMELEN(msg);
 	if (MSG_CMSG_COMPAT & flags) {
 		err = verify_compat_iovec(&msg_sys, iov, addr, VERIFY_WRITE);
@@ -1807,7 +1805,7 @@
  *  it is set by the callees. 
  */
 
-asmlinkage long sys_socketcall(int call, unsigned long *args)
+asmlinkage long sys_socketcall(int call, unsigned long __user *args)
 {
 	unsigned long a[6];
 	unsigned long a0,a1;
@@ -1829,54 +1827,54 @@
 			err = sys_socket(a0,a1,a[2]);
 			break;
 		case SYS_BIND:
-			err = sys_bind(a0,(struct sockaddr *)a1, a[2]);
+			err = sys_bind(a0,(struct sockaddr __user *)a1, a[2]);
 			break;
 		case SYS_CONNECT:
-			err = sys_connect(a0, (struct sockaddr *)a1, a[2]);
+			err = sys_connect(a0, (struct sockaddr __user *)a1, a[2]);
 			break;
 		case SYS_LISTEN:
 			err = sys_listen(a0,a1);
 			break;
 		case SYS_ACCEPT:
-			err = sys_accept(a0,(struct sockaddr *)a1, (int *)a[2]);
+			err = sys_accept(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
 			break;
 		case SYS_GETSOCKNAME:
-			err = sys_getsockname(a0,(struct sockaddr *)a1, (int *)a[2]);
+			err = sys_getsockname(a0,(struct sockaddr __user *)a1, (int __user *)a[2]);
 			break;
 		case SYS_GETPEERNAME:
-			err = sys_getpeername(a0, (struct sockaddr *)a1, (int *)a[2]);
+			err = sys_getpeername(a0, (struct sockaddr __user *)a1, (int __user *)a[2]);
 			break;
 		case SYS_SOCKETPAIR:
-			err = sys_socketpair(a0,a1, a[2], (int *)a[3]);
+			err = sys_socketpair(a0,a1, a[2], (int __user *)a[3]);
 			break;
 		case SYS_SEND:
-			err = sys_send(a0, (void *)a1, a[2], a[3]);
+			err = sys_send(a0, (void __user *)a1, a[2], a[3]);
 			break;
 		case SYS_SENDTO:
-			err = sys_sendto(a0,(void *)a1, a[2], a[3],
-					 (struct sockaddr *)a[4], a[5]);
+			err = sys_sendto(a0,(void __user *)a1, a[2], a[3],
+					 (struct sockaddr __user *)a[4], a[5]);
 			break;
 		case SYS_RECV:
-			err = sys_recv(a0, (void *)a1, a[2], a[3]);
+			err = sys_recv(a0, (void __user *)a1, a[2], a[3]);
 			break;
 		case SYS_RECVFROM:
-			err = sys_recvfrom(a0, (void *)a1, a[2], a[3],
-					   (struct sockaddr *)a[4], (int *)a[5]);
+			err = sys_recvfrom(a0, (void __user *)a1, a[2], a[3],
+					   (struct sockaddr __user *)a[4], (int __user *)a[5]);
 			break;
 		case SYS_SHUTDOWN:
 			err = sys_shutdown(a0,a1);
 			break;
 		case SYS_SETSOCKOPT:
-			err = sys_setsockopt(a0, a1, a[2], (char *)a[3], a[4]);
+			err = sys_setsockopt(a0, a1, a[2], (char __user *)a[3], a[4]);
 			break;
 		case SYS_GETSOCKOPT:
-			err = sys_getsockopt(a0, a1, a[2], (char *)a[3], (int *)a[4]);
+			err = sys_getsockopt(a0, a1, a[2], (char __user *)a[3], (int __user *)a[4]);
 			break;
 		case SYS_SENDMSG:
-			err = sys_sendmsg(a0, (struct msghdr *) a1, a[2]);
+			err = sys_sendmsg(a0, (struct msghdr __user *) a1, a[2]);
 			break;
 		case SYS_RECVMSG:
-			err = sys_recvmsg(a0, (struct msghdr *) a1, a[2]);
+			err = sys_recvmsg(a0, (struct msghdr __user *) a1, a[2]);
 			break;
 		default:
 			err = -EINVAL;
diff -Nru a/net/sunrpc/cache.c b/net/sunrpc/cache.c
--- a/net/sunrpc/cache.c	Tue Apr 29 02:29:49 2003
+++ b/net/sunrpc/cache.c	Sat May 10 11:46:35 2003
@@ -733,6 +733,7 @@
 
 
 static struct file_operations cache_file_operations = {
+	.owner		= THIS_MODULE,
 	.llseek		= no_llseek,
 	.read		= cache_read,
 	.write		= cache_write,
diff -Nru a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
--- a/net/sunrpc/clnt.c	Thu Mar 27 10:32:25 2003
+++ b/net/sunrpc/clnt.c	Wed May  7 04:03:10 2003
@@ -57,8 +57,7 @@
 static void	call_refreshresult(struct rpc_task *task);
 static void	call_timeout(struct rpc_task *task);
 static void	call_connect(struct rpc_task *task);
-static void	child_connect(struct rpc_task *task);
-static void	child_connect_status(struct rpc_task *task);
+static void	call_connect_status(struct rpc_task *task);
 static u32 *	call_header(struct rpc_task *task);
 static u32 *	call_verify(struct rpc_task *task);
 
@@ -602,40 +601,48 @@
 call_connect(struct rpc_task *task)
 {
 	struct rpc_clnt *clnt = task->tk_client;
-	struct rpc_task *child;
 
 	dprintk("RPC: %4d call_connect status %d\n",
 				task->tk_pid, task->tk_status);
 
-	task->tk_action = call_transmit;
-	if (task->tk_status < 0 || !clnt->cl_xprt->stream)
+	if (xprt_connected(clnt->cl_xprt)) {
+		task->tk_action = call_transmit;
 		return;
-
-	/* Run as a child to ensure it runs as an rpciod task.  Rpciod
-	 * guarantees we have the correct capabilities for socket bind
-	 * to succeed. */
-	child = rpc_new_child(clnt, task);
-	if (child) {
-		child->tk_action = child_connect;
-		rpc_run_child(task, child, NULL);
 	}
+	task->tk_action = call_connect_status;
+	if (task->tk_status < 0)
+		return;
+	xprt_connect(task);
 }
 
+/*
+ * 4b. Sort out connect result
+ */
 static void
-child_connect(struct rpc_task *task)
+call_connect_status(struct rpc_task *task)
 {
+	struct rpc_clnt *clnt = task->tk_client;
+	int status = task->tk_status;
+
 	task->tk_status = 0;
-	task->tk_action = child_connect_status;
-	xprt_connect(task);
-}
+	if (status >= 0) {
+		clnt->cl_stats->netreconn++;
+		task->tk_action = call_transmit;
+		return;
+	}
 
-static void
-child_connect_status(struct rpc_task *task)
-{
-	if (task->tk_status == -EAGAIN)
-		task->tk_action = child_connect;
-	else
-		task->tk_action = NULL;
+	/* Something failed: we may have to rebind */
+	if (clnt->cl_autobind)
+		clnt->cl_port = 0;
+	switch (status) {
+	case -ENOTCONN:
+	case -ETIMEDOUT:
+	case -EAGAIN:
+		task->tk_action = (clnt->cl_port == 0) ? call_bind : call_connect;
+		break;
+	default:
+		rpc_exit(task, -EIO);
+	}
 }
 
 /*
@@ -696,6 +703,7 @@
 		break;
 	case -ECONNREFUSED:
 	case -ENOTCONN:
+		req->rq_bytes_sent = 0;
 		if (clnt->cl_autobind)
 			clnt->cl_port = 0;
 		task->tk_action = call_bind;
diff -Nru a/net/sunrpc/pmap_clnt.c b/net/sunrpc/pmap_clnt.c
--- a/net/sunrpc/pmap_clnt.c	Wed Nov 13 07:08:03 2002
+++ b/net/sunrpc/pmap_clnt.c	Tue May 20 19:39:24 2003
@@ -288,7 +288,7 @@
 struct rpc_program	pmap_program = {
 	.name		= "portmap",
 	.number		= RPC_PMAP_PROGRAM,
-	.nrvers		= sizeof(pmap_version)/sizeof(pmap_version[0]),
+	.nrvers		= ARRAY_SIZE(pmap_version),
 	.version	= pmap_version,
 	.stats		= &pmap_stats,
 };
diff -Nru a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c
--- a/net/sunrpc/rpc_pipe.c	Fri Apr 25 15:16:53 2003
+++ b/net/sunrpc/rpc_pipe.c	Tue May 13 13:42:28 2003
@@ -156,7 +156,7 @@
 }
 
 static ssize_t
-rpc_pipe_read(struct file *filp, char *buf, size_t len, loff_t *offset)
+rpc_pipe_read(struct file *filp, char __user *buf, size_t len, loff_t *offset)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct rpc_inode *rpci = RPC_I(inode);
@@ -193,7 +193,7 @@
 }
 
 static ssize_t
-rpc_pipe_write(struct file *filp, const char *buf, size_t len, loff_t *offset)
+rpc_pipe_write(struct file *filp, const char __user *buf, size_t len, loff_t *offset)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
 	struct rpc_inode *rpci = RPC_I(inode);
@@ -310,6 +310,7 @@
 }
 
 static struct file_operations rpc_info_operations = {
+	.owner		= THIS_MODULE,
 	.open		= rpc_info_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
diff -Nru a/net/sunrpc/sched.c b/net/sunrpc/sched.c
--- a/net/sunrpc/sched.c	Thu May  1 09:52:23 2003
+++ b/net/sunrpc/sched.c	Wed May  7 03:59:41 2003
@@ -1110,9 +1110,10 @@
 	alltask_for_each(t, le, &all_tasks)
 		printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n",
 			t->tk_pid,
-			(t->tk_msg.rpc_proc->p_proc ? t->tk_msg.rpc_proc->p_proc : -1),
+			(t->tk_msg.rpc_proc ? t->tk_msg.rpc_proc->p_proc : -1),
 			t->tk_flags, t->tk_status,
-			t->tk_client, t->tk_client->cl_prog,
+			t->tk_client,
+			(t->tk_client ? t->tk_client->cl_prog : 0),
 			t->tk_rqstp, t->tk_timeout,
 			rpc_qname(t->tk_rpcwait),
 			t->tk_action, t->tk_exit);
diff -Nru a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c
--- a/net/sunrpc/svcsock.c	Tue Apr 29 02:29:49 2003
+++ b/net/sunrpc/svcsock.c	Mon May 19 23:34:35 2003
@@ -35,6 +35,7 @@
 #include <net/sock.h>
 #include <net/checksum.h>
 #include <net/ip.h>
+#include <net/tcp.h>
 #include <asm/uaccess.h>
 #include <asm/ioctls.h>
 
@@ -116,6 +117,22 @@
 }
 
 /*
+ * Any space to write?
+ */
+static inline unsigned long
+svc_sock_wspace(struct svc_sock *svsk)
+{
+	int wspace;
+
+	if (svsk->sk_sock->type == SOCK_STREAM)
+		wspace = tcp_wspace(svsk->sk_sk);
+	else
+		wspace = sock_wspace(svsk->sk_sk);
+
+	return wspace;
+}
+
+/*
  * Queue up a socket with data pending. If there are idle nfsd
  * processes, wake 'em up.
  *
@@ -149,16 +166,18 @@
 		goto out_unlock;
 	}
 
+	set_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
 	if (((svsk->sk_reserved + serv->sv_bufsz)*2
-	     > sock_wspace(svsk->sk_sk))
+	     > svc_sock_wspace(svsk))
 	    && !test_bit(SK_CLOSE, &svsk->sk_flags)
 	    && !test_bit(SK_CONN, &svsk->sk_flags)) {
 		/* Don't enqueue while not enough space for reply */
 		dprintk("svc: socket %p  no space, %d*2 > %ld, not enqueued\n",
 			svsk->sk_sk, svsk->sk_reserved+serv->sv_bufsz,
-			sock_wspace(svsk->sk_sk));
+			svc_sock_wspace(svsk));
 		goto out_unlock;
 	}
+	clear_bit(SOCK_NOSPACE, &svsk->sk_sock->flags);
 
 	/* Mark socket as busy. It will remain in this state until the
 	 * server has processed all pending data and put the socket back
@@ -341,9 +360,6 @@
 
 	slen = xdr->len;
 
-	/* Grab svsk->sk_sem to serialize outgoing data. */
-	down(&svsk->sk_sem);
-
 	if (rqstp->rq_prot == IPPROTO_UDP) {
 		/* set the destination */
 		struct msghdr	msg;
@@ -396,8 +412,6 @@
 			len += result;
 	}
 out:
-	up(&svsk->sk_sem);
-
 	dprintk("svc: socket %p sendto([%p %Zu... ], %d) = %d (addr %x)\n",
 			rqstp->rq_sock, xdr->head[0].iov_base, xdr->head[0].iov_len, xdr->len, len,
 		rqstp->rq_addr.sin_addr.s_addr);
@@ -886,8 +900,12 @@
 			goto error;
 		svsk->sk_tcplen += len;
 
-		if (len < want)
-			return 0;
+		if (len < want) {
+			dprintk("svc: short recvfrom while reading record length (%d of %lu)\n",
+			        len, want);
+			svc_sock_received(svsk);
+			return -EAGAIN; /* record header not complete */
+		}
 
 		svsk->sk_reclen = ntohl(svsk->sk_reclen);
 		if (!(svsk->sk_reclen & 0x80000000)) {
@@ -1011,6 +1029,7 @@
 svc_tcp_init(struct svc_sock *svsk)
 {
 	struct sock	*sk = svsk->sk_sk;
+	struct tcp_opt  *tp = tcp_sk(sk);
 
 	svsk->sk_recvfrom = svc_tcp_recvfrom;
 	svsk->sk_sendto = svc_tcp_sendto;
@@ -1028,6 +1047,8 @@
 		svsk->sk_reclen = 0;
 		svsk->sk_tcplen = 0;
 
+		tp->nonagle = 1;        /* disable Nagle's algorithm */
+
 		/* initialise setting must have enough space to
 		 * receive and respond to one request.  
 		 * svc_tcp_recvfrom will re-adjust if necessary
@@ -1232,7 +1253,13 @@
 		xb->page_len +
 		xb->tail[0].iov_len;
 
-	len = svsk->sk_sendto(rqstp);
+	/* Grab svsk->sk_sem to serialize outgoing data. */
+	down(&svsk->sk_sem);
+	if (test_bit(SK_DEAD, &svsk->sk_flags))
+		len = -ENOTCONN;
+	else
+		len = svsk->sk_sendto(rqstp);
+	up(&svsk->sk_sem);
 	svc_sock_release(rqstp);
 
 	if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
diff -Nru a/net/sunrpc/xdr.c b/net/sunrpc/xdr.c
--- a/net/sunrpc/xdr.c	Wed Dec 18 09:22:06 2002
+++ b/net/sunrpc/xdr.c	Wed May  7 04:07:31 2003
@@ -13,6 +13,8 @@
 #include <linux/pagemap.h>
 #include <linux/errno.h>
 #include <linux/in.h>
+#include <linux/net.h>
+#include <net/sock.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/msg_prot.h>
 
@@ -314,8 +316,113 @@
 	} while ((pglen -= len) != 0);
 copy_tail:
 	len = xdr->tail[0].iov_len;
-	if (len)
-		copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len);
+	if (base < len)
+		copy_actor(desc, (char *)xdr->tail[0].iov_base + base, len - base);
+}
+
+
+int
+xdr_sendpages(struct socket *sock, struct sockaddr *addr, int addrlen,
+		struct xdr_buf *xdr, unsigned int base, int msgflags)
+{
+	struct page **ppage = xdr->pages;
+	unsigned int len, pglen = xdr->page_len;
+	int err, ret = 0;
+	ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
+	mm_segment_t oldfs;
+
+	len = xdr->head[0].iov_len;
+	if (base < len || (addr != NULL && base == 0)) {
+		struct iovec iov = {
+			.iov_base = xdr->head[0].iov_base + base,
+			.iov_len  = len - base,
+		};
+		struct msghdr msg = {
+			.msg_name    = addr,
+			.msg_namelen = addrlen,
+			.msg_flags   = msgflags,
+		};
+
+		if (iov.iov_len != 0) {
+			msg.msg_iov     = &iov;
+			msg.msg_iovlen  = 1;
+		}
+		if (xdr->len > len)
+			msg.msg_flags |= MSG_MORE;
+		oldfs = get_fs(); set_fs(get_ds());
+		err = sock_sendmsg(sock, &msg, iov.iov_len);
+		set_fs(oldfs);
+		if (ret == 0)
+			ret = err;
+		else if (err > 0)
+			ret += err;
+		if (err != iov.iov_len)
+			goto out;
+		base = 0;
+	} else
+		base -= len;
+
+	if (pglen == 0)
+		goto copy_tail;
+	if (base >= pglen) {
+		base -= pglen;
+		goto copy_tail;
+	}
+	if (base || xdr->page_base) {
+		pglen -= base;
+		base  += xdr->page_base;
+		ppage += base >> PAGE_CACHE_SHIFT;
+		base &= ~PAGE_CACHE_MASK;
+	}
+
+	sendpage = sock->ops->sendpage ? : sock_no_sendpage;
+	do {
+		int flags = msgflags;
+
+		len = PAGE_CACHE_SIZE;
+		if (base)
+			len -= base;
+		if (pglen < len)
+			len = pglen;
+
+		if (pglen != len || xdr->tail[0].iov_len != 0)
+			flags |= MSG_MORE;
+
+		/* Hmm... We might be dealing with highmem pages */
+		if (PageHighMem(*ppage))
+			sendpage = sock_no_sendpage;
+		err = sendpage(sock, *ppage, base, len, flags);
+		if (ret == 0)
+			ret = err;
+		else if (err > 0)
+			ret += err;
+		if (err != len)
+			goto out;
+		base = 0;
+		ppage++;
+	} while ((pglen -= len) != 0);
+copy_tail:
+	len = xdr->tail[0].iov_len;
+	if (base < len) {
+		struct iovec iov = {
+			.iov_base = xdr->tail[0].iov_base + base,
+			.iov_len  = len - base,
+		};
+		struct msghdr msg = {
+			.msg_iov     = &iov,
+			.msg_iovlen  = 1,
+			.msg_flags   = msgflags,
+		};
+		oldfs = get_fs(); set_fs(get_ds());
+		err = sock_sendmsg(sock, &msg, iov.iov_len);
+		set_fs(oldfs);
+		if (ret == 0)
+			ret = err;
+		else if (err > 0)
+			ret += err;
+	}
+out:
+	return ret;
 }
 
 
diff -Nru a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
--- a/net/sunrpc/xprt.c	Mon Apr  7 15:18:12 2003
+++ b/net/sunrpc/xprt.c	Wed May  7 04:07:31 2003
@@ -85,7 +85,7 @@
 static void	xprt_request_init(struct rpc_task *, struct rpc_xprt *);
 static inline void	do_xprt_reserve(struct rpc_task *);
 static void	xprt_disconnect(struct rpc_xprt *);
-static void	xprt_conn_status(struct rpc_task *task);
+static void	xprt_connect_status(struct rpc_task *task);
 static struct rpc_xprt * xprt_setup(int proto, struct sockaddr_in *ap,
 						struct rpc_timeout *to);
 static struct socket *xprt_create_socket(int, struct rpc_timeout *, int);
@@ -213,11 +213,10 @@
 xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req)
 {
 	struct socket	*sock = xprt->sock;
-	struct msghdr	msg;
 	struct xdr_buf	*xdr = &req->rq_snd_buf;
-	struct iovec	niv[MAX_IOVEC];
-	unsigned int	niov, slen, skip;
-	mm_segment_t	oldfs;
+	struct sockaddr *addr = NULL;
+	int addrlen = 0;
+	unsigned int	skip;
 	int		result;
 
 	if (!sock)
@@ -227,27 +226,18 @@
 				req->rq_svec->iov_base,
 				req->rq_svec->iov_len);
 
+	/* For UDP, we need to provide an address */
+	if (!xprt->stream) {
+		addr = (struct sockaddr *) &xprt->addr;
+		addrlen = sizeof(xprt->addr);
+	}
 	/* Dont repeat bytes */
 	skip = req->rq_bytes_sent;
-	slen = xdr->len - skip;
-	niov = xdr_kmap(niv, xdr, skip);
-
-	msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
-	msg.msg_iov	= niv;
-	msg.msg_iovlen	= niov;
-	msg.msg_name	= (struct sockaddr *) &xprt->addr;
-	msg.msg_namelen = sizeof(xprt->addr);
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
 
-	oldfs = get_fs(); set_fs(get_ds());
 	clear_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
-	result = sock_sendmsg(sock, &msg, slen);
-	set_fs(oldfs);
+	result = xdr_sendpages(sock, addr, addrlen, xdr, skip, MSG_DONTWAIT);
 
-	xdr_kunmap(xdr, skip);
-
-	dprintk("RPC:      xprt_sendmsg(%d) = %d\n", slen, result);
+	dprintk("RPC:      xprt_sendmsg(%d) = %d\n", xdr->len - skip, result);
 
 	if (result >= 0)
 		return result;
@@ -259,6 +249,7 @@
 		 */
 	case -EAGAIN:
 		break;
+	case -ECONNRESET:
 	case -ENOTCONN:
 	case -EPIPE:
 		/* connection broken */
@@ -376,6 +367,7 @@
 	if (!sk)
 		return;
 
+	write_lock_bh(&sk->callback_lock);
 	xprt->inet = NULL;
 	xprt->sock = NULL;
 
@@ -383,6 +375,7 @@
 	sk->data_ready   = xprt->old_data_ready;
 	sk->state_change = xprt->old_state_change;
 	sk->write_space  = xprt->old_write_space;
+	write_unlock_bh(&sk->callback_lock);
 
 	xprt_disconnect(xprt);
 	sk->no_check	 = 0;
@@ -397,14 +390,15 @@
 xprt_disconnect(struct rpc_xprt *xprt)
 {
 	dprintk("RPC:      disconnected transport %p\n", xprt);
+	spin_lock_bh(&xprt->sock_lock);
 	xprt_clear_connected(xprt);
 	rpc_wake_up_status(&xprt->pending, -ENOTCONN);
+	spin_unlock_bh(&xprt->sock_lock);
 }
 
 /*
  * Attempt to connect a TCP socket.
  *
- * NB: This never collides with TCP reads, as both run from rpciod
  */
 void
 xprt_connect(struct rpc_task *task)
@@ -442,6 +436,10 @@
 		goto out_write;
 	}
 	xprt_bind_socket(xprt, sock);
+
+	if (!xprt->stream)
+		goto out_write;
+
 	inet = sock->sk;
 
 	/*
@@ -452,6 +450,9 @@
 	dprintk("RPC: %4d  connect status %d connected %d sock state %d\n",
 		task->tk_pid, -status, xprt_connected(xprt), inet->state);
 
+	if (status >= 0)
+		return;
+
 	switch (status) {
 	case -EINPROGRESS:
 	case -EALREADY:
@@ -464,53 +465,37 @@
 			/* if the socket is already closing, delay briefly */
 			if ((1 << inet->state) & ~(TCPF_SYN_SENT|TCPF_SYN_RECV))
 				task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
-			rpc_sleep_on(&xprt->pending, task, xprt_conn_status,
+			rpc_sleep_on(&xprt->pending, task, xprt_connect_status,
 									NULL);
-			release_sock(inet);
-			/* task status set when task wakes up again */
-			return;
 		}
 		release_sock(inet);
-		task->tk_status = 0;
 		break;
-
-	case 0:
-	case -EISCONN:	/* not likely, but just in case */
-		/* Half closed state.  No race -- this socket is dead. */
-		if (inet->state != TCP_ESTABLISHED) {
-			xprt_close(xprt);
-			task->tk_status = -EAGAIN;
-			goto out_write;
+	case -ECONNREFUSED:
+	case -ECONNRESET:
+	case -ENOTCONN:
+		if (!task->tk_client->cl_softrtry) {
+			rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
+			task->tk_status = -ENOTCONN;
+			break;
 		}
-
-		/* Otherwise, the connection is already established. */
-		task->tk_status = 0;
-		break;
-
-	case -EPIPE:
-		xprt_close(xprt);
-		task->tk_status = -ENOTCONN;
-		goto out_write;
-
 	default:
 		/* Report myriad other possible returns.  If this file
 		 * system is soft mounted, just error out, like Solaris.  */
-		xprt_close(xprt);
 		if (task->tk_client->cl_softrtry) {
 			printk(KERN_WARNING
 			"RPC: error %d connecting to server %s, exiting\n",
 					-status, task->tk_client->cl_server);
 			task->tk_status = -EIO;
-		} else {
-			printk(KERN_WARNING
-			"RPC: error %d connecting to server %s\n",
-					-status, task->tk_client->cl_server);
-			rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
-			task->tk_status = status;
+			goto out_write;
 		}
+		printk(KERN_WARNING "RPC: error %d connecting to server %s\n",
+				-status, task->tk_client->cl_server);
+		/* This will prevent anybody else from reconnecting */
+		rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
+		task->tk_status = status;
 		break;
 	}
-
+	return;
  out_write:
 	xprt_release_write(xprt, task);
 }
@@ -519,33 +504,32 @@
  * We arrive here when awoken from waiting on connection establishment.
  */
 static void
-xprt_conn_status(struct rpc_task *task)
+xprt_connect_status(struct rpc_task *task)
 {
 	struct rpc_xprt	*xprt = task->tk_xprt;
 
-	switch (task->tk_status) {
-	case 0:
-		dprintk("RPC: %4d xprt_conn_status: connection established\n",
+	if (task->tk_status >= 0) {
+		dprintk("RPC: %4d xprt_connect_status: connection established\n",
 				task->tk_pid);
-		goto out;
+		return;
+	}
+
+	/* if soft mounted, just cause this RPC to fail */
+	if (task->tk_client->cl_softrtry)
+		task->tk_status = -EIO;
+
+	switch (task->tk_status) {
+	case -ENOTCONN:
+		rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
+		return;
 	case -ETIMEDOUT:
-		dprintk("RPC: %4d xprt_conn_status: timed out\n",
+		dprintk("RPC: %4d xprt_connect_status: timed out\n",
 				task->tk_pid);
-		/* prevent TCP from continuing to retry SYNs */
-		xprt_close(xprt);
 		break;
 	default:
 		printk(KERN_ERR "RPC: error %d connecting to server %s\n",
 				-task->tk_status, task->tk_client->cl_server);
-		xprt_close(xprt);
-		rpc_delay(task, RPC_REESTABLISH_TIMEOUT);
-		break;
 	}
-	/* if soft mounted, cause this RPC to fail */
-	if (task->tk_client->cl_softrtry)
-		task->tk_status = -EIO;
-
- out:
 	xprt_release_write(xprt, task);
 }
 
@@ -695,6 +679,7 @@
 	struct sk_buff	*skb;
 	int		err, repsize, copied;
 
+	read_lock(&sk->callback_lock);
 	dprintk("RPC:      udp_data_ready...\n");
 	if (!(xprt = xprt_from_sock(sk))) {
 		printk("RPC:      udp_data_ready request not found!\n");
@@ -745,6 +730,7 @@
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
+	read_unlock(&sk->callback_lock);
 }
 
 /*
@@ -939,7 +925,7 @@
 		}
 		/* Skip over any trailing bytes on short reads */
 		tcp_read_discard(xprt, &desc);
-	} while (desc.count && xprt_connected(xprt));
+	} while (desc.count);
 	dprintk("RPC:      tcp_data_recv done\n");
 	return len - desc.count;
 }
@@ -949,18 +935,21 @@
 	struct rpc_xprt *xprt;
 	read_descriptor_t rd_desc;
 
+	read_lock(&sk->callback_lock);
 	dprintk("RPC:      tcp_data_ready...\n");
 	if (!(xprt = xprt_from_sock(sk))) {
 		printk("RPC:      tcp_data_ready socket info not found!\n");
-		return;
+		goto out;
 	}
 	if (xprt->shutdown)
-		return;
+		goto out;
 
 	/* We use rd_desc to pass struct xprt to tcp_data_recv */
 	rd_desc.buf = (char *)xprt;
 	rd_desc.count = 65536;
 	tcp_read_sock(sk, &rd_desc, tcp_data_recv);
+out:
+	read_unlock(&sk->callback_lock);
 }
 
 static void
@@ -968,6 +957,7 @@
 {
 	struct rpc_xprt	*xprt;
 
+	read_lock(&sk->callback_lock);
 	if (!(xprt = xprt_from_sock(sk)))
 		goto out;
 	dprintk("RPC:      tcp_state_change client %p...\n", xprt);
@@ -977,19 +967,19 @@
 
 	switch (sk->state) {
 	case TCP_ESTABLISHED:
-		if (xprt_test_and_set_connected(xprt))
-			break;
+		spin_lock_bh(&xprt->sock_lock);
+		if (!xprt_test_and_set_connected(xprt)) {
+			/* Reset TCP record info */
+			xprt->tcp_offset = 0;
+			xprt->tcp_reclen = 0;
+			xprt->tcp_copied = 0;
+			xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
 
-		/* Reset TCP record info */
-		xprt->tcp_offset = 0;
-		xprt->tcp_reclen = 0;
-		xprt->tcp_copied = 0;
-		xprt->tcp_flags = XPRT_COPY_RECM | XPRT_COPY_XID;
-
-		spin_lock(&xprt->sock_lock);
-		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
-			rpc_wake_up_task(xprt->snd_task);
-		spin_unlock(&xprt->sock_lock);
+			if (xprt->snd_task)
+				rpc_wake_up_task(xprt->snd_task);
+			rpc_wake_up(&xprt->pending);
+		}
+		spin_unlock_bh(&xprt->sock_lock);
 		break;
 	case TCP_SYN_SENT:
 	case TCP_SYN_RECV:
@@ -1001,6 +991,7 @@
  out:
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible_all(sk->sleep);
+	read_unlock(&sk->callback_lock);
 }
 
 /*
@@ -1015,24 +1006,25 @@
 	struct rpc_xprt	*xprt;
 	struct socket	*sock;
 
+	read_lock(&sk->callback_lock);
 	if (!(xprt = xprt_from_sock(sk)) || !(sock = sk->socket))
-		return;
+		goto out;
 	if (xprt->shutdown)
-		return;
+		goto out;
 
 	/* Wait until we have enough socket memory */
 	if (xprt->stream) {
 		/* from net/ipv4/tcp.c:tcp_write_space */
 		if (tcp_wspace(sk) < tcp_min_write_space(sk))
-			return;
+			goto out;
 	} else {
 		/* from net/core/sock.c:sock_def_write_space */
 		if (!sock_writeable(sk))
-			return;
+			goto out;
 	}
 
 	if (!test_and_clear_bit(SOCK_NOSPACE, &sock->flags))
-		return;
+		goto out;
 
 	spin_lock_bh(&xprt->sock_lock);
 	if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->pending)
@@ -1040,6 +1032,8 @@
 	spin_unlock_bh(&xprt->sock_lock);
 	if (sk->sleep && waitqueue_active(sk->sleep))
 		wake_up_interruptible(sk->sleep);
+out:
+	read_unlock(&sk->callback_lock);
 }
 
 /*
@@ -1107,9 +1101,6 @@
 	if (xprt->shutdown)
 		return -EIO;
 
-	if (!xprt_connected(xprt))
-		return -ENOTCONN;
-
 	if (task->tk_rpcwait)
 		rpc_remove_wait_queue(task);
 
@@ -1118,6 +1109,12 @@
 		err = -EAGAIN;
 		goto out_unlock;
 	}
+
+	if (!xprt_connected(xprt)) {
+		err = -ENOTCONN;
+		goto out_unlock;
+	}
+
 	if (list_empty(&req->rq_list)) {
 		list_add_tail(&req->rq_list, &xprt->recv);
 		req->rq_received = 0;
@@ -1192,7 +1189,10 @@
 		if (test_bit(SOCK_ASYNC_NOSPACE, &xprt->sock->flags)) {
 			/* Protect against races with xprt_write_space */
 			spin_lock_bh(&xprt->sock_lock);
-			if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) {
+			/* Don't race with disconnect */
+			if (!xprt_connected(xprt))
+				task->tk_status = -ENOTCONN;
+			else if (test_bit(SOCK_NOSPACE, &xprt->sock->flags)) {
 				task->tk_timeout = req->rq_timeout.to_current;
 				rpc_sleep_on(&xprt->pending, task, NULL, NULL);
 			}
@@ -1203,20 +1203,17 @@
 		rpc_delay(task, HZ>>4);
 		return;
 	case -ECONNREFUSED:
+		task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
+		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
 	case -ENOTCONN:
-		if (!xprt->stream) {
-			task->tk_timeout = RPC_REESTABLISH_TIMEOUT;
-			rpc_sleep_on(&xprt->sending, task, NULL, NULL);
-			return;
-		}
-		/* fall through */
+		return;
 	default:
 		if (xprt->stream)
 			xprt_disconnect(xprt);
-		req->rq_bytes_sent = 0;
 	}
  out_release:
 	xprt_release_write(xprt, task);
+	req->rq_bytes_sent = 0;
 	return;
  out_receive:
 	dprintk("RPC: %4d xmit complete\n", task->tk_pid);
@@ -1230,10 +1227,14 @@
 	} else
 		task->tk_timeout = req->rq_timeout.to_current;
 	spin_lock_bh(&xprt->sock_lock);
-	if (!req->rq_received)
+	/* Don't race with disconnect */
+	if (!xprt_connected(xprt))
+		task->tk_status = -ENOTCONN;
+	else if (!req->rq_received)
 		rpc_sleep_on(&xprt->pending, task, NULL, xprt_timer);
 	__xprt_release_write(xprt, task);
 	spin_unlock_bh(&xprt->sock_lock);
+	req->rq_bytes_sent = 0;
 }
 
 /*
@@ -1417,6 +1418,9 @@
 	req->rq_next = NULL;
 	xprt->free = xprt->slot;
 
+	/* Check whether we want to use a reserved port */
+	xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
+
 	dprintk("RPC:      created transport %p\n", xprt);
 	
 	return xprt;
@@ -1430,6 +1434,12 @@
 {
 	struct sockaddr_in myaddr;
 	int		err, port;
+	kernel_cap_t saved_cap = current->cap_effective;
+
+	/* Override capabilities.
+	 * They were checked in xprt_create_proto i.e. at mount time
+	 */
+	cap_raise(current->cap_effective, CAP_NET_BIND_SERVICE);
 
 	memset(&myaddr, 0, sizeof(myaddr));
 	myaddr.sin_family = AF_INET;
@@ -1439,6 +1449,7 @@
 		err = sock->ops->bind(sock, (struct sockaddr *) &myaddr,
 						sizeof(myaddr));
 	} while (err == -EADDRINUSE && --port > 0);
+	current->cap_effective = saved_cap;
 
 	if (err < 0)
 		printk("RPC: Can't bind to reserved port (%d).\n", -err);
@@ -1454,6 +1465,7 @@
 	if (xprt->inet)
 		return;
 
+	write_lock_bh(&sk->callback_lock);
 	sk->user_data = xprt;
 	xprt->old_data_ready = sk->data_ready;
 	xprt->old_state_change = sk->state_change;
@@ -1474,6 +1486,7 @@
 	/* Reset to new socket */
 	xprt->sock = sock;
 	xprt->inet = sk;
+	write_unlock_bh(&sk->callback_lock);
 
 	return;
 }
@@ -1543,16 +1556,6 @@
 	xprt = xprt_setup(proto, sap, to);
 	if (!xprt)
 		goto out_bad;
-
-	xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
-	if (!xprt->stream) {
-		struct socket *sock;
-
-		sock = xprt_create_socket(proto, to, xprt->resvport);
-		if (!sock)
-			goto out_bad;
-		xprt_bind_socket(xprt, sock);
-	}
 
 	dprintk("RPC:      xprt_create_proto created xprt %p\n", xprt);
 	return xprt;
diff -Nru a/net/unix/af_unix.c b/net/unix/af_unix.c
--- a/net/unix/af_unix.c	Fri May  2 23:39:37 2003
+++ b/net/unix/af_unix.c	Wed May 14 20:37:15 2003
@@ -169,7 +169,7 @@
 	return peer;
 }
 
-extern inline void unix_release_addr(struct unix_address *addr)
+static inline void unix_release_addr(struct unix_address *addr)
 {
 	if (atomic_dec_and_test(&addr->refcnt))
 		kfree(addr);
@@ -625,7 +625,7 @@
 			goto put_fail;
 
 		if (u->type == type)
-			UPDATE_ATIME(nd.dentry->d_inode);
+			update_atime(nd.dentry->d_inode);
 
 		path_release(&nd);
 
@@ -641,7 +641,7 @@
 			struct dentry *dentry;
 			dentry = unix_sk(u)->dentry;
 			if (dentry)
-				UPDATE_ATIME(dentry->d_inode);
+				update_atime(dentry->d_inode);
 		} else
 			goto fail;
 	}
diff -Nru a/net/wanrouter/af_wanpipe.c b/net/wanrouter/af_wanpipe.c
--- a/net/wanrouter/af_wanpipe.c	Fri May  2 23:40:20 2003
+++ b/net/wanrouter/af_wanpipe.c	Thu May 15 14:42:07 2003
@@ -170,7 +170,7 @@
 {
 	void   *mbox;		/* Mail box  */
 	void   *card; 		/* Card bouded to */
-	netdevice_t *dev;	/* Bounded device */
+	struct net_device *dev;	/* Bounded device */
 	unsigned short lcn;	/* Binded LCN */
 	unsigned char  svc;	/* 0=pvc, 1=svc */
 	unsigned char  timer;   /* flag for delayed transmit*/	
@@ -185,25 +185,26 @@
 extern struct proto_ops wanpipe_ops;
 static unsigned long find_free_critical;
 
-static void wanpipe_unlink_driver (struct sock *);
-static void wanpipe_link_driver (netdevice_t *,struct sock *sk);
+static void wanpipe_unlink_driver(struct sock *sk);
+static void wanpipe_link_driver(struct net_device *dev, struct sock *sk);
 static void wanpipe_wakeup_driver(struct sock *sk);
 static int execute_command(struct sock *, unsigned char, unsigned int);
-static int check_dev (netdevice_t *, sdla_t *);
-netdevice_t * wanpipe_find_free_dev (sdla_t *);
+static int check_dev(struct net_device *dev, sdla_t *card);
+struct net_device *wanpipe_find_free_dev(sdla_t *card);
 static void wanpipe_unlink_card (struct sock *);
 static int wanpipe_link_card (struct sock *);
 static struct sock *wanpipe_make_new(struct sock *);
 static struct sock *wanpipe_alloc_socket(void);
-static inline int get_atomic_device (netdevice_t *);
+static inline int get_atomic_device(struct net_device *dev);
 static int wanpipe_exec_cmd(struct sock *, int, unsigned int);
 static int get_ioctl_cmd (struct sock *, void *);
 static int set_ioctl_cmd (struct sock *, void *);
-static void release_device (netdevice_t *);
+static void release_device(struct net_device *dev);
 static void wanpipe_kill_sock_timer (unsigned long data);
 static void wanpipe_kill_sock_irq (struct sock *);
 static void wanpipe_kill_sock_accept (struct sock *);
-static int wanpipe_do_bind(struct sock *, netdevice_t *, int);
+static int wanpipe_do_bind(struct sock *sk, struct net_device *dev,
+			   int protocol);
 struct sock * get_newsk_from_skb (struct sk_buff *);
 static int wanpipe_debug (struct sock *, void *);
 static void wanpipe_delayed_transmit (unsigned long data);
@@ -225,7 +226,8 @@
  *      WANPIPE driver private.
  *===========================================================*/
 
-static int wanpipe_rcv(struct sk_buff *skb, netdevice_t *dev,  struct sock *sk)
+static int wanpipe_rcv(struct sk_buff *skb, struct net_device *dev,
+		       struct sock *sk)
 {
 	struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb;
 	wanpipe_common_t *chan = dev->priv;
@@ -323,7 +325,7 @@
 	wanpipe_opt *wp = wp_sk(sk), *newwp;
 	struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)skb->cb;
 	struct sock *newsk;
-	netdevice_t *dev; 
+	struct net_device *dev; 
 	sdla_t *card;
 	mbox_cmd_t *mbox_ptr;
 	wanpipe_common_t *chan;
@@ -539,7 +541,7 @@
 	struct sock *sk = sock->sk;
 	struct wan_sockaddr_ll *saddr=(struct wan_sockaddr_ll *)msg->msg_name;
 	struct sk_buff *skb;
-	netdevice_t *dev;
+	struct net_device *dev;
 	unsigned short proto;
 	unsigned char *addr;
 	int ifindex, err, reserve = 0;
@@ -664,7 +666,7 @@
 	struct sock *sk=(struct sock *)data;
 	struct sk_buff *skb;
 	wanpipe_opt *wp = wp_sk(sk);
-	netdevice_t *dev = wp->dev;
+	struct net_device *dev = wp->dev;
 	sdla_t *card = (sdla_t*)wp->card;
 
 	if (!card || !dev){
@@ -756,7 +758,7 @@
 static int execute_command(struct sock *sk,  unsigned char cmd, unsigned int flags)
 {
 	wanpipe_opt *wp = wp_sk(sk);
-	netdevice_t *dev;
+	struct net_device *dev;
 	wanpipe_common_t *chan=NULL;
 	int err=0;
 	DECLARE_WAITQUEUE(wait, current);
@@ -861,7 +863,7 @@
  *===========================================================*/
 static void wanpipe_unlink_driver (struct sock *sk)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	wanpipe_common_t *chan=NULL;
 
 	sk->zapped=0;
@@ -901,7 +903,7 @@
  *      data up the socket.
  *===========================================================*/
 
-static void wanpipe_link_driver (netdevice_t *dev, struct sock *sk)
+static void wanpipe_link_driver(struct net_device *dev, struct sock *sk)
 {
 	wanpipe_opt *wp = wp_sk(sk);
 	wanpipe_common_t *chan = dev->priv;
@@ -926,7 +928,7 @@
  *===========================================================*/
 
 
-static void release_device (netdevice_t *dev)
+static void release_device(struct net_device *dev)
 {
 	wanpipe_common_t *chan=dev->priv;
 	clear_bit(0,(void*)&chan->rw_bind);
@@ -965,7 +967,7 @@
 
 	if (wp->num == htons(X25_PROT) &&
 	    sk->state != WANSOCK_DISCONNECTED && sk->zapped) {
-		netdevice_t *dev = dev_get_by_index(sk->bound_dev_if);
+		struct net_device *dev = dev_get_by_index(sk->bound_dev_if);
 		wanpipe_common_t *chan;
 		if (dev){
 			chan=dev->priv;
@@ -1153,7 +1155,7 @@
 
 	if (wp_sk(sk)->num == htons(X25_PROT) &&
 	    sk->state != WANSOCK_DISCONNECTED){
-		netdevice_t *dev = dev_get_by_index(sk->bound_dev_if);
+		struct net_device *dev = dev_get_by_index(sk->bound_dev_if);
 		wanpipe_common_t *chan;
 		if (dev){
 			chan=dev->priv;
@@ -1268,7 +1270,8 @@
  *      sock to the driver.
  *===========================================================*/
 
-static int wanpipe_do_bind(struct sock *sk, netdevice_t *dev, int protocol)
+static int wanpipe_do_bind(struct sock *sk, struct net_device *dev,
+			   int protocol)
 {
 	wanpipe_opt *wp = wp_sk(sk);
 	wanpipe_common_t *chan=NULL;
@@ -1341,7 +1344,7 @@
 	struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr;
 	struct sock *sk=sock->sk;
 	wanpipe_opt *wp = wp_sk(sk);
-	netdevice_t *dev = NULL;
+	struct net_device *dev = NULL;
 	sdla_t *card=NULL;
 	char name[15];
 
@@ -1436,7 +1439,7 @@
  *===========================================================*/
 
 
-static inline int get_atomic_device (netdevice_t *dev)
+static inline int get_atomic_device(struct net_device *dev)
 {
 	wanpipe_common_t *chan = dev->priv;
 	if (!test_and_set_bit(0,(void *)&chan->rw_bind)){
@@ -1451,11 +1454,12 @@
  *  	Check that device name belongs to a particular card.
  *===========================================================*/
 
-static int check_dev (netdevice_t *dev, sdla_t *card)
+static int check_dev(struct net_device *dev, sdla_t *card)
 {
-	netdevice_t* tmp_dev;
+	struct net_device* tmp_dev;
 
-	for (tmp_dev = card->wandev.dev; tmp_dev; tmp_dev=*((netdevice_t**)tmp_dev->priv)){
+	for (tmp_dev = card->wandev.dev; tmp_dev;
+	     tmp_dev = *((struct net_device **)tmp_dev->priv)) {
 		if (tmp_dev->ifindex == dev->ifindex){ 
 			return 0;	
 		}
@@ -1471,16 +1475,17 @@
  *      X25API Specific.
  *===========================================================*/
 
-netdevice_t * wanpipe_find_free_dev (sdla_t *card)
+struct net_device *wanpipe_find_free_dev(sdla_t *card)
 {
-	netdevice_t* dev;
+	struct net_device* dev;
 	volatile wanpipe_common_t *chan;
 
 	if (test_and_set_bit(0,&find_free_critical)){
 		printk(KERN_INFO "CRITICAL in Find Free\n");
 	}	
 
-	for (dev = card->wandev.dev; dev; dev=*((netdevice_t**)dev->priv)){
+	for (dev = card->wandev.dev; dev;
+	     dev = *((struct net_device **)dev->priv)) {
 		chan = dev->priv;
 		if (!chan) 
 			continue;
@@ -1646,7 +1651,7 @@
 
 static void wanpipe_wakeup_driver(struct sock *sk)
 {
-	netdevice_t *dev=NULL;
+	struct net_device *dev = NULL;
 	wanpipe_common_t *chan=NULL;
 
 	dev = dev_get_by_index(sk->bound_dev_if);
@@ -1680,7 +1685,7 @@
 static int wanpipe_getname(struct socket *sock, struct sockaddr *uaddr,
 			  int *uaddr_len, int peer)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	struct sock *sk = sock->sk;
 	struct wan_sockaddr_ll *sll = (struct wan_sockaddr_ll*)uaddr;
 
@@ -1718,7 +1723,7 @@
 static int wanpipe_notifier(struct notifier_block *this, unsigned long msg, void *data)
 {
 	struct sock *sk;
-	netdevice_t *dev = (netdevice_t*)data;
+	struct net_device *dev = (struct net_device *)data;
 	struct wanpipe_opt *po;
 
 	for (sk = wanpipe_sklist; sk; sk = sk->next) {
@@ -1867,7 +1872,7 @@
 static int wanpipe_debug (struct sock *origsk, void *arg)
 {
 	struct sock *sk=NULL;
-	netdevice_t *dev=NULL;
+	struct net_device *dev = NULL;
 	wanpipe_common_t *chan=NULL;
 	int cnt=0, err=0;
 	wan_debug_t *dbg_data = (wan_debug_t *)arg;
@@ -2010,7 +2015,7 @@
 
 	if (!wp_sk(sk)->mbox) {
 		void *mbox_ptr;
-		netdevice_t *dev = dev_get_by_index(sk->bound_dev_if);
+		struct net_device *dev = dev_get_by_index(sk->bound_dev_if);
 		if (!dev)
 			return -ENODEV;
 
@@ -2351,7 +2356,7 @@
 
 static int check_driver_busy (struct sock *sk)
 {
-	netdevice_t *dev = dev_get_by_index(sk->bound_dev_if);
+	struct net_device *dev = dev_get_by_index(sk->bound_dev_if);
 	wanpipe_common_t *chan;
 
 	if (!dev)
@@ -2456,7 +2461,7 @@
 
 struct sock * get_newsk_from_skb (struct sk_buff *skb)
 {
-	netdevice_t *dev = skb->dev;
+	struct net_device *dev = skb->dev;
 	wanpipe_common_t *chan;	
 
 	if (!dev){
@@ -2486,7 +2491,7 @@
 {
 	struct sock *sk = sock->sk;
 	struct wan_sockaddr_ll *addr = (struct wan_sockaddr_ll*)uaddr;
-	netdevice_t *dev;
+	struct net_device *dev;
 	int err;
 
 	if (wp_sk(sk)->num != htons(X25_PROT))
diff -Nru a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
--- a/net/wanrouter/wanmain.c	Mon Nov 25 11:02:36 2002
+++ b/net/wanrouter/wanmain.c	Thu May 15 14:42:07 2003
@@ -127,18 +127,18 @@
  *	WAN device IOCTL handlers
  */
 
-static int device_setup(wan_device_t *wandev, wandev_conf_t *u_conf);
-static int device_stat(wan_device_t *wandev, wandev_stat_t *u_stat);
-static int device_shutdown(wan_device_t *wandev);
-static int device_new_if(wan_device_t *wandev, wanif_conf_t *u_conf);
-static int device_del_if(wan_device_t *wandev, char *u_name);
+static int device_setup(struct wan_device *wandev, wandev_conf_t *u_conf);
+static int device_stat(struct wan_device *wandev, wandev_stat_t *u_stat);
+static int device_shutdown(struct wan_device *wandev);
+static int device_new_if(struct wan_device *wandev, wanif_conf_t *u_conf);
+static int device_del_if(struct wan_device *wandev, char *u_name);
 
 /*
  *	Miscellaneous
  */
 
-static wan_device_t *find_device (char *name);
-static int delete_interface (wan_device_t *wandev, char *name);
+static struct wan_device *find_device (char *name);
+static int delete_interface (struct wan_device *wandev, char *name);
 void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
 void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
 
@@ -148,11 +148,11 @@
  *	Global Data
  */
 
-static char fullname[]		= "Sangoma WANPIPE Router";
-static char copyright[]		= "(c) 1995-2000 Sangoma Technologies Inc.";
-static char modname[]		= ROUTER_NAME;	/* short module name */
-wan_device_t* router_devlist 	= NULL;	/* list of registered devices */
-static int devcnt 		= 0;
+static char fullname[]	= "Sangoma WANPIPE Router";
+static char copyright[]	= "(c) 1995-2000 Sangoma Technologies Inc.";
+static char modname[]   = ROUTER_NAME;	/* short module name */
+struct wan_device* router_devlist;	/* list of registered devices */
+static int devcnt;
 
 /*
  *	Organize Unique Identifiers for encapsulation/decapsulation
@@ -262,7 +262,7 @@
  */
 
 
-int register_wan_device(wan_device_t *wandev)
+int register_wan_device(struct wan_device *wandev)
 {
 	int err, namelen;
 
@@ -322,7 +322,7 @@
 
 int unregister_wan_device(char *name)
 {
-	wan_device_t *wandev, *prev;
+	struct wan_device *wandev, *prev;
 
 	if (name == NULL)
 		return -EINVAL;
@@ -363,8 +363,8 @@
  */
 
 
-int wanrouter_encapsulate (struct sk_buff *skb, netdevice_t *dev,
-	unsigned short type)
+int wanrouter_encapsulate(struct sk_buff *skb, struct net_device *dev,
+			  unsigned short type)
 {
 	int hdr_len = 0;
 
@@ -406,7 +406,7 @@
  */
 
 
-unsigned short wanrouter_type_trans (struct sk_buff *skb, netdevice_t *dev)
+unsigned short wanrouter_type_trans(struct sk_buff *skb, struct net_device *dev)
 {
 	int cnt = skb->data[0] ? 0 : 1;	/* there may be a pad present */
 	unsigned short ethertype;
@@ -457,7 +457,7 @@
 {
 	int err = 0;
 	struct proc_dir_entry *dent;
-	wan_device_t *wandev;
+	struct wan_device *wandev;
 
 	if (!capable(CAP_NET_ADMIN))
 		return -EPERM;
@@ -519,7 +519,7 @@
  *	o call driver's setup() entry point
  */
 
-static int device_setup (wan_device_t *wandev, wandev_conf_t *u_conf)
+static int device_setup(struct wan_device *wandev, wandev_conf_t *u_conf)
 {
 	void *data = NULL;
 	wandev_conf_t *conf;
@@ -595,9 +595,9 @@
  *	o call driver's shutdown() entry point
  */
 
-static int device_shutdown (wan_device_t *wandev)
+static int device_shutdown(struct wan_device *wandev)
 {
-	netdevice_t *dev;
+	struct net_device *dev;
 	int err=0;
 
 	if (wandev->state == WAN_UNCONFIGURED)
@@ -628,7 +628,7 @@
  *	Get WAN device status & statistics.
  */
 
-static int device_stat (wan_device_t *wandev, wandev_stat_t *u_stat)
+static int device_stat(struct wan_device *wandev, wandev_stat_t *u_stat)
 {
 	wandev_stat_t stat;
 
@@ -658,10 +658,10 @@
  *	o register network interface
  */
 
-static int device_new_if (wan_device_t *wandev, wanif_conf_t *u_conf)
+static int device_new_if(struct wan_device *wandev, wanif_conf_t *u_conf)
 {
 	wanif_conf_t conf;
-	netdevice_t *dev=NULL;
+	struct net_device *dev = NULL;
 #ifdef CONFIG_WANPIPE_MULTPPP
 	struct ppp_device *pppdev=NULL;
 #endif
@@ -682,13 +682,14 @@
 		if (pppdev == NULL)
 			return -ENOBUFS;
 		memset(pppdev, 0, sizeof(struct ppp_device));
-		pppdev->dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL);
+		pppdev->dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
 		if (pppdev->dev == NULL) {
 			kfree(pppdev);
 			return -ENOBUFS;
 		}
-		memset(pppdev->dev, 0, sizeof(netdevice_t));
-		err = wandev->new_if(wandev, (netdevice_t *)pppdev, &conf);
+		memset(pppdev->dev, 0, sizeof(struct net_device));
+		err = wandev->new_if(wandev,
+				     (struct net_device *)pppdev, &conf);
 		dev = pppdev->dev;
 #else
 		printk(KERN_INFO "%s: Wanpipe Mulit-Port PPP support has not been compiled in!\n",
@@ -696,10 +697,10 @@
 		return -EPROTONOSUPPORT;
 #endif
 	} else {
-		dev = kmalloc(sizeof(netdevice_t), GFP_KERNEL);
+		dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
 		if (dev == NULL)
 			return -ENOBUFS;
-		memset(dev, 0, sizeof(netdevice_t));
+		memset(dev, 0, sizeof(struct net_device));
 		err = wandev->new_if(wandev, dev, &conf);
 	}
 
@@ -722,7 +723,7 @@
 
 			err = register_netdev(dev);
 			if (!err) {
-				netdevice_t *slave=NULL;
+				struct net_device *slave = NULL;
 				unsigned long smp_flags=0;
 
 				lock_adapter_irq(&wandev->lock, &smp_flags);
@@ -731,10 +732,10 @@
 					wandev->dev = dev;
 				} else {
 					for (slave=wandev->dev;
-					     *((netdevice_t**)slave->priv);
-					     slave=*((netdevice_t**)slave->priv));
+					 *((struct net_device **)slave->priv);
+				 slave = *((struct net_device **)slave->priv));
 
-					*((netdevice_t**)slave->priv) = dev;
+				     *((struct net_device **)slave->priv) = dev;
 				}
 				++wandev->ndev;
 
@@ -774,7 +775,7 @@
  *	 o copy configuration data to kernel address space
  */
 
-static int device_del_if (wan_device_t *wandev, char *u_name)
+static int device_del_if(struct wan_device *wandev, char *u_name)
 {
 	char name[WAN_IFNAME_SZ + 1];
         int err = 0;
@@ -815,9 +816,9 @@
  *	Return pointer to the WAN device data space or NULL if device not found.
  */
 
-static wan_device_t *find_device(char *name)
+static struct wan_device *find_device(char *name)
 {
-	wan_device_t *wandev;
+	struct wan_device *wandev;
 
 	for (wandev = router_devlist;wandev && strcmp(wandev->name, name);
 		wandev = wandev->next);
@@ -841,16 +842,16 @@
  *	sure that opened interfaces are not removed!
  */
 
-static int delete_interface (wan_device_t *wandev, char *name)
+static int delete_interface(struct wan_device *wandev, char *name)
 {
-	netdevice_t *dev=NULL, *prev=NULL;
+	struct net_device *dev = NULL, *prev = NULL;
 	unsigned long smp_flags=0;
 
 	lock_adapter_irq(&wandev->lock, &smp_flags);
 	dev = wandev->dev;
 	prev = NULL;
 	while (dev && strcmp(name, dev->name)) {
-		netdevice_t **slave = dev->priv;
+		struct net_device **slave = dev->priv;
 		prev = dev;
 		dev = *slave;
 	}
@@ -867,12 +868,12 @@
 
 	lock_adapter_irq(&wandev->lock, &smp_flags);
 	if (prev) {
-		netdevice_t **prev_slave = prev->priv;
-		netdevice_t **slave = dev->priv;
+		struct net_device **prev_slave = prev->priv;
+		struct net_device **slave = dev->priv;
 
 		*prev_slave = *slave;
 	} else {
-		netdevice_t **slave = dev->priv;
+		struct net_device **slave = dev->priv;
 		wandev->dev = *slave;
 	}
 	--wandev->ndev;
diff -Nru a/net/wanrouter/wanproc.c b/net/wanrouter/wanproc.c
--- a/net/wanrouter/wanproc.c	Sun Oct  6 21:15:15 2002
+++ b/net/wanrouter/wanproc.c	Sun May 18 07:58:29 2003
@@ -4,7 +4,7 @@
 *		This module is completely hardware-independent and provides
 *		access to the router using Linux /proc filesystem.
 *
-* Author: 	Gideon Hack	
+* Author: 	Gideon Hack
 *
 * Copyright:	(c) 1995-1999 Sangoma Technologies Inc.
 *
@@ -20,21 +20,17 @@
 * Dec 13, 1996	Gene Kozin	Initial version (based on Sangoma's WANPIPE)
 *****************************************************************************/
 
-#include <linux/version.h>
 #include <linux/config.h>
+#include <linux/init.h>		/* __initfunc et al. */
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/kernel.h>
-#include <linux/slab.h>	/* kmalloc(), kfree() */
-#include <linux/mm.h>		/* verify_area(), etc. */
-#include <linux/string.h>	/* inline mem*, str* functions */
-#include <asm/byteorder.h>	/* htons(), etc. */
-#include <asm/io.h>
+#include <linux/module.h>
 #include <linux/wanrouter.h>	/* WAN router API definitions */
 #include <linux/seq_file.h>
 #include <linux/smp_lock.h>
-#include <linux/init.h>	/* __initfunc et al. */
-#include <asm/uaccess.h>       /* copy_to_user */
+
+#include <asm/io.h>
 
 #define PROC_STATS_FORMAT "%30s: %12lu\n"
 
@@ -46,16 +42,6 @@
 				    (prot == WANCONFIG_CHDLC) ? " CHDLC": \
 				       (prot == WANCONFIG_MPPP) ? " MPPP" : \
 				           " Unknown" )
-	
-/****** Data Types **********************************************************/
-
-typedef struct wan_stat_entry
-{
-	struct wan_stat_entry *next;
-	char *description;		/* description string */
-	void *data;			/* -> data */
-	unsigned data_type;		/* data type */
-} wan_stat_entry_t;
 
 /****** Function Prototypes *************************************************/
 
@@ -73,11 +59,11 @@
  */
 
 /*
- *	Generic /proc/net/router/<file> file and inode operations 
+ *	Generic /proc/net/router/<file> file and inode operations
  */
 
 /*
- *	/proc/net/router 
+ *	/proc/net/router
  */
 
 static struct proc_dir_entry *proc_router;
@@ -95,7 +81,7 @@
  */
 static void *r_start(struct seq_file *m, loff_t *pos)
 {
-	wan_device_t *wandev;
+	struct wan_device *wandev;
 	loff_t l = *pos;
 
 	lock_kernel();
@@ -105,12 +91,14 @@
 		;
 	return wandev;
 }
+
 static void *r_next(struct seq_file *m, void *v, loff_t *pos)
 {
-	wan_device_t *wandev = v;
+	struct wan_device *wandev = v;
 	(*pos)++;
 	return (v == (void *)1) ? router_devlist : wandev->next;
 }
+
 static void r_stop(struct seq_file *m, void *v)
 {
 	unlock_kernel();
@@ -118,10 +106,10 @@
 
 static int config_show(struct seq_file *m, void *v)
 {
-	wan_device_t *p = v;
+	struct wan_device *p = v;
 	if (v == (void *)1) {
-		seq_puts(m, "Device name    | port |IRQ|DMA|  mem.addr  |");
-		seq_puts(m, "mem.size|option1|option2|option3|option4\n");
+		seq_puts(m, "Device name    | port |IRQ|DMA|  mem.addr  |"
+			    "mem.size|option1|option2|option3|option4\n");
 		return 0;
 	}
 	if (!p->state)
@@ -134,23 +122,23 @@
 
 static int status_show(struct seq_file *m, void *v)
 {
-	wan_device_t *p = v;
+	struct wan_device *p = v;
 	if (v == (void *)1) {
-		seq_puts(m, "Device name    |protocol|station|interface|");
-		seq_puts(m, "clocking|baud rate| MTU |ndev|link state\n");
+		seq_puts(m, "Device name    |protocol|station|interface|"
+			    "clocking|baud rate| MTU |ndev|link state\n");
 		return 0;
 	}
 	if (!p->state)
 		return 0;
-	seq_printf(m, "%-15s|%-8s|%-7s|%-9s|%-8s|%9u|%5u|%3u |",
+	seq_printf(m, "%-15s|%-8s| %-7s| %-9s|%-8s|%9u|%5u|%3u |",
 		p->name,
 		PROT_DECODE(p->config_id),
-		p->config_id == WANCONFIG_FR ? 
-			(p->station ? " Node" : " CPE") :
+		p->config_id == WANCONFIG_FR ?
+			(p->station ? "Node" : "CPE") :
 			(p->config_id == WANCONFIG_X25 ?
-			(p->station ? " DCE" : " DTE") :
-			(" N/A")),
-		p->interface ? " V.35" : " RS-232",
+			(p->station ? "DCE" : "DTE") :
+			("N/A")),
+		p->interface ? "V.35" : "RS-232",
 		p->clocking ? "internal" : "external",
 		p->bps,
 		p->mtu,
@@ -177,17 +165,17 @@
 }
 
 static struct seq_operations config_op = {
-	.start =r_start,
-	.next =	r_next,
-	.stop =	r_stop,
-	.show =	config_show
+	.start	= r_start,
+	.next	= r_next,
+	.stop	= r_stop,
+	.show	= config_show,
 };
 
 static struct seq_operations status_op = {
-	.start =r_start,
-	.next =	r_next,
-	.stop =	r_stop,
-	.show =	status_show
+	.start	= r_start,
+	.next	= r_next,
+	.stop	= r_stop,
+	.show	= status_show,
 };
 
 static int config_open(struct inode *inode, struct file *file)
@@ -200,25 +188,25 @@
 	return seq_open(file, &status_op);
 }
 
-static struct file_operations config_fops =
-{
-	.open =		config_open,
-	.read =		seq_read,
-	.llseek =	seq_lseek,
-	.release =	seq_release,
+static struct file_operations config_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = config_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release,
 };
 
-static struct file_operations status_fops =
-{
-	.open =		status_open,
-	.read =		seq_read,
-	.llseek =	seq_lseek,
-	.release =	seq_release,
+static struct file_operations status_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = status_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = seq_release,
 };
 
 static int wandev_show(struct seq_file *m, void *v)
 {
-	wan_device_t *wandev = v;
+	struct wan_device *wandev = v;
 
 	if (wandev->magic != ROUTER_MAGIC)
 		return 0;
@@ -232,11 +220,11 @@
 	if (wandev->update) {
 		int err = wandev->update(wandev);
 		if (err == -EAGAIN) {
-			seq_printf(m, "Device is busy!\n");
+			seq_puts(m, "Device is busy!\n");
 			return 0;
 		}
 		if (err) {
-			seq_printf(m, "Device is not configured!\n");
+			seq_puts(m, "Device is not configured!\n");
 			return 0;
 		}
 	}
@@ -283,20 +271,20 @@
 	return single_open(file, wandev_show, PDE(inode)->data);
 }
 
-static struct file_operations wandev_fops =
-{
-	.open =		wandev_open,
-	.read =		seq_read,
-	.llseek =	seq_lseek,
-	.release =	single_release,
-	.ioctl =	wanrouter_ioctl,
+static struct file_operations wandev_fops = {
+	.owner	 = THIS_MODULE,
+	.open	 = wandev_open,
+	.read	 = seq_read,
+	.llseek	 = seq_lseek,
+	.release = single_release,
+	.ioctl	 = wanrouter_ioctl,
 };
 
 /*
  *	Initialize router proc interface.
  */
 
-int __init wanrouter_proc_init (void)
+int __init wanrouter_proc_init(void)
 {
 	struct proc_dir_entry *p;
 	proc_router = proc_mkdir(ROUTER_NAME, proc_net);
@@ -324,22 +312,22 @@
  *	Clean up router proc interface.
  */
 
-void wanrouter_proc_cleanup (void)
+void wanrouter_proc_cleanup(void)
 {
 	remove_proc_entry("config", proc_router);
 	remove_proc_entry("status", proc_router);
-	remove_proc_entry(ROUTER_NAME,proc_net);
+	remove_proc_entry(ROUTER_NAME, proc_net);
 }
 
 /*
  *	Add directory entry for WAN device.
  */
 
-int wanrouter_proc_add (wan_device_t* wandev)
+int wanrouter_proc_add(struct wan_device* wandev)
 {
 	if (wandev->magic != ROUTER_MAGIC)
 		return -EINVAL;
-		
+
 	wandev->dent = create_proc_entry(wandev->name, S_IRUGO, proc_router);
 	if (!wandev->dent)
 		return -ENOMEM;
@@ -351,8 +339,7 @@
 /*
  *	Delete directory entry for WAN device.
  */
- 
-int wanrouter_proc_delete(wan_device_t* wandev)
+int wanrouter_proc_delete(struct wan_device* wandev)
 {
 	if (wandev->magic != ROUTER_MAGIC)
 		return -EINVAL;
@@ -375,12 +362,12 @@
 {
 }
 
-int wanrouter_proc_add(wan_device_t *wandev)
+int wanrouter_proc_add(struct wan_device *wandev)
 {
 	return 0;
 }
 
-int wanrouter_proc_delete(wan_device_t *wandev)
+int wanrouter_proc_delete(struct wan_device *wandev)
 {
 	return 0;
 }
diff -Nru a/net/x25/x25_proc.c b/net/x25/x25_proc.c
--- a/net/x25/x25_proc.c	Sun Oct  6 21:15:15 2002
+++ b/net/x25/x25_proc.c	Sat May 10 11:46:35 2003
@@ -189,6 +189,7 @@
 }
 
 static struct file_operations x25_seq_socket_fops = {
+	.owner		= THIS_MODULE,
 	.open		= x25_seq_socket_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
@@ -196,6 +197,7 @@
 };
 
 static struct file_operations x25_seq_route_fops = {
+	.owner		= THIS_MODULE,
 	.open		= x25_seq_route_open,
 	.read		= seq_read,
 	.llseek		= seq_lseek,
diff -Nru a/net/xfrm/xfrm_algo.c b/net/xfrm/xfrm_algo.c
--- a/net/xfrm/xfrm_algo.c	Mon Apr  7 00:03:41 2003
+++ b/net/xfrm/xfrm_algo.c	Tue May 20 19:39:24 2003
@@ -251,17 +251,17 @@
 
 static inline int aalg_entries(void)
 {
-	return sizeof(aalg_list) / sizeof(aalg_list[0]);
+	return ARRAY_SIZE(aalg_list);
 }
 
 static inline int ealg_entries(void)
 {
-	return sizeof(ealg_list) / sizeof(ealg_list[0]);
+	return ARRAY_SIZE(ealg_list);
 }
 
 static inline int calg_entries(void)
 {
-	return sizeof(calg_list) / sizeof(calg_list[0]);
+	return ARRAY_SIZE(calg_list);
 }
 
 /* Todo: generic iterators */
diff -Nru a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
--- a/net/xfrm/xfrm_input.c	Thu Apr  3 05:19:44 2003
+++ b/net/xfrm/xfrm_input.c	Fri May 16 14:02:36 2003
@@ -34,7 +34,7 @@
 		offset_seq = offsetof(struct ip_esp_hdr, seq_no);
 		break;
 	case IPPROTO_COMP:
-		if (!pskb_may_pull(skb, 4))
+		if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
 			return -EINVAL;
 		*spi = ntohl(ntohs(*(u16*)(skb->h.raw + 2)));
 		*seq = 0;
diff -Nru a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
--- a/net/xfrm/xfrm_policy.c	Tue Apr  8 16:16:05 2003
+++ b/net/xfrm/xfrm_policy.c	Thu May 15 21:05:01 2003
@@ -19,7 +19,6 @@
 
 DECLARE_MUTEX(xfrm_cfg_sem);
 
-static u32      xfrm_policy_genid;
 static rwlock_t xfrm_policy_lock = RW_LOCK_UNLOCKED;
 
 struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2];
@@ -29,142 +28,6 @@
 
 kmem_cache_t *xfrm_dst_cache;
 
-/* Limited flow cache. Its function now is to accelerate search for
- * policy rules.
- *
- * Flow cache is private to cpus, at the moment this is important
- * mostly for flows which do not match any rule, so that flow lookups
- * are absolultely cpu-local. When a rule exists we do some updates
- * to rule (refcnt, stats), so that locality is broken. Later this
- * can be repaired.
- */
-
-struct flow_entry
-{
-	struct flow_entry	*next;
-	struct flowi		fl;
-	u8			dir;
-	u32			genid;
-	struct xfrm_policy	*pol;
-};
-
-static kmem_cache_t *flow_cachep;
-
-struct flow_entry **flow_table;
-
-static int flow_lwm = 2*XFRM_FLOWCACHE_HASH_SIZE;
-static int flow_hwm = 4*XFRM_FLOWCACHE_HASH_SIZE;
-
-static int flow_number[NR_CPUS] __cacheline_aligned;
-
-#define flow_count(cpu)		(flow_number[cpu])
-
-static void flow_cache_shrink(int cpu)
-{
-	int i;
-	struct flow_entry *fle, **flp;
-	int shrink_to = flow_lwm/XFRM_FLOWCACHE_HASH_SIZE;
-
-	for (i=0; i<XFRM_FLOWCACHE_HASH_SIZE; i++) {
-		int k = 0;
-		flp = &flow_table[cpu*XFRM_FLOWCACHE_HASH_SIZE+i];
-		while ((fle=*flp) != NULL && k<shrink_to) {
-			k++;
-			flp = &fle->next;
-		}
-		while ((fle=*flp) != NULL) {
-			*flp = fle->next;
-			if (fle->pol)
-				xfrm_pol_put(fle->pol);
-			kmem_cache_free(flow_cachep, fle);
-		}
-	}
-}
-
-struct xfrm_policy *flow_lookup(int dir, struct flowi *fl, 
-				unsigned short family)
-{
-	struct xfrm_policy *pol = NULL;
-	struct flow_entry *fle;
-	u32 hash;
-	int cpu;
-
-	hash = flow_hash(fl, family);
-
-	local_bh_disable();
-	cpu = smp_processor_id();
-
-	for (fle = flow_table[cpu*XFRM_FLOWCACHE_HASH_SIZE+hash];
-	     fle; fle = fle->next) {
-		if (memcmp(fl, &fle->fl, sizeof(fle->fl)) == 0 &&
-		    fle->dir == dir) {
-			if (fle->genid == xfrm_policy_genid) {
-				if ((pol = fle->pol) != NULL)
-					atomic_inc(&pol->refcnt);
-				local_bh_enable();
-				return pol;
-			}
-			break;
-		}
-	}
-
-	pol = xfrm_policy_lookup(dir, fl, family);
-
-	if (fle) {
-		/* Stale flow entry found. Update it. */
-		fle->genid = xfrm_policy_genid;
-
-		if (fle->pol)
-			xfrm_pol_put(fle->pol);
-		fle->pol = pol;
-		if (pol)
-			atomic_inc(&pol->refcnt);
-	} else {
-		if (flow_count(cpu) > flow_hwm)
-			flow_cache_shrink(cpu);
-
-		fle = kmem_cache_alloc(flow_cachep, SLAB_ATOMIC);
-		if (fle) {
-			flow_count(cpu)++;
-			fle->fl = *fl;
-			fle->genid = xfrm_policy_genid;
-			fle->dir = dir;
-			fle->pol = pol;
-			if (pol)
-				atomic_inc(&pol->refcnt);
-			fle->next = flow_table[cpu*XFRM_FLOWCACHE_HASH_SIZE+hash];
-			flow_table[cpu*XFRM_FLOWCACHE_HASH_SIZE+hash] = fle;
-		}
-	}
-	local_bh_enable();
-	return pol;
-}
-
-void __init flow_cache_init(void)
-{
-	int order;
-
-	flow_cachep = kmem_cache_create("flow_cache",
-					sizeof(struct flow_entry),
-					0, SLAB_HWCACHE_ALIGN,
-					NULL, NULL);
-
-	if (!flow_cachep)
-		panic("NET: failed to allocate flow cache slab\n");
-
-	for (order = 0;
-	     (PAGE_SIZE<<order) < (NR_CPUS*sizeof(struct flow_entry *)*XFRM_FLOWCACHE_HASH_SIZE);
-	     order++)
-		/* NOTHING */;
-
-	flow_table = (struct flow_entry **)__get_free_pages(GFP_ATOMIC, order);
-
-	if (!flow_table)
-		panic("Failed to allocate flow cache hash table\n");
-
-	memset(flow_table, 0, PAGE_SIZE<<order);
-}
-
 int xfrm_register_type(struct xfrm_type *type, unsigned short family)
 {
 	struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
@@ -274,7 +137,7 @@
 	}
 	if (next != LONG_MAX &&
 	    !mod_timer(&xp->timer, jiffies + make_jiffies(next)))
-		atomic_inc(&xp->refcnt);
+		xfrm_pol_hold(xp);
 
 out:
 	xfrm_pol_put(xp);
@@ -392,16 +255,16 @@
 			break;
 		}
 	}
-	atomic_inc(&policy->refcnt);
+	xfrm_pol_hold(policy);
 	policy->next = pol ? pol->next : NULL;
 	*p = policy;
-	xfrm_policy_genid++;
+	atomic_inc(&flow_cache_genid);
 	policy->index = pol ? pol->index : xfrm_gen_index(dir);
 	policy->curlft.add_time = (unsigned long)xtime.tv_sec;
 	policy->curlft.use_time = 0;
 	if (policy->lft.hard_add_expires_seconds &&
 	    !mod_timer(&policy->timer, jiffies + HZ))
-		atomic_inc(&policy->refcnt);
+		xfrm_pol_hold(policy);
 	write_unlock_bh(&xfrm_policy_lock);
 
 	if (pol) {
@@ -424,7 +287,7 @@
 		}
 	}
 	if (pol)
-		xfrm_policy_genid++;
+		atomic_inc(&flow_cache_genid);
 	write_unlock_bh(&xfrm_policy_lock);
 	return pol;
 }
@@ -443,9 +306,9 @@
 	}
 	if (pol) {
 		if (delete)
-			xfrm_policy_genid++;
+			atomic_inc(&flow_cache_genid);
 		else
-			atomic_inc(&pol->refcnt);
+			xfrm_pol_hold(pol);
 	}
 	write_unlock_bh(&xfrm_policy_lock);
 	return pol;
@@ -468,7 +331,7 @@
 			write_lock_bh(&xfrm_policy_lock);
 		}
 	}
-	xfrm_policy_genid++;
+	atomic_inc(&flow_cache_genid);
 	write_unlock_bh(&xfrm_policy_lock);
 }
 
@@ -507,8 +370,8 @@
 
 /* Find policy to apply to this flow. */
 
-struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl, 
-				       unsigned short family)
+void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,
+			void **objp, atomic_t **obj_refp)
 {
 	struct xfrm_policy *pol;
 
@@ -522,12 +385,13 @@
 
 		match = xfrm_selector_match(sel, fl, family);
 		if (match) {
-			atomic_inc(&pol->refcnt);
+			xfrm_pol_hold(pol);
 			break;
 		}
 	}
 	read_unlock_bh(&xfrm_policy_lock);
-	return pol;
+	if ((*objp = (void *) pol) != NULL)
+		*obj_refp = &pol->refcnt;
 }
 
 struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
@@ -540,7 +404,7 @@
 
 		match = xfrm_selector_match(&pol->selector, fl, sk->family);
 		if (match)
-			atomic_inc(&pol->refcnt);
+			xfrm_pol_hold(pol);
 		else
 			pol = NULL;
 	}
@@ -552,7 +416,7 @@
 {
 	pol->next = xfrm_policy_list[XFRM_POLICY_MAX+dir];
 	xfrm_policy_list[XFRM_POLICY_MAX+dir] = pol;
-	atomic_inc(&pol->refcnt);
+	xfrm_pol_hold(pol);
 }
 
 void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir)
@@ -719,6 +583,23 @@
 	return err;
 }
 
+static inline int policy_to_flow_dir(int dir)
+{
+	if (XFRM_POLICY_IN == FLOW_DIR_IN &&
+	    XFRM_POLICY_OUT == FLOW_DIR_OUT &&
+	    XFRM_POLICY_FWD == FLOW_DIR_FWD)
+		return dir;
+	switch (dir) {
+	default:
+	case XFRM_POLICY_IN:
+		return FLOW_DIR_IN;
+	case XFRM_POLICY_OUT:
+		return FLOW_DIR_OUT;
+	case XFRM_POLICY_FWD:
+		return FLOW_DIR_FWD;
+	};
+}
+
 /* Main function: finds/creates a bundle for given flow.
  *
  * At the moment we eat a raw IP route. Mostly to speed up lookups
@@ -749,7 +630,7 @@
 	}
 
 restart:
-	genid = xfrm_policy_genid;
+	genid = atomic_read(&flow_cache_genid);
 	policy = NULL;
 	if (sk && sk->policy[1])
 		policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
@@ -759,7 +640,9 @@
 		if ((rt->u.dst.flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT])
 			return 0;
 
-		policy = flow_lookup(XFRM_POLICY_OUT, fl, family);
+		policy = flow_cache_lookup(fl, family,
+					   policy_to_flow_dir(XFRM_POLICY_OUT),
+					   xfrm_policy_lookup);
 	}
 
 	if (!policy)
@@ -817,7 +700,7 @@
 					goto error;
 				}
 				if (err == -EAGAIN ||
-				    genid != xfrm_policy_genid)
+				    genid != atomic_read(&flow_cache_genid))
 					goto restart;
 			}
 			if (err)
@@ -941,7 +824,9 @@
 		pol = xfrm_sk_policy_lookup(sk, dir, &fl);
 
 	if (!pol)
-		pol = flow_lookup(dir, &fl, family);
+		pol = flow_cache_lookup(&fl, family,
+					policy_to_flow_dir(dir),
+					xfrm_policy_lookup);
 
 	if (!pol)
 		return 1;
@@ -1237,7 +1122,6 @@
 void __init xfrm_init(void)
 {
 	xfrm_state_init();
-	flow_cache_init();
 	xfrm_policy_init();
 }
 
diff -Nru a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
--- a/net/xfrm/xfrm_state.c	Mon Apr  7 22:10:43 2003
+++ b/net/xfrm/xfrm_state.c	Mon May 12 13:58:03 2003
@@ -144,7 +144,7 @@
 resched:
 	if (next != LONG_MAX &&
 	    !mod_timer(&x->timer, jiffies + make_jiffies(next)))
-		atomic_inc(&x->refcnt);
+		xfrm_state_hold(x);
 	goto out;
 
 expired:
@@ -172,6 +172,7 @@
 	if (x) {
 		memset(x, 0, sizeof(struct xfrm_state));
 		atomic_set(&x->refcnt, 1);
+		atomic_set(&x->tunnel_users, 0);
 		INIT_LIST_HEAD(&x->bydst);
 		INIT_LIST_HEAD(&x->byspi);
 		init_timer(&x->timer);
@@ -234,6 +235,7 @@
 
 void xfrm_state_delete(struct xfrm_state *x)
 {
+	xfrm_state_delete_tunnel(x);
 	spin_lock_bh(&x->lock);
 	__xfrm_state_delete(x);
 	spin_unlock_bh(&x->lock);
@@ -248,8 +250,9 @@
 	for (i = 0; i < XFRM_DST_HSIZE; i++) {
 restart:
 		list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
-			if (proto == IPSEC_PROTO_ANY || x->id.proto == proto) {
-				atomic_inc(&x->refcnt);
+			if (!xfrm_state_kern(x) &&
+			    (proto == IPSEC_PROTO_ANY || x->id.proto == proto)) {
+				xfrm_state_hold(x);
 				spin_unlock_bh(&xfrm_state_lock);
 
 				xfrm_state_delete(x);
@@ -329,7 +332,7 @@
 	}
 
 	if (best) {
-		atomic_inc(&best->refcnt);
+		xfrm_state_hold(best);
 		spin_unlock_bh(&xfrm_state_lock);
 		return best;
 	}
@@ -344,14 +347,14 @@
 		if (km_query(x, tmpl, pol) == 0) {
 			x->km.state = XFRM_STATE_ACQ;
 			list_add_tail(&x->bydst, xfrm_state_bydst+h);
-			atomic_inc(&x->refcnt);
+			xfrm_state_hold(x);
 			if (x->id.spi) {
 				h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family);
 				list_add(&x->byspi, xfrm_state_byspi+h);
-				atomic_inc(&x->refcnt);
+				xfrm_state_hold(x);
 			}
 			x->lft.hard_add_expires_seconds = XFRM_ACQ_EXPIRES;
-			atomic_inc(&x->refcnt);
+			xfrm_state_hold(x);
 			mod_timer(&x->timer, XFRM_ACQ_EXPIRES*HZ);
 		} else {
 			x->km.state = XFRM_STATE_DEAD;
@@ -373,15 +376,15 @@
 
 	spin_lock_bh(&xfrm_state_lock);
 	list_add(&x->bydst, xfrm_state_bydst+h);
-	atomic_inc(&x->refcnt);
+	xfrm_state_hold(x);
 
 	h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
 
 	list_add(&x->byspi, xfrm_state_byspi+h);
-	atomic_inc(&x->refcnt);
+	xfrm_state_hold(x);
 
 	if (!mod_timer(&x->timer, jiffies + HZ))
-		atomic_inc(&x->refcnt);
+		xfrm_state_hold(x);
 
 	spin_unlock_bh(&xfrm_state_lock);
 	wake_up(&km_waitq);
@@ -399,7 +402,7 @@
 	    x->curlft.packets >= x->lft.hard_packet_limit) {
 		km_expired(x);
 		if (!mod_timer(&x->timer, jiffies + XFRM_ACQ_EXPIRES*HZ))
-			atomic_inc(&x->refcnt);
+			xfrm_state_hold(x);
 		return -EINVAL;
 	}
 
@@ -466,7 +469,7 @@
 	for (i = 0; i < XFRM_DST_HSIZE; i++) {
 		list_for_each_entry(x, xfrm_state_bydst+i, bydst) {
 			if (x->km.seq == seq) {
-				atomic_inc(&x->refcnt);
+				xfrm_state_hold(x);
 				spin_unlock_bh(&xfrm_state_lock);
 				return x;
 			}
@@ -521,7 +524,7 @@
 		spin_lock_bh(&xfrm_state_lock);
 		h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family);
 		list_add(&x->byspi, xfrm_state_byspi+h);
-		atomic_inc(&x->refcnt);
+		xfrm_state_hold(x);
 		spin_unlock_bh(&xfrm_state_lock);
 		wake_up(&km_waitq);
 	}
@@ -788,6 +791,20 @@
 	if (unlikely(afinfo == NULL))
 		return;
 	read_unlock(&afinfo->lock);
+}
+
+/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
+void xfrm_state_delete_tunnel(struct xfrm_state *x)
+{
+	if (x->tunnel) {
+		struct xfrm_state *t = x->tunnel;
+
+		if (atomic_read(&t->tunnel_users) == 2)
+			xfrm_state_delete(t);
+		atomic_dec(&t->tunnel_users);
+		xfrm_state_put(t);
+		x->tunnel = NULL;
+	}
 }
 
 void __init xfrm_state_init(void)
diff -Nru a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
--- a/net/xfrm/xfrm_user.c	Thu Apr  3 06:30:36 2003
+++ b/net/xfrm/xfrm_user.c	Mon May 12 13:58:03 2003
@@ -281,6 +281,11 @@
 	if (x == NULL)
 		return -ESRCH;
 
+	if (xfrm_state_kern(x)) {
+		xfrm_state_put(x);
+		return -EPERM;
+	}
+
 	xfrm_state_delete(x);
 	xfrm_state_put(x);
 
diff -Nru a/scripts/Makefile.build b/scripts/Makefile.build
--- a/scripts/Makefile.build	Mon Mar 10 13:03:33 2003
+++ b/scripts/Makefile.build	Thu May  8 13:34:28 2003
@@ -66,6 +66,12 @@
 	 $(subdir-ym) $(always)
 	@:
 
+# Linus' kernel sanity checking tool
+ifneq ($(KBUILD_CHECKSRC),0)
+quiet_cmd_checksrc = CHECK   $<
+      cmd_checksrc = $(CHECK) $(c_flags) $< ;
+endif
+ 
 # Module versioning
 # ---------------------------------------------------------------------------
 
@@ -91,6 +97,8 @@
 cmd_vcc_o_c       = $(CC) $(c_flags) -c -o $(@D)/.tmp_$(@F) $<
 
 define rule_vcc_o_c
+	$(if $($(quiet)cmd_checksrc),echo '  $($(quiet)cmd_checksrc)';)	      \
+	$(cmd_checksrc)							      \
 	$(if $($(quiet)cmd_vcc_o_c),echo '  $($(quiet)cmd_vcc_o_c)';)	      \
 	$(cmd_vcc_o_c);							      \
 									      \
@@ -158,6 +166,15 @@
 
 quiet_cmd_cc_o_c = CC $(quiet_modtag)  $@
 cmd_cc_o_c       = $(CC) $(c_flags) -c -o $@ $<
+define rule_cc_o_c
+	$(if $($(quiet)cmd_checksrc),echo '  $($(quiet)cmd_checksrc)';)	      \
+	$(cmd_checksrc)							      \
+	$(if $($(quiet)cmd_cc_o_c),echo '  $($(quiet)cmd_cc_o_c)';)	      \
+	$(cmd_cc_o_c);							      \
+	scripts/fixdep $(depfile) $@ '$(cmd_cc_o_c)' > $(@D)/.$(@F).tmp;      \
+	rm -f $(depfile);						      \
+	mv -f $(@D)/.$(@F).tmp $(@D)/.$(@F).cmd
+endef
 
 # Built-in and composite module parts
 
@@ -165,7 +182,7 @@
 ifdef CONFIG_MODVERSIONS
 	$(call if_changed_rule,vcc_o_c)
 else
-	$(call if_changed_dep,cc_o_c)
+	$(call if_changed_rule,cc_o_c)
 endif
 
 # Single-part modules are special since we need to mark them in $(MODVERDIR)
@@ -174,7 +191,7 @@
 ifdef CONFIG_MODVERSIONS
 	$(call if_changed_rule,vcc_o_c)
 else
-	$(call if_changed_dep,cc_o_c)
+	$(call if_changed_rule,cc_o_c)
 endif
 	$(touch-module)
 
diff -Nru a/scripts/ver_linux b/scripts/ver_linux
--- a/scripts/ver_linux	Sun Feb  9 17:29:38 2003
+++ b/scripts/ver_linux	Thu Mar 20 14:32:27 2003
@@ -28,7 +28,7 @@
 
 mount --version | awk -F\- '{print "mount                 ", $NF}'
 
-depmod -V  2>&1 | awk 'NR==1 {print "module-init-tools     ",$NF}'
+depmod -V  2>&1 | grep version | awk 'NR==1 {print "module-init-tools     ",$NF}'
 
 tune2fs 2>&1 | grep "^tune2fs" | sed 's/,//' |  awk \
 'NR==1 {print "e2fsprogs             ", $2}'
diff -Nru a/security/dummy.c b/security/dummy.c
--- a/security/dummy.c	Sun Feb 16 08:54:39 2003
+++ b/security/dummy.c	Tue May  6 07:02:55 2003
@@ -334,6 +334,11 @@
 	return 0;
 }
 
+static void dummy_inode_post_setxattr (struct dentry *dentry, char *name, void *value,
+				       size_t size, int flags)
+{
+}
+
 static int dummy_inode_getxattr (struct dentry *dentry, char *name)
 {
 	return 0;
@@ -803,6 +808,7 @@
 	set_to_dummy_if_null(ops, inode_getattr);
 	set_to_dummy_if_null(ops, inode_delete);
 	set_to_dummy_if_null(ops, inode_setxattr);
+	set_to_dummy_if_null(ops, inode_post_setxattr);
 	set_to_dummy_if_null(ops, inode_getxattr);
 	set_to_dummy_if_null(ops, inode_listxattr);
 	set_to_dummy_if_null(ops, inode_removexattr);
diff -Nru a/sound/core/info.c b/sound/core/info.c
--- a/sound/core/info.c	Thu Apr 10 03:28:10 2003
+++ b/sound/core/info.c	Wed May 14 23:40:18 2003
@@ -1079,15 +1079,9 @@
 	p->data = (void *) entry;
 	entry->p = p;
 	up(&info_mutex);
-#ifdef CONFIG_DEVFS_FS
-	if (strncmp(name, "controlC", 8)) {	/* created in sound.c */
-		char dname[32];
-		sprintf(dname, "snd/%s", name);
-		devfs_register(NULL, dname, DEVFS_FL_DEFAULT,
-				_major, minor, mode,
-				&snd_fops, NULL);
-	}
-#endif
+
+	if (strncmp(name, "controlC", 8) != 0)	/* created in sound.c */
+		devfs_mk_cdev(MKDEV(_major, minor), mode, "snd/%s", name);
 	return entry;
 }
 
diff -Nru a/sound/core/memalloc.c b/sound/core/memalloc.c
--- a/sound/core/memalloc.c	Thu Apr 10 22:38:48 2003
+++ b/sound/core/memalloc.c	Sun May 18 13:07:55 2003
@@ -27,6 +27,7 @@
 #include <linux/proc_fs.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/mm.h>
 #include <asm/semaphore.h>
 #include <sound/memalloc.h>
 
diff -Nru a/sound/core/seq/oss/seq_oss_device.h b/sound/core/seq/oss/seq_oss_device.h
--- a/sound/core/seq/oss/seq_oss_device.h	Thu Feb 14 11:13:30 2002
+++ b/sound/core/seq/oss/seq_oss_device.h	Tue May 13 14:58:07 2003
@@ -135,8 +135,8 @@
 int snd_seq_oss_open(struct file *file, int level);
 void snd_seq_oss_release(seq_oss_devinfo_t *dp);
 int snd_seq_oss_ioctl(seq_oss_devinfo_t *dp, unsigned int cmd, unsigned long arg);
-int snd_seq_oss_read(seq_oss_devinfo_t *dev, char *buf, int count);
-int snd_seq_oss_write(seq_oss_devinfo_t *dp, const char *buf, int count, struct file *opt);
+int snd_seq_oss_read(seq_oss_devinfo_t *dev, char __user *buf, int count);
+int snd_seq_oss_write(seq_oss_devinfo_t *dp, const char __user *buf, int count, struct file *opt);
 unsigned int snd_seq_oss_poll(seq_oss_devinfo_t *dp, struct file *file, poll_table * wait);
 
 void snd_seq_oss_reset(seq_oss_devinfo_t *dp);
diff -Nru a/sound/core/seq/oss/seq_oss_ioctl.c b/sound/core/seq/oss/seq_oss_ioctl.c
--- a/sound/core/seq/oss/seq_oss_ioctl.c	Tue Oct  1 10:06:00 2002
+++ b/sound/core/seq/oss/seq_oss_ioctl.c	Tue May 13 14:58:07 2003
@@ -35,7 +35,7 @@
 	struct synth_info inf;
 	struct midi_info minf;
 	unsigned char ev[8];
-	void *arg = (void*)carg;
+	void __user *arg = (void __user *)carg;
 	snd_seq_event_t tmpev;
 
 	switch (cmd) {
diff -Nru a/sound/core/seq/oss/seq_oss_rw.c b/sound/core/seq/oss/seq_oss_rw.c
--- a/sound/core/seq/oss/seq_oss_rw.c	Tue Oct  1 10:06:00 2002
+++ b/sound/core/seq/oss/seq_oss_rw.c	Tue May 13 14:58:07 2003
@@ -41,7 +41,7 @@
  */
 
 int
-snd_seq_oss_read(seq_oss_devinfo_t *dp, char *buf, int count)
+snd_seq_oss_read(seq_oss_devinfo_t *dp, char __user *buf, int count)
 {
 	seq_oss_readq_t *readq = dp->readq;
 	int cnt, pos;
@@ -81,7 +81,7 @@
  */
 
 int
-snd_seq_oss_write(seq_oss_devinfo_t *dp, const char *buf, int count, struct file *opt)
+snd_seq_oss_write(seq_oss_devinfo_t *dp, const char __user *buf, int count, struct file *opt)
 {
 	int rc, c, p, ev_size;
 	evrec_t rec;
diff -Nru a/sound/core/seq/oss/seq_oss_synth.c b/sound/core/seq/oss/seq_oss_synth.c
--- a/sound/core/seq/oss/seq_oss_synth.c	Thu Mar 20 08:41:12 2003
+++ b/sound/core/seq/oss/seq_oss_synth.c	Tue May 13 14:58:07 2003
@@ -450,7 +450,7 @@
  */
 int
 snd_seq_oss_synth_load_patch(seq_oss_devinfo_t *dp, int dev, int fmt,
-			    const char *buf, int p, int c)
+			    const char __user *buf, int p, int c)
 {
 	seq_oss_synth_t *rec;
 	int rc;
diff -Nru a/sound/core/seq/oss/seq_oss_timer.c b/sound/core/seq/oss/seq_oss_timer.c
--- a/sound/core/seq/oss/seq_oss_timer.c	Tue Oct  1 10:06:00 2002
+++ b/sound/core/seq/oss/seq_oss_timer.c	Tue May 13 14:58:07 2003
@@ -227,19 +227,19 @@
  * ioctls
  */
 int
-snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, void *arg)
+snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, int __user *arg)
 {
 	int value;
 
 	if (cmd == SNDCTL_SEQ_CTRLRATE) {
 		debug_printk(("ctrl rate\n"));
 		/* if *arg == 0, just return the current rate */
-		if (get_user(value, (int *)arg))
+		if (get_user(value, arg))
 			return -EFAULT;
 		if (value)
 			return -EINVAL;
 		value = ((timer->oss_tempo * timer->oss_timebase) + 30) / 60;
-		return put_user(value, (int *)arg) ? -EFAULT : 0;
+		return put_user(value, arg) ? -EFAULT : 0;
 	}
 
 	if (timer->dp->seq_mode == SNDRV_SEQ_OSS_MODE_SYNTH)
@@ -257,12 +257,12 @@
 		return snd_seq_oss_timer_continue(timer);
 	case SNDCTL_TMR_TEMPO:
 		debug_printk(("timer tempo\n"));
-		if (get_user(value, (int *)arg))
+		if (get_user(value, arg))
 			return -EFAULT;
 		return snd_seq_oss_timer_tempo(timer, value);
 	case SNDCTL_TMR_TIMEBASE:
 		debug_printk(("timer timebase\n"));
-		if (get_user(value, (int *)arg))
+		if (get_user(value, arg))
 			return -EFAULT;
 		if (value < MIN_OSS_TIMEBASE)
 			value = MIN_OSS_TIMEBASE;
diff -Nru a/sound/core/seq/oss/seq_oss_timer.h b/sound/core/seq/oss/seq_oss_timer.h
--- a/sound/core/seq/oss/seq_oss_timer.h	Wed Feb 13 11:32:02 2002
+++ b/sound/core/seq/oss/seq_oss_timer.h	Tue May 13 14:58:07 2003
@@ -46,7 +46,7 @@
 int snd_seq_oss_timer_tempo(seq_oss_timer_t *timer, int value);
 #define snd_seq_oss_timer_reset  snd_seq_oss_timer_start
 
-int snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, void *arg);
+int snd_seq_oss_timer_ioctl(seq_oss_timer_t *timer, unsigned int cmd, int __user *arg);
 
 /*
  * get current processed time
diff -Nru a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c
--- a/sound/core/seq/seq_clientmgr.c	Sat Feb  8 12:10:47 2003
+++ b/sound/core/seq/seq_clientmgr.c	Sat May 17 12:39:14 2003
@@ -136,7 +136,6 @@
 		static char card_requested[SNDRV_CARDS];
 		if (clientid < 64) {
 			int idx;
-			char name[32];
 			
 			if (! client_requested[clientid]) {
 				client_requested[clientid] = 1;
@@ -144,8 +143,7 @@
 					if (seq_client_load[idx] < 0)
 						break;
 					if (seq_client_load[idx] == clientid) {
-						sprintf(name, "snd-seq-client-%i", clientid);
-						request_module(name);
+						request_module("snd-seq-client-%i", clientid);
 						break;
 					}
 				}
@@ -365,7 +363,7 @@
  *	-EINVAL	no enough user-space buffer to write the whole event
  *	-EFAULT	seg. fault during copy to user space
  */
-static ssize_t snd_seq_read(struct file *file, char *buf, size_t count, loff_t *offset)
+static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count, loff_t *offset)
 {
 	client_t *client = (client_t *) file->private_data;
 	fifo_t *fifo;
@@ -959,7 +957,7 @@
  *	-EMLINK	too many hops
  *	others	depends on return value from driver callback
  */
-static ssize_t snd_seq_write(struct file *file, const char *buf, size_t count, loff_t *offset)
+static ssize_t snd_seq_write(struct file *file, const char __user *buf, size_t count, loff_t *offset)
 {
 	client_t *client = (client_t *) file->private_data;
 	int written = 0, len;
@@ -1077,7 +1075,7 @@
 
 
 /* SYSTEM_INFO ioctl() */
-static int snd_seq_ioctl_system_info(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_system_info(client_t *client, void __user *arg)
 {
 	snd_seq_system_info_t info;
 
@@ -1090,20 +1088,20 @@
 	info.cur_clients = client_usage.cur;
 	info.cur_queues = snd_seq_queue_get_cur_queues();
 
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 	return 0;
 }
 
 
 /* RUNNING_MODE ioctl() */
-static int snd_seq_ioctl_running_mode(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_running_mode(client_t *client, void __user *arg)
 {
 	struct sndrv_seq_running_info info;
 	client_t *cptr;
 	int err = 0;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	/* requested client number */
@@ -1148,12 +1146,12 @@
 	memset(info->reserved, 0, sizeof(info->reserved));
 }
 
-static int snd_seq_ioctl_get_client_info(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_get_client_info(client_t * client, void __user *arg)
 {
 	client_t *cptr;
 	snd_seq_client_info_t client_info;
 
-	if (copy_from_user(&client_info, (void*)arg, sizeof(client_info)))
+	if (copy_from_user(&client_info, arg, sizeof(client_info)))
 		return -EFAULT;
 
 	/* requested client number */
@@ -1164,18 +1162,18 @@
 	get_client_info(cptr, &client_info);
 	snd_seq_client_unlock(cptr);
 
-	if (copy_to_user((void*)arg, &client_info, sizeof(client_info)))
+	if (copy_to_user(arg, &client_info, sizeof(client_info)))
 		return -EFAULT;
 	return 0;
 }
 
 
 /* CLIENT_INFO ioctl() */
-static int snd_seq_ioctl_set_client_info(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_set_client_info(client_t * client, void __user *arg)
 {
 	snd_seq_client_info_t client_info;
 
-	if (copy_from_user(&client_info, (void*)arg, sizeof(client_info)))
+	if (copy_from_user(&client_info, arg, sizeof(client_info)))
 		return -EFAULT;
 
 	/* it is not allowed to set the info fields for an another client */
@@ -1201,13 +1199,13 @@
 /* 
  * CREATE PORT ioctl() 
  */
-static int snd_seq_ioctl_create_port(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_create_port(client_t * client, void __user *arg)
 {
 	client_port_t *port;
 	snd_seq_port_info_t info;
 	snd_seq_port_callback_t *callback;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	/* it is not allowed to create the port for an another client */
@@ -1242,7 +1240,7 @@
 	snd_seq_set_port_info(port, &info);
 	snd_seq_system_client_ev_port_start(port->addr.client, port->addr.port);
 
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 
 	return 0;
@@ -1251,13 +1249,13 @@
 /* 
  * DELETE PORT ioctl() 
  */
-static int snd_seq_ioctl_delete_port(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_delete_port(client_t * client, void __user *arg)
 {
 	snd_seq_port_info_t info;
 	int err;
 
 	/* set passed parameters */
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 	
 	/* it is not allowed to remove the port for an another client */
@@ -1274,13 +1272,13 @@
 /* 
  * GET_PORT_INFO ioctl() (on any client) 
  */
-static int snd_seq_ioctl_get_port_info(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_get_port_info(client_t *client, void __user *arg)
 {
 	client_t *cptr;
 	client_port_t *port;
 	snd_seq_port_info_t info;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 	cptr = snd_seq_client_use_ptr(info.addr.client);
 	if (cptr == NULL)
@@ -1297,7 +1295,7 @@
 	snd_seq_port_unlock(port);
 	snd_seq_client_unlock(cptr);
 
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 	return 0;
 }
@@ -1306,12 +1304,12 @@
 /* 
  * SET_PORT_INFO ioctl() (only ports on this/own client) 
  */
-static int snd_seq_ioctl_set_port_info(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_set_port_info(client_t * client, void __user *arg)
 {
 	client_port_t *port;
 	snd_seq_port_info_t info;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	if (info.addr.client != client->number) /* only set our own ports ! */
@@ -1381,14 +1379,14 @@
 /* 
  * add to port's subscription list IOCTL interface 
  */
-static int snd_seq_ioctl_subscribe_port(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_subscribe_port(client_t * client, void __user *arg)
 {
 	int result = -EINVAL;
 	client_t *receiver = NULL, *sender = NULL;
 	client_port_t *sport = NULL, *dport = NULL;
 	snd_seq_port_subscribe_t subs;
 
-	if (copy_from_user(&subs, (void*)arg, sizeof(subs)))
+	if (copy_from_user(&subs, arg, sizeof(subs)))
 		return -EFAULT;
 
 	if ((receiver = snd_seq_client_use_ptr(subs.dest.client)) == NULL)
@@ -1425,14 +1423,14 @@
 /* 
  * remove from port's subscription list 
  */
-static int snd_seq_ioctl_unsubscribe_port(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_unsubscribe_port(client_t * client, void __user *arg)
 {
 	int result = -ENXIO;
 	client_t *receiver = NULL, *sender = NULL;
 	client_port_t *sport = NULL, *dport = NULL;
 	snd_seq_port_subscribe_t subs;
 
-	if (copy_from_user(&subs, (void*)arg, sizeof(subs)))
+	if (copy_from_user(&subs, arg, sizeof(subs)))
 		return -EFAULT;
 
 	if ((receiver = snd_seq_client_use_ptr(subs.dest.client)) == NULL)
@@ -1466,13 +1464,13 @@
 
 
 /* CREATE_QUEUE ioctl() */
-static int snd_seq_ioctl_create_queue(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_create_queue(client_t *client, void __user *arg)
 {
 	snd_seq_queue_info_t info;
 	int result;
 	queue_t *q;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	result = snd_seq_queue_alloc(client->number, info.locked, info.flags);
@@ -1494,30 +1492,30 @@
 	q->name[sizeof(q->name)-1] = 0;
 	queuefree(q);
 
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 
 	return 0;
 }
 
 /* DELETE_QUEUE ioctl() */
-static int snd_seq_ioctl_delete_queue(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_delete_queue(client_t *client, void __user *arg)
 {
 	snd_seq_queue_info_t info;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	return snd_seq_queue_delete(client->number, info.queue);
 }
 
 /* GET_QUEUE_INFO ioctl() */
-static int snd_seq_ioctl_get_queue_info(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_get_queue_info(client_t *client, void __user *arg)
 {
 	snd_seq_queue_info_t info;
 	queue_t *q;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	q = queueptr(info.queue);
@@ -1532,19 +1530,19 @@
 	info.name[sizeof(info.name)-1] = 0;
 	queuefree(q);
 
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 
 	return 0;
 }
 
 /* SET_QUEUE_INFO ioctl() */
-static int snd_seq_ioctl_set_queue_info(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_set_queue_info(client_t *client, void __user *arg)
 {
 	snd_seq_queue_info_t info;
 	queue_t *q;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	if (info.owner != client->number)
@@ -1575,12 +1573,12 @@
 }
 
 /* GET_NAMED_QUEUE ioctl() */
-static int snd_seq_ioctl_get_named_queue(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_get_named_queue(client_t *client, void __user *arg)
 {
 	snd_seq_queue_info_t info;
 	queue_t *q;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	q = snd_seq_queue_find_name(info.name);
@@ -1591,20 +1589,20 @@
 	info.locked = q->locked;
 	queuefree(q);
 
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 
 	return 0;
 }
 
 /* GET_QUEUE_STATUS ioctl() */
-static int snd_seq_ioctl_get_queue_status(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_get_queue_status(client_t * client, void __user *arg)
 {
 	snd_seq_queue_status_t status;
 	queue_t *queue;
 	seq_timer_t *tmr;
 
-	if (copy_from_user(&status, (void*)arg, sizeof(status)))
+	if (copy_from_user(&status, arg, sizeof(status)))
 		return -EFAULT;
 
 	queue = queueptr(status.queue);
@@ -1624,20 +1622,20 @@
 	status.flags = queue->flags;
 	queuefree(queue);
 
-	if (copy_to_user((void*)arg, &status, sizeof(status)))
+	if (copy_to_user(arg, &status, sizeof(status)))
 		return -EFAULT;
 	return 0;
 }
 
 
 /* GET_QUEUE_TEMPO ioctl() */
-static int snd_seq_ioctl_get_queue_tempo(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_get_queue_tempo(client_t * client, void __user *arg)
 {
 	snd_seq_queue_tempo_t tempo;
 	queue_t *queue;
 	seq_timer_t *tmr;
 
-	if (copy_from_user(&tempo, (void*)arg, sizeof(tempo)))
+	if (copy_from_user(&tempo, arg, sizeof(tempo)))
 		return -EFAULT;
 
 	queue = queueptr(tempo.queue);
@@ -1654,19 +1652,19 @@
 	tempo.skew_base = tmr->skew_base;
 	queuefree(queue);
 
-	if (copy_to_user((void*)arg, &tempo, sizeof(tempo)))
+	if (copy_to_user(arg, &tempo, sizeof(tempo)))
 		return -EFAULT;
 	return 0;
 }
 
 
 /* SET_QUEUE_TEMPO ioctl() */
-static int snd_seq_ioctl_set_queue_tempo(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_set_queue_tempo(client_t * client, void __user *arg)
 {
 	int result;
 	snd_seq_queue_tempo_t tempo;
 
-	if (copy_from_user(&tempo, (void*)arg, sizeof(tempo)))
+	if (copy_from_user(&tempo, arg, sizeof(tempo)))
 		return -EFAULT;
 
 	if (snd_seq_queue_check_access(tempo.queue, client->number)) {
@@ -1682,13 +1680,13 @@
 
 
 /* GET_QUEUE_TIMER ioctl() */
-static int snd_seq_ioctl_get_queue_timer(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_get_queue_timer(client_t * client, void __user *arg)
 {
 	snd_seq_queue_timer_t timer;
 	queue_t *queue;
 	seq_timer_t *tmr;
 
-	if (copy_from_user(&timer, (void*)arg, sizeof(timer)))
+	if (copy_from_user(&timer, arg, sizeof(timer)))
 		return -EFAULT;
 
 	queue = queueptr(timer.queue);
@@ -1711,19 +1709,19 @@
 	up(&queue->timer_mutex);
 	queuefree(queue);
 	
-	if (copy_to_user((void*)arg, &timer, sizeof(timer)))
+	if (copy_to_user(arg, &timer, sizeof(timer)))
 		return -EFAULT;
 	return 0;
 }
 
 
 /* SET_QUEUE_TIMER ioctl() */
-static int snd_seq_ioctl_set_queue_timer(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_set_queue_timer(client_t * client, void __user *arg)
 {
 	int result = 0;
 	snd_seq_queue_timer_t timer;
 
-	if (copy_from_user(&timer, (void*)arg, sizeof(timer)))
+	if (copy_from_user(&timer, arg, sizeof(timer)))
 		return -EFAULT;
 
 	if (timer.type != SNDRV_SEQ_TIMER_ALSA)
@@ -1759,12 +1757,12 @@
 
 
 /* GET_QUEUE_CLIENT ioctl() */
-static int snd_seq_ioctl_get_queue_client(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_get_queue_client(client_t * client, void __user *arg)
 {
 	snd_seq_queue_client_t info;
 	int used;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	used = snd_seq_queue_is_used(info.queue, client->number);
@@ -1773,19 +1771,19 @@
 	info.used = used;
 	info.client = client->number;
 
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 	return 0;
 }
 
 
 /* SET_QUEUE_CLIENT ioctl() */
-static int snd_seq_ioctl_set_queue_client(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_set_queue_client(client_t * client, void __user *arg)
 {
 	int err;
 	snd_seq_queue_client_t info;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	if (info.used >= 0) {
@@ -1799,12 +1797,12 @@
 
 
 /* GET_CLIENT_POOL ioctl() */
-static int snd_seq_ioctl_get_client_pool(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_get_client_pool(client_t * client, void __user *arg)
 {
 	snd_seq_client_pool_t info;
 	client_t *cptr;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	cptr = snd_seq_client_use_ptr(info.client);
@@ -1827,18 +1825,18 @@
 	}
 	snd_seq_client_unlock(cptr);
 	
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 	return 0;
 }
 
 /* SET_CLIENT_POOL ioctl() */
-static int snd_seq_ioctl_set_client_pool(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_set_client_pool(client_t * client, void __user *arg)
 {
 	snd_seq_client_pool_t info;
 	int rc;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	if (client->number != info.client)
@@ -1877,11 +1875,11 @@
 
 
 /* REMOVE_EVENTS ioctl() */
-static int snd_seq_ioctl_remove_events(client_t * client, unsigned long arg)
+static int snd_seq_ioctl_remove_events(client_t * client, void __user *arg)
 {
 	snd_seq_remove_events_t info;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	/*
@@ -1906,7 +1904,7 @@
 /*
  * get subscription info
  */
-static int snd_seq_ioctl_get_subscription(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_get_subscription(client_t *client, void __user *arg)
 {
 	int result;
 	client_t *sender = NULL;
@@ -1914,7 +1912,7 @@
 	snd_seq_port_subscribe_t subs;
 	subscribers_t *p;
 
-	if (copy_from_user(&subs, (void*)arg, sizeof(subs)))
+	if (copy_from_user(&subs, arg, sizeof(subs)))
 		return -EFAULT;
 
 	result = -EINVAL;
@@ -1935,7 +1933,7 @@
 	if (sender)
 		snd_seq_client_unlock(sender);
 	if (result >= 0) {
-		if (copy_to_user((void*)arg, &subs, sizeof(subs)))
+		if (copy_to_user(arg, &subs, sizeof(subs)))
 			return -EFAULT;
 	}
 	return result;
@@ -1945,7 +1943,7 @@
 /*
  * get subscription info - check only its presence
  */
-static int snd_seq_ioctl_query_subs(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_query_subs(client_t *client, void __user *arg)
 {
 	int result = -ENXIO;
 	client_t *cptr = NULL;
@@ -1955,7 +1953,7 @@
 	struct list_head *p;
 	int i;
 
-	if (copy_from_user(&subs, (void*)arg, sizeof(subs)))
+	if (copy_from_user(&subs, arg, sizeof(subs)))
 		return -EFAULT;
 
 	if ((cptr = snd_seq_client_use_ptr(subs.root.client)) == NULL)
@@ -2004,7 +2002,7 @@
 	if (cptr)
 		snd_seq_client_unlock(cptr);
 	if (result >= 0) {
-		if (copy_to_user((void*)arg, &subs, sizeof(subs)))
+		if (copy_to_user(arg, &subs, sizeof(subs)))
 			return -EFAULT;
 	}
 	return result;
@@ -2014,12 +2012,12 @@
 /*
  * query next client
  */
-static int snd_seq_ioctl_query_next_client(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_query_next_client(client_t *client, void __user *arg)
 {
 	client_t *cptr = NULL;
 	snd_seq_client_info_t info;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 
 	/* search for next client */
@@ -2037,7 +2035,7 @@
 	get_client_info(cptr, &info);
 	snd_seq_client_unlock(cptr);
 
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 	return 0;
 }
@@ -2045,13 +2043,13 @@
 /* 
  * query next port
  */
-static int snd_seq_ioctl_query_next_port(client_t *client, unsigned long arg)
+static int snd_seq_ioctl_query_next_port(client_t *client, void __user *arg)
 {
 	client_t *cptr;
 	client_port_t *port = NULL;
 	snd_seq_port_info_t info;
 
-	if (copy_from_user(&info, (void*)arg, sizeof(info)))
+	if (copy_from_user(&info, arg, sizeof(info)))
 		return -EFAULT;
 	cptr = snd_seq_client_use_ptr(info.addr.client);
 	if (cptr == NULL)
@@ -2071,7 +2069,7 @@
 	snd_seq_port_unlock(port);
 	snd_seq_client_unlock(cptr);
 
-	if (copy_to_user((void*)arg, &info, sizeof(info)))
+	if (copy_to_user(arg, &info, sizeof(info)))
 		return -EFAULT;
 	return 0;
 }
@@ -2080,7 +2078,7 @@
 
 static struct seq_ioctl_table {
 	unsigned int cmd;
-	int (*func)(client_t *client, unsigned long arg);
+	int (*func)(client_t *client, void __user * arg);
 } ioctl_tables[] = {
 	{ SNDRV_SEQ_IOCTL_SYSTEM_INFO, snd_seq_ioctl_system_info },
 	{ SNDRV_SEQ_IOCTL_RUNNING_MODE, snd_seq_ioctl_running_mode },
@@ -2114,7 +2112,7 @@
 	{ 0, NULL },
 };
 
-static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, unsigned long arg)
+static int snd_seq_do_ioctl(client_t *client, unsigned int cmd, void __user *arg)
 {
 	struct seq_ioctl_table *p;
 
@@ -2131,7 +2129,7 @@
 		return -EFAULT;
 	for (p = ioctl_tables; p->cmd; p++) {
 		if (p->cmd == cmd)
-			return p->func(client, arg);
+			return p->func(client, (void __user *) arg);
 	}
 	snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n",
 		   cmd, _IOC_TYPE(cmd), _IOC_NR(cmd));
@@ -2146,7 +2144,7 @@
 
 	snd_assert(client != NULL, return -ENXIO);
 		
-	return snd_seq_do_ioctl(client, cmd, arg);
+	return snd_seq_do_ioctl(client, cmd, (void __user *) arg);
 }
 
 
@@ -2315,7 +2313,7 @@
  * exported, called by kernel clients to perform same functions as with
  * userland ioctl() 
  */
-int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void *arg)
+int snd_seq_kernel_client_ctl(int clientid, unsigned int cmd, void __user *arg)
 {
 	client_t *client;
 	mm_segment_t fs;
@@ -2325,7 +2323,7 @@
 	if (client == NULL)
 		return -ENXIO;
 	fs = snd_enter_user();
-	result = snd_seq_do_ioctl(client, cmd, (unsigned long)arg);
+	result = snd_seq_do_ioctl(client, cmd, arg);
 	snd_leave_user(fs);
 	return result;
 }
diff -Nru a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
--- a/sound/core/seq/seq_device.c	Sun Feb 16 05:47:41 2003
+++ b/sound/core/seq/seq_device.c	Sat May 17 12:39:14 2003
@@ -131,7 +131,6 @@
 {
 #ifdef CONFIG_KMOD
 	struct list_head *head;
-	char modname[64];
 
 	down(&ops_mutex);
 	list_for_each(head, &opslist) {
@@ -141,8 +140,7 @@
 			ops->used++;
 			up(&ops_mutex);
 			ops->driver |= DRIVER_REQUESTED;
-			sprintf(modname, "snd-%s", ops->id);
-			request_module(modname);
+			request_module("snd-%s", ops->id);
 			down(&ops_mutex);
 			ops->used--;
 		}
diff -Nru a/sound/core/sound.c b/sound/core/sound.c
--- a/sound/core/sound.c	Fri Apr 18 11:18:17 2003
+++ b/sound/core/sound.c	Sat May 17 12:39:14 2003
@@ -79,7 +79,6 @@
  */
 void snd_request_card(int card)
 {
-	char str[32];
 	int locked;
 
 	read_lock(&snd_card_rwlock);
@@ -89,8 +88,7 @@
 		return;
 	if (card < 0 || card >= cards_limit)
 		return;
-	sprintf(str, "snd-card-%i", card);
-	request_module(str);
+	request_module("snd-card-%i", card);
 }
 
 static void snd_request_other(int minor)
@@ -323,13 +321,8 @@
 
 static int __init alsa_sound_init(void)
 {
-#ifdef CONFIG_DEVFS_FS
 	short controlnum;
-	char controlname[24];
-#endif
-#ifdef CONFIG_SND_OSSEMUL
-	int err;
-#endif
+	int err = 0;
 	int card;
 
 	snd_ecards_limit = cards_limit;
@@ -356,21 +349,19 @@
 #ifdef CONFIG_SND_OSSEMUL
 	snd_info_minor_register();
 #endif
-#ifdef CONFIG_DEVFS_FS
+
 	for (controlnum = 0; controlnum < cards_limit; controlnum++) {
-		sprintf(controlname, "snd/controlC%d", controlnum);
-		devfs_register(NULL, controlname, DEVFS_FL_DEFAULT,
-				major, controlnum<<5, device_mode | S_IFCHR,
-				&snd_fops, NULL);
+		devfs_mk_cdev(MKDEV(major, controlnum<<5),
+			device_mode | S_IFCHR, "snd/controlC%d", controlnum);
 	}
-#endif
+
 #ifndef MODULE
 	printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n");
 #endif
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) && defined(CONFIG_APM)
 	pm_init();
 #endif
-	return 0;
+	return err;
 }
 
 static void __exit alsa_sound_exit(void)
diff -Nru a/sound/oss/cs4281/cs4281m.c b/sound/oss/cs4281/cs4281m.c
--- a/sound/oss/cs4281/cs4281m.c	Thu Apr 24 03:36:08 2003
+++ b/sound/oss/cs4281/cs4281m.c	Sat May 17 14:09:50 2003
@@ -1944,8 +1944,8 @@
 		len -= x;
 	}
 	CS_DBGOUT(CS_WAVE_WRITE, 4, printk(KERN_INFO
-		"cs4281: clear_advance(): memset %d at 0x%.8x for %d size \n",
-			(unsigned)c, (unsigned)((char *) buf) + bptr, len));
+		"cs4281: clear_advance(): memset %d at %p for %d size \n",
+			(unsigned)c, ((char *) buf) + bptr, len));
 	memset(((char *) buf) + bptr, c, len);
 }
 
@@ -1980,9 +1980,8 @@
 				wake_up(&s->dma_adc.wait);
 		}
 		CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
-			"cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",
-				(unsigned)s, s->dma_adc.hwptr, 
-				s->dma_adc.total_bytes, s->dma_adc.count));
+			"cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
+				s, s->dma_adc.hwptr, s->dma_adc.total_bytes, s->dma_adc.count));
 	}
 	// update DAC pointer 
 	//
@@ -2014,11 +2013,10 @@
 				// Continue to play silence until the _release.
 				//
 				CS_DBGOUT(CS_WAVE_WRITE, 6, printk(KERN_INFO
-					"cs4281: cs4281_update_ptr(): memset %d at 0x%.8x for %d size \n",
+					"cs4281: cs4281_update_ptr(): memset %d at %p for %d size \n",
 						(unsigned)(s->prop_dac.fmt & 
 						(AFMT_U8 | AFMT_U16_LE)) ? 0x80 : 0, 
-						(unsigned)s->dma_dac.rawbuf, 
-						s->dma_dac.dmasize));
+						s->dma_dac.rawbuf, s->dma_dac.dmasize));
 				memset(s->dma_dac.rawbuf,
 				       (s->prop_dac.
 					fmt & (AFMT_U8 | AFMT_U16_LE)) ?
@@ -2049,9 +2047,8 @@
 			}
 		}
 		CS_DBGOUT(CS_PARMS, 8, printk(KERN_INFO
-			"cs4281: cs4281_update_ptr(): s=0x%.8x hwptr=%d total_bytes=%d count=%d \n",
-				(unsigned) s, s->dma_dac.hwptr, 
-				s->dma_dac.total_bytes, s->dma_dac.count));
+			"cs4281: cs4281_update_ptr(): s=%p hwptr=%d total_bytes=%d count=%d \n",
+				s, s->dma_dac.hwptr, s->dma_dac.total_bytes, s->dma_dac.count));
 	}
 }
 
@@ -2182,8 +2179,7 @@
 
 	VALIDATE_STATE(s);
 	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
-		 "cs4281: mixer_ioctl(): s=0x%.8x cmd=0x%.8x\n",
-			 (unsigned) s, cmd));
+		 "cs4281: mixer_ioctl(): s=%p cmd=0x%.8x\n", s, cmd));
 #if CSDEBUG
 	cs_printioctl(cmd);
 #endif
@@ -2748,9 +2744,8 @@
 	CS_DBGOUT(CS_FUNCTION, 2,
 		  printk(KERN_INFO "cs4281: CopySamples()+ "));
 	CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
-		 " dst=0x%x src=0x%x count=%d iChannels=%d fmt=0x%x\n",
-			 (unsigned) dst, (unsigned) src, (unsigned) count,
-			 (unsigned) iChannels, (unsigned) fmt));
+		 " dst=%p src=%p count=%d iChannels=%d fmt=0x%x\n",
+			 dst, src, (unsigned) count, (unsigned) iChannels, (unsigned) fmt));
 
 	// Gershwin does format conversion in hardware so normally
 	// we don't do any host based coversion. The data formatter
@@ -2830,9 +2825,9 @@
 	void *src = hwsrc;	//default to the standard destination buffer addr
 
 	CS_DBGOUT(CS_FUNCTION, 6, printk(KERN_INFO
-		"cs_copy_to_user()+ fmt=0x%x fmt_o=0x%x cnt=%d dest=0x%.8x\n",
+		"cs_copy_to_user()+ fmt=0x%x fmt_o=0x%x cnt=%d dest=%p\n",
 			s->prop_adc.fmt, s->prop_adc.fmt_original,
-			(unsigned) cnt, (unsigned) dest));
+			(unsigned) cnt, dest));
 
 	if (cnt > s->dma_adc.dmasize) {
 		cnt = s->dma_adc.dmasize;
@@ -2877,7 +2872,7 @@
 	unsigned copied = 0;
 
 	CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
-		  printk(KERN_INFO "cs4281: cs4281_read()+ %d \n", count));
+		  printk(KERN_INFO "cs4281: cs4281_read()+ %Zu \n", count));
 
 	VALIDATE_STATE(s);
 	if (ppos != &file->f_pos)
@@ -2900,7 +2895,7 @@
 //
 	while (count > 0) {
 		CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
-			"_read() count>0 count=%d .count=%d .swptr=%d .hwptr=%d \n",
+			"_read() count>0 count=%Zu .count=%d .swptr=%d .hwptr=%d \n",
 				count, s->dma_adc.count,
 				s->dma_adc.swptr, s->dma_adc.hwptr));
 		spin_lock_irqsave(&s->lock, flags);
@@ -2957,11 +2952,10 @@
 		// the "cnt" is the number of bytes to read.
 
 		CS_DBGOUT(CS_WAVE_READ, 2, printk(KERN_INFO
-			"_read() copy_to cnt=%d count=%d ", cnt, count));
+			"_read() copy_to cnt=%d count=%Zu ", cnt, count));
 		CS_DBGOUT(CS_WAVE_READ, 8, printk(KERN_INFO
-			 " .dmasize=%d .count=%d buffer=0x%.8x ret=%d\n",
-				 s->dma_adc.dmasize, s->dma_adc.count,
-				 (unsigned) buffer, ret));
+			 " .dmasize=%d .count=%d buffer=%p ret=%Zd\n",
+				 s->dma_adc.dmasize, s->dma_adc.count, buffer, ret));
 
 		if (cs_copy_to_user
 		    (s, buffer, s->dma_adc.rawbuf + swptr, cnt, &copied))
@@ -2977,7 +2971,7 @@
 		start_adc(s);
 	}
 	CS_DBGOUT(CS_FUNCTION | CS_WAVE_READ, 2,
-		  printk(KERN_INFO "cs4281: cs4281_read()- %d\n", ret));
+		  printk(KERN_INFO "cs4281: cs4281_read()- %Zd\n", ret));
 	return ret;
 }
 
@@ -2993,7 +2987,7 @@
 	int cnt;
 
 	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
-		  printk(KERN_INFO "cs4281: cs4281_write()+ count=%d\n",
+		  printk(KERN_INFO "cs4281: cs4281_write()+ count=%Zu\n",
 			 count));
 	VALIDATE_STATE(s);
 
@@ -3049,7 +3043,7 @@
 		start_dac(s);
 	}
 	CS_DBGOUT(CS_FUNCTION | CS_WAVE_WRITE, 2,
-		  printk(KERN_INFO "cs4281: cs4281_write()- %d\n", ret));
+		  printk(KERN_INFO "cs4281: cs4281_write()- %Zd\n", ret));
 	return ret;
 }
 
@@ -3170,8 +3164,7 @@
 	int val, mapped, ret;
 
 	CS_DBGOUT(CS_FUNCTION, 4, printk(KERN_INFO
-		 "cs4281: cs4281_ioctl(): file=0x%.8x cmd=0x%.8x\n",
-			 (unsigned) file, cmd));
+		 "cs4281: cs4281_ioctl(): file=%p cmd=0x%.8x\n", file, cmd));
 #if CSDEBUG
 	cs_printioctl(cmd);
 #endif
@@ -3601,8 +3594,8 @@
 	    (struct cs4281_state *) file->private_data;
 
 	CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 2, printk(KERN_INFO
-		 "cs4281: cs4281_release(): inode=0x%.8x file=0x%.8x f_mode=%d\n",
-			 (unsigned) inode, (unsigned) file, file->f_mode));
+		 "cs4281: cs4281_release(): inode=%p file=%p f_mode=%d\n",
+			 inode, file, file->f_mode));
 
 	VALIDATE_STATE(s);
 
@@ -3636,8 +3629,8 @@
 	struct list_head *entry;
 
 	CS_DBGOUT(CS_FUNCTION | CS_OPEN, 2, printk(KERN_INFO
-		"cs4281: cs4281_open(): inode=0x%.8x file=0x%.8x f_mode=0x%x\n",
-			(unsigned) inode, (unsigned) file, file->f_mode));
+		"cs4281: cs4281_open(): inode=%p file=%p f_mode=0x%x\n",
+			inode, file, file->f_mode));
 
 	list_for_each(entry, &cs4281_devs)
 	{
@@ -4347,10 +4340,8 @@
 
 	CS_DBGOUT(CS_INIT, 2,
 		  printk(KERN_INFO
-			 "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=0x%.8x pBA1=0x%.8x \n",
-			 (unsigned) temp1, (unsigned) temp2,
-			 (unsigned) s->pBA0, (unsigned) s->pBA1));
-
+			 "cs4281: probe() BA0=0x%.8x BA1=0x%.8x pBA0=%p pBA1=%p \n",
+			 (unsigned) temp1, (unsigned) temp2, s->pBA0, s->pBA1));
 	CS_DBGOUT(CS_INIT, 2,
 		  printk(KERN_INFO
 			 "cs4281: probe() pBA0phys=0x%.8x pBA1phys=0x%.8x\n",
@@ -4397,15 +4388,13 @@
 	if (pmdev)
 	{
 		CS_DBGOUT(CS_INIT | CS_PM, 4, printk(KERN_INFO
-			 "cs4281: probe() pm_register() succeeded (0x%x).\n",
-				(unsigned)pmdev));
+			 "cs4281: probe() pm_register() succeeded (%p).\n", pmdev));
 		pmdev->data = s;
 	}
 	else
 	{
 		CS_DBGOUT(CS_INIT | CS_PM | CS_ERROR, 0, printk(KERN_INFO
-			 "cs4281: probe() pm_register() failed (0x%x).\n",
-				(unsigned)pmdev));
+			 "cs4281: probe() pm_register() failed (%p).\n", pmdev));
 		s->pm.flags |= CS4281_PM_NOT_REGISTERED;
 	}
 #endif
diff -Nru a/sound/oss/cs4281/cs4281pm-24.c b/sound/oss/cs4281/cs4281pm-24.c
--- a/sound/oss/cs4281/cs4281pm-24.c	Mon Nov 18 04:40:55 2002
+++ b/sound/oss/cs4281/cs4281pm-24.c	Sat May 17 14:09:50 2003
@@ -46,8 +46,8 @@
 	struct cs4281_state *state;
 
 	CS_DBGOUT(CS_PM, 2, printk(KERN_INFO 
-		"cs4281: cs4281_pm_callback dev=0x%x rqst=0x%x state=%d\n",
-			(unsigned)dev,(unsigned)rqst,(unsigned)data));
+		"cs4281: cs4281_pm_callback dev=%p rqst=0x%x state=%p\n",
+			dev,(unsigned)rqst,data));
 	state = (struct cs4281_state *) dev->data;
 	if (state) {
 		switch(rqst) {
diff -Nru a/sound/oss/i810_audio.c b/sound/oss/i810_audio.c
--- a/sound/oss/i810_audio.c	Thu Apr 24 03:36:42 2003
+++ b/sound/oss/i810_audio.c	Sat Apr 26 07:08:06 2003
@@ -66,16 +66,19 @@
  *
  *	This driver is cursed. (Ben LaHaise)
  *
+ *  ICH 3 caveats
+ *	Intel errata #7 for ICH3 IO. We need to disable SMI stuff
+ *	when codec probing. [Not Yet Done]
  *
  *  ICH 4 caveats
  *
- *      The ICH4 has the feature, that the codec ID doesn't have to be 
- *      congruent with the IO connection.
+ *	The ICH4 has the feature, that the codec ID doesn't have to be 
+ *	congruent with the IO connection.
  * 
- *      Therefore, from driver version 0.23 on, there is a "codec ID" <->
- *      "IO register base offset" mapping (card->ac97_id_map) field.
+ *	Therefore, from driver version 0.23 on, there is a "codec ID" <->
+ *	"IO register base offset" mapping (card->ac97_id_map) field.
  *   
- *      Juergen "George" Sawinski (jsaw) 
+ *	Juergen "George" Sawinski (jsaw) 
  */
  
 #include <linux/module.h>
@@ -639,6 +642,10 @@
 {
 	int	aud_reg;
 	struct ac97_codec *codec = state->card->ac97_codec[0];
+
+	/* No codec, no setup */
+	if(codec == NULL)
+		return;
 
 	aud_reg = i810_ac97_get(codec, AC97_EXTENDED_STATUS);
 	aud_reg |= AC97_EA_PRI | AC97_EA_PRJ | AC97_EA_PRK;
diff -Nru a/sound/oss/opl3sa2.c b/sound/oss/opl3sa2.c
--- a/sound/oss/opl3sa2.c	Sun Apr  6 15:38:31 2003
+++ b/sound/oss/opl3sa2.c	Tue May  6 07:44:10 2003
@@ -353,7 +353,8 @@
 	}
 }
 
-
+/* Currently only used for power management */
+#ifdef CONFIG_PM
 static void opl3sa2_mixer_restore(opl3sa2_state_t* devc)
 {
 	if (devc) {
@@ -366,7 +367,7 @@
 		}
 	}
 }
-
+#endif
 
 static inline void arg_to_vol_mono(unsigned int vol, int* value)
 {
@@ -961,7 +962,6 @@
 	spin_unlock_irqrestore(&opl3sa2_lock,flags);
 	return 0;
 }
-#endif /* CONFIG_PM */
 
 static int opl3sa2_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
 {
@@ -976,6 +976,7 @@
 	}
 	return 0;
 }
+#endif /* CONFIG_PM */
 
 /*
  * Install OPL3-SA2 based card(s).
@@ -1127,10 +1128,11 @@
 	int card;
 
 	for(card = 0; card < opl3sa2_cards_num; card++) {
+#ifdef CONFIG_PM
 		if (opl3sa2_state[card].pmdev)
 			pm_unregister(opl3sa2_state[card].pmdev);
-
-	        if(opl3sa2_state[card].cfg_mpu.slots[1] != -1) {
+#endif
+	        if (opl3sa2_state[card].cfg_mpu.slots[1] != -1) {
 			unload_opl3sa2_mpu(&opl3sa2_state[card].cfg_mpu);
  		}
 		unload_opl3sa2_mss(&opl3sa2_state[card].cfg_mss);
diff -Nru a/sound/oss/soundcard.c b/sound/oss/soundcard.c
--- a/sound/oss/soundcard.c	Thu Apr  3 14:35:48 2003
+++ b/sound/oss/soundcard.c	Sat May 17 12:39:14 2003
@@ -216,9 +216,7 @@
 	case SND_DEV_CTL:
 		dev >>= 4;
 		if (dev >= 0 && dev < MAX_MIXER_DEV && mixer_devs[dev] == NULL) {
-			char modname[20];
-			sprintf(modname, "mixer%d", dev);
-			request_module(modname);
+			request_module("mixer%d", dev);
 		}
 		if (dev && (dev >= num_mixers || mixer_devs[dev] == NULL))
 			return -ENXIO;
@@ -318,9 +316,7 @@
  		return -ENXIO;
  	/* Try to load the mixer... */
  	if (mixer_devs[mixdev] == NULL) {
- 		char modname[20];
- 		sprintf(modname, "mixer%d", mixdev);
- 		request_module(modname);
+ 		request_module("mixer%d", mixdev);
  	}
  	if (mixdev >= num_mixers || !mixer_devs[mixdev])
  		return -ENXIO;
@@ -549,7 +545,6 @@
 static int __init oss_init(void)
 {
 	int             err;
-	char name_buf[32];
 	int i, j;
 	
 	/* drag in sound_syms.o */
@@ -573,19 +568,18 @@
 	sound_dmap_flag = (dmabuf > 0 ? 1 : 0);
 
 	for (i = 0; i < sizeof (dev_list) / sizeof *dev_list; i++) {
-		sprintf(name_buf, "sound/%s", dev_list[i].name);
-		devfs_register (NULL, name_buf, DEVFS_FL_NONE,
-			SOUND_MAJOR, dev_list[i].minor,
-			S_IFCHR | dev_list[i].mode,
-			&oss_sound_fops, NULL);
+		devfs_mk_cdev(MKDEV(SOUND_MAJOR, dev_list[i].minor),
+				S_IFCHR | dev_list[i].mode,
+				"sound/%s", dev_list[i].name);
+
 		if (!dev_list[i].num)
 			continue;
+
 		for (j = 1; j < *dev_list[i].num; j++) {
-			sprintf(name_buf, "sound/%s%d", dev_list[i].name, j);
-			devfs_register (NULL, name_buf, DEVFS_FL_NONE,
-				SOUND_MAJOR, dev_list[i].minor + (j * 0x10),
-				S_IFCHR | dev_list[i].mode,
-				&oss_sound_fops, NULL);
+			devfs_mk_cdev(MKDEV(SOUND_MAJOR,
+						dev_list[i].minor + (j*0x10)),
+					S_IFCHR | dev_list[i].mode,
+					"sound/%s%d", dev_list[i].name, j);
 		}
 	}
 
diff -Nru a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
--- a/sound/pci/emu10k1/emufx.c	Thu Apr 10 03:28:13 2003
+++ b/sound/pci/emu10k1/emufx.c	Sat May 17 14:09:51 2003
@@ -2206,7 +2206,7 @@
 	unsigned short fxbus_mask, extin_mask, extout_mask;
 	int res;
 
-	memset(info, 0, sizeof(info));
+	memset(info, 0, sizeof(*info));
 	info->card = emu->card_type;
 	info->internal_tram_size = emu->fx8010.itram_size;
 	info->external_tram_size = emu->fx8010.etram_size;
diff -Nru a/sound/sound_core.c b/sound/sound_core.c
--- a/sound/sound_core.c	Fri Apr 18 11:59:04 2003
+++ b/sound/sound_core.c	Sat May 17 12:39:14 2003
@@ -168,8 +168,8 @@
 	else
 		sprintf(s->name, "sound/%s%d", name, r / SOUND_STEP);
 
-	devfs_register(NULL, s->name, 0, SOUND_MAJOR, s->unit_minor,
-			S_IFCHR | mode, fops, NULL);
+	devfs_mk_cdev(MKDEV(SOUND_MAJOR, s->unit_minor),
+			S_IFCHR | mode, s->name);
 	return r;
 
  fail:
@@ -500,8 +500,6 @@
 	if (s)
 		new_fops = fops_get(s->unit_fops);
 	if (!new_fops) {
-		char mod[32];
-	
 		spin_unlock(&sound_loader_lock);
 		/*
 		 *  Please, don't change this order or code.
@@ -510,10 +508,8 @@
 		 *  ALSA toplevel modules for soundcards, thus we need
 		 *  load them at first.	  [Jaroslav Kysela <perex@jcu.cz>]
 		 */
-		sprintf(mod, "sound-slot-%i", unit>>4);
-		request_module(mod);
-		sprintf(mod, "sound-service-%i-%i", unit>>4, chain);
-		request_module(mod);
+		request_module("sound-slot-%i", unit>>4);
+		request_module("sound-service-%i-%i", unit>>4, chain);
 		spin_lock(&sound_loader_lock);
 		s = __look_for_unit(chain, unit);
 		if (s)
